false
false
0

Contract Address Details

0xa76906EfBA6dFAe155FfC4c0eb36cDF0A28ae24D

Contract Name
VoterWhitelister
Creator
0x493044–a7586e at 0x453b91–847986
Balance
0 SGB
Tokens
Fetching tokens...
Transactions
60,099 Transactions
Transfers
0 Transfers
Gas Used
42,184,792,557
Last Balance Update
58368508
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
VoterWhitelister




Optimization enabled
true
Compiler version
v0.7.6+commit.7338295f




Optimization runs
200
EVM Version
default




Verified at
2021-09-17T13:57:26.715937Z

Constructor Arguments

000000000000000000000000493044fbbaa7f9f78379864fa88accaff6a7586e00000000000000000000000010000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000064

Arg [0] (address) : 0x493044fbbaa7f9f78379864fa88accaff6a7586e
Arg [1] (address) : 0x1000000000000000000000000000000000000003
Arg [2] (uint256) : 100

              

Contract source code

// Sources flattened with hardhat v2.3.0 https://hardhat.org
pragma abicoder v2;

// File contracts/userInterfaces/IVoterWhitelister.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;

interface IVoterWhitelister {
    /**
     * Raised when an account is removed from the voter whitelist.
     */
    event VoterWhitelisted(address voter, uint256 ftsoIndex);

    /**
     * Raised when an account is removed from the voter whitelist.
     */
    event VoterRemovedFromWhitelist(address voter, uint256 ftsoIndex);

    /**
     * Request to whitelist `_voter` account to ftso at `_ftsoIndex`. Will revert if vote power too low.
     * May be called by any address.
     */
    function requestWhitelistingVoter(address _voter, uint256 _ftsoIndex) external;

    /**
     * Request to whitelist `_voter` account to all active ftsos.
     * May be called by any address.
     * It returns an array of supported ftso indices and success flag per index.
     */
    function requestFullVoterWhitelisting(
        address _voter
    )
        external
        returns (
            uint256[] memory _supportedIndices,
            bool[] memory _success
        );

    /**
     * Maximum number of voters in the whitelist for a new FTSO.
     */
    function defaultMaxVotersForFtso() external view returns (uint256);

    /**
     * Maximum number of voters in the whitelist for FTSO at index `_ftsoIndex`.
     */
    function maxVotersForFtso(uint256 _ftsoIndex) external view returns (uint256);

    /**
     * Get whitelisted price providers for ftso with `_symbol`
     */
    function getFtsoWhitelistedPriceProvidersBySymbol(string memory _symbol) external view returns (address[] memory);

    /**
     * Get whitelisted price providers for ftso at `_ftsoIndex`
     */
    function getFtsoWhitelistedPriceProviders(uint256 _ftsoIndex) external view returns (address[] memory);
}


// File contracts/utils/interface/IIVoterWhitelister.sol

//
pragma solidity 0.7.6;

interface IIVoterWhitelister is IVoterWhitelister {
    /**
     * Set the maximum number of voters in the whitelist for FTSO at index `_ftsoIndex`.
     * Possibly removes several voters with the least votepower from the whitelist.
     * Only governance can call this method.
     */
    function setMaxVotersForFtso(uint256 _ftsoIndex, uint256 _newMaxVoters) external;

    /**
     * Set the maximum number of voters in the whitelist for a new FTSO.
     * Only governance can call this method.
     */
    function setDefaultMaxVotersForFtso(uint256 _defaultMaxVotersForFtso) external;

    /**
     * Create whitelist with default size for ftso.
     * Only ftso manager can call this method.
     */
    function addFtso(uint256 _ftsoIndex) external;

    /**
     * Clear whitelist for ftso at `_ftsoIndex`.
     * Only ftso manager can call this method.
     */
    function removeFtso(uint256 _ftsoIndex) external;

    /**
     * Remove `_trustedAddress` from whitelist for ftso at `_ftsoIndex`.
     */
    function removeTrustedAddressFromWhitelist(address _trustedAddress, uint256 _ftsoIndex) external;
}


// File contracts/genesis/interface/IFtsoGenesis.sol

//
pragma solidity 0.7.6;


interface IFtsoGenesis {

    /**
     * @notice Submits price hash for current epoch - only price submitter
     * @param _sender               Sender address
     * @param _epochId              Target epoch id to which hashes are submitted
     * @param _hash                 Hashed price and random number
     * @notice Emits PriceHashSubmitted event.
     */
    function submitPriceHashSubmitter(address _sender, uint256 _epochId, bytes32 _hash) external;

    /**
     * @notice Reveals submitted price during epoch reveal period - only price submitter
     * @param _voter                Voter address
     * @param _epochId              Id of the epoch in which the price hash was submitted
     * @param _price                Submitted price in USD
     * @param _random               Submitted random number
     * @notice The hash of _price and _random must be equal to the submitted hash
     * @notice Emits PriceRevealed event
     */
    function revealPriceSubmitter(
        address _voter,
        uint256 _epochId,
        uint256 _price,
        uint256 _random,
        uint256 _wNatVP
    ) external;

    /**
     * @notice Get (and cache) wNat vote power for specified voter and given epoch id
     * @param _voter                Voter address
     * @param _epochId              Id of the epoch in which the price hash was submitted
     * @return wNat vote power
     */
    function wNatVotePowerCached(address _voter, uint256 _epochId) external returns (uint256);
}


// File contracts/genesis/interface/IFtsoRegistryGenesis.sol

//
pragma solidity 0.7.6;

interface IFtsoRegistryGenesis {

    function getFtsos(uint256[] memory _indices) external view returns(IFtsoGenesis[] memory _ftsos);
}


// File contracts/userInterfaces/IPriceSubmitter.sol

//
pragma solidity 0.7.6;


interface IPriceSubmitter {
    /**
     * Event emitted when price hashes were submitted through PriceSubmitter.
     * @param submitter the address of the sender
     * @param epochId current price epoch id
     * @param ftsos array of ftsos that correspond to the indexes in call
     * @param hashes the submitted hashes
     * @param timestamp current block timestamp
     */
    event PriceHashesSubmitted(
        address indexed submitter,
        uint256 indexed epochId,
        IFtsoGenesis[] ftsos,
        bytes32[] hashes,
        uint256 timestamp
    );

    /**
     * Event emitted when prices were revealed through PriceSubmitter.
     * @param voter the address of the sender
     * @param epochId id of the epoch in which the price hash was submitted
     * @param ftsos array of ftsos that correspond to the indexes in the call
     * @param prices the submitted prices
     * @param timestamp current block timestamp
     */
    event PricesRevealed(
        address indexed voter,
        uint256 indexed epochId,
        IFtsoGenesis[] ftsos,
        uint256[] prices,
        uint256[] randoms,
        uint256 timestamp
    );

    /**
     * @notice Submits price hashes for current epoch
     * @param _epochId              Target epoch id to which hashes are submitted
     * @param _ftsoIndices          List of ftso indices
     * @param _hashes               List of hashed price and random number
     * @notice Emits PriceHashesSubmitted event
     */
    function submitPriceHashes(
        uint256 _epochId,
        uint256[] memory _ftsoIndices,
        bytes32[] memory _hashes
    ) external;

    /**
     * @notice Reveals submitted prices during epoch reveal period
     * @param _epochId              Id of the epoch in which the price hashes was submitted
     * @param _ftsoIndices          List of ftso indices
     * @param _prices               List of submitted prices in USD
     * @param _randoms              List of submitted random numbers
     * @notice The hash of _price and _random must be equal to the submitted hash
     * @notice Emits PricesRevealed event
     */
    function revealPrices(
        uint256 _epochId,
        uint256[] memory _ftsoIndices,
        uint256[] memory _prices,
        uint256[] memory _randoms
    ) external;

    /**
     * Returns bitmap of all ftso's for which `_voter` is allowed to submit prices/hashes.
     * If voter is allowed to vote for ftso at index (see *_FTSO_INDEX), the corrsponding
     * bit in the result will be 1.
     */
    function voterWhitelistBitmap(address _voter) external view returns (uint256);

    function getVoterWhitelister() external view returns (address);
    function getFtsoRegistry() external view returns (IFtsoRegistryGenesis);
    function getFtsoManager() external view returns (address);
}


// File contracts/genesis/interface/IIPriceSubmitter.sol

//
pragma solidity 0.7.6;

interface IIPriceSubmitter is IPriceSubmitter {

    /**
     * Sets ftso registry, voter whitelist and ftso manager contracts.
     * Only governance can call this method.
     * If replacing the registry or the whitelist and the old one is not empty, make sure to replicate the state,
     * otherwise internal whitelist bitmaps won't match.
     */
    function setContractAddresses(
        IFtsoRegistryGenesis _ftsoRegistry,
        address _voterWhitelister,
        address _ftsoManager
    ) external;

    /**
     * Set trusted addresses that are always allowed to submit and reveal.
     * Only ftso manager can call this method.
     */
    function setTrustedAddresses(address[] memory _trustedAddresses) external;

    /**
     * Called from whitelister when new voter has been whitelisted.
     */
    function voterWhitelisted(address _voter, uint256 _ftsoIndex) external;

    /**
     * Called from whitelister when one or more voters have been removed.
     */
    function votersRemovedFromWhitelist(address[] memory _voters, uint256 _ftsoIndex) external;

    /**
     * Returns a list of trusted addresses that are always allowed to submit and reveal.
     */
    function getTrustedAddresses() external view returns (address[] memory);
}


// File contracts/governance/implementation/GovernedBase.sol

//
pragma solidity 0.7.6;


/**
 * @title Governed Base
 * @notice This abstract base class defines behaviors for a governed contract.
 * @dev This class is abstract so that specific behaviors can be defined for the constructor.
 *   Contracts should not be left ungoverned, but not all contract will have a constructor
 *   (for example those pre-defined in genesis).
 **/
abstract contract GovernedBase {
    address public governance;
    address public proposedGovernance;
    bool private initialised;

    event GovernanceProposed(address proposedGovernance);
    event GovernanceUpdated (address oldGovernance, address newGoveranance);

    modifier onlyGovernance () {
        require (msg.sender == governance, "only governance");
        _;
    }

    constructor(address _governance) {
        if (_governance != address(0)) {
            initialise(_governance);
        }
    }

    /**
     * @notice First of a two step process for turning over governance to another address.
     * @param _governance The address to propose to receive governance role.
     * @dev Must hold governance to propose another address.
     */
    function proposeGovernance(address _governance) external onlyGovernance {
        proposedGovernance = _governance;
        emit GovernanceProposed(_governance);
    }

    /**
     * @notice Once proposed, claimant can claim the governance role as the second of a two-step process.
     */
    function claimGovernance() external {
        require(msg.sender == proposedGovernance, "not claimaint");

        emit GovernanceUpdated(governance, proposedGovernance);
        governance = proposedGovernance;
        proposedGovernance = address(0);
    }

    /**
     * @notice In a one-step process, turn over governance to another address.
     * @dev Must hold governance to transfer.
     */
    function transferGovernance(address _governance) external onlyGovernance {
        emit GovernanceUpdated(governance, _governance);
        governance = _governance;
        proposedGovernance = address(0);
    }

    /**
     * @notice Initialize the governance address if not first initialized.
     */
    function initialise(address _governance) public virtual {
        require(initialised == false, "initialised != false");

        initialised = true;
        emit GovernanceUpdated(governance, _governance);
        governance = _governance;
        proposedGovernance = address(0);
    }
}


// File contracts/governance/implementation/Governed.sol

//
pragma solidity 0.7.6;

/**
 * @title Governed
 * @dev For deployed, governed contracts, enforce a non-zero address at create time.
 **/
contract Governed is GovernedBase {
    constructor(address _governance) GovernedBase(_governance) {
        require(_governance != address(0), "_governance zero");
    }
}


// File @openzeppelin/contracts/token/ERC20/[email protected]

//

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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


// File contracts/userInterfaces/IGovernanceVotePower.sol

//
pragma solidity 0.7.6;

interface IGovernanceVotePower {
    /**
     * @notice Delegate all governance vote power of `msg.sender` to `_to`.
     * @param _to The address of the recipient
     **/
    function delegate(address _to) external;

    /**
     * @notice Undelegate all governance vote power that `msg.sender` has delegated.
     **/
    function undelegate() external;

    /**
    * @notice Get the governance vote power of `_who` at block `_blockNumber`
    * @param _who The address to get voting power.
    * @param _blockNumber The block number at which to fetch.
    * @return Governance vote power of `_who` at `_blockNumber`.
    */
    function votePowerOfAt(address _who, uint256 _blockNumber) external view returns(uint256);
}


// File contracts/userInterfaces/IVPContractEvents.sol

//
pragma solidity 0.7.6;

interface IVPContractEvents {
    /**
     * Event triggered when an account delegates or undelegates another account.
     * Definition: `votePowerFromTo(from, to)` is `changed` from `priorVotePower` to `newVotePower`.
     * For undelegation, `newVotePower` is 0.
     *
     * Note: the event is always emitted from VPToken's `writeVotePowerContract`.
     */
    event Delegate(address indexed from, address indexed to, uint256 priorVotePower, uint256 newVotePower);

    /**
     * Event triggered only when account `delegator` revokes delegation to `delegatee`
     * for a single block in the past (typically the current vote block).
     *
     * Note: the event is always emitted from VPToken's `writeVotePowerContract` and/or `readVotePowerContract`.
     */
    event Revoke(address indexed delegator, address indexed delegatee, uint256 votePower, uint256 blockNumber);
}


// File contracts/userInterfaces/IVPToken.sol

//
pragma solidity 0.7.6;



interface IVPToken is IERC20 {
    /**
     * @notice Delegate by percentage `_bips` of voting power to `_to` from `msg.sender`.
     * @param _to The address of the recipient
     * @param _bips The percentage of voting power to be delegated expressed in basis points (1/100 of one percent).
     *   Not cummulative - every call resets the delegation value (and value of 0 undelegates `to`).
     **/
    function delegate(address _to, uint256 _bips) external;

    /**
     * @notice Explicitly delegate `_amount` of voting power to `_to` from `msg.sender`.
     * @param _to The address of the recipient
     * @param _amount An explicit vote power amount to be delegated.
     *   Not cummulative - every call resets the delegation value (and value of 0 undelegates `to`).
     **/
    function delegateExplicit(address _to, uint _amount) external;

    /**
    * @notice Revoke all delegation from sender to `_who` at given block.
    *    Only affects the reads via `votePowerOfAtCached()` in the block `_blockNumber`.
    *    Block `_blockNumber` must be in the past.
    *    This method should be used only to prevent rogue delegate voting in the current voting block.
    *    To stop delegating use delegate/delegateExplicit with value of 0 or undelegateAll/undelegateAllExplicit.
    * @param _who Address of the delegatee
    * @param _blockNumber The block number at which to revoke delegation.
    */
    function revokeDelegationAt(address _who, uint _blockNumber) external;

    /**
     * @notice Undelegate all voting power for delegates of `msg.sender`
     *    Can only be used with percentage delegation.
     *    Does not reset delegation mode back to NOTSET.
     **/
    function undelegateAll() external;

    /**
     * @notice Undelegate all explicit vote power by amount delegates for `msg.sender`.
     *    Can only be used with explicit delegation.
     *    Does not reset delegation mode back to NOTSET.
     * @param _delegateAddresses Explicit delegation does not store delegatees' addresses,
     *   so the caller must supply them.
     * @return The amount still delegated (in case the list of delegates was incomplete).
     */
    function undelegateAllExplicit(address[] memory _delegateAddresses) external returns (uint256);


    /**
     * @dev Should be compatible with ERC20 method
     */
    function name() external view returns (string memory);

    /**
     * @dev Should be compatible with ERC20 method
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Should be compatible with ERC20 method
     */
    function decimals() external view returns (uint8);


    /**
     * @notice Total amount of tokens at a specific `_blockNumber`.
     * @param _blockNumber The block number when the totalSupply is queried
     * @return The total amount of tokens at `_blockNumber`
     **/
    function totalSupplyAt(uint _blockNumber) external view returns(uint256);

    /**
     * @dev Queries the token balance of `_owner` at a specific `_blockNumber`.
     * @param _owner The address from which the balance will be retrieved.
     * @param _blockNumber The block number when the balance is queried.
     * @return The balance at `_blockNumber`.
     **/
    function balanceOfAt(address _owner, uint _blockNumber) external view returns (uint256);


    /**
     * @notice Get the current total vote power.
     * @return The current total vote power (sum of all accounts' vote powers).
     */
    function totalVotePower() external view returns(uint256);

    /**
    * @notice Get the total vote power at block `_blockNumber`
    * @param _blockNumber The block number at which to fetch.
    * @return The total vote power at the block  (sum of all accounts' vote powers).
    */
    function totalVotePowerAt(uint _blockNumber) external view returns(uint256);

    /**
     * @notice Get the current vote power of `_owner`.
     * @param _owner The address to get voting power.
     * @return Current vote power of `_owner`.
     */
    function votePowerOf(address _owner) external view returns(uint256);

    /**
    * @notice Get the vote power of `_owner` at block `_blockNumber`
    * @param _owner The address to get voting power.
    * @param _blockNumber The block number at which to fetch.
    * @return Vote power of `_owner` at `_blockNumber`.
    */
    function votePowerOfAt(address _owner, uint256 _blockNumber) external view returns(uint256);


    /**
     * @notice Get the delegation mode for '_who'. This mode determines whether vote power is
     *  allocated by percentage or by explicit value. Once the delegation mode is set,
     *  it never changes, even if all delegations are removed.
     * @param _who The address to get delegation mode.
     * @return delegation mode: 0 = NOTSET, 1 = PERCENTAGE, 2 = AMOUNT (i.e. explicit)
     */
    function delegationModeOf(address _who) external view returns(uint256);

    /**
    * @notice Get current delegated vote power `_from` delegator delegated `_to` delegatee.
    * @param _from Address of delegator
    * @param _to Address of delegatee
    * @return The delegated vote power.
    */
    function votePowerFromTo(address _from, address _to) external view returns(uint256);

    /**
    * @notice Get delegated the vote power `_from` delegator delegated `_to` delegatee at `_blockNumber`.
    * @param _from Address of delegator
    * @param _to Address of delegatee
    * @param _blockNumber The block number at which to fetch.
    * @return The delegated vote power.
    */
    function votePowerFromToAt(address _from, address _to, uint _blockNumber) external view returns(uint256);

    /**
     * @notice Compute the current undelegated vote power of `_owner`
     * @param _owner The address to get undelegated voting power.
     * @return The unallocated vote power of `_owner`
     */
    function undelegatedVotePowerOf(address _owner) external view returns(uint256);

    /**
     * @notice Get the undelegated vote power of `_owner` at given block.
     * @param _owner The address to get undelegated voting power.
     * @param _blockNumber The block number at which to fetch.
     * @return The undelegated vote power of `_owner` (= owner's own balance minus all delegations from owner)
     */
    function undelegatedVotePowerOfAt(address _owner, uint256 _blockNumber) external view returns(uint256);

    /**
    * @notice Get the vote power delegation `delegationAddresses`
    *  and `_bips` of `_who`. Returned in two separate positional arrays.
    * @param _who The address to get delegations.
    * @return _delegateAddresses Positional array of delegation addresses.
    * @return _bips Positional array of delegation percents specified in basis points (1/100 or 1 percent)
    * @return _count The number of delegates.
    * @return _delegationMode The mode of the delegation (NOTSET=0, PERCENTAGE=1, AMOUNT=2).
    */
    function delegatesOf(address _who)
        external view
        returns (
            address[] memory _delegateAddresses,
            uint256[] memory _bips,
            uint256 _count,
            uint256 _delegationMode
        );

    /**
    * @notice Get the vote power delegation `delegationAddresses`
    *  and `pcts` of `_who`. Returned in two separate positional arrays.
    * @param _who The address to get delegations.
    * @param _blockNumber The block for which we want to know the delegations.
    * @return _delegateAddresses Positional array of delegation addresses.
    * @return _bips Positional array of delegation percents specified in basis points (1/100 or 1 percent)
    * @return _count The number of delegates.
    * @return _delegationMode The mode of the delegation (NOTSET=0, PERCENTAGE=1, AMOUNT=2).
    */
    function delegatesOfAt(address _who, uint256 _blockNumber)
        external view
        returns (
            address[] memory _delegateAddresses,
            uint256[] memory _bips,
            uint256 _count,
            uint256 _delegationMode
        );

    /**
     * Returns VPContract used for readonly operations (view methods).
     * The only non-view method that might be called on it is `revokeDelegationAt`.
     *
     * @notice `readVotePowerContract` is almost always equal to `writeVotePowerContract`
     * except during upgrade from one VPContract to a new version (which should happen
     * rarely or never and will be anounced before).
     *
     * @notice You shouldn't call any methods on VPContract directly, all are exposed
     * via VPToken (and state changing methods are forbidden from direct calls).
     * This is the reason why this method returns `IVPContractEvents` - it should only be used
     * for listening to events (`Revoke` only).
     */
    function readVotePowerContract() external view returns (IVPContractEvents);

    /**
     * Returns VPContract used for state changing operations (non-view methods).
     * The only non-view method that might be called on it is `revokeDelegationAt`.
     *
     * @notice `writeVotePowerContract` is almost always equal to `readVotePowerContract`
     * except during upgrade from one VPContract to a new version (which should happen
     * rarely or never and will be anounced before). In the case of upgrade,
     * `writeVotePowerContract` will be replaced first to establish delegations, and
     * after some perio (e.g. after a reward epoch ends) `readVotePowerContract` will be set equal to it.
     *
     * @notice You shouldn't call any methods on VPContract directly, all are exposed
     * via VPToken (and state changing methods are forbidden from direct calls).
     * This is the reason why this method returns `IVPContractEvents` - it should only be used
     * for listening to events (`Delegate` and `Revoke` only).
     */
    function writeVotePowerContract() external view returns (IVPContractEvents);

    /**
     * When set, allows token owners to participate in governance voting
     * and delegate governance vote power.
     */
    function governanceVotePower() external view returns (IGovernanceVotePower);
}


// File contracts/token/interface/IICleanable.sol

//
pragma solidity 0.7.6;

interface IICleanable {
    /**
     * Set the contract that is allowed to call history cleaning methods.
     */
    function setCleanerContract(address _cleanerContract) external;

    /**
     * Set the cleanup block number.
     * Historic data for the blocks before `cleanupBlockNumber` can be erased,
     * history before that block should never be used since it can be inconsistent.
     * In particular, cleanup block number must be before current vote power block.
     * @param _blockNumber The new cleanup block number.
     */
    function setCleanupBlockNumber(uint256 _blockNumber) external;

    /**
     * Set the contract that is allowed to set cleanupBlockNumber.
     * Usually this will be an instance of CleanupBlockNumberManager.
     */
    function setCleanupBlockNumberManager(address _cleanupBlockNumberManager) external;

    /**
     * Get the current cleanup block number.
     */
    function cleanupBlockNumber() external view returns (uint256);
}


// File contracts/token/interface/IIVPContract.sol

//
pragma solidity 0.7.6;



interface IIVPContract is IICleanable, IVPContractEvents {
    /**
     * Update vote powers when tokens are transfered.
     * Also update delegated vote powers for percentage delegation
     * and check for enough funds for explicit delegations.
     **/
    function updateAtTokenTransfer(
        address _from,
        address _to,
        uint256 _fromBalance,
        uint256 _toBalance,
        uint256 _amount
    ) external;

    /**
     * @notice Delegate `_bips` percentage of voting power to `_to` from `_from`
     * @param _from The address of the delegator
     * @param _to The address of the recipient
     * @param _balance The delegator's current balance
     * @param _bips The percentage of voting power to be delegated expressed in basis points (1/100 of one percent).
     *   Not cummulative - every call resets the delegation value (and value of 0 revokes delegation).
     **/
    function delegate(
        address _from,
        address _to,
        uint256 _balance,
        uint256 _bips
    ) external;

    /**
     * @notice Explicitly delegate `_amount` of voting power to `_to` from `msg.sender`.
     * @param _from The address of the delegator
     * @param _to The address of the recipient
     * @param _balance The delegator's current balance
     * @param _amount An explicit vote power amount to be delegated.
     *   Not cummulative - every call resets the delegation value (and value of 0 undelegates `to`).
     **/
    function delegateExplicit(
        address _from,
        address _to,
        uint256 _balance,
        uint _amount
    ) external;

    /**
     * @notice Revoke all delegation from sender to `_who` at given block.
     *    Only affects the reads via `votePowerOfAtCached()` in the block `_blockNumber`.
     *    Block `_blockNumber` must be in the past.
     *    This method should be used only to prevent rogue delegate voting in the current voting block.
     *    To stop delegating use delegate/delegateExplicit with value of 0 or undelegateAll/undelegateAllExplicit.
     * @param _from The address of the delegator
     * @param _who Address of the delegatee
     * @param _balance The delegator's current balance
     * @param _blockNumber The block number at which to revoke delegation.
     **/
    function revokeDelegationAt(
        address _from,
        address _who,
        uint256 _balance,
        uint _blockNumber
    ) external;

        /**
     * @notice Undelegate all voting power for delegates of `msg.sender`
     *    Can only be used with percentage delegation.
     *    Does not reset delegation mode back to NOTSET.
     * @param _from The address of the delegator
     **/
    function undelegateAll(
        address _from,
        uint256 _balance
    ) external;

    /**
     * @notice Undelegate all explicit vote power by amount delegates for `msg.sender`.
     *    Can only be used with explicit delegation.
     *    Does not reset delegation mode back to NOTSET.
     * @param _from The address of the delegator
     * @param _delegateAddresses Explicit delegation does not store delegatees' addresses,
     *   so the caller must supply them.
     * @return The amount still delegated (in case the list of delegates was incomplete).
     */
    function undelegateAllExplicit(
        address _from,
        address[] memory _delegateAddresses
    ) external returns (uint256);

    /**
    * @notice Get the vote power of `_who` at block `_blockNumber`
    *   Reads/updates cache and upholds revocations.
    * @param _who The address to get voting power.
    * @param _blockNumber The block number at which to fetch.
    * @return Vote power of `_who` at `_blockNumber`.
    */
    function votePowerOfAtCached(address _who, uint256 _blockNumber) external returns(uint256);

    /**
     * @notice Get the current vote power of `_who`.
     * @param _who The address to get voting power.
     * @return Current vote power of `_who`.
     */
    function votePowerOf(address _who) external view returns(uint256);

    /**
    * @notice Get the vote power of `_who` at block `_blockNumber`
    * @param _who The address to get voting power.
    * @param _blockNumber The block number at which to fetch.
    * @return Vote power of `_who` at `_blockNumber`.
    */
    function votePowerOfAt(address _who, uint256 _blockNumber) external view returns(uint256);

    /**
     * Return vote powers for several addresses in a batch.
     * @param _owners The list of addresses to fetch vote power of.
     * @param _blockNumber The block number at which to fetch.
     * @return A list of vote powers.
     */
    function batchVotePowerOfAt(
        address[] memory _owners,
        uint256 _blockNumber
    )
        external view returns(uint256[] memory);

    /**
    * @notice Get current delegated vote power `_from` delegator delegated `_to` delegatee.
    * @param _from Address of delegator
    * @param _to Address of delegatee
    * @param _balance The delegator's current balance
    * @return The delegated vote power.
    */
    function votePowerFromTo(
        address _from,
        address _to,
        uint256 _balance
    ) external view returns(uint256);

    /**
    * @notice Get delegated the vote power `_from` delegator delegated `_to` delegatee at `_blockNumber`.
    * @param _from Address of delegator
    * @param _to Address of delegatee
    * @param _balance The delegator's current balance
    * @param _blockNumber The block number at which to fetch.
    * @return The delegated vote power.
    */
    function votePowerFromToAt(
        address _from,
        address _to,
        uint256 _balance,
        uint _blockNumber
    ) external view returns(uint256);

    /**
     * @notice Compute the current undelegated vote power of `_owner`
     * @param _owner The address to get undelegated voting power.
     * @param _balance Owner's current balance
     * @return The unallocated vote power of `_owner`
     */
    function undelegatedVotePowerOf(
        address _owner,
        uint256 _balance
    ) external view returns(uint256);

    /**
     * @notice Get the undelegated vote power of `_owner` at given block.
     * @param _owner The address to get undelegated voting power.
     * @param _blockNumber The block number at which to fetch.
     * @return The undelegated vote power of `_owner` (= owner's own balance minus all delegations from owner)
     */
    function undelegatedVotePowerOfAt(
        address _owner,
        uint256 _balance,
        uint256 _blockNumber
    ) external view returns(uint256);

    /**
     * @notice Get the delegation mode for '_who'. This mode determines whether vote power is
     *  allocated by percentage or by explicit value.
     * @param _who The address to get delegation mode.
     * @return Delegation mode (NOTSET=0, PERCENTAGE=1, AMOUNT=2))
     */
    function delegationModeOf(address _who) external view returns (uint256);

    /**
    * @notice Get the vote power delegation `_delegateAddresses`
    *  and `pcts` of an `_owner`. Returned in two separate positional arrays.
    * @param _owner The address to get delegations.
    * @return _delegateAddresses Positional array of delegation addresses.
    * @return _bips Positional array of delegation percents specified in basis points (1/100 or 1 percent)
    * @return _count The number of delegates.
    * @return _delegationMode The mode of the delegation (NOTSET=0, PERCENTAGE=1, AMOUNT=2).
    */
    function delegatesOf(
        address _owner
    )
        external view
        returns (
            address[] memory _delegateAddresses,
            uint256[] memory _bips,
            uint256 _count,
            uint256 _delegationMode
        );

    /**
    * @notice Get the vote power delegation `delegationAddresses`
    *  and `pcts` of an `_owner`. Returned in two separate positional arrays.
    * @param _owner The address to get delegations.
    * @param _blockNumber The block for which we want to know the delegations.
    * @return _delegateAddresses Positional array of delegation addresses.
    * @return _bips Positional array of delegation percents specified in basis points (1/100 or 1 percent)
    * @return _count The number of delegates.
    * @return _delegationMode The mode of the delegation (NOTSET=0, PERCENTAGE=1, AMOUNT=2).
    */
    function delegatesOfAt(
        address _owner,
        uint256 _blockNumber
    )
        external view
        returns (
            address[] memory _delegateAddresses,
            uint256[] memory _bips,
            uint256 _count,
            uint256 _delegationMode
        );

    /**
     * The VPToken (or some other contract) that owns this VPContract.
     * All state changing methods may be called only from this address.
     * This is because original msg.sender is sent in `_from` parameter
     * and we must be sure that it cannot be faked by directly calling VPContract.
     * Owner token is also used in case of replacement to recover vote powers from balances.
     */
    function ownerToken() external view returns (IVPToken);

    /**
     * Return true if this IIVPContract is configured to be used as a replacement for other contract.
     * It means that vote powers are not necessarily correct at the initialization, therefore
     * every method that reads vote power must check whether it is initialized for that address and block.
     */
    function isReplacement() external view returns (bool);
}


// File contracts/token/interface/IIGovernanceVotePower.sol

//
pragma solidity 0.7.6;


interface IIGovernanceVotePower is IGovernanceVotePower {
    /**
     * Update vote powers when tokens are transfered.
     **/
    function updateAtTokenTransfer(
        address _from,
        address _to,
        uint256 _fromBalance,
        uint256 _toBalance,
        uint256 _amount
    ) external;

    /**
     * Set the cleanup block number.
     * Historic data for the blocks before `cleanupBlockNumber` can be erased,
     * history before that block should never be used since it can be inconsistent.
     * In particular, cleanup block number must be before current vote power block.
     * @param _blockNumber The new cleanup block number.
     */
    function setCleanupBlockNumber(uint256 _blockNumber) external;

    /**
     * Set the contract that is allowed to call history cleaning methods.
     */
    function setCleanerContract(address _cleanerContract) external;

   /**
    * @notice Get the token that this governance vote power contract belongs to.
    */
    function ownerToken() external view returns(IVPToken);
}


// File contracts/token/interface/IIVPToken.sol

//
pragma solidity 0.7.6;





interface IIVPToken is IVPToken, IICleanable {
    /**
     * Sets new governance vote power contract that allows token owners to participate in governance voting
     * and delegate governance vote power.
     */
    function setGovernanceVotePower(IIGovernanceVotePower _governanceVotePower) external;

    /**
    * @notice Get the total vote power at block `_blockNumber` using cache.
    *   It tries to read the cached value and if not found, reads the actual value and stores it in cache.
    *   Can only be used if `_blockNumber` is in the past, otherwise reverts.
    * @param _blockNumber The block number at which to fetch.
    * @return The total vote power at the block (sum of all accounts' vote powers).
    */
    function totalVotePowerAtCached(uint256 _blockNumber) external returns(uint256);

    /**
    * @notice Get the vote power of `_owner` at block `_blockNumber` using cache.
    *   It tries to read the cached value and if not found, reads the actual value and stores it in cache.
    *   Can only be used if _blockNumber is in the past, otherwise reverts.
    * @param _owner The address to get voting power.
    * @param _blockNumber The block number at which to fetch.
    * @return Vote power of `_owner` at `_blockNumber`.
    */
    function votePowerOfAtCached(address _owner, uint256 _blockNumber) external returns(uint256);

    /**
     * Return vote powers for several addresses in a batch.
     * @param _owners The list of addresses to fetch vote power of.
     * @param _blockNumber The block number at which to fetch.
     * @return A list of vote powers.
     */
    function batchVotePowerOfAt(
        address[] memory _owners,
        uint256 _blockNumber
    ) external view returns(uint256[] memory);
}


// File contracts/userInterfaces/IFtso.sol

//
pragma solidity 0.7.6;

interface IFtso {
    enum PriceFinalizationType {
        // initial state
        NOT_FINALIZED,
        // median calculation used to decide price
        WEIGHTED_MEDIAN,
        // low turnout - price decided from average of trusted addresses
        TRUSTED_ADDRESSES,
        // low turnout + no votes from trusted addresses - price copied from previous epoch
        PREVIOUS_PRICE_COPIED,
        // price decided from average of trusted addresses - triggered due to an exception
        TRUSTED_ADDRESSES_EXCEPTION,
        // previous price copied - triggered due to an exception
        PREVIOUS_PRICE_COPIED_EXCEPTION
    }

    // events
    event PriceHashSubmitted(
        address indexed submitter, uint256 indexed epochId, bytes32 hash, uint256 timestamp
    );

    event PriceRevealed(
        address indexed voter, uint256 indexed epochId, uint256 price, uint256 random, uint256 timestamp,
        uint256 votePowerNat, uint256 votePowerAsset
    );

    event PriceFinalized(
        uint256 indexed epochId, uint256 price, bool rewardedFtso,
        uint256 lowRewardPrice, uint256 highRewardPrice, PriceFinalizationType finalizationType,
        uint256 timestamp
    );

    event PriceEpochInitializedOnFtso(
        uint256 indexed epochId, uint256 endTime, uint256 timestamp
    );

    event LowTurnout(
        uint256 indexed epochId,
        uint256 natTurnout,
        uint256 lowNatTurnoutThresholdBIPS,
        uint256 timestamp
    );

    /**
     * @notice Returns if FTSO is active
     */
    function active() external view returns (bool);

    /**
     * @notice Returns the FTSO symbol
     */
    function symbol() external view returns (string memory);

    /**
     * @notice Returns current epoch id
     */
    function getCurrentEpochId() external view returns (uint256);

    /**
     * @notice Returns id of the epoch which was opened for price submission at the specified timestamp
     * @param _timestamp            Timestamp as seconds from unix epoch
     */
    function getEpochId(uint256 _timestamp) external view returns (uint256);

    /**
     * @notice Returns random number of the specified epoch
     * @param _epochId              Id of the epoch
     */
    function getRandom(uint256 _epochId) external view returns (uint256);

    /**
     * @notice Returns asset price consented in specific epoch
     * @param _epochId              Id of the epoch
     * @return Price in USD multiplied by ASSET_PRICE_USD_DECIMALS
     */
    function getEpochPrice(uint256 _epochId) external view returns (uint256);

    /**
     * @notice Returns current epoch data
     * @return _epochId                 Current epoch id
     * @return _epochSubmitEndTime      End time of the current epoch price submission as seconds from unix epoch
     * @return _epochRevealEndTime      End time of the current epoch price reveal as seconds from unix epoch
     * @return _votePowerBlock          Vote power block for the current epoch
     * @return _fallbackMode            Current epoch in fallback mode - only votes from trusted addresses will be used
     * @dev half-closed intervals - end time not included
     */
    function getPriceEpochData() external view returns (
        uint256 _epochId,
        uint256 _epochSubmitEndTime,
        uint256 _epochRevealEndTime,
        uint256 _votePowerBlock,
        bool _fallbackMode
    );

    /**
     * @notice Returns current epoch data
     * @return _firstEpochStartTime         First epoch start time
     * @return _submitPeriod                Submit period in seconds
     * @return _revealPeriod                Reveal period in seconds
     */
    function getPriceEpochConfiguration() external view returns (
        uint256 _firstEpochStartTime,
        uint256 _submitPeriod,
        uint256 _revealPeriod
    );

    /**
     * @notice Returns asset price submitted by voter in specific epoch
     * @param _epochId              Id of the epoch
     * @param _voter                Address of the voter
     * @return Price in USD multiplied by ASSET_PRICE_USD_DECIMALS
     */
    function getEpochPriceForVoter(uint256 _epochId, address _voter) external view returns (uint256);

    /**
     * @notice Returns current asset price
     * @return _price               Price in USD multiplied by ASSET_PRICE_USD_DECIMALS
     * @return _timestamp           Time when price was updated for the last time
     */
    function getCurrentPrice() external view returns (uint256 _price, uint256 _timestamp);

    /**
     * @notice Returns current random number
     */
    function getCurrentRandom() external view returns (uint256);
}


// File contracts/ftso/interface/IIFtso.sol

//
pragma solidity 0.7.6;



interface IIFtso is IFtso, IFtsoGenesis {

    /// function finalizePriceReveal
    /// called by reward manager only on correct timing.
    /// if price reveal period for epoch x ended. finalize.
    /// iterate list of price submissions
    /// find weighted median
    /// find adjucant 50% of price submissions.
    /// Allocate reward for any price submission which is same as a "winning" submission
    function finalizePriceEpoch(uint256 _epochId, bool _returnRewardData) external
        returns(
            address[] memory _eligibleAddresses,
            uint256[] memory _natWeights,
            uint256 _totalNatWeight
        );

    function averageFinalizePriceEpoch(uint256 _epochId) external;

    function forceFinalizePriceEpoch(uint256 _epochId) external;

    // activateFtso will be called by ftso manager once ftso is added
    // before this is done, FTSO can't run
    function activateFtso(
        uint256 _firstEpochStartTs,
        uint256 _epochPeriod,
        uint256 _revealPeriod
    ) external;

    function deactivateFtso() external;

    // update initial price and timestamp - only if not active
    function updateInitialPrice(uint256 _initialPriceUSD, uint256 _initialPriceTimestamp) external;

    function configureEpochs(
        uint256 _maxVotePowerNatThresholdFraction,
        uint256 _maxVotePowerAssetThresholdFraction,
        uint256 _lowAssetUSDThreshold,
        uint256 _highAssetUSDThreshold,
        uint256 _highAssetTurnoutThresholdBIPS,
        uint256 _lowNatTurnoutThresholdBIPS,
        address[] memory _trustedAddresses
    ) external;

    function setAsset(IIVPToken _asset) external;

    function setAssetFtsos(IIFtso[] memory _assetFtsos) external;

    // current vote power block will update per reward epoch.
    // the FTSO doesn't have notion of reward epochs.
    // reward manager only can set this data.
    function setVotePowerBlock(uint256 _blockNumber) external;

    function initializeCurrentEpochStateForReveal(uint256 _circulatingSupplyNat, bool _fallbackMode) external;

    /**
     * @notice Returns the FTSO asset
     * @dev Asset is null in case of multi-asset FTSO
     */
    function getAsset() external view returns (IIVPToken);

    /**
     * @notice Returns the Asset FTSOs
     * @dev AssetFtsos is not null only in case of multi-asset FTSO
     */
    function getAssetFtsos() external view returns (IIFtso[] memory);

    /**
     * @notice Returns current configuration of epoch state
     * @return _maxVotePowerNatThresholdFraction        High threshold for native token vote power per voter
     * @return _maxVotePowerAssetThresholdFraction      High threshold for asset vote power per voter
     * @return _lowAssetUSDThreshold            Threshold for low asset vote power
     * @return _highAssetUSDThreshold           Threshold for high asset vote power
     * @return _highAssetTurnoutThresholdBIPS   Threshold for high asset turnout
     * @return _lowNatTurnoutThresholdBIPS      Threshold for low nat turnout
     * @return _trustedAddresses                Trusted addresses - use their prices if low nat turnout is not achieved
     */
    function epochsConfiguration() external view
        returns (
            uint256 _maxVotePowerNatThresholdFraction,
            uint256 _maxVotePowerAssetThresholdFraction,
            uint256 _lowAssetUSDThreshold,
            uint256 _highAssetUSDThreshold,
            uint256 _highAssetTurnoutThresholdBIPS,
            uint256 _lowNatTurnoutThresholdBIPS,
            address[] memory _trustedAddresses
        );

    /**
     * @notice Returns parameters necessary for approximately replicating vote weighting.
     * @return _assets                  the list of Assets that are accounted in vote
     * @return _assetMultipliers        weight of each asset in (multiasset) ftso, mutiplied by TERA
     * @return _totalVotePowerNat       total native token vote power at block
     * @return _totalVotePowerAsset     total combined asset vote power at block
     * @return _assetWeightRatio        ratio of combined asset vp vs. native token vp (in BIPS)
     * @return _votePowerBlock          vote powewr block for given epoch
     */
    function getVoteWeightingParameters() external view
        returns (
            IIVPToken[] memory _assets,
            uint256[] memory _assetMultipliers,
            uint256 _totalVotePowerNat,
            uint256 _totalVotePowerAsset,
            uint256 _assetWeightRatio,
            uint256 _votePowerBlock
        );

    function wNat() external view returns (IIVPToken);
}


// File contracts/userInterfaces/IFtsoRegistry.sol

//
pragma solidity 0.7.6;


interface IFtsoRegistry is IFtsoRegistryGenesis {

    function getFtso(uint256 _ftsoIndex) external view returns(IIFtso _activeFtsoAddress);
    function getFtsoBySymbol(string memory _symbol) external view returns(IIFtso _activeFtsoAddress);
    function getSupportedIndices() external view returns(uint256[] memory _supportedIndices);
    function getSupportedSymbols() external view returns(string[] memory _supportedSymbols);
    function getSupportedFtsos() external view returns(IIFtso[] memory _ftsos);
    function getFtsoIndex(string memory _symbol) external view returns (uint256 _assetIndex);
    function getFtsoSymbol(uint256 _ftsoIndex) external view returns (string memory _symbol);
    function getCurrentPrice(uint256 _ftsoIndex) external view returns(uint256 _price, uint256 _timestamp);
    function getCurrentPrice(string memory _symbol) external view returns(uint256 _price, uint256 _timestamp);

    function getSupportedIndicesAndFtsos() external view
        returns(uint256[] memory _supportedIndices, IIFtso[] memory _ftsos);

    function getSupportedSymbolsAndFtsos() external view
        returns(string[] memory _supportedSymbols, IIFtso[] memory _ftsos);

    function getSupportedIndicesAndSymbols() external view
        returns(uint256[] memory _supportedIndices, string[] memory _supportedSymbols);

    function getSupportedIndicesSymbolsAndFtsos() external view
        returns(uint256[] memory _supportedIndices, string[] memory _supportedSymbols, IIFtso[] memory _ftsos);
}


// File @openzeppelin/contracts/math/[email protected]

//

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

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

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) return (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.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        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.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a % b;
    }
}


// File contracts/utils/implementation/SafePct.sol

//

pragma solidity 0.7.6;

/**
 * @dev Compute percentages safely without phantom overflows.
 *
 * Intermediate operations can overflow even when the result will always
 * fit into computed type. Developers usually
 * assume that overflows raise errors. `SafePct` 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.
 *
 * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and `int256` and then downcasting.
 */
library SafePct {
    using SafeMath for uint256;
    /**
     * Requirements:
     *
     * - intermediate operations must revert on overflow
     */
    function mulDiv(uint256 x, uint256 y, uint256 z) internal pure returns (uint256) {
        require(z > 0, "Division by zero");

        if (x == 0) return 0;
        uint256 xy = x * y;
        if (xy / x == y) { // no overflow happened - same as in SafeMath mul
            return xy / z;
        }

        //slither-disable-next-line divide-before-multiply
        uint256 a = x / z;
        uint256 b = x % z; // x = a * z + b

        //slither-disable-next-line divide-before-multiply
        uint256 c = y / z;
        uint256 d = y % z; // y = c * z + d

        return (a.mul(c).mul(z)).add(a.mul(d)).add(b.mul(c)).add(b.mul(d).div(z));
    }
}


// File contracts/utils/implementation/VoterWhitelister.sol

//
pragma solidity 0.7.6;







contract VoterWhitelister is IIVoterWhitelister, Governed {
    using SafeMath for uint256;
    using SafePct for uint256;

    uint256 internal constant TERA = 10 ** 12;                    // 10^12
    uint256 internal constant BIPS100 = 10 ** 4;                  // 100 * 100%

    uint256 public override defaultMaxVotersForFtso;

    /**
     * Maximum number of voters in a single ftso whitelist.
     * Adjustable separately for each ftsoIndex.
     */
    mapping (uint256 => uint256) public override maxVotersForFtso;

    // mapping: ftsoIndex => array of whitelisted voters for this ftso
    mapping (uint256 => address[]) internal whitelist;

    IIPriceSubmitter public immutable priceSubmitter;

    IFtsoRegistry public ftsoRegistry;

    address public ftsoManager;

    modifier onlyFtsoManager {
        require(msg.sender == ftsoManager, "only ftso manager");
        _;
    }

    constructor(
        address _governance,
        IIPriceSubmitter _priceSubmitter,
        uint256 _defaultMaxVotersForFtso
    )
        Governed(_governance)
    {
        priceSubmitter = _priceSubmitter;
        defaultMaxVotersForFtso = _defaultMaxVotersForFtso;
    }

    /**
     * Request to whitelist `_voter` account to all active ftsos.
     * May be called by any address.
     * It returns an array of supported ftso indices and success flag per index.
     */
    function requestFullVoterWhitelisting(
        address _voter
    )
        external override
        returns (
            uint256[] memory _supportedIndices,
            bool[] memory _success
        )
    {
        if (_isTrustedAddress(_voter)) {
            revert("trusted address");
        }

        _supportedIndices = ftsoRegistry.getSupportedIndices();
        uint256 len = _supportedIndices.length;
        _success = new bool[](len);
        for (uint256 i = 0; i < len; i++) {
            _success[i] = _requestWhitelistingVoter(_voter, _supportedIndices[i]);
        }
    }

    /**
     * Request to whitelist `_voter` account to ftso at `_ftsoIndex`. Will revert if vote power too low.
     * May be called by any address.
     */
    function requestWhitelistingVoter(address _voter, uint256 _ftsoIndex) external override {
        if (_isTrustedAddress(_voter)) {
            revert("trusted address");
        }

        bool success = _requestWhitelistingVoter(_voter, _ftsoIndex);
        require(success, "vote power too low");
    }

    /**
     * Set the maximum number of voters in the whitelist for FTSO at index `_ftsoIndex`.
     * Calling this function might remove several voters with the least votepower from the whitelist.
     */
    function setMaxVotersForFtso(uint256 _ftsoIndex, uint256 _newMaxVoters) external override onlyGovernance {
        maxVotersForFtso[_ftsoIndex] = _newMaxVoters;
        // need to remove any?
        address[] storage addressesForFtso = whitelist[_ftsoIndex];
        if (_newMaxVoters >= addressesForFtso.length) {
            return;
        }
        // remove voters with minimum vote power
        IIFtso ftso = ftsoRegistry.getFtso(_ftsoIndex);
        uint256[] memory votePowers = _getVotePowerWeights(ftso, addressesForFtso);
        uint256 length = votePowers.length;
        uint256 toRemove = length - _newMaxVoters;
        address[] memory removedVoters = new address[](toRemove);
        for (uint256 n = 0; n < toRemove; n++) {
            uint256 minIndex = _findMinimum(votePowers, length);
            removedVoters[n] = addressesForFtso[minIndex];
            if (minIndex < length - 1) {
                addressesForFtso[minIndex] = addressesForFtso[length - 1];
                votePowers[minIndex] = votePowers[length - 1];
            }
            addressesForFtso.pop();
            --length;
        }
        _votersRemovedFromWhitelist(removedVoters, _ftsoIndex);
    }

    /**
     * Set the maximum number of voters in the whitelist for a new FTSO.
     */
    function setDefaultMaxVotersForFtso(uint256 _defaultMaxVotersForFtso) external override onlyGovernance {
        defaultMaxVotersForFtso = _defaultMaxVotersForFtso;
    }

    /**
     * Sets ftsoRegistry and ftsoManager addresses.
     * Only governance can call this method.
     */
    function setContractAddresses(IFtsoRegistry _ftsoRegistry, address _ftsoManager) external onlyGovernance {
        ftsoRegistry = _ftsoRegistry;
        ftsoManager = _ftsoManager;
    }

    /**
     * Create whitelist with default size for ftso.
     */
    function addFtso(uint256 _ftsoIndex) external override onlyFtsoManager {
        require(maxVotersForFtso[_ftsoIndex] == 0, "whitelist already exist");
        maxVotersForFtso[_ftsoIndex] = defaultMaxVotersForFtso;
    }

    /**
     * Clear whitelist for ftso at `_ftsoIndex`.
     */
    function removeFtso(uint256 _ftsoIndex) external override onlyFtsoManager {
        _votersRemovedFromWhitelist(whitelist[_ftsoIndex], _ftsoIndex);
        delete whitelist[_ftsoIndex];
        delete maxVotersForFtso[_ftsoIndex];
    }

    /**
     * Remove `_trustedAddress` from whitelist for ftso at `_ftsoIndex`.
     */
    function removeTrustedAddressFromWhitelist(address _trustedAddress, uint256 _ftsoIndex) external override {
        if (!_isTrustedAddress(_trustedAddress)) {
            revert("not trusted address");
        }
        address[] storage addressesForFtso = whitelist[_ftsoIndex];
        uint256 length = addressesForFtso.length;

        // find index of _trustedAddress
        uint256 index = 0;
        for ( ; index < length; index++) {
            if (addressesForFtso[index] == _trustedAddress) {
                break;
            }
        }

        require(index < length, "trusted address not whitelisted");

        // kick the index out and replace it with the last one
        address[] memory removedVoters = new address[](1);
        removedVoters[0] = addressesForFtso[index];
        addressesForFtso[index] = addressesForFtso[length - 1];
        addressesForFtso.pop();
        _votersRemovedFromWhitelist(removedVoters, _ftsoIndex);
    }

    /**
     * Get whitelisted price providers for ftso with `_symbol`
     */
    function getFtsoWhitelistedPriceProvidersBySymbol(
        string memory _symbol
    )
        external view override
        returns (
            address[] memory
    )
    {
        uint256 ftsoIndex = ftsoRegistry.getFtsoIndex(_symbol);
        return getFtsoWhitelistedPriceProviders(ftsoIndex);
    }

    /**
     * Get whitelisted price providers for ftso at `_ftsoIndex`
     */
    function getFtsoWhitelistedPriceProviders(uint256 _ftsoIndex) public view override returns (address[] memory) {
        uint256 maxVoters = maxVotersForFtso[_ftsoIndex];
        require(maxVoters > 0, "FTSO index not supported");
        return whitelist[_ftsoIndex];
    }

    /**
     * Request to whitelist `_voter` account to ftso at `_ftsoIndex` - implementation.
     */
    function _requestWhitelistingVoter(address _voter, uint256 _ftsoIndex) internal returns(bool) {
        uint256 maxVoters = maxVotersForFtso[_ftsoIndex];
        require(maxVoters > 0, "FTSO index not supported");

        address[] storage addressesForFtso = whitelist[_ftsoIndex];
        uint256 length = addressesForFtso.length;

        // copy to memory and check if it contains _voter
        address[] memory addresses = new address[](length + 1);
        for (uint256 i = 0; i < length; i++) {
            address addr = addressesForFtso[i];
            if (addr == _voter) {
                // _voter is already whitelisted, return
                return true;
            }
            addresses[i] = addr;
        }
        addresses[length] = _voter;

        // can we just add a new one?
        if (length < maxVoters) {
            addressesForFtso.push(_voter);
            _voterWhitelisted(_voter, _ftsoIndex);
            return true;
        }

        // find a candidate to kick out
        uint256 minIndex = _minVotePowerIndex(addresses, _ftsoIndex);
        if (minIndex == length) {
            // the new _voter has the minimum vote power, do nothing
            return false;
        }

        // kick the minIndex out and replace it with _voter
        address[] memory removedVoters = new address[](1);
        removedVoters[0] = addresses[minIndex];
        addressesForFtso[minIndex] = _voter;
        _votersRemovedFromWhitelist(removedVoters, _ftsoIndex);
        _voterWhitelisted(_voter, _ftsoIndex);

        return true;
    }

    /**
     * Find index of the element with minimum vote power weight.
     * In case of a tie, returns later index.
     */
    function _minVotePowerIndex(address[] memory _addresses, uint256 _ftsoIndex) internal returns (uint256) {
        IIFtso ftso = ftsoRegistry.getFtso(_ftsoIndex);
        uint256[] memory votePowers = _getVotePowerWeights(ftso, _addresses);
        return _findMinimum(votePowers, votePowers.length);
    }

    /**
     * Calculate vote power weights like FTSO.
     * Unlike FTSO, it calls VPToken vote power in a batch to limit gas consumption.
     * Another difference with FTSO is that voter turnout is ignored (it makes
     * no sense for whitelist, since it has to be initialized before any voting occurs).
     * Apart from turnout, the results should be equal as for FTSO.
     */
    function _getVotePowerWeights(IIFtso ftso, address[] memory _addresses) internal
        returns (uint256[] memory _votePowers)
    {
        // get parameters
        IIVPToken[] memory assets;
        uint256[] memory assetMultipliers;
        uint256 totalVotePowerNat;
        uint256 totalVotePowerAsset;
        uint256 assetWeightRatio;
        uint256 votePowerBlock;
        (assets, assetMultipliers, totalVotePowerNat, totalVotePowerAsset, assetWeightRatio, votePowerBlock)
            = ftso.getVoteWeightingParameters();
        // nat vote powers
        uint256[] memory wNatVP =
            _getNativeVotePowerWeights(ftso.wNat(), totalVotePowerNat, _addresses, votePowerBlock);
        // asset vote powers
        uint256[] memory combinedAssetVP =
            _getAssetVotePowerWeights(assets, assetMultipliers, totalVotePowerAsset, _addresses, votePowerBlock);
        // combine asset and wNat
        return _computeWeightedSum(wNatVP, combinedAssetVP, assetWeightRatio);
    }

    /**
     * Calculate native vote power weights like FTSO.
     */
    function _getNativeVotePowerWeights(
        IIVPToken _wNat,
        uint256 _totalVotePowerNat,
        address[] memory _addresses,
        uint256 _blockNumber
    )
        internal
        returns (uint256[] memory _wNatVP)
    {
        _wNatVP = _getVotePowers(_wNat, _addresses, _blockNumber);
        if (_totalVotePowerNat == 0) {
            return _wNatVP;  // if total is 0, all values must be 0, no division needed
        }
        for (uint256 i = 0; i < _addresses.length; i++) {
            _wNatVP[i] = _wNatVP[i].mulDiv(TERA, _totalVotePowerNat);
        }
    }

    /**
     * Calculate asset vote power weights like FTSO.
     */
    function _getAssetVotePowerWeights(
        IIVPToken[] memory _assets,
        uint256[] memory _assetMultipliers,
        uint256 _totalVotePowerAsset,
        address[] memory _addresses,
        uint256 _blockNumber
    )
        internal
        returns (uint256[] memory _combinedAssetVP)
    {
        _combinedAssetVP = new uint256[](_addresses.length);
        for (uint256 i = 0; i < _addresses.length; i++) {
            _combinedAssetVP[i] = 0;
        }
        if (_totalVotePowerAsset == 0) {
            return _combinedAssetVP;
        }
        uint256 divisor = _totalVotePowerAsset.mul(1e18);
        for (uint256 n = 0; n < _assets.length; n++) {
            IIVPToken asset = _assets[n];
            if (address(asset) != address(0)) {
                uint256[] memory assetVP = _getVotePowers(asset, _addresses, _blockNumber);
                // add
                for (uint256 i = 0; i < _addresses.length; i++) {
                    uint256 weightedVP = assetVP[i].mulDiv(_assetMultipliers[n], divisor);
                    _combinedAssetVP[i] = _combinedAssetVP[i].add(weightedVP);
                }
            }
        }
    }

    /**
     * Get vote powers from VPToken in a batch.
     * This is needed to avoid gas consumption of many cros-contract calls.
     */
    function _getVotePowers(
        IIVPToken _token,
        address[] memory _addresses,
        uint256 _blockNumber
    )
        internal
        returns (uint256[] memory)
    {
        // warm up cache for new voter (in this way everyone pays cache storing price for himself)
        _token.votePowerOfAtCached(_addresses[_addresses.length - 1], _blockNumber);
        // get all vote powers in a batch
        return _token.batchVotePowerOfAt(_addresses, _blockNumber);
    }

    /**
     * Checks if _voter is trusted address
     */
    function _isTrustedAddress(address _voter) internal view returns(bool) {
        address[] memory trustedAddresses = priceSubmitter.getTrustedAddresses();
        for (uint256 i = 0; i < trustedAddresses.length; i++) {
            if (trustedAddresses[i] == _voter) {
                return true;
            }
        }
        return false;
    }

    /**
     * Update a voter whitelisting and emit an event.
     */
    function _voterWhitelisted(address _voter, uint256 _ftsoIndex) private {
        emit VoterWhitelisted(_voter, _ftsoIndex);
        priceSubmitter.voterWhitelisted(_voter, _ftsoIndex);
    }

    /**
     * Update when a  voter is removed from the whitelist. And emit an event.
     */
    function _votersRemovedFromWhitelist(address[] memory _removedVoters, uint256 _ftsoIndex) private {
        for (uint256 i = 0; i < _removedVoters.length; i++) {
            emit VoterRemovedFromWhitelist(_removedVoters[i], _ftsoIndex);
        }
        priceSubmitter.votersRemovedFromWhitelist(_removedVoters, _ftsoIndex);
    }

    /**
     * Calculate sum of all values in an array.
     */
    function _arraySum(uint256[] memory array) private pure returns (uint256) {
        uint256 result = 0;
        for (uint256 i = 0; i < array.length; i++) {
            result = result.add(array[i]);
        }
        return result;
    }

    /**
     * Calculate weighted sum of two arrays (like in FTSO):
     *  result[i] = (100% - _assetWeightRatio) * _weightsNat[i] + _assetWeightRatio * _weightsAsset[i]
     */
    function _computeWeightedSum(
        uint256[] memory _weightsNat,
        uint256[] memory _weightsAsset,
        uint256 _assetWeightRatio
    )
        private pure
        returns (uint256[] memory _weights)
    {
        uint256 weightAssetSum = _arraySum(_weightsAsset);
        uint256 weightNatSum = _arraySum(_weightsNat);
        uint256 weightAssetShare = weightAssetSum > 0 ? _assetWeightRatio : 0;
        uint256 weightNatShare = weightNatSum > 0 ? BIPS100 - weightAssetShare : 0;
        _weights = new uint256[](_weightsNat.length);
        for (uint256 i = 0; i < _weightsNat.length; i++) {
            uint256 weightNat = 0;
            if (weightNatShare > 0) {
                weightNat = weightNatShare.mulDiv(TERA * _weightsNat[i], weightNatSum * BIPS100);
            }
            uint256 weightAsset = 0;
            if (weightAssetShare > 0) {
                weightAsset = weightAssetShare.mulDiv(TERA * _weightsAsset[i], weightAssetSum * BIPS100);
            }
            _weights[i] = weightNat + weightAsset;
        }
    }

    /**
     * Find minimum index of an uint256 array.
     * In case of a tie, returns later index.
     */
    function _findMinimum(uint256[] memory _votePowers, uint256 _length) private pure returns (uint256) {
        uint256 minIndex = 0;
        uint256 minVP = _votePowers[0];
        for (uint256 i = 0; i < _length; i++) {
            uint256 vp = _votePowers[i];
            // using `<=` ensures that later index is used if there is a tie
            // this is useful because in requestWhitelistingVoter, the new voter is last
            // also, when removing, it is cheaper to remove last element
            if (vp <= minVP) {
                minIndex = i;
                minVP = vp;
            }
        }
        return minIndex;
    }
}
        

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_governance","internalType":"address"},{"type":"address","name":"_priceSubmitter","internalType":"contract IIPriceSubmitter"},{"type":"uint256","name":"_defaultMaxVotersForFtso","internalType":"uint256"}]},{"type":"event","name":"GovernanceProposed","inputs":[{"type":"address","name":"proposedGovernance","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"GovernanceUpdated","inputs":[{"type":"address","name":"oldGovernance","internalType":"address","indexed":false},{"type":"address","name":"newGoveranance","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"VoterRemovedFromWhitelist","inputs":[{"type":"address","name":"voter","internalType":"address","indexed":false},{"type":"uint256","name":"ftsoIndex","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"VoterWhitelisted","inputs":[{"type":"address","name":"voter","internalType":"address","indexed":false},{"type":"uint256","name":"ftsoIndex","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addFtso","inputs":[{"type":"uint256","name":"_ftsoIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimGovernance","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"defaultMaxVotersForFtso","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"ftsoManager","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IFtsoRegistry"}],"name":"ftsoRegistry","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getFtsoWhitelistedPriceProviders","inputs":[{"type":"uint256","name":"_ftsoIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getFtsoWhitelistedPriceProvidersBySymbol","inputs":[{"type":"string","name":"_symbol","internalType":"string"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"governance","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialise","inputs":[{"type":"address","name":"_governance","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxVotersForFtso","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IIPriceSubmitter"}],"name":"priceSubmitter","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"proposeGovernance","inputs":[{"type":"address","name":"_governance","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"proposedGovernance","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeFtso","inputs":[{"type":"uint256","name":"_ftsoIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeTrustedAddressFromWhitelist","inputs":[{"type":"address","name":"_trustedAddress","internalType":"address"},{"type":"uint256","name":"_ftsoIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256[]","name":"_supportedIndices","internalType":"uint256[]"},{"type":"bool[]","name":"_success","internalType":"bool[]"}],"name":"requestFullVoterWhitelisting","inputs":[{"type":"address","name":"_voter","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"requestWhitelistingVoter","inputs":[{"type":"address","name":"_voter","internalType":"address"},{"type":"uint256","name":"_ftsoIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setContractAddresses","inputs":[{"type":"address","name":"_ftsoRegistry","internalType":"contract IFtsoRegistry"},{"type":"address","name":"_ftsoManager","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setDefaultMaxVotersForFtso","inputs":[{"type":"uint256","name":"_defaultMaxVotersForFtso","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMaxVotersForFtso","inputs":[{"type":"uint256","name":"_ftsoIndex","internalType":"uint256"},{"type":"uint256","name":"_newMaxVoters","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferGovernance","inputs":[{"type":"address","name":"_governance","internalType":"address"}]}]
              

Contract Creation Code

0x60a06040523480156200001157600080fd5b50604051620027f9380380620027f9833981810160405260608110156200003757600080fd5b508051602082015160409092015190919082806001600160a01b0381161562000065576200006581620000d3565b506001600160a01b038116620000b5576040805162461bcd60e51b815260206004820152601060248201526f5f676f7665726e616e6365207a65726f60801b604482015290519081900360640190fd5b5060609190911b6001600160601b03191660805260025550620001b7565b600154600160a01b900460ff161562000133576040805162461bcd60e51b815260206004820152601460248201527f696e697469616c6973656420213d2066616c7365000000000000000000000000604482015290519081900360640190fd5b6001805460ff60a01b1916600160a01b179055600054604080516001600160a01b039283168152918316602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a1600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b60805160601c612615620001e46000398061146252806114895280611bd45280611cd852506126156000f3fe608060405234801561001057600080fd5b50600436106101375760003560e01c80637ecfcfa3116100b8578063b06cbaf71161007c578063b06cbaf7146103a5578063c373a08e14610464578063cd931e401461048a578063d38bfff4146104b8578063d8736171146104de578063f937d6ad146104fb57610137565b80637ecfcfa31461026f57806398dccfc2146102925780639d6a890f146102af5780639dc950ab146102d5578063aa89dfd41461030157610137565b80633de2cb1c116100ff5780633de2cb1c1461021157806347ed51b11461023d5780635aa6e675146102575780635d36b1901461025f57806360f7ac971461026757610137565b806309fcb4001461013c57806311a7aaaa146101a95780632ee96140146101cd578063345705a4146101ec57806338b5f86914610209575b600080fd5b6101596004803603602081101561015257600080fd5b5035610503565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561019557818101518382015260200161017d565b505050509050019250505060405180910390f35b6101b16105ce565b604080516001600160a01b039092168252519081900360200190f35b6101ea600480360360208110156101e357600080fd5b50356105dd565b005b6101ea6004803603602081101561020257600080fd5b5035610633565b6101b16106fc565b6101ea6004803603604081101561022757600080fd5b506001600160a01b03813516906020013561070b565b6102456107b2565b60408051918252519081900360200190f35b6101b16107b8565b6101ea6107c7565b6101b1610889565b6101ea6004803603604081101561028557600080fd5b5080359060200135610898565b610245600480360360208110156102a857600080fd5b5035610ba3565b6101ea600480360360208110156102c557600080fd5b50356001600160a01b0316610bb5565b6101ea600480360360408110156102eb57600080fd5b506001600160a01b038135169060200135610c8f565b6101596004803603602081101561031757600080fd5b810190602081018135600160201b81111561033157600080fd5b82018360208201111561034357600080fd5b803590602001918460018302840111600160201b8311171561036457600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610ea0945050505050565b6103cb600480360360208110156103bb57600080fd5b50356001600160a01b0316610f8f565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b8381101561040f5781810151838201526020016103f7565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561044e578181015183820152602001610436565b5050505090500194505050505060405180910390f35b6101ea6004803603602081101561047a57600080fd5b50356001600160a01b0316611193565b6101ea600480360360408110156104a057600080fd5b506001600160a01b0381358116916020013516611238565b6101ea600480360360208110156104ce57600080fd5b50356001600160a01b03166112b7565b6101ea600480360360208110156104f457600080fd5b5035611379565b6101b1611460565b60008181526003602052604090205460609080610562576040805162461bcd60e51b8152602060048201526018602482015277119514d3c81a5b99195e081b9bdd081cdd5c1c1bdc9d195960421b604482015290519081900360640190fd5b600083815260046020908152604091829020805483518184028101840190945280845290918301828280156105c057602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116105a2575b50505050509150505b919050565b6006546001600160a01b031681565b6000546001600160a01b0316331461062e576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600255565b6006546001600160a01b03163314610686576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333a39b79036b0b730b3b2b960791b604482015290519081900360640190fd5b600081815260036020526040902054156106e7576040805162461bcd60e51b815260206004820152601760248201527f77686974656c69737420616c7265616479206578697374000000000000000000604482015290519081900360640190fd5b60025460009182526003602052604090912055565b6005546001600160a01b031681565b61071482611484565b15610758576040805162461bcd60e51b815260206004820152600f60248201526e74727573746564206164647265737360881b604482015290519081900360640190fd5b600061076483836115ff565b9050806107ad576040805162461bcd60e51b8152602060048201526012602482015271766f746520706f77657220746f6f206c6f7760701b604482015290519081900360640190fd5b505050565b60025481565b6000546001600160a01b031681565b6001546001600160a01b03163314610816576040805162461bcd60e51b815260206004820152600d60248201526c1b9bdd0818db185a5b585a5b9d609a1b604482015290519081900360640190fd5b600054600154604080516001600160a01b03938416815292909116602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6001546001600160a01b031681565b6000546001600160a01b031633146108e9576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600082815260036020908152604080832084905560049091529020805482106109125750610b9f565b6005546040805163d75f6d8160e01b81526004810186905290516000926001600160a01b03169163d75f6d81916024808301926020929190829003018186803b15801561095e57600080fd5b505afa158015610972573d6000803e3d6000fd5b505050506040513d602081101561098857600080fd5b50518254604080516020838102820181019092528281529293506000926109f19285928791908301828280156109e757602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116109c9575b505050505061188b565b805190915084810360008167ffffffffffffffff81118015610a1257600080fd5b50604051908082528060200260200182016040528015610a3c578160200160208202803683370190505b50905060005b82811015610b8d576000610a568686611afe565b9050878181548110610a6457fe5b9060005260206000200160009054906101000a90046001600160a01b0316838381518110610a8e57fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060018503811015610b5057876001860381548110610ac857fe5b9060005260206000200160009054906101000a90046001600160a01b0316888281548110610af257fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550856001860381518110610b2f57fe5b6020026020010151868281518110610b4357fe5b6020026020010181815250505b87805480610b5a57fe5b600082815260209020810160001990810180546001600160a01b0319169055908101909155949094019350600101610a42565b50610b988189611b62565b5050505050505b5050565b60036020526000908152604090205481565b600154600160a01b900460ff1615610c0b576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b6001805460ff60a01b1916600160a01b179055600054604080516001600160a01b039283168152918316602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a1600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b610c9882611484565b610cdf576040805162461bcd60e51b81526020600482015260136024820152726e6f742074727573746564206164647265737360681b604482015290519081900360640190fd5b6000818152600460205260408120805490915b81811015610d3857846001600160a01b0316838281548110610d1057fe5b6000918252602090912001546001600160a01b03161415610d3057610d38565b600101610cf2565b818110610d8c576040805162461bcd60e51b815260206004820152601f60248201527f747275737465642061646472657373206e6f742077686974656c697374656400604482015290519081900360640190fd5b60408051600180825281830190925260009160208083019080368337019050509050838281548110610dba57fe5b600091825260208220015482516001600160a01b03909116918391610ddb57fe5b60200260200101906001600160a01b031690816001600160a01b031681525050836001840381548110610e0a57fe5b9060005260206000200160009054906101000a90046001600160a01b0316848381548110610e3457fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555083805480610e6c57fe5b600082815260209020810160001990810180546001600160a01b0319169055019055610e988186611b62565b505050505050565b600554604051630e848da360e41b81526020600482018181528451602484015284516060946000946001600160a01b039091169363e848da3093889390928392604490910191908501908083838b5b83811015610f07578181015183820152602001610eef565b50505050905090810190601f168015610f345780820380516001836020036101000a031916815260200191505b509250505060206040518083038186803b158015610f5157600080fd5b505afa158015610f65573d6000803e3d6000fd5b505050506040513d6020811015610f7b57600080fd5b50519050610f8881610503565b9392505050565b606080610f9b83611484565b15610fdf576040805162461bcd60e51b815260206004820152600f60248201526e74727573746564206164647265737360881b604482015290519081900360640190fd5b600560009054906101000a90046001600160a01b03166001600160a01b031663798aac5b6040518163ffffffff1660e01b815260040160006040518083038186803b15801561102d57600080fd5b505afa158015611041573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561106a57600080fd5b8101908080516040519392919084600160201b82111561108957600080fd5b90830190602082018581111561109e57600080fd5b82518660208202830111600160201b821117156110ba57600080fd5b82525081516020918201928201910280838360005b838110156110e75781810151838201526020016110cf565b5050505090500160405250505091506000825190508067ffffffffffffffff8111801561111357600080fd5b5060405190808252806020026020018201604052801561113d578160200160208202803683370190505b50915060005b8181101561118c576111688585838151811061115b57fe5b60200260200101516115ff565b83828151811061117457fe5b91151560209283029190910190910152600101611143565b5050915091565b6000546001600160a01b031633146111e4576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600180546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f1f95fb40be3a947982072902a887b521248d1d8931a39eb38f84f4d6fd758b699181900360200190a150565b6000546001600160a01b03163314611289576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600580546001600160a01b039384166001600160a01b03199182161790915560068054929093169116179055565b6000546001600160a01b03163314611308576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600054604080516001600160a01b039283168152918316602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a1600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b6006546001600160a01b031633146113cc576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333a39b79036b0b730b3b2b960791b604482015290519081900360640190fd5b6000818152600460209081526040918290208054835181840281018401909452808452611438939283018282801561142d57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161140f575b505050505082611b62565b600081815260046020526040812061144f91612584565b600090815260036020526040812055565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ffacb84e6040518163ffffffff1660e01b815260040160006040518083038186803b1580156114e057600080fd5b505afa1580156114f4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561151d57600080fd5b8101908080516040519392919084600160201b82111561153c57600080fd5b90830190602082018581111561155157600080fd5b82518660208202830111600160201b8211171561156d57600080fd5b82525081516020918201928201910280838360005b8381101561159a578181015183820152602001611582565b50505050905001604052505050905060005b81518110156115f557836001600160a01b03168282815181106115cb57fe5b60200260200101516001600160a01b031614156115ed576001925050506105c9565b6001016115ac565b5060009392505050565b6000818152600360205260408120548061165b576040805162461bcd60e51b8152602060048201526018602482015277119514d3c81a5b99195e081b9bdd081cdd5c1c1bdc9d195960421b604482015290519081900360640190fd5b6000838152600460205260408120805490916001820167ffffffffffffffff8111801561168757600080fd5b506040519080825280602002602001820160405280156116b1578160200160208202803683370190505b50905060005b8281101561172c5760008482815481106116cd57fe5b6000918252602090912001546001600160a01b03908116915089168114156116fe5760019650505050505050611885565b8083838151811061170b57fe5b6001600160a01b0390921660209283029190910190910152506001016116b7565b508681838151811061173a57fe5b60200260200101906001600160a01b031690816001600160a01b031681525050838210156117a45782546001810184556000848152602090200180546001600160a01b0319166001600160a01b0389161790556117978787611c92565b6001945050505050611885565b60006117b08288611d4d565b9050828114156117c857600095505050505050611885565b604080516001808252818301909252600091602080830190803683370190505090508282815181106117f657fe5b60200260200101518160008151811061180b57fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508885838154811061183857fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506118708189611b62565b61187a8989611c92565b600196505050505050505b92915050565b6060806060600080600080886001600160a01b0316638357d08c6040518163ffffffff1660e01b815260040160006040518083038186803b1580156118cf57600080fd5b505afa1580156118e3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260c081101561190c57600080fd5b8101908080516040519392919084600160201b82111561192b57600080fd5b90830190602082018581111561194057600080fd5b82518660208202830111600160201b8211171561195c57600080fd5b82525081516020918201928201910280838360005b83811015611989578181015183820152602001611971565b5050505090500160405260200180516040519392919084600160201b8211156119b157600080fd5b9083019060208201858111156119c657600080fd5b82518660208202830111600160201b821117156119e257600080fd5b82525081516020918201928201910280838360005b83811015611a0f5781810151838201526020016119f7565b5050505090500160405260200180519060200190929190805190602001909291908051906020019092919080519060200190929190505050809650819750829850839950849a50859b505050505050506000611ad18a6001600160a01b0316639edbf0076040518163ffffffff1660e01b815260040160206040518083038186803b158015611a9d57600080fd5b505afa158015611ab1573d6000803e3d6000fd5b505050506040513d6020811015611ac757600080fd5b5051868b85611dee565b90506000611ae28888878d87611e69565b9050611aef828286611fdc565b9b9a5050505050505050505050565b60008060009050600084600081518110611b1457fe5b6020026020010151905060005b84811015611b58576000868281518110611b3757fe5b60200260200101519050828111611b4f578193508092505b50600101611b21565b5090949350505050565b60005b8251811015611bd1577f33359f2769756ca8d0da4683f25ee440744d6f18bfb166dbfb59315a8c62b016838281518110611b9b57fe5b60200260200101518360405180836001600160a01b031681526020018281526020019250505060405180910390a1600101611b65565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166376794efb83836040518363ffffffff1660e01b81526004018080602001838152602001828103825284818151815260200191508051906020019060200280838360005b83811015611c58578181015183820152602001611c40565b505050509050019350505050600060405180830381600087803b158015611c7e57600080fd5b505af1158015610e98573d6000803e3d6000fd5b604080516001600160a01b03841681526020810183905281517f66a8b13abe95391d1851f5bc319f3dde54ce8f2f40a5fe226aa3251d805832e3929181900390910190a17f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639d986f9183836040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015611c7e57600080fd5b6005546040805163d75f6d8160e01b815260048101849052905160009283926001600160a01b039091169163d75f6d8191602480820192602092909190829003018186803b158015611d9e57600080fd5b505afa158015611db2573d6000803e3d6000fd5b505050506040513d6020811015611dc857600080fd5b505190506000611dd8828661188b565b9050611de5818251611afe565b95945050505050565b6060611dfb858484612121565b905083611e0757611e61565b60005b8351811015611e5f57611e4064e8d4a5100086848481518110611e2957fe5b60200260200101516123199092919063ffffffff16565b828281518110611e4c57fe5b6020908102919091010152600101611e0a565b505b949350505050565b6060825167ffffffffffffffff81118015611e8357600080fd5b50604051908082528060200260200182016040528015611ead578160200160208202803683370190505b50905060005b8351811015611edd576000828281518110611eca57fe5b6020908102919091010152600101611eb3565b5083611ee857611de5565b6000611efc85670de0b6b3a7640000612425565b905060005b8751811015611fd1576000888281518110611f1857fe5b6020026020010151905060006001600160a01b0316816001600160a01b031614611fc8576000611f49828888612121565b905060005b8751811015611fc5576000611f7d8b8681518110611f6857fe5b602002602001015187858581518110611e2957fe5b9050611fa581888481518110611f8f57fe5b602002602001015161247e90919063ffffffff16565b878381518110611fb157fe5b602090810291909101015250600101611f4e565b50505b50600101611f01565b505095945050505050565b60606000611fe9846124d8565b90506000611ff6866124d8565b9050600080831161200857600061200a565b845b9050600080831161201c576000612022565b81612710035b9050875167ffffffffffffffff8111801561203c57600080fd5b50604051908082528060200260200182016040528015612066578160200160208202803683370190505b50945060005b885181101561211557600082156120b3576120b08a838151811061208c57fe5b602002602001015164e8d4a51000026127108702856123199092919063ffffffff16565b90505b600084156120f1576120ee8a84815181106120ca57fe5b602002602001015164e8d4a51000026127108902876123199092919063ffffffff16565b90505b80820188848151811061210057fe5b6020908102919091010152505060010161206c565b50505050509392505050565b6060836001600160a01b031663e587497e8460018651038151811061214257fe5b6020026020010151846040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561219157600080fd5b505af11580156121a5573d6000803e3d6000fd5b505050506040513d60208110156121bb57600080fd5b5050604080516349e3c7e560e01b815260248101849052600481019182528451604482015284516001600160a01b038716926349e3c7e592879287929182916064909101906020868101910280838360005b8381101561222557818101518382015260200161220d565b50505050905001935050505060006040518083038186803b15801561224957600080fd5b505afa15801561225d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561228657600080fd5b8101908080516040519392919084600160201b8211156122a557600080fd5b9083019060208201858111156122ba57600080fd5b82518660208202830111600160201b821117156122d657600080fd5b82525081516020918201928201910280838360005b838110156123035781810151838201526020016122eb565b5050505090500160405250505090509392505050565b6000808211612362576040805162461bcd60e51b815260206004820152601060248201526f4469766973696f6e206279207a65726f60801b604482015290519081900360640190fd5b8361236f57506000610f88565b8383028385828161237c57fe5b0414156123955782818161238c57fe5b04915050610f88565b60008386816123a057fe5b04905060008487816123ae57fe5b06905060008587816123bc57fe5b04905060008688816123ca57fe5b0690506124186123e4886123de8685612425565b9061251d565b6124126123f18686612425565b6124126123fe8987612425565b6124128d61240c8c8b612425565b90612425565b9061247e565b9998505050505050505050565b60008261243457506000611885565b8282028284828161244157fe5b0414610f885760405162461bcd60e51b81526004018080602001828103825260218152602001806125bf6021913960400191505060405180910390fd5b600082820183811015610f88576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600080805b83518110156125165761250c8482815181106124f557fe5b60200260200101518361247e90919063ffffffff16565b91506001016124dd565b5092915050565b6000808211612573576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161257c57fe5b049392505050565b50805460008255906000526020600020908101906125a291906125a5565b50565b5b808211156125ba57600081556001016125a6565b509056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a2646970667358221220cdbf8cd41d816a42348d2f6f5c54600d2fcc25d562b1efa1819378c1fb02ebc164736f6c63430007060033000000000000000000000000493044fbbaa7f9f78379864fa88accaff6a7586e00000000000000000000000010000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000064

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106101375760003560e01c80637ecfcfa3116100b8578063b06cbaf71161007c578063b06cbaf7146103a5578063c373a08e14610464578063cd931e401461048a578063d38bfff4146104b8578063d8736171146104de578063f937d6ad146104fb57610137565b80637ecfcfa31461026f57806398dccfc2146102925780639d6a890f146102af5780639dc950ab146102d5578063aa89dfd41461030157610137565b80633de2cb1c116100ff5780633de2cb1c1461021157806347ed51b11461023d5780635aa6e675146102575780635d36b1901461025f57806360f7ac971461026757610137565b806309fcb4001461013c57806311a7aaaa146101a95780632ee96140146101cd578063345705a4146101ec57806338b5f86914610209575b600080fd5b6101596004803603602081101561015257600080fd5b5035610503565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561019557818101518382015260200161017d565b505050509050019250505060405180910390f35b6101b16105ce565b604080516001600160a01b039092168252519081900360200190f35b6101ea600480360360208110156101e357600080fd5b50356105dd565b005b6101ea6004803603602081101561020257600080fd5b5035610633565b6101b16106fc565b6101ea6004803603604081101561022757600080fd5b506001600160a01b03813516906020013561070b565b6102456107b2565b60408051918252519081900360200190f35b6101b16107b8565b6101ea6107c7565b6101b1610889565b6101ea6004803603604081101561028557600080fd5b5080359060200135610898565b610245600480360360208110156102a857600080fd5b5035610ba3565b6101ea600480360360208110156102c557600080fd5b50356001600160a01b0316610bb5565b6101ea600480360360408110156102eb57600080fd5b506001600160a01b038135169060200135610c8f565b6101596004803603602081101561031757600080fd5b810190602081018135600160201b81111561033157600080fd5b82018360208201111561034357600080fd5b803590602001918460018302840111600160201b8311171561036457600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610ea0945050505050565b6103cb600480360360208110156103bb57600080fd5b50356001600160a01b0316610f8f565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b8381101561040f5781810151838201526020016103f7565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561044e578181015183820152602001610436565b5050505090500194505050505060405180910390f35b6101ea6004803603602081101561047a57600080fd5b50356001600160a01b0316611193565b6101ea600480360360408110156104a057600080fd5b506001600160a01b0381358116916020013516611238565b6101ea600480360360208110156104ce57600080fd5b50356001600160a01b03166112b7565b6101ea600480360360208110156104f457600080fd5b5035611379565b6101b1611460565b60008181526003602052604090205460609080610562576040805162461bcd60e51b8152602060048201526018602482015277119514d3c81a5b99195e081b9bdd081cdd5c1c1bdc9d195960421b604482015290519081900360640190fd5b600083815260046020908152604091829020805483518184028101840190945280845290918301828280156105c057602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116105a2575b50505050509150505b919050565b6006546001600160a01b031681565b6000546001600160a01b0316331461062e576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600255565b6006546001600160a01b03163314610686576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333a39b79036b0b730b3b2b960791b604482015290519081900360640190fd5b600081815260036020526040902054156106e7576040805162461bcd60e51b815260206004820152601760248201527f77686974656c69737420616c7265616479206578697374000000000000000000604482015290519081900360640190fd5b60025460009182526003602052604090912055565b6005546001600160a01b031681565b61071482611484565b15610758576040805162461bcd60e51b815260206004820152600f60248201526e74727573746564206164647265737360881b604482015290519081900360640190fd5b600061076483836115ff565b9050806107ad576040805162461bcd60e51b8152602060048201526012602482015271766f746520706f77657220746f6f206c6f7760701b604482015290519081900360640190fd5b505050565b60025481565b6000546001600160a01b031681565b6001546001600160a01b03163314610816576040805162461bcd60e51b815260206004820152600d60248201526c1b9bdd0818db185a5b585a5b9d609a1b604482015290519081900360640190fd5b600054600154604080516001600160a01b03938416815292909116602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6001546001600160a01b031681565b6000546001600160a01b031633146108e9576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600082815260036020908152604080832084905560049091529020805482106109125750610b9f565b6005546040805163d75f6d8160e01b81526004810186905290516000926001600160a01b03169163d75f6d81916024808301926020929190829003018186803b15801561095e57600080fd5b505afa158015610972573d6000803e3d6000fd5b505050506040513d602081101561098857600080fd5b50518254604080516020838102820181019092528281529293506000926109f19285928791908301828280156109e757602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116109c9575b505050505061188b565b805190915084810360008167ffffffffffffffff81118015610a1257600080fd5b50604051908082528060200260200182016040528015610a3c578160200160208202803683370190505b50905060005b82811015610b8d576000610a568686611afe565b9050878181548110610a6457fe5b9060005260206000200160009054906101000a90046001600160a01b0316838381518110610a8e57fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060018503811015610b5057876001860381548110610ac857fe5b9060005260206000200160009054906101000a90046001600160a01b0316888281548110610af257fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550856001860381518110610b2f57fe5b6020026020010151868281518110610b4357fe5b6020026020010181815250505b87805480610b5a57fe5b600082815260209020810160001990810180546001600160a01b0319169055908101909155949094019350600101610a42565b50610b988189611b62565b5050505050505b5050565b60036020526000908152604090205481565b600154600160a01b900460ff1615610c0b576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b6001805460ff60a01b1916600160a01b179055600054604080516001600160a01b039283168152918316602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a1600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b610c9882611484565b610cdf576040805162461bcd60e51b81526020600482015260136024820152726e6f742074727573746564206164647265737360681b604482015290519081900360640190fd5b6000818152600460205260408120805490915b81811015610d3857846001600160a01b0316838281548110610d1057fe5b6000918252602090912001546001600160a01b03161415610d3057610d38565b600101610cf2565b818110610d8c576040805162461bcd60e51b815260206004820152601f60248201527f747275737465642061646472657373206e6f742077686974656c697374656400604482015290519081900360640190fd5b60408051600180825281830190925260009160208083019080368337019050509050838281548110610dba57fe5b600091825260208220015482516001600160a01b03909116918391610ddb57fe5b60200260200101906001600160a01b031690816001600160a01b031681525050836001840381548110610e0a57fe5b9060005260206000200160009054906101000a90046001600160a01b0316848381548110610e3457fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555083805480610e6c57fe5b600082815260209020810160001990810180546001600160a01b0319169055019055610e988186611b62565b505050505050565b600554604051630e848da360e41b81526020600482018181528451602484015284516060946000946001600160a01b039091169363e848da3093889390928392604490910191908501908083838b5b83811015610f07578181015183820152602001610eef565b50505050905090810190601f168015610f345780820380516001836020036101000a031916815260200191505b509250505060206040518083038186803b158015610f5157600080fd5b505afa158015610f65573d6000803e3d6000fd5b505050506040513d6020811015610f7b57600080fd5b50519050610f8881610503565b9392505050565b606080610f9b83611484565b15610fdf576040805162461bcd60e51b815260206004820152600f60248201526e74727573746564206164647265737360881b604482015290519081900360640190fd5b600560009054906101000a90046001600160a01b03166001600160a01b031663798aac5b6040518163ffffffff1660e01b815260040160006040518083038186803b15801561102d57600080fd5b505afa158015611041573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561106a57600080fd5b8101908080516040519392919084600160201b82111561108957600080fd5b90830190602082018581111561109e57600080fd5b82518660208202830111600160201b821117156110ba57600080fd5b82525081516020918201928201910280838360005b838110156110e75781810151838201526020016110cf565b5050505090500160405250505091506000825190508067ffffffffffffffff8111801561111357600080fd5b5060405190808252806020026020018201604052801561113d578160200160208202803683370190505b50915060005b8181101561118c576111688585838151811061115b57fe5b60200260200101516115ff565b83828151811061117457fe5b91151560209283029190910190910152600101611143565b5050915091565b6000546001600160a01b031633146111e4576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600180546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f1f95fb40be3a947982072902a887b521248d1d8931a39eb38f84f4d6fd758b699181900360200190a150565b6000546001600160a01b03163314611289576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600580546001600160a01b039384166001600160a01b03199182161790915560068054929093169116179055565b6000546001600160a01b03163314611308576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600054604080516001600160a01b039283168152918316602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a1600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b6006546001600160a01b031633146113cc576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333a39b79036b0b730b3b2b960791b604482015290519081900360640190fd5b6000818152600460209081526040918290208054835181840281018401909452808452611438939283018282801561142d57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161140f575b505050505082611b62565b600081815260046020526040812061144f91612584565b600090815260036020526040812055565b7f000000000000000000000000100000000000000000000000000000000000000381565b6000807f00000000000000000000000010000000000000000000000000000000000000036001600160a01b031663ffacb84e6040518163ffffffff1660e01b815260040160006040518083038186803b1580156114e057600080fd5b505afa1580156114f4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561151d57600080fd5b8101908080516040519392919084600160201b82111561153c57600080fd5b90830190602082018581111561155157600080fd5b82518660208202830111600160201b8211171561156d57600080fd5b82525081516020918201928201910280838360005b8381101561159a578181015183820152602001611582565b50505050905001604052505050905060005b81518110156115f557836001600160a01b03168282815181106115cb57fe5b60200260200101516001600160a01b031614156115ed576001925050506105c9565b6001016115ac565b5060009392505050565b6000818152600360205260408120548061165b576040805162461bcd60e51b8152602060048201526018602482015277119514d3c81a5b99195e081b9bdd081cdd5c1c1bdc9d195960421b604482015290519081900360640190fd5b6000838152600460205260408120805490916001820167ffffffffffffffff8111801561168757600080fd5b506040519080825280602002602001820160405280156116b1578160200160208202803683370190505b50905060005b8281101561172c5760008482815481106116cd57fe5b6000918252602090912001546001600160a01b03908116915089168114156116fe5760019650505050505050611885565b8083838151811061170b57fe5b6001600160a01b0390921660209283029190910190910152506001016116b7565b508681838151811061173a57fe5b60200260200101906001600160a01b031690816001600160a01b031681525050838210156117a45782546001810184556000848152602090200180546001600160a01b0319166001600160a01b0389161790556117978787611c92565b6001945050505050611885565b60006117b08288611d4d565b9050828114156117c857600095505050505050611885565b604080516001808252818301909252600091602080830190803683370190505090508282815181106117f657fe5b60200260200101518160008151811061180b57fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508885838154811061183857fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506118708189611b62565b61187a8989611c92565b600196505050505050505b92915050565b6060806060600080600080886001600160a01b0316638357d08c6040518163ffffffff1660e01b815260040160006040518083038186803b1580156118cf57600080fd5b505afa1580156118e3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260c081101561190c57600080fd5b8101908080516040519392919084600160201b82111561192b57600080fd5b90830190602082018581111561194057600080fd5b82518660208202830111600160201b8211171561195c57600080fd5b82525081516020918201928201910280838360005b83811015611989578181015183820152602001611971565b5050505090500160405260200180516040519392919084600160201b8211156119b157600080fd5b9083019060208201858111156119c657600080fd5b82518660208202830111600160201b821117156119e257600080fd5b82525081516020918201928201910280838360005b83811015611a0f5781810151838201526020016119f7565b5050505090500160405260200180519060200190929190805190602001909291908051906020019092919080519060200190929190505050809650819750829850839950849a50859b505050505050506000611ad18a6001600160a01b0316639edbf0076040518163ffffffff1660e01b815260040160206040518083038186803b158015611a9d57600080fd5b505afa158015611ab1573d6000803e3d6000fd5b505050506040513d6020811015611ac757600080fd5b5051868b85611dee565b90506000611ae28888878d87611e69565b9050611aef828286611fdc565b9b9a5050505050505050505050565b60008060009050600084600081518110611b1457fe5b6020026020010151905060005b84811015611b58576000868281518110611b3757fe5b60200260200101519050828111611b4f578193508092505b50600101611b21565b5090949350505050565b60005b8251811015611bd1577f33359f2769756ca8d0da4683f25ee440744d6f18bfb166dbfb59315a8c62b016838281518110611b9b57fe5b60200260200101518360405180836001600160a01b031681526020018281526020019250505060405180910390a1600101611b65565b507f00000000000000000000000010000000000000000000000000000000000000036001600160a01b03166376794efb83836040518363ffffffff1660e01b81526004018080602001838152602001828103825284818151815260200191508051906020019060200280838360005b83811015611c58578181015183820152602001611c40565b505050509050019350505050600060405180830381600087803b158015611c7e57600080fd5b505af1158015610e98573d6000803e3d6000fd5b604080516001600160a01b03841681526020810183905281517f66a8b13abe95391d1851f5bc319f3dde54ce8f2f40a5fe226aa3251d805832e3929181900390910190a17f00000000000000000000000010000000000000000000000000000000000000036001600160a01b0316639d986f9183836040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015611c7e57600080fd5b6005546040805163d75f6d8160e01b815260048101849052905160009283926001600160a01b039091169163d75f6d8191602480820192602092909190829003018186803b158015611d9e57600080fd5b505afa158015611db2573d6000803e3d6000fd5b505050506040513d6020811015611dc857600080fd5b505190506000611dd8828661188b565b9050611de5818251611afe565b95945050505050565b6060611dfb858484612121565b905083611e0757611e61565b60005b8351811015611e5f57611e4064e8d4a5100086848481518110611e2957fe5b60200260200101516123199092919063ffffffff16565b828281518110611e4c57fe5b6020908102919091010152600101611e0a565b505b949350505050565b6060825167ffffffffffffffff81118015611e8357600080fd5b50604051908082528060200260200182016040528015611ead578160200160208202803683370190505b50905060005b8351811015611edd576000828281518110611eca57fe5b6020908102919091010152600101611eb3565b5083611ee857611de5565b6000611efc85670de0b6b3a7640000612425565b905060005b8751811015611fd1576000888281518110611f1857fe5b6020026020010151905060006001600160a01b0316816001600160a01b031614611fc8576000611f49828888612121565b905060005b8751811015611fc5576000611f7d8b8681518110611f6857fe5b602002602001015187858581518110611e2957fe5b9050611fa581888481518110611f8f57fe5b602002602001015161247e90919063ffffffff16565b878381518110611fb157fe5b602090810291909101015250600101611f4e565b50505b50600101611f01565b505095945050505050565b60606000611fe9846124d8565b90506000611ff6866124d8565b9050600080831161200857600061200a565b845b9050600080831161201c576000612022565b81612710035b9050875167ffffffffffffffff8111801561203c57600080fd5b50604051908082528060200260200182016040528015612066578160200160208202803683370190505b50945060005b885181101561211557600082156120b3576120b08a838151811061208c57fe5b602002602001015164e8d4a51000026127108702856123199092919063ffffffff16565b90505b600084156120f1576120ee8a84815181106120ca57fe5b602002602001015164e8d4a51000026127108902876123199092919063ffffffff16565b90505b80820188848151811061210057fe5b6020908102919091010152505060010161206c565b50505050509392505050565b6060836001600160a01b031663e587497e8460018651038151811061214257fe5b6020026020010151846040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561219157600080fd5b505af11580156121a5573d6000803e3d6000fd5b505050506040513d60208110156121bb57600080fd5b5050604080516349e3c7e560e01b815260248101849052600481019182528451604482015284516001600160a01b038716926349e3c7e592879287929182916064909101906020868101910280838360005b8381101561222557818101518382015260200161220d565b50505050905001935050505060006040518083038186803b15801561224957600080fd5b505afa15801561225d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561228657600080fd5b8101908080516040519392919084600160201b8211156122a557600080fd5b9083019060208201858111156122ba57600080fd5b82518660208202830111600160201b821117156122d657600080fd5b82525081516020918201928201910280838360005b838110156123035781810151838201526020016122eb565b5050505090500160405250505090509392505050565b6000808211612362576040805162461bcd60e51b815260206004820152601060248201526f4469766973696f6e206279207a65726f60801b604482015290519081900360640190fd5b8361236f57506000610f88565b8383028385828161237c57fe5b0414156123955782818161238c57fe5b04915050610f88565b60008386816123a057fe5b04905060008487816123ae57fe5b06905060008587816123bc57fe5b04905060008688816123ca57fe5b0690506124186123e4886123de8685612425565b9061251d565b6124126123f18686612425565b6124126123fe8987612425565b6124128d61240c8c8b612425565b90612425565b9061247e565b9998505050505050505050565b60008261243457506000611885565b8282028284828161244157fe5b0414610f885760405162461bcd60e51b81526004018080602001828103825260218152602001806125bf6021913960400191505060405180910390fd5b600082820183811015610f88576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600080805b83518110156125165761250c8482815181106124f557fe5b60200260200101518361247e90919063ffffffff16565b91506001016124dd565b5092915050565b6000808211612573576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161257c57fe5b049392505050565b50805460008255906000526020600020908101906125a291906125a5565b50565b5b808211156125ba57600081556001016125a6565b509056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a2646970667358221220cdbf8cd41d816a42348d2f6f5c54600d2fcc25d562b1efa1819378c1fb02ebc164736f6c63430007060033