Contract Address Details

0xbfA12e4E1411B62EdA8B035d71735667422A6A9e

Contract Name
FtsoManager
Creator
0x493044–a7586e at 0xdeb3f3–1fdf93
Balance
0 SGB
Tokens
Fetching tokens...
Transactions
20 Transactions
Transfers
0 Transfers
Gas Used
7,340,616
Last Balance Update
19120021
Contract name:
FtsoManager




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




Optimization runs
200
EVM Version
default




Verified at
2021-09-17 13:58:11.135604Z

Constructor Arguments

5265776172642065706f6368206475726174696f6e20636f6e646974696f6e20696e76616c69645265776172642065706f636820737461727420636f6e646974696f6e20696e76616c6964000000000000000000000000493044fbbaa7f9f78379864fa88accaff6a7586e00000000000000000000000010000000000000000000000000000000000000020000000000000000000000001000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000006143aba100000000000000000000000000000000000000000000000000000000000000b4000000000000000000000000000000000000000000000000000000000000005a000000000000000000000000000000000000000000000000000000006145a63b0000000000000000000000000000000000000000000000000000000000093a800000000000000000000000000000000000000000000000000000000000000004

Arg [0] (address) : 0x206475726174696f6e20636f6e646974696f6e20
Arg [1] (address) : 0x642065706f636820737461727420636f6e646974
Arg [2] (address) : 0x0000000000000000000000493044fbbaa7f9f783
Arg [3] (uint256) : 54967161967105272774295421565322653183809673969712434805607800255944322973696
Arg [4] (uint256) : 748288838313422294120286634351032053969016814829568
Arg [5] (uint256) : 1122433257470133441180429951526105359095756193005568
Arg [6] (uint256) : 610538142335660755365900103581175507970488629865276197830656
Arg [7] (uint256) : 67345995448208006470825797091566321545745371580334080
Arg [8] (uint256) : 33672997724104003235412898545783160772872685790167040

              

Contract source code

// Sources flattened with hardhat v2.3.0 https://hardhat.org
pragma abicoder v2;
// File contracts/genesis/interface/IFtsoGenesis.sol
// SPDX-License-Identifier: MIT
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/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 @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/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/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/userInterfaces/IFtsoManager.sol
//
pragma solidity 0.7.6;
interface IFtsoManager {
event FtsoAdded(IIFtso ftso, bool add);
event FallbackMode(bool fallbackMode);
event FtsoFallbackMode(IIFtso ftso, bool fallbackMode);
event RewardEpochFinalized(uint256 votepowerBlock, uint256 startBlock);
event PriceEpochFinalized(address chosenFtso, uint256 rewardEpochId);
event InitializingCurrentEpochStateForRevealFailed(IIFtso ftso, uint256 epochId);
event FinalizingPriceEpochFailed(IIFtso ftso, uint256 epochId, IFtso.PriceFinalizationType failingType);
event DistributingRewardsFailed(address ftso, uint256 epochId);
function active() external view returns (bool);
function getPriceSubmitter() external view returns (IPriceSubmitter);
function getCurrentRewardEpoch() external view returns (uint256);
function getRewardEpochVotePowerBlock(uint256 _rewardEpoch) external view returns (uint256);
function getCurrentPriceEpochData() external view
returns (
uint256 _priceEpochId,
uint256 _priceEpochStartTimestamp,
uint256 _priceEpochEndTimestamp,
uint256 _priceEpochRevealEndTimestamp,
uint256 _currentTimestamp
);
function getFtsos() external view returns (IIFtso[] memory _ftsos);
function getPriceEpochConfiguration() external view
returns (
uint256 _firstPriceEpochStartTs,
uint256 _priceEpochDurationSeconds,
uint256 _revealEpochDurationSeconds
);
function getFallbackMode() external view
returns (
bool _fallbackMode,
IIFtso[] memory _ftsos,
bool[] memory _ftsoInFallbackMode
);
}
// File contracts/ftso/interface/IIFtsoManager.sol
//
pragma solidity 0.7.6;
interface IIFtsoManager is IFtsoManager {
event ClosingExpiredRewardEpochFailed(uint256 _rewardEpoch);
event CleanupBlockNumberManagerUnset();
event CleanupBlockNumberManagerFailedForBlock(uint256 blockNumber);
function activate() external;
function setGovernanceParameters(
uint256 _maxVotePowerNatThresholdFraction,
uint256 _maxVotePowerAssetThresholdFraction,
uint256 _lowAssetUSDThreshold,
uint256 _highAssetUSDThreshold,
uint256 _highAssetTurnoutThresholdBIPS,
uint256 _lowNatTurnoutThresholdBIPS,
uint256 _rewardExpiryOffsetSeconds,
address[] memory _trustedAddresses
) external;
function addFtso(IIFtso _ftso) external;
function removeFtso(IIFtso _ftso) external;
function replaceFtso(
IIFtso _ftsoToRemove,
IIFtso _ftsoToAdd,
bool copyCurrentPrice,
bool copyAssetOrAssetFtsos
) external;
function setFtsoAsset(IIFtso _ftso, IIVPToken _asset) external;
function setFtsoAssetFtsos(IIFtso _ftso, IIFtso[] memory _assetFtsos) external;
function setFallbackMode(bool _fallbackMode) external;
function setFtsoFallbackMode(IIFtso _ftso, bool _fallbackMode) external;
}
// File contracts/ftso/lib/FtsoManagerSettings.sol
//
pragma solidity 0.7.6;
/**
* @title A library used for Ftso Manager settings management
*/
library FtsoManagerSettings {
struct State {
// struct holding settings related to FTSOs
// configurable settings
uint256 maxVotePowerNatThresholdFraction; // high threshold for native token vote power per voter
uint256 maxVotePowerAssetThresholdFraction; // high threshold for asset vote power per voter
uint256 lowAssetUSDThreshold; // threshold for low asset vote power (in scaled USD)
uint256 highAssetUSDThreshold; // threshold for high asset vote power (in scaled USD)
uint256 highAssetTurnoutThresholdBIPS; // threshold for high asset turnout (in BIPS)
// actual vote power in (W)NATs / total native token circulating supply (in BIPS)
uint256 lowNatTurnoutThresholdBIPS;
uint256 rewardExpiryOffsetSeconds; // Reward epoch closed earlier than
//block.timestamp - rewardExpiryOffsetSeconds expire
address[] trustedAddresses; //trusted addresses will be used as a fallback mechanism for setting the price
bool changed;
bool initialized;
}
function _setState (
State storage _state,
uint256 _maxVotePowerNatThresholdFraction,
uint256 _maxVotePowerAssetThresholdFraction,
uint256 _lowAssetUSDThreshold,
uint256 _highAssetUSDThreshold,
uint256 _highAssetTurnoutThresholdBIPS,
uint256 _lowNatTurnoutThresholdBIPS,
uint256 _rewardExpiryOffsetSeconds,
address[] memory _trustedAddresses
)
internal
{
if (_state.maxVotePowerNatThresholdFraction != _maxVotePowerNatThresholdFraction) {
_state.changed = true;
_state.maxVotePowerNatThresholdFraction = _maxVotePowerNatThresholdFraction;
}
if (_state.maxVotePowerAssetThresholdFraction != _maxVotePowerAssetThresholdFraction) {
_state.changed = true;
_state.maxVotePowerAssetThresholdFraction = _maxVotePowerAssetThresholdFraction;
}
if (_state.lowAssetUSDThreshold != _lowAssetUSDThreshold) {
_state.changed = true;
_state.lowAssetUSDThreshold = _lowAssetUSDThreshold;
}
if (_state.highAssetUSDThreshold != _highAssetUSDThreshold) {
_state.changed = true;
_state.highAssetUSDThreshold = _highAssetUSDThreshold;
}
if (_state.highAssetTurnoutThresholdBIPS != _highAssetTurnoutThresholdBIPS) {
_state.changed = true;
_state.highAssetTurnoutThresholdBIPS = _highAssetTurnoutThresholdBIPS;
}
if (_state.lowNatTurnoutThresholdBIPS != _lowNatTurnoutThresholdBIPS) {
_state.changed = true;
_state.lowNatTurnoutThresholdBIPS = _lowNatTurnoutThresholdBIPS;
}
if (_state.rewardExpiryOffsetSeconds != _rewardExpiryOffsetSeconds) {
_state.changed = true;
_state.rewardExpiryOffsetSeconds = _rewardExpiryOffsetSeconds;
}
if (_state.trustedAddresses.length != _trustedAddresses.length) {
_state.trustedAddresses = _trustedAddresses;
_state.changed = true;
} else {
for (uint i = 0; i < _trustedAddresses.length; i++) {
if (_state.trustedAddresses[i] != _trustedAddresses[i]) {
_state.changed = true;
_state.trustedAddresses[i] = _trustedAddresses[i];
}
}
}
_state.initialized = true;
}
}
// 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/GovernedAtGenesis.sol
//
pragma solidity 0.7.6;
/**
* @title Governed At Genesis
* @dev This contract enforces a fixed governance address when the constructor
* is not executed on a contract (for instance when directly loaded to the genesis block).
* This is required to fix governance on a contract when the network starts, at such point
* where theoretically no accounts yet exist, and leaving it ungoverned could result in a race
* to claim governance by an unauthorized address.
**/
contract GovernedAtGenesis is GovernedBase {
constructor(address _governance) GovernedBase(_governance) { }
/**
* @notice Set governance to a fixed address when constructor is not called.
**/
function initialiseFixedAddress() public virtual returns (address) {
address governanceAddress = address(0xfffEc6C83c8BF5c3F4AE0cCF8c45CE20E4560BD7);
super.initialise(governanceAddress);
return governanceAddress;
}
/**
* @notice Disallow initialise to be called
* @param _governance The governance address for initial claiming
**/
// solhint-disable-next-line no-unused-vars
function initialise(address _governance) public override pure {
assert(false);
}
}
// File contracts/genesis/interface/IInflationGenesis.sol
//
pragma solidity 0.7.6;
interface IInflationGenesis {
/**
* @notice Receive newly minted native tokens from the FlareDaemon.
* @dev Assume that the amount received will be >= last topup requested across all services.
* If there is not enough balance sent to cover the topup request, expect library method will revert.
* Also assume that any balance received greater than the topup request calculated
* came from self-destructor sending a balance to this contract.
*/
function receiveMinting() external payable;
}
// File contracts/genesis/interface/IFlareDaemonize.sol
//
pragma solidity 0.7.6;
/// Any contracts that want to recieve a trigger from Flare daemon should
/// implement IFlareDaemonize
interface IFlareDaemonize {
/// Implement this function for recieving a trigger from FlareDaemon.
function daemonize() external returns (bool);
/// This function will be called after an error is caught in daemonize().
/// It will switch the contract to a simpler fallback mode, which hopefully works when full mode doesn't.
/// Not every contract needs to support fallback mode (FtsoManager does), so this method may be empty.
/// Switching back to normal mode is left to the contract (typically a governed method call).
/// This function may be called due to low-gas error, so it shouldn't use more than ~30.000 gas.
/// @return true if switched to fallback mode, false if already in fallback mode or if falback not supported
function switchToFallbackMode() external returns (bool);
}
// 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/genesis/implementation/FlareDaemon.sol
//
// WARNING, WARNING, WARNING
// If you modify this contract, you need to re-install the binary into the validator
// genesis file for the chain you wish to run. See ./docs/CompilingContracts.md for more information.
// You have been warned. That is all.
pragma solidity 0.7.6;
/**
* @title Flare Daemon contract
* @notice This contract exists to coordinate regular daemon-like polling of contracts
* that are registered to receive said polling. The trigger method is called by the
* validator right at the end of block state transition.
*/
contract FlareDaemon is GovernedAtGenesis {
using SafeMath for uint256;
using SafePct for uint256;
//====================================================================
// Data Structures
//====================================================================
struct DaemonizedError {
uint192 lastErrorBlock;
uint64 numErrors;
address fromContract;
uint64 errorTypeIndex;
string errorMessage;
}
struct LastErrorData {
uint192 totalDaemonizedErrors;
uint64 lastErrorTypeIndex;
}
struct Registration {
IFlareDaemonize daemonizedContract;
uint256 gasLimit;
}
string internal constant ERR_OUT_OF_BALANCE = "out of balance";
string internal constant ERR_NOT_INFLATION = "not inflation";
string internal constant ERR_TOO_MANY = "too many";
string internal constant ERR_TOO_BIG = "too big";
string internal constant ERR_TOO_OFTEN = "too often";
string internal constant ERR_INFLATION_ZERO = "inflation zero";
string internal constant ERR_BLOCK_NUMBER_SMALL = "block.number small";
string internal constant INDEX_TOO_HIGH = "start index high";
string internal constant UPDATE_GAP_TOO_SHORT = "time gap too short";
string internal constant MAX_MINT_TOO_HIGH = "max mint too high";
string internal constant MAX_MINT_IS_ZERO = "max mint is zero";
string internal constant ERR_DUPLICATE_ADDRESS = "dup address";
string internal constant ERR_ADDRESS_ZERO = "address zero";
string internal constant ERR_OUT_OF_GAS = "out of gas";
string internal constant ERR_INFLATION_MINT_RECEIVE_FAIL = "unknown error. receiveMinting";
uint256 internal constant MAX_DAEMONIZE_CONTRACTS = 10;
// Initial max mint request - 50 million native token
uint256 internal constant MAX_MINTING_REQUEST_DEFAULT = 50000000 ether;
// How often can inflation request minting from the validator - 23 hours constant
uint256 internal constant MAX_MINTING_FREQUENCY_SEC = 23 hours;
// How often can the maximal mint request amount be updated
uint256 internal constant MAX_MINTING_REQUEST_FREQUENCY_SEC = 24 hours;
// By how much can the maximum be increased (as a percentage of the previous maximum)
uint256 internal constant MAX_MINTING_REQUEST_INCREASE_PERCENT = 110;
// upper estimate of gas needed after error occurs in call to daemonizedContract.daemonize()
uint256 internal constant MIN_GAS_LEFT_AFTER_DAEMONIZE = 300000;
// lower estimate for gas needed for daemonize() call in trigger
uint256 internal constant MIN_GAS_FOR_DAEMONIZE_CALL = 5000;
IInflationGenesis public inflation;
uint256 public systemLastTriggeredAt;
uint256 public totalMintingRequestedWei;
uint256 public totalMintingReceivedWei;
uint256 public totalMintingWithdrawnWei;
uint256 public totalSelfDestructReceivedWei;
uint256 public maxMintingRequestWei;
uint256 public lastMintRequestTs;
uint256 public lastUpdateMaxMintRequestTs;
LastErrorData public errorData;
uint256 public blockHoldoff;
uint256 private lastBalance;
uint256 private expectedMintRequest;
bool private initialized;
// track deamonized contracts
IFlareDaemonize[] internal daemonizeContracts;
mapping (IFlareDaemonize => uint256) internal gasLimits;
mapping (IFlareDaemonize => uint256) internal blockHoldoffsRemaining;
// track daemonize errors
mapping(bytes32 => DaemonizedError) internal daemonizedErrors;
bytes32 [] internal daemonizeErrorHashes;
event ContractDaemonized(address theContract, uint256 gasConsumed);
event ContractDaemonizeErrored(address theContract, uint256 atBlock, string theMessage, uint256 gasConsumed);
event ContractHeldOff(address theContract, uint256 blockHoldoffsRemaining);
event ContractsSkippedOutOfGas(uint256 numberOfSkippedConstracts);
event MintingRequestReceived(uint256 amountWei);
event MintingRequestTriggered(uint256 amountWei);
event MintingReceived(uint256 amountWei);
event MintingWithdrawn(uint256 amountWei);
event RegistrationUpdated(IFlareDaemonize theContract, bool add);
event SelfDestructReceived(uint256 amountWei);
event InflationSet(IInflationGenesis theNewContract, IInflationGenesis theOldContract);
/**
* @dev As there is not a constructor, this modifier exists to make sure the inflation
* contract is set for methods that require it.
*/
modifier inflationSet {
// Don't revert...just report.
if (address(inflation) == address(0)) {
addDaemonizeError(address(this), ERR_INFLATION_ZERO, 0);
}
_;
}
/**
* @dev This modifier ensures that this contract's balance matches the expected balance.
*/
modifier mustBalance {
_;
// We should be in balance - don't revert, just report...
uint256 contractBalanceExpected = getExpectedBalance();
if (contractBalanceExpected != address(this).balance) {
addDaemonizeError(address(this), ERR_OUT_OF_BALANCE, 0);
}
}
/**
* @dev Access control to protect methods to allow only minters to call select methods
* (like transferring balance out).
*/
modifier onlyInflation (address _inflation) {
require (address(inflation) == _inflation, ERR_NOT_INFLATION);
_;
}
/**
* @dev Access control to protect trigger() method.
* Please note that the sender address is the same as deployed FlareDaemon address in this case.
*/
modifier onlySystemTrigger {
require (msg.sender == 0x1000000000000000000000000000000000000002);
_;
}
//====================================================================
// Constructor for pre-compiled code
//====================================================================
/**
* @dev This constructor should contain no code as this contract is pre-loaded into the genesis block.
* The super constructor is called for testing convenience.
*/
constructor() GovernedAtGenesis(address(0)) {
/* empty block */
}
//====================================================================
// Functions
//====================================================================
/**
* @notice Register contracts to be polled by the daemon process.
* @param _registrations An array of Registration structures of IFlareDaemonize contracts to daemonize
* and gas limits for each contract.
* @dev A gas limit of zero will set no limit for the contract but the validator has an overall
* limit for the trigger() method.
* @dev If any registrations already exist, they will be unregistered.
* @dev Contracts will be daemonized in the order in which presented via the _registrations array.
*/
function registerToDaemonize(Registration[] calldata _registrations) external onlyGovernance {
// Make sure there are not too many contracts to register.
uint256 registrationsLength = _registrations.length;
require(registrationsLength <= MAX_DAEMONIZE_CONTRACTS, ERR_TOO_MANY);
// Unregister everything first
_unregisterAll();
// Loop over all contracts to register
for (uint256 registrationIndex = 0; registrationIndex < registrationsLength; registrationIndex++) {
// Address cannot be zero
require(address(_registrations[registrationIndex].daemonizedContract) != address(0), ERR_ADDRESS_ZERO);
uint256 daemonizeContractsLength = daemonizeContracts.length;
// Make sure no dups...yes, inefficient. Registration should not be done often.
for (uint256 i = 0; i < daemonizeContractsLength; i++) {
require(_registrations[registrationIndex].daemonizedContract != daemonizeContracts[i],
ERR_DUPLICATE_ADDRESS); // already registered
}
// Store off the registered contract to daemonize, in the order presented.
daemonizeContracts.push(_registrations[registrationIndex].daemonizedContract);
// Record the gas limit for the contract.
gasLimits[_registrations[registrationIndex].daemonizedContract] =
_registrations[registrationIndex].gasLimit;
// Clear any blocks being held off for the given contract, if any. Contracts may be re-presented
// if only order is being modified, for example.
blockHoldoffsRemaining[_registrations[registrationIndex].daemonizedContract] = 0;
emit RegistrationUpdated (_registrations[registrationIndex].daemonizedContract, true);
}
}
/**
* @notice Queue up a minting request to send to the validator at next trigger.
* @param _amountWei The amount to mint.
*/
function requestMinting(uint256 _amountWei) external onlyInflation(msg.sender) {
require(_amountWei <= maxMintingRequestWei, ERR_TOO_BIG);
require(_getNextMintRequestAllowedTs() < block.timestamp, ERR_TOO_OFTEN);
if (_amountWei > 0) {
lastMintRequestTs = block.timestamp;
totalMintingRequestedWei = totalMintingRequestedWei.add(_amountWei);
emit MintingRequestReceived(_amountWei);
}
}
/**
* @notice Set number of blocks that must elapse before a daemonized contract exceeding gas limit can have
* its daemonize() method called again.
* @param _blockHoldoff The number of blocks to holdoff.
*/
function setBlockHoldoff(uint256 _blockHoldoff) external onlyGovernance {
blockHoldoff = _blockHoldoff;
}
/**
* @notice Set limit on how much can be minted per request.
* @param _maxMintingRequestWei The request maximum in wei.
* @notice this number can't be udated too often
*/
function setMaxMintingRequest(uint256 _maxMintingRequestWei) external onlyGovernance {
// make sure increase amount is reasonable
require(
_maxMintingRequestWei <= (maxMintingRequestWei.mulDiv(MAX_MINTING_REQUEST_INCREASE_PERCENT,100)),
MAX_MINT_TOO_HIGH
);
require(_maxMintingRequestWei > 0, MAX_MINT_IS_ZERO);
// make sure enough time since last update
require(
block.timestamp > lastUpdateMaxMintRequestTs + MAX_MINTING_REQUEST_FREQUENCY_SEC,
UPDATE_GAP_TOO_SHORT
);
maxMintingRequestWei = _maxMintingRequestWei;
lastUpdateMaxMintRequestTs = block.timestamp;
}
/**
* @notice Sets the inflation contract, which will receive minted inflation funds for funding to
* rewarding contracts.
* @param _inflation The inflation contract.
*/
function setInflation(IInflationGenesis _inflation) external onlyGovernance {
require(address(_inflation) != address(0), ERR_INFLATION_ZERO);
emit InflationSet(_inflation, inflation);
inflation = _inflation;
if (maxMintingRequestWei == 0) {
maxMintingRequestWei = MAX_MINTING_REQUEST_DEFAULT;
}
}
/**
* @notice The meat of this contract. Poll all registered contracts, calling the daemonize() method of each,
* in the order in which registered.
* @return _toMintWei Return the amount to mint back to the validator. The asked for balance will show
* up in the next block (it is actually added right before this block's state transition,
* but well after this method call will see it.)
* @dev This method watches for balances being added to this contract and handles appropriately - legit
* mint requests as made via requestMinting, and also self-destruct sending to this contract, should
* it happen for some reason.
*/
//slither-disable-next-line reentrancy-eth // method protected by reentrancy guard (see comment below)
function trigger() external virtual inflationSet mustBalance onlySystemTrigger returns (uint256 _toMintWei) {
return triggerInternal();
}
/**
* @notice Unregister all contracts from being polled by the daemon process.
*/
function unregisterAll() external onlyGovernance {
_unregisterAll();
}
function getDaemonizedContractsData() external view
returns(
IFlareDaemonize[] memory _daemonizeContracts,
uint256[] memory _gasLimits,
uint256[] memory _blockHoldoffsRemaining
)
{
uint256 len = daemonizeContracts.length;
_daemonizeContracts = new IFlareDaemonize[](len);
_gasLimits = new uint256[](len);
_blockHoldoffsRemaining = new uint256[](len);
for (uint256 i; i < len; i++) {
IFlareDaemonize daemonizeContract = daemonizeContracts[i];
_daemonizeContracts[i] = daemonizeContract;
_gasLimits[i] = gasLimits[daemonizeContract];
_blockHoldoffsRemaining[i] = blockHoldoffsRemaining[daemonizeContract];
}
}
function getNextMintRequestAllowedTs() external view returns(uint256) {
return _getNextMintRequestAllowedTs();
}
function showLastDaemonizedError () external view
returns(
uint256[] memory _lastErrorBlock,
uint256[] memory _numErrors,
string[] memory _errorString,
address[] memory _erroringContract,
uint256 _totalDaemonizedErrors
)
{
return showDaemonizedErrors(errorData.lastErrorTypeIndex, 1);
}
/**
* @notice Set the governance address to a hard-coded known address.
* @dev This should be done at contract deployment time.
* @return The governance address.
*/
function initialiseFixedAddress() public override returns(address) {
if (!initialized) {
initialized = true;
address governanceAddress = super.initialiseFixedAddress();
return governanceAddress;
} else {
return governance;
}
}
function showDaemonizedErrors (uint startIndex, uint numErrorTypesToShow) public view
returns(
uint256[] memory _lastErrorBlock,
uint256[] memory _numErrors,
string[] memory _errorString,
address[] memory _erroringContract,
uint256 _totalDaemonizedErrors
)
{
require(startIndex < daemonizeErrorHashes.length, INDEX_TOO_HIGH);
uint256 numReportElements =
daemonizeErrorHashes.length >= startIndex + numErrorTypesToShow ?
numErrorTypesToShow :
daemonizeErrorHashes.length - startIndex;
_lastErrorBlock = new uint256[] (numReportElements);
_numErrors = new uint256[] (numReportElements);
_errorString = new string[] (numReportElements);
_erroringContract = new address[] (numReportElements);
// we have error data error type.
// error type is hash(error_string, source contract)
// per error type we report how many times it happened.
// what was last block it happened.
// what is the error string.
// what is the erroring contract
for (uint i = 0; i < numReportElements; i++) {
bytes32 hash = daemonizeErrorHashes[startIndex + i];
_lastErrorBlock[i] = daemonizedErrors[hash].lastErrorBlock;
_numErrors[i] = daemonizedErrors[hash].numErrors;
_errorString[i] = daemonizedErrors[hash].errorMessage;
_erroringContract[i] = daemonizedErrors[hash].fromContract;
}
_totalDaemonizedErrors = errorData.totalDaemonizedErrors;
}
/**
* @notice Implementation of the trigger() method. The external wrapper has extra guard for msg.sender.
*/
//slither-disable-next-line reentrancy-eth // method protected by reentrancy guard (see comment below)
function triggerInternal() internal returns (uint256 _toMintWei) {
// only one trigger() call per block allowed
// this also serves as reentrancy guard, since any re-entry will happen in the same block
if(block.number == systemLastTriggeredAt) return 0;
systemLastTriggeredAt = block.number;
uint256 currentBalance = address(this).balance;
// Did the validator or a self-destructor conjure some native token?
if (currentBalance > lastBalance) {
uint256 balanceExpected = lastBalance.add(expectedMintRequest);
// Did we get what was last asked for?
if (currentBalance == balanceExpected) {
// Yes, so assume it all came from the validator.
uint256 minted = expectedMintRequest;
totalMintingReceivedWei = totalMintingReceivedWei.add(minted);
emit MintingReceived(minted);
//slither-disable-next-line arbitrary-send // only sent to inflation, set by governance
try inflation.receiveMinting{ value: minted }() {
totalMintingWithdrawnWei = totalMintingWithdrawnWei.add(minted);
emit MintingWithdrawn(minted);
} catch Error(string memory message) {
addDaemonizeError(address(this), message, 0);
} catch {
addDaemonizeError(address(this), ERR_INFLATION_MINT_RECEIVE_FAIL, 0);
}
} else if (currentBalance < balanceExpected) {
// No, and if less, there are two possibilities: 1) the validator did not
// send us what we asked (not possible unless a bug), or 2) an attacker
// sent us something in between a request and a mint. Assume 2.
uint256 selfDestructReceived = currentBalance.sub(lastBalance);
totalSelfDestructReceivedWei = totalSelfDestructReceivedWei.add(selfDestructReceived);
emit SelfDestructReceived(selfDestructReceived);
} else {
// No, so assume we got a minting request (perhaps zero...does not matter)
// and some self-destruct proceeds (unlikely but can happen).
totalMintingReceivedWei = totalMintingReceivedWei.add(expectedMintRequest);
uint256 selfDestructReceived = currentBalance.sub(lastBalance).sub(expectedMintRequest);
totalSelfDestructReceivedWei = totalSelfDestructReceivedWei.add(selfDestructReceived);
emit MintingReceived(expectedMintRequest);
emit SelfDestructReceived(selfDestructReceived);
//slither-disable-next-line arbitrary-send // only sent to inflation, set by governance
try inflation.receiveMinting{ value: expectedMintRequest }() {
totalMintingWithdrawnWei = totalMintingWithdrawnWei.add(expectedMintRequest);
emit MintingWithdrawn(expectedMintRequest);
} catch Error(string memory message) {
addDaemonizeError(address(this), message, 0);
} catch {
addDaemonizeError(address(this), ERR_INFLATION_MINT_RECEIVE_FAIL, 0);
}
}
}
uint256 len = daemonizeContracts.length;
// Perform trigger operations here
for (uint256 i = 0; i < len; i++) {
IFlareDaemonize daemonizedContract = daemonizeContracts[i];
uint256 blockHoldoffRemainingForContract = blockHoldoffsRemaining[daemonizedContract];
if (blockHoldoffRemainingForContract > 0) {
blockHoldoffsRemaining[daemonizedContract] = blockHoldoffRemainingForContract - 1;
emit ContractHeldOff(address(daemonizedContract), blockHoldoffRemainingForContract);
} else {
// Figure out what gas to limit call by
uint256 gasLimit = gasLimits[daemonizedContract];
uint256 startGas = gasleft();
// End loop if there isn't enough gas left for any daemonize call
if (startGas < MIN_GAS_LEFT_AFTER_DAEMONIZE + MIN_GAS_FOR_DAEMONIZE_CALL) {
emit ContractsSkippedOutOfGas(len - i);
break;
}
// Calculate the gas limit for the next call
uint256 useGas = startGas - MIN_GAS_LEFT_AFTER_DAEMONIZE;
if (gasLimit > 0 && gasLimit < useGas) {
useGas = gasLimit;
}
// Run daemonize for the contract, consume errors, and record
try daemonizedContract.daemonize{gas: useGas}() {
emit ContractDaemonized(address(daemonizedContract), (startGas - gasleft()));
// Catch all requires with messages
} catch Error(string memory message) {
addDaemonizeError(address(daemonizedContract), message, (startGas - gasleft()));
daemonizedContract.switchToFallbackMode();
// Catch everything else...out of gas, div by zero, asserts, etc.
} catch {
uint256 endGas = gasleft();
// Interpret out of gas errors
if (gasLimit > 0 && startGas.sub(endGas) >= gasLimit) {
addDaemonizeError(address(daemonizedContract), ERR_OUT_OF_GAS, (startGas - endGas));
// When daemonize() fails with out-of-gas, try to fix it in two steps:
// 1) try to switch contract to fallback mode
// (to allow the contract's daemonize() to recover in fallback mode in next block)
// 2) if constract is already in fallback mode or fallback mode is not supported
// (switchToFallbackMode() returns false), start the holdoff for this contract
bool switchedToFallback = daemonizedContract.switchToFallbackMode();
if (!switchedToFallback) {
blockHoldoffsRemaining[daemonizedContract] = blockHoldoff;
}
} else {
// Don't know error cause...just log it as unknown
addDaemonizeError(address(daemonizedContract), "unknown", (startGas - endGas));
daemonizedContract.switchToFallbackMode();
}
}
}
}
// Get any requested minting and return to validator
_toMintWei = getPendingMintRequest();
if (_toMintWei > 0) {
expectedMintRequest = _toMintWei;
emit MintingRequestTriggered(_toMintWei);
} else {
expectedMintRequest = 0;
}
lastBalance = address(this).balance;
}
function addDaemonizeError(address daemonizedContract, string memory message, uint256 gasConsumed) internal {
bytes32 errorStringHash = keccak256(abi.encode(daemonizedContract, message));
DaemonizedError storage daemonizedError = daemonizedErrors[errorStringHash];
if (daemonizedError.numErrors == 0) {
// first time we recieve this error string.
daemonizeErrorHashes.push(errorStringHash);
daemonizedError.fromContract = daemonizedContract;
// limit message length to fit in fixed number of storage words (to make gas usage predictable)
daemonizedError.errorMessage = truncateString(message, 64);
daemonizedError.errorTypeIndex = uint64(daemonizeErrorHashes.length - 1);
}
daemonizedError.numErrors += 1;
daemonizedError.lastErrorBlock = uint192(block.number);
emit ContractDaemonizeErrored(daemonizedContract, block.number, message, gasConsumed);
errorData.totalDaemonizedErrors += 1;
errorData.lastErrorTypeIndex = daemonizedError.errorTypeIndex;
}
/**
* @notice Unregister all contracts from being polled by the daemon process.
*/
function _unregisterAll() private {
uint256 len = daemonizeContracts.length;
for (uint256 i = 0; i < len; i++) {
IFlareDaemonize daemonizedContract = daemonizeContracts[daemonizeContracts.length - 1];
daemonizeContracts.pop();
emit RegistrationUpdated (daemonizedContract, false);
}
}
/**
* @notice Net totals to obtain the expected balance of the contract.
*/
function getExpectedBalance() private view returns(uint256 _balanceExpectedWei) {
_balanceExpectedWei = totalMintingReceivedWei.
sub(totalMintingWithdrawnWei).
add(totalSelfDestructReceivedWei);
}
/**
* @notice Net total received from total requested.
*/
function getPendingMintRequest() private view returns(uint256 _mintRequestPendingWei) {
_mintRequestPendingWei = totalMintingRequestedWei.sub(totalMintingReceivedWei);
}
function _getNextMintRequestAllowedTs() internal view returns (uint256) {
return (lastMintRequestTs + MAX_MINTING_FREQUENCY_SEC);
}
function truncateString(string memory _str, uint256 _maxlength) private pure returns (string memory) {
bytes memory strbytes = bytes(_str);
if (strbytes.length <= _maxlength) {
return _str;
}
bytes memory result = new bytes(_maxlength);
for (uint256 i = 0; i < _maxlength; i++) {
result[i] = strbytes[i];
}
return string(result);
}
}
// 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/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 contracts/inflation/interface/IISupply.sol
//
pragma solidity 0.7.6;
interface IISupply {
/**
* @notice Sets inflation contract. Only governance can call this method.
*/
function setInflation(address _inflation) external;
/**
* @notice Updates authorized inflation and circulating supply - emits event if error
* @param _inflationAuthorizedWei Authorized inflation
* @dev Also updates the burn address amount
*/
function updateAuthorizedInflationAndCirculatingSupply(uint256 _inflationAuthorizedWei) external;
/**
* @notice Get approximate circulating supply for given block number from cache - only past block
* @param _blockNumber Block number
* @return _circulatingSupplyWei Return approximate circulating supply for last known block <= _blockNumber
*/
function getCirculatingSupplyAtCached(uint256 _blockNumber) external returns(uint256 _circulatingSupplyWei);
/**
* @notice Get approximate circulating supply for given block number
* @param _blockNumber Block number
* @return _circulatingSupplyWei Return approximate circulating supply for last known block <= _blockNumber
*/
function getCirculatingSupplyAt(uint256 _blockNumber) external view returns(uint256 _circulatingSupplyWei);
/**
* @notice Get total inflatable balance (initial genesis amount + total authorized inflation)
* @return _inflatableBalanceWei Return inflatable balance
*/
function getInflatableBalance() external view returns(uint256 _inflatableBalanceWei);
}
// File contracts/userInterfaces/IFtsoRewardManager.sol
//
pragma solidity 0.7.6;
interface IFtsoRewardManager {
event RewardClaimed(
address indexed dataProvider,
address indexed whoClaimed,
address indexed sentTo,
uint256 rewardEpoch,
uint256 amount
);
event RewardsDistributed(
address indexed ftso,
uint256 epochId,
address[] addresses,
uint256[] rewards
);
event FeePercentageChanged(
address indexed dataProvider,
uint256 value,
uint256 validFromEpoch
);
event RewardClaimsExpired(
uint256 rewardEpochId
);
/**
* @notice Allows a percentage delegator to claim rewards.
* @notice This function is intended to be used to claim rewards in case of delegation by percentage.
* @param _recipient address to transfer funds to
* @param _rewardEpochs array of reward epoch numbers to claim for
* @return _rewardAmount amount of total claimed rewards
* @dev Reverts if `msg.sender` is delegating by amount
*/
function claimReward(address payable _recipient, uint256[] memory _rewardEpochs)
external returns (uint256 _rewardAmount);
/**
* @notice Allows the sender to claim the rewards from specified data providers.
* @notice This function is intended to be used to claim rewards in case of delegation by amount.
* @param _recipient address to transfer funds to
* @param _rewardEpochs array of reward epoch numbers to claim for
* @param _dataProviders array of addresses representing data providers to claim the reward from
* @return _rewardAmount amount of total claimed rewards
* @dev Function can be used by a percentage delegator but is more gas consuming than `claimReward`.
*/
function claimRewardFromDataProviders(
address payable _recipient,
uint256[] memory _rewardEpochs,
address[] memory _dataProviders
)
external
returns (uint256 _rewardAmount);
/**
* @notice Allows data provider to set (or update last) fee percentage.
* @param _feePercentageBIPS number representing fee percentage in BIPS
* @return _validFromEpoch reward epoch number when the setting becomes effective.
*/
function setDataProviderFeePercentage(uint256 _feePercentageBIPS)
external returns (uint256 _validFromEpoch);
/**
* @notice Returns the current fee percentage of `_dataProvider`
* @param _dataProvider address representing data provider
*/
function getDataProviderCurrentFeePercentage(address _dataProvider)
external view returns (uint256 _feePercentageBIPS);
/**
* @notice Returns the scheduled fee percentage changes of `_dataProvider`
* @param _dataProvider address representing data provider
* @return _feePercentageBIPS positional array of fee percentages in BIPS
* @return _validFromEpoch positional array of block numbers the fee setings are effective from
* @return _fixed positional array of boolean values indicating if settings are subjected to change
*/
function getDataProviderScheduledFeePercentageChanges(address _dataProvider) external view
returns (
uint256[] memory _feePercentageBIPS,
uint256[] memory _validFromEpoch,
bool[] memory _fixed
);
/**
* @notice Returns information on epoch reward
* @param _rewardEpoch reward epoch number
* @return _totalReward number representing the total epoch reward
* @return _claimedReward number representing the amount of total epoch reward that has been claimed
*/
function getEpochReward(uint256 _rewardEpoch) external view
returns (uint256 _totalReward, uint256 _claimedReward);
/**
* @notice Returns the state of rewards for `_beneficiary` at `_rewardEpoch`
* @param _beneficiary address of reward beneficiary
* @param _rewardEpoch reward epoch number
* @return _dataProviders positional array of addresses representing data providers
* @return _rewardAmounts positional array of reward amounts
* @return _claimed positional array of boolean values indicating if reward is claimed
* @return _claimable boolean value indicating if rewards are claimable
* @dev Reverts when queried with `_beneficary` delegating by amount
*/
function getStateOfRewards(
address _beneficiary,
uint256 _rewardEpoch
)
external view
returns (
address[] memory _dataProviders,
uint256[] memory _rewardAmounts,
bool[] memory _claimed,
bool _claimable
);
/**
* @notice Returns the state of rewards for `_beneficiary` at `_rewardEpoch` from `_dataProviders`
* @param _beneficiary address of reward beneficiary
* @param _rewardEpoch reward epoch number
* @param _dataProviders positional array of addresses representing data providers
* @return _rewardAmounts positional array of reward amounts
* @return _claimed positional array of boolean values indicating if reward is claimed
* @return _claimable boolean value indicating if rewards are claimable
*/
function getStateOfRewardsFromDataProviders(
address _beneficiary,
uint256 _rewardEpoch,
address[] memory _dataProviders
)
external view
returns (
uint256[] memory _rewardAmounts,
bool[] memory _claimed,
bool _claimable
);
/**
* @notice Returns the start and the end of the reward epoch range for which the reward is claimable
* @param _startEpochId the oldest epoch id that allows reward claiming
* @param _endEpochId the newest epoch id that allows reward claiming
*/
function getEpochsWithClaimableRewards() external view
returns (
uint256 _startEpochId,
uint256 _endEpochId
);
/**
* @notice Returns the array of claimable epoch ids for which the reward has not yet been claimed
* @param _beneficiary address of reward beneficiary
* @return _epochIds array of epoch ids
* @dev Reverts when queried with `_beneficary` delegating by amount
*/
function getEpochsWithUnclaimedRewards(address _beneficiary) external view returns (
uint256[] memory _epochIds
);
/**
* @notice Returns the information on claimed reward of `_dataProvider` for `_rewardEpoch` by `_claimer`
* @param _rewardEpoch reward epoch number
* @param _dataProvider address representing the data provider
* @param _claimer address representing the claimer
* @return _claimed boolean indicating if reward has been claimed
* @return _amount number representing the claimed amount
*/
function getClaimedReward(
uint256 _rewardEpoch,
address _dataProvider,
address _claimer
)
external view
returns (
bool _claimed,
uint256 _amount
);
/**
* @notice Return reward epoch that will expire, when new reward epoch will start
* @return Reward epoch id that will expire next
*/
function getRewardEpochToExpireNext() external view returns (uint256);
}
// File contracts/tokenPools/interface/IIFtsoRewardManager.sol
//
pragma solidity 0.7.6;
interface IIFtsoRewardManager is IFtsoRewardManager {
event DailyAuthorizedInflationSet(uint256 authorizedAmountWei);
event InflationReceived(uint256 amountReceivedWei);
function activate() external;
function deactivate() external;
function closeExpiredRewardEpoch(uint256 _rewardEpochId) external;
function distributeRewards(
address[] memory addresses,
uint256[] memory weights,
uint256 totalWeight,
uint256 epochId,
address ftso,
uint256 priceEpochDurationSeconds,
uint256 currentRewardEpoch,
uint256 priceEpochEndTime,
uint256 votePowerBlock
) external;
/**
* @notice Returns the information on unclaimed reward of `_dataProvider` for `_rewardEpoch`
* @param _rewardEpoch reward epoch number
* @param _dataProvider address representing the data provider
* @return _amount number representing the unclaimed amount
* @return _weight number representing the share that has not yet been claimed
*/
function getUnclaimedReward(
uint256 _rewardEpoch,
address _dataProvider
)
external view
returns (
uint256 _amount,
uint256 _weight
);
}
// File contracts/token/implementation/CleanupBlockNumberManager.sol
//
pragma solidity 0.7.6;
/**
* @title Token history cleanup manager
* @notice Maintains the list of cleanable tokens for which history cleanup can be collectively cleaned u
*/
contract CleanupBlockNumberManager is Governed {
string internal constant ERR_CONTRACT_NOT_FOUND = "contract not found";
string internal constant ERR_TRIGGER_CONTRACT_OR_GOVERNANCE_ONLY = "trigger or governance only";
IICleanable[] public registeredTokens;
address public triggerContract;
event RegistrationUpdated (IICleanable theContract, bool add);
event CleanupBlockNumberSet (IICleanable theContract, uint256 blockNumber, bool success);
modifier onlyTriggerOrGovernance {
require(
msg.sender == address(triggerContract) ||
msg.sender == governance, ERR_TRIGGER_CONTRACT_OR_GOVERNANCE_ONLY
);
_;
}
constructor(address _governance) Governed(_governance) {
/* empty block */
}
/**
* @notice Sets trigger contract address.
* @dev Usually this is FTSO Manager contract address.
*/
function setTriggerContractAddress(address _triggerContract) external onlyGovernance {
triggerContract = _triggerContract;
}
/**
* @notice Register a contract of which history cleanup index is to be managed
* @param _cleanableToken The address of the contract to be managed.
* @dev when using this function take care that call of setCleanupBlockNumber
* is permitted by this object
*/
function registerToken(IICleanable _cleanableToken) external onlyGovernance {
uint256 len = registeredTokens.length;
for (uint256 i = 0; i < len; i++) {
if (_cleanableToken == registeredTokens[i]) {
return; // already registered
}
}
registeredTokens.push(_cleanableToken);
emit RegistrationUpdated (_cleanableToken, true);
}
/**
* @notice Unregiseter a contract from history cleanup index management
* @param _cleanableToken The address of the contract to unregister.
*/
function unregisterToken(IICleanable _cleanableToken) external onlyGovernance {
uint256 len = registeredTokens.length;
for (uint256 i = 0; i < len; i++) {
if (_cleanableToken == registeredTokens[i]) {
registeredTokens[i] = registeredTokens[len -1];
registeredTokens.pop();
emit RegistrationUpdated (_cleanableToken, false);
return;
}
}
revert(ERR_CONTRACT_NOT_FOUND);
}
/**
* @notice Sets clean up block number on managed cleanable tokens
* @param _blockNumber cleanup block number
*/
function setCleanUpBlockNumber(uint256 _blockNumber) external onlyTriggerOrGovernance {
uint256 len = registeredTokens.length;
for (uint256 i = 0; i < len; i++) {
try registeredTokens[i].setCleanupBlockNumber(_blockNumber) {
emit CleanupBlockNumberSet(registeredTokens[i], _blockNumber, true);
} catch {
emit CleanupBlockNumberSet(registeredTokens[i], _blockNumber, false);
}
}
}
}
// File contracts/utils/implementation/GovernedAndFlareDaemonized.sol
//
pragma solidity 0.7.6;
contract GovernedAndFlareDaemonized is Governed {
FlareDaemon public immutable flareDaemon;
modifier onlyFlareDaemon () {
require (msg.sender == address(flareDaemon), "only flare daemon");
_;
}
constructor(address _governance, FlareDaemon _flareDaemon) Governed(_governance) {
require(address(_flareDaemon) != address(0), "flare daemon zero");
flareDaemon = _flareDaemon;
}
}
// File contracts/utils/implementation/RevertErrorTracking.sol
//
pragma solidity 0.7.6;
/**
* @title Revert Error Tracking
* @notice A contract to track and store revert errors
**/
contract RevertErrorTracking {
struct RevertedError {
uint192 lastErrorBlock;
uint64 numErrors;
address fromContract;
uint64 errorTypeIndex;
string errorMessage;
}
struct LastErrorData {
uint192 totalRevertedErrors;
uint64 lastErrorTypeIndex;
}
string internal constant INDEX_TOO_HIGH = "start index high";
mapping(bytes32 => RevertedError) internal revertedErrors;
bytes32 [] internal revertErrorHashes;
LastErrorData public errorData;
event ContractRevertError(address theContract, uint256 atBlock, string theMessage);
/**
* @notice Returns latest reverted error
* @return _lastErrorBlock Block number of last reverted error
* @return _numErrors Number of times same error with same contract address has been reverted
* @return _errorString Revert error message
* @return _erroringContract Array of addresses of the reverting contracts
* @return _totalRevertedErrors Total number of revert errors across all contracts
*/
function showLastRevertedError () external view
returns(
uint256[] memory _lastErrorBlock,
uint256[] memory _numErrors,
string[] memory _errorString,
address[] memory _erroringContract,
uint256 _totalRevertedErrors
)
{
return showRevertedErrors(errorData.lastErrorTypeIndex, 1);
}
/**
* @notice Adds caught error to reverted errors mapping
* @param revertedContract Address of the reverting contract
* @param message Reverte message
*/
function addRevertError(address revertedContract, string memory message) public {
bytes32 errorStringHash = keccak256(abi.encode(revertedContract, message));
revertedErrors[errorStringHash].numErrors += 1;
revertedErrors[errorStringHash].lastErrorBlock = uint192(block.number);
emit ContractRevertError(revertedContract, block.number, message);
errorData.totalRevertedErrors += 1;
if (revertedErrors[errorStringHash].numErrors > 1) {
// not first time this errors
return;
}
// first time we recieve this error string.
revertErrorHashes.push(errorStringHash);
revertedErrors[errorStringHash].fromContract = revertedContract;
revertedErrors[errorStringHash].errorMessage = message;
revertedErrors[errorStringHash].errorTypeIndex = uint64(revertErrorHashes.length - 1);
errorData.lastErrorTypeIndex = revertedErrors[errorStringHash].errorTypeIndex;
}
/**
* @notice Returns latest reverted error
* @param startIndex Starting index in the error list array
* @param numErrorTypesToShow Number of error types to show
* @return _lastErrorBlock Array of last block number this error reverted
* @return _numErrors Number of times the same error with same contract address has been tracked
* @return _errorString Array of revert error messages
* @return _erroringContract Array of addresses of the reverting contracts
* @return _totalRevertedErrors Total number of errors reverted across all contracts
*/
function showRevertedErrors (uint startIndex, uint numErrorTypesToShow) public view
returns(
uint256[] memory _lastErrorBlock,
uint256[] memory _numErrors,
string[] memory _errorString,
address[] memory _erroringContract,
uint256 _totalRevertedErrors
)
{
require(startIndex < revertErrorHashes.length, INDEX_TOO_HIGH);
uint256 numReportElements =
revertErrorHashes.length >= startIndex + numErrorTypesToShow ?
numErrorTypesToShow :
revertErrorHashes.length - startIndex;
_lastErrorBlock = new uint256[] (numReportElements);
_numErrors = new uint256[] (numReportElements);
_errorString = new string[] (numReportElements);
_erroringContract = new address[] (numReportElements);
// we have error data error type.
// error type is hash(error_string, source contract)
// per error type we report how many times it happened.
// what was last block it happened.
// what is the error string.
// what is the erroring contract
for (uint i = 0; i < numReportElements; i++) {
bytes32 hash = revertErrorHashes[startIndex + i];
_lastErrorBlock[i] = revertedErrors[hash].lastErrorBlock;
_numErrors[i] = revertedErrors[hash].numErrors;
_errorString[i] = revertedErrors[hash].errorMessage;
_erroringContract[i] = revertedErrors[hash].fromContract;
}
_totalRevertedErrors = errorData.totalRevertedErrors;
}
}
// 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 contracts/utils/interface/IIFtsoRegistry.sol
//
pragma solidity 0.7.6;
interface IIFtsoRegistry is IFtsoRegistry {
function setFtsoManagerAddress(IIFtsoManager _ftsoManager) external;
// returns ftso index
function addFtso(IIFtso _ftsoContract) external returns(uint256);
function removeFtso(IIFtso _ftso) external;
}
// File contracts/userInterfaces/IVoterWhitelister.sol
//
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/ftso/implementation/FtsoManager.sol
//
pragma solidity 0.7.6;
/**
* FtsoManager is in charge of:
* - defining reward epochs (few days)
* - per reward epoch choose a single block that represents vote power of this epoch.
* - keep track of all FTSO contracts
* - per price epoch (few minutes)
* - randomly choose one FTSO for rewarding.
* - trigger finalize price reveal epoch
* - determines addresses and reward weights and triggers rewardDistribution
*/
contract FtsoManager is IIFtsoManager, GovernedAndFlareDaemonized, IFlareDaemonize, RevertErrorTracking {
using FtsoManagerSettings for FtsoManagerSettings.State;
struct RewardEpochData {
uint256 votepowerBlock;
uint256 startBlock;
uint256 startTimestamp;
}
uint256 public constant MAX_TRUSTED_ADDRESSES_LENGTH = 5;
string internal constant ERR_FIRST_EPOCH_START_TS_IN_FUTURE = "First epoch start timestamp in future";
string internal constant ERR_REWARD_EPOCH_DURATION_ZERO = "Reward epoch 0";
string internal constant ERR_REWARD_EPOCH_START_TOO_SOON = "Reward epoch start too soon";
string internal constant ERR_REWARD_EPOCH_NOT_INITIALIZED = "Reward epoch not initialized yet";
string internal constant ERR_REWARD_EPOCH_START_CONDITION_INVALID = "Reward epoch start condition invalid";
string internal constant ERR_REWARD_EPOCH_DURATION_CONDITION_INVALID = "Reward epoch duration condition invalid";
string internal constant ERR_PRICE_EPOCH_DURATION_ZERO = "Price epoch 0";
string internal constant ERR_VOTE_POWER_INTERVAL_FRACTION_ZERO = "Vote power interval fraction 0";
string internal constant ERR_REVEAL_PRICE_EPOCH_DURATION_ZERO = "Reveal price epoch 0";
string internal constant ERR_REVEAL_PRICE_EPOCH_TOO_LONG = "Reveal price epoch too long";
string internal constant ERR_GOV_PARAMS_NOT_INIT_FOR_FTSOS = "Gov. params not initialized";
string internal constant ERR_GOV_PARAMS_INVALID = "Gov. params invalid";
string internal constant ERR_ASSET_FTSO_NOT_MANAGED = "Asset FTSO not managed by ftso manager";
string internal constant ERR_NOT_FOUND = "Not found";
string internal constant ERR_ALREADY_ADDED = "Already added";
string internal constant ERR_FTSO_ASSET_FTSO_ZERO = "Asset ftsos list empty";
string internal constant ERR_FTSO_EQUALS_ASSET_FTSO = "ftso equals asset ftso";
string internal constant ERR_FTSO_SYMBOLS_MUST_MATCH = "FTSO symbols must match";
string internal constant ERR_REWARD_EXPIRY_OFFSET_INVALID = "Reward expiry invalid";
string internal constant ERR_MAX_TRUSTED_ADDRESSES_LENGTH_EXCEEDED = "Max trusted addresses length exceeded";
string internal constant ERR_CLOSING_EXPIRED_REWARD_EPOCH_FAIL = "Unknown fail when closing expired";
string internal constant ERR_SET_CLEANUP_BLOCK_FAIL = "unknown fail. setting cleanup block";
string internal constant ERR_PRICE_EPOCH_FINALIZE_FAIL = "unknown fail. finalize price epoch";
string internal constant ERR_DISTRIBUTE_REWARD_FAIL = "unknown fail. distribute rewards";
string internal constant ERR_FALLBACK_FINALIZE_FAIL = "unknown fail. fallback finalize price epoch";
string internal constant ERR_INIT_EPOCH_REVEAL_FAIL = "unknown fail. init epoch for reveal";
string internal constant ERR_FALLBACK_INIT_EPOCH_REVEAL_FAIL = "unknown fail. fallback init epoch for reveal";
bool public override active;
RewardEpochData[] public rewardEpochs;
address public lastRewardedFtsoAddress;
FtsoManagerSettings.State public settings;
// price epoch data
uint256 immutable internal firstPriceEpochStartTs;
uint256 immutable internal priceEpochDurationSeconds;
uint256 immutable internal revealEpochDurationSeconds;
uint256 internal lastUnprocessedPriceEpoch;
uint256 internal lastUnprocessedPriceEpochRevealEnds;
// reward Epoch data
uint256 immutable public rewardEpochDurationSeconds;
uint256 immutable public rewardEpochsStartTs;
uint256 immutable internal votePowerIntervalFraction;
uint256 internal currentRewardEpochEnds;
uint256 internal nextRewardEpochToExpire;
mapping(IIFtso => bool) internal managedFtsos;
mapping(IIFtso => bool) internal notInitializedFtsos;
IIPriceSubmitter public immutable priceSubmitter;
IIFtsoRewardManager public rewardManager;
IIFtsoRegistry public ftsoRegistry;
IIVoterWhitelister public voterWhitelister;
IISupply public supply;
CleanupBlockNumberManager public cleanupBlockNumberManager;
// indicates if lastUnprocessedPriceEpoch is initialized for reveal
// it has to be finalized before new reward epoch can start
bool private priceEpochInitialized;
// fallback mode
bool internal fallbackMode; // all ftsos in fallback mode
mapping(IIFtso => bool) internal ftsoInFallbackMode;
constructor(
address _governance,
FlareDaemon _flareDaemon,
IIPriceSubmitter _priceSubmitter,
uint256 _firstEpochStartTs,
uint256 _priceEpochDurationSeconds,
uint256 _revealEpochDurationSeconds,
uint256 _rewardEpochsStartTs,
uint256 _rewardEpochDurationSeconds,
uint256 _votePowerIntervalFraction
)
GovernedAndFlareDaemonized(_governance, _flareDaemon)
{
require(block.timestamp >= _firstEpochStartTs, ERR_FIRST_EPOCH_START_TS_IN_FUTURE);
require(_rewardEpochDurationSeconds > 0, ERR_REWARD_EPOCH_DURATION_ZERO);
require(_priceEpochDurationSeconds > 0, ERR_PRICE_EPOCH_DURATION_ZERO);
require(_revealEpochDurationSeconds > 0, ERR_REVEAL_PRICE_EPOCH_DURATION_ZERO);
require(_votePowerIntervalFraction > 0, ERR_VOTE_POWER_INTERVAL_FRACTION_ZERO);
require(_revealEpochDurationSeconds < _priceEpochDurationSeconds, ERR_REVEAL_PRICE_EPOCH_TOO_LONG);
require(_firstEpochStartTs + _revealEpochDurationSeconds <= _rewardEpochsStartTs,
ERR_REWARD_EPOCH_START_TOO_SOON);
require((_rewardEpochsStartTs - _revealEpochDurationSeconds - _firstEpochStartTs) %
_priceEpochDurationSeconds == 0, ERR_REWARD_EPOCH_START_CONDITION_INVALID);
require(_rewardEpochDurationSeconds % _priceEpochDurationSeconds == 0,
ERR_REWARD_EPOCH_DURATION_CONDITION_INVALID);
// reward epoch
rewardEpochDurationSeconds = _rewardEpochDurationSeconds;
rewardEpochsStartTs = _rewardEpochsStartTs;
votePowerIntervalFraction = _votePowerIntervalFraction;
currentRewardEpochEnds = _rewardEpochsStartTs + _rewardEpochDurationSeconds;
// price epoch
firstPriceEpochStartTs = _firstEpochStartTs;
priceEpochDurationSeconds = _priceEpochDurationSeconds;
revealEpochDurationSeconds = _revealEpochDurationSeconds;
lastUnprocessedPriceEpochRevealEnds = _rewardEpochsStartTs;
lastUnprocessedPriceEpoch = (_rewardEpochsStartTs - _firstEpochStartTs) / _priceEpochDurationSeconds;
priceSubmitter = _priceSubmitter;
}
function setContractAddresses(
IIFtsoRewardManager _rewardManager,
IIFtsoRegistry _ftsoRegistry,
IIVoterWhitelister _voterWhitelister,
IISupply _supply,
CleanupBlockNumberManager _cleanupBlockNumberManager
)
external
onlyGovernance
{
rewardManager = _rewardManager;
ftsoRegistry = _ftsoRegistry;
voterWhitelister = _voterWhitelister;
supply = _supply;
cleanupBlockNumberManager = _cleanupBlockNumberManager;
}
/**
* @notice Activates FTSO manager (daemonize() runs jobs)
*/
function activate() external override onlyGovernance {
active = true;
}
/**
* @notice Runs task triggered by Daemon.
* The tasks include the following by priority
* - finalizePriceEpoch
* - Set governance parameters and initialize epochs
* - finalizeRewardEpoch
*/
function daemonize() external override onlyFlareDaemon returns (bool) {
// flare daemon trigger. once every block
if (!active) return false;
if (rewardEpochs.length == 0) {
_initializeFirstRewardEpoch();
} else {
// all three conditions can be executed in the same block,
// but are split into three `if else if` groups to reduce gas usage per one block
if (priceEpochInitialized && lastUnprocessedPriceEpochRevealEnds <= block.timestamp) {
// finalizes initialized price epoch if reveal period is over
// sets priceEpochInitialized = false
_finalizePriceEpoch();
} else if (!priceEpochInitialized && currentRewardEpochEnds <= block.timestamp) {
// initialized price epoch must be finalized before new reward epoch can start
// advance currentRewardEpochEnds
_finalizeRewardEpoch();
_closeExpiredRewardEpochs();
_cleanupOnRewardEpochFinalization();
} else if (lastUnprocessedPriceEpochRevealEnds <= block.timestamp) {
// new price epoch can be initialized after previous was finalized
// and after new reward epoch was started (if needed)
// initializes price epoch and sets governance parameters on ftsos and price submitter
// advance lastUnprocessedPriceEpochRevealEnds, sets priceEpochInitialized = true
_initializeCurrentEpochFTSOStatesForReveal();
}
}
return true;
}
function switchToFallbackMode() external override onlyFlareDaemon returns (bool) {
if (!fallbackMode) {
fallbackMode = true;
emit FallbackMode(true);
return true;
}
return false;
}
/**
* @notice Adds FTSO to the list of rewarded FTSOs
* All ftsos in multi asset ftso must be managed by this ftso manager
*/
function addFtso(IIFtso _ftso) external override onlyGovernance {
_addFtso(_ftso, true);
}
/**
* @notice Removes FTSO from the list of the rewarded FTSOs - revert if ftso is used in multi asset ftso
* @dev Deactivates _ftso
*/
function removeFtso(IIFtso _ftso) external override onlyGovernance {
uint256 ftsoIndex = ftsoRegistry.getFtsoIndex(_ftso.symbol());
voterWhitelister.removeFtso(ftsoIndex);
ftsoRegistry.removeFtso(_ftso);
_cleanFtso(_ftso);
}
/**
* @notice Replaces one ftso with another - symbols must match
* All ftsos in multi asset ftso must be managed by this ftso manager
* @dev Deactivates _ftsoToRemove
*/
function replaceFtso(
IIFtso _ftsoToRemove,
IIFtso _ftsoToAdd,
bool _copyCurrentPrice,
bool _copyAssetOrAssetFtsos
)
external override
onlyGovernance
{
// should compare strings but it is not supported - comparing hashes instead
require(keccak256(abi.encode(_ftsoToRemove.symbol())) == keccak256(abi.encode(_ftsoToAdd.symbol())),
ERR_FTSO_SYMBOLS_MUST_MATCH);
// Check if it already exists
IIFtso[] memory availableFtsos = _getFtsos();
uint256 len = availableFtsos.length;
uint256 k = 0;
while (k < len) {
if (availableFtsos[k] == _ftsoToRemove) {
break;
}
++k;
}
if (k == len) {
revert(ERR_NOT_FOUND);
}
if (_copyCurrentPrice) {
(uint256 currentPrice, uint256 timestamp) = _ftsoToRemove.getCurrentPrice();
_ftsoToAdd.updateInitialPrice(currentPrice, timestamp);
}
if (_copyAssetOrAssetFtsos) {
IIVPToken asset = _ftsoToRemove.getAsset();
if (address(asset) != address(0)) { // copy asset if exists
_ftsoToAdd.setAsset(asset);
} else { // copy assetFtsos list if not empty
IIFtso[] memory assetFtsos = _ftsoToRemove.getAssetFtsos();
if (assetFtsos.length > 0) {
_ftsoToAdd.setAssetFtsos(assetFtsos);
}
}
}
// Add without duplicate check
_addFtso(_ftsoToAdd, false);
// replace old contract with the new one in multi asset ftsos
IIFtso[] memory contracts = _getFtsos();
uint256 ftsosLen = contracts.length;
for (uint256 i = 0; i < ftsosLen; i++) {
IIFtso ftso = contracts[i];
if (ftso == _ftsoToRemove) {
continue;
}
IIFtso[] memory assetFtsos = ftso.getAssetFtsos();
uint256 assetFtsosLen = assetFtsos.length;
if (assetFtsosLen > 0) {
bool changed = false;
for (uint256 j = 0; j < assetFtsosLen; j++) {
if (assetFtsos[j] == _ftsoToRemove) {
assetFtsos[j] = _ftsoToAdd;
changed = true;
}
}
if (changed) {
ftso.setAssetFtsos(assetFtsos);
}
}
}
// cleanup old contract
_cleanFtso(_ftsoToRemove);
}
/**
* @notice Set asset for FTSO
*/
function setFtsoAsset(IIFtso _ftso, IIVPToken _asset) external override onlyGovernance {
_ftso.setAsset(_asset);
}
/**
* @notice Set asset FTSOs for FTSO - all ftsos should already be managed by this ftso manager
*/
function setFtsoAssetFtsos(IIFtso _ftso, IIFtso[] memory _assetFtsos) external override onlyGovernance {
uint256 len = _assetFtsos.length;
require (len > 0, ERR_FTSO_ASSET_FTSO_ZERO);
for (uint256 i = 0; i < len; i++) {
if (_ftso == _assetFtsos[i]) {
revert(ERR_FTSO_EQUALS_ASSET_FTSO);
}
}
_checkAssetFtsosAreManaged(_assetFtsos);
_ftso.setAssetFtsos(_assetFtsos);
}
/**
* @notice Set fallback mode
*/
function setFallbackMode(bool _fallbackMode) external override onlyGovernance {
fallbackMode = _fallbackMode;
emit FallbackMode(_fallbackMode);
}
/**
* @notice Set fallback mode for ftso
*/
function setFtsoFallbackMode(IIFtso _ftso, bool _fallbackMode) external override onlyGovernance {
require(managedFtsos[_ftso], ERR_NOT_FOUND);
ftsoInFallbackMode[_ftso] = _fallbackMode;
emit FtsoFallbackMode(_ftso, _fallbackMode);
}
/**
* @notice Sets governance parameters for FTSOs
*/
function setGovernanceParameters(
uint256 _maxVotePowerNatThresholdFraction,
uint256 _maxVotePowerAssetThresholdFraction,
uint256 _lowAssetUSDThreshold,
uint256 _highAssetUSDThreshold,
uint256 _highAssetTurnoutThresholdBIPS,
uint256 _lowNatTurnoutThresholdBIPS,
uint256 _rewardExpiryOffsetSeconds,
address[] memory _trustedAddresses
)
external override onlyGovernance
{
require(_maxVotePowerNatThresholdFraction > 0, ERR_GOV_PARAMS_INVALID);
require(_maxVotePowerAssetThresholdFraction > 0, ERR_GOV_PARAMS_INVALID);
require(_highAssetUSDThreshold >= _lowAssetUSDThreshold, ERR_GOV_PARAMS_INVALID);
require(_highAssetTurnoutThresholdBIPS <= 1e4, ERR_GOV_PARAMS_INVALID);
require(_lowNatTurnoutThresholdBIPS <= 1e4, ERR_GOV_PARAMS_INVALID);
require(_rewardExpiryOffsetSeconds > 0, ERR_REWARD_EXPIRY_OFFSET_INVALID);
require(_trustedAddresses.length <= MAX_TRUSTED_ADDRESSES_LENGTH, ERR_MAX_TRUSTED_ADDRESSES_LENGTH_EXCEEDED);
settings._setState(
_maxVotePowerNatThresholdFraction,
_maxVotePowerAssetThresholdFraction,
_lowAssetUSDThreshold,
_highAssetUSDThreshold,
_highAssetTurnoutThresholdBIPS,
_lowNatTurnoutThresholdBIPS,
_rewardExpiryOffsetSeconds,
_trustedAddresses
);
}
function getVotePowerIntervalFraction() external view returns (uint256) {
return votePowerIntervalFraction;
}
function getPriceSubmitter() external view override returns (IPriceSubmitter) {
return priceSubmitter;
}
/**
* @dev half-closed intervals - end time not included
*/
function getCurrentPriceEpochData() external view override
returns (
uint256 priceEpochId,
uint256 priceEpochStartTimestamp,
uint256 priceEpochEndTimestamp,
uint256 priceEpochRevealEndTimestamp,
uint256 currentTimestamp
)
{
uint256 epochId = _getCurrentPriceEpochId();
return (
epochId,
firstPriceEpochStartTs + epochId * priceEpochDurationSeconds,
firstPriceEpochStartTs + (epochId + 1) * priceEpochDurationSeconds,
firstPriceEpochStartTs + (epochId + 1) * priceEpochDurationSeconds + revealEpochDurationSeconds,
block.timestamp
);
}
/**
* @notice Gets vote power block of the specified reward epoch
* @param _rewardEpoch Reward epoch sequence number
*/
function getRewardEpochVotePowerBlock(uint256 _rewardEpoch) external view override returns (uint256) {
return rewardEpochs[_rewardEpoch].votepowerBlock;
}
/*
* @notice Returns the list of FTSOs
*/
function getFtsos() external view override returns (IIFtso[] memory _ftsos) {
return _getFtsos();
}
function getPriceEpochConfiguration() external view override
returns (
uint256 _firstPriceEpochStartTs,
uint256 _priceEpochDurationSeconds,
uint256 _revealEpochDurationSeconds
)
{
return (firstPriceEpochStartTs, priceEpochDurationSeconds, revealEpochDurationSeconds);
}
function getFallbackMode() external view override
returns (
bool _fallbackMode,
IIFtso[] memory _ftsos,
bool[] memory _ftsoInFallbackMode
)
{
_fallbackMode = fallbackMode;
_ftsos = _getFtsos();
uint256 len = _ftsos.length;
_ftsoInFallbackMode = new bool[](len);
for (uint256 i = 0; i < len; i++) {
_ftsoInFallbackMode[i] = ftsoInFallbackMode[_ftsos[i]];
}
}
/**
* @notice Returns current reward epoch index (one currently running)
*/
function getCurrentRewardEpoch() public view override returns (uint256) {
uint256 rewardEpochsLength = rewardEpochs.length;
require(rewardEpochsLength != 0, ERR_REWARD_EPOCH_NOT_INITIALIZED);
return rewardEpochsLength - 1;
}
function _addFtso(IIFtso _ftso, bool _addNewFtso) internal {
require(settings.initialized, ERR_GOV_PARAMS_NOT_INIT_FOR_FTSOS);
_checkAssetFtsosAreManaged(_ftso.getAssetFtsos());
if (_addNewFtso) {
// Check if symbol already exists in registry
bytes32 symbol = keccak256(abi.encode(_ftso.symbol()));
string[] memory supportedSymbols = ftsoRegistry.getSupportedSymbols();
uint256 len = supportedSymbols.length;
while (len > 0) {
--len;
if (keccak256(abi.encode(supportedSymbols[len])) == symbol) {
revert(ERR_ALREADY_ADDED);
}
}
}
_ftso.activateFtso(firstPriceEpochStartTs, priceEpochDurationSeconds, revealEpochDurationSeconds);
// Set the vote power block
if (rewardEpochs.length != 0) {
_ftso.setVotePowerBlock(rewardEpochs[rewardEpochs.length - 1].votepowerBlock);
}
// Configure
_ftso.configureEpochs(
settings.maxVotePowerNatThresholdFraction,
settings.maxVotePowerAssetThresholdFraction,
settings.lowAssetUSDThreshold,
settings.highAssetUSDThreshold,
settings.highAssetTurnoutThresholdBIPS,
settings.lowNatTurnoutThresholdBIPS,
settings.trustedAddresses
);
// skip first round of price finalization if price epoch was already initialized for reveal
notInitializedFtsos[_ftso] = priceEpochInitialized;
managedFtsos[_ftso] = true;
uint256 ftsoIndex = ftsoRegistry.addFtso(_ftso);
// When a new ftso is added we also add it to the voter whitelister contract
if (_addNewFtso) {
voterWhitelister.addFtso(ftsoIndex);
}
emit FtsoAdded(_ftso, true);
}
function _cleanFtso(IIFtso _ftso) internal {
_ftso.deactivateFtso();
// Since this is as mapping, we can also just delete it, as false is default value for non-existing keys
delete ftsoInFallbackMode[_ftso];
delete notInitializedFtsos[_ftso];
delete managedFtsos[_ftso];
_checkMultiAssetFtsosAreManaged(_getFtsos());
emit FtsoAdded(_ftso, false);
}
/**
* @notice Initializes first reward epoch. Also sets vote power block to FTSOs
*/
function _initializeFirstRewardEpoch() internal {
if (block.timestamp >= currentRewardEpochEnds - rewardEpochDurationSeconds) {
IIFtso[] memory ftsos = _getFtsos();
uint256 numFtsos = ftsos.length;
// Prime the reward epoch array with a new reward epoch
RewardEpochData memory epochData = RewardEpochData({
votepowerBlock: block.number - 1,
startBlock: block.number,
startTimestamp: block.timestamp
});
rewardEpochs.push(epochData);
for (uint256 i = 0; i < numFtsos; ++i) {
ftsos[i].setVotePowerBlock(epochData.votepowerBlock);
}
}
}
/**
* @notice Finalizes reward epoch
*/
function _finalizeRewardEpoch() internal {
IIFtso[] memory ftsos = _getFtsos();
uint256 numFtsos = ftsos.length;
uint256 lastRandom = block.timestamp;
// Are there any FTSOs to process?
if (numFtsos > 0) {
for (uint256 i = 0; i < numFtsos; ++i) {
lastRandom += ftsos[i].getCurrentRandom();
}
}
lastRandom = uint256(keccak256(abi.encode(lastRandom)));
// @dev when considering block boundary for vote power block:
// - if far from now, it doesn't reflect last vote power changes
// - if too small, possible loan attacks.
// IMPORTANT: currentRewardEpoch is actually the one just getting finalized!
uint256 votepowerBlockBoundary =
(block.number - rewardEpochs[getCurrentRewardEpoch()].startBlock) / votePowerIntervalFraction;
// note: votePowerIntervalFraction > 0
if (votepowerBlockBoundary == 0) {
votepowerBlockBoundary = 1;
}
//slither-disable-next-line weak-prng // lastRandom calculated from ftso inputs
uint256 votepowerBlocksAgo = lastRandom % votepowerBlockBoundary;
// prevent block.number becoming votePowerBlock
// if lastRandom % votepowerBlockBoundary == 0
if (votepowerBlocksAgo == 0) {
votepowerBlocksAgo = 1;
}
RewardEpochData memory epochData = RewardEpochData({
votepowerBlock: block.number - votepowerBlocksAgo,
startBlock: block.number,
startTimestamp: block.timestamp
});
rewardEpochs.push(epochData);
for (uint256 i = 0; i < numFtsos; i++) {
ftsos[i].setVotePowerBlock(epochData.votepowerBlock);
}
emit RewardEpochFinalized(epochData.votepowerBlock, epochData.startBlock);
// Advance reward epoch end-time
currentRewardEpochEnds += rewardEpochDurationSeconds;
}
/**
* @notice Closes expired reward epochs
*/
function _closeExpiredRewardEpochs() internal {
uint256 currentRewardEpoch = getCurrentRewardEpoch();
uint256 expiryThreshold = block.timestamp - settings.rewardExpiryOffsetSeconds;
// NOTE: start time of (i+1)th reward epoch is the end time of i-th
// This loop is clearly bounded by the value currentRewardEpoch, which is
// always kept to the value of rewardEpochs.length - 1 in code and this value
// does not change in the loop.
while (
nextRewardEpochToExpire < currentRewardEpoch &&
rewardEpochs[nextRewardEpochToExpire + 1].startTimestamp <= expiryThreshold)
{ // Note: Since nextRewardEpochToExpire + 1 starts at that time
// nextRewardEpochToExpire ends strictly before expiryThreshold,
try rewardManager.closeExpiredRewardEpoch(nextRewardEpochToExpire) {
nextRewardEpochToExpire++;
} catch Error(string memory message) {
// closing of expired failed, which is not critical
// just emit event for diagnostics
emit ClosingExpiredRewardEpochFailed(nextRewardEpochToExpire);
addRevertError(address(rewardManager), message);
// Do not proceed with the loop.
break;
} catch {
emit ClosingExpiredRewardEpochFailed(nextRewardEpochToExpire);
addRevertError(address(rewardManager), ERR_CLOSING_EXPIRED_REWARD_EPOCH_FAIL);
// Do not proceed with the loop.
break;
}
}
}
/**
* @notice Performs any cleanup needed immediately after a reward epoch is finalized
*/
function _cleanupOnRewardEpochFinalization() internal {
if (address(cleanupBlockNumberManager) == address(0)) {
emit CleanupBlockNumberManagerUnset();
return;
}
uint256 cleanupBlock = rewardEpochs[nextRewardEpochToExpire].votepowerBlock;
try cleanupBlockNumberManager.setCleanUpBlockNumber(cleanupBlock) {
} catch Error(string memory message) {
// cleanup block number manager call failed, which is not critical
// just emit event for diagnostics
emit CleanupBlockNumberManagerFailedForBlock(cleanupBlock);
addRevertError(address(cleanupBlockNumberManager), message);
} catch {
emit CleanupBlockNumberManagerFailedForBlock(cleanupBlock);
addRevertError(address(cleanupBlockNumberManager), ERR_SET_CLEANUP_BLOCK_FAIL);
}
}
function _finalizePriceEpochFailed(IIFtso ftso, string memory message) internal {
emit FinalizingPriceEpochFailed(
ftso,
lastUnprocessedPriceEpoch,
IFtso.PriceFinalizationType.WEIGHTED_MEDIAN
);
addRevertError(address(ftso), message);
_fallbackFinalizePriceEpoch(ftso);
}
/**
* @notice Finalizes price epoch
*/
function _finalizePriceEpoch() internal {
IIFtso[] memory ftsos = _getFtsos();
uint256 numFtsos = ftsos.length;
// Are there any FTSOs to process?
if (numFtsos > 0 && !fallbackMode) {
// choose winning ftso
uint256 chosenFtsoId;
if (lastRewardedFtsoAddress == address(0)) {
// pump not yet primed
//slither-disable-next-line weak-prng // only used for first epoch
chosenFtsoId = uint256(keccak256(abi.encode(
block.difficulty, block.timestamp
))) % numFtsos;
} else {
// at least one finalize with real FTSO
uint256 currentRandomSum = 0;
for (uint256 i = 0; i < numFtsos; i++) {
currentRandomSum += ftsos[i].getCurrentRandom(); // may overflow but it is still ok
}
//slither-disable-next-line weak-prng // ftso random calculated safely from inputs
chosenFtsoId = uint256(keccak256(abi.encode(
currentRandomSum, block.timestamp
))) % numFtsos;
}
address[] memory addresses;
uint256[] memory weights;
uint256 totalWeight;
// On the off chance that the winning FTSO does not have any
// recipient within the truncated price distribution to
// receive rewards, find the next FTSO that does have reward
// recipients and declare it the winner. Start with the next ftso.
bool wasDistributed = false;
address rewardedFtsoAddress = address(0);
for (uint256 i = 0; i < numFtsos; i++) {
//slither-disable-next-line weak-prng // not a random, just choosing next
uint256 id = (chosenFtsoId + i) % numFtsos;
IIFtso ftso = ftsos[id];
// skip finalizing ftso, as it is not initialized for reveal and tx would revert
if (notInitializedFtsos[ftso]) {
delete notInitializedFtsos[ftso];
continue;
}
try ftso.finalizePriceEpoch(lastUnprocessedPriceEpoch, !wasDistributed) returns (
address[] memory _addresses,
uint256[] memory _weights,
uint256 _totalWeight
) {
if (!wasDistributed && _addresses.length > 0) { // change also in FTSO if condition changes
(addresses, weights, totalWeight) = (_addresses, _weights, _totalWeight);
wasDistributed = true;
rewardedFtsoAddress = address(ftso);
}
} catch Error(string memory message) {
_finalizePriceEpochFailed(ftso, message);
} catch {
_finalizePriceEpochFailed(ftso, ERR_PRICE_EPOCH_FINALIZE_FAIL);
}
}
uint256 currentRewardEpoch = getCurrentRewardEpoch();
if (wasDistributed) {
try rewardManager.distributeRewards(
addresses,
weights,
totalWeight,
lastUnprocessedPriceEpoch,
rewardedFtsoAddress,
priceEpochDurationSeconds,
currentRewardEpoch,
_getPriceEpochEndTime(lastUnprocessedPriceEpoch) - 1, // actual end time (included)
rewardEpochs[currentRewardEpoch].votepowerBlock) {
} catch Error(string memory message) {
emit DistributingRewardsFailed(rewardedFtsoAddress, lastUnprocessedPriceEpoch);
addRevertError(address(rewardManager), message);
} catch {
emit DistributingRewardsFailed(rewardedFtsoAddress, lastUnprocessedPriceEpoch);
addRevertError(address(rewardManager), ERR_DISTRIBUTE_REWARD_FAIL);
}
}
lastRewardedFtsoAddress = rewardedFtsoAddress;
emit PriceEpochFinalized(rewardedFtsoAddress, currentRewardEpoch);
} else {
// only for fallback mode
for (uint256 i = 0; i < numFtsos; i++) {
IIFtso ftso = ftsos[i];
// skip finalizing ftso, as it is not initialized for reveal and tx would revert
if (notInitializedFtsos[ftso]) {
delete notInitializedFtsos[ftso];
continue;
}
_fallbackFinalizePriceEpoch(ftso);
}
lastRewardedFtsoAddress = address(0);
emit PriceEpochFinalized(address(0), getCurrentRewardEpoch());
}
priceEpochInitialized = false;
}
function _fallbackFinalizePriceEpochFailed(IIFtso _ftso, string memory message) internal {
emit FinalizingPriceEpochFailed(
_ftso,
lastUnprocessedPriceEpoch,
IFtso.PriceFinalizationType.TRUSTED_ADDRESSES
);
addRevertError(address(_ftso), message);
// if reverts we want to propagate up to daemon
_ftso.forceFinalizePriceEpoch(lastUnprocessedPriceEpoch);
}
function _fallbackFinalizePriceEpoch(IIFtso _ftso) internal {
try _ftso.averageFinalizePriceEpoch(lastUnprocessedPriceEpoch) {
} catch Error(string memory message) {
_fallbackFinalizePriceEpochFailed(_ftso, message);
} catch {
_fallbackFinalizePriceEpochFailed(_ftso, ERR_FALLBACK_FINALIZE_FAIL);
}
}
/**
* @notice Initializes epoch states in FTSOs for reveal.
* Prior to initialization it sets governance parameters, if
* governance has changed them. It also sets price submitter trusted addresses.
*/
function _initializeCurrentEpochFTSOStatesForReveal() internal {
if (settings.changed) {
priceSubmitter.setTrustedAddresses(settings.trustedAddresses);
}
IIFtso[] memory ftsos = _getFtsos();
uint256 numFtsos = ftsos.length;
// circulating supply is used only when ftso is not in fallback mode
uint256 circulatingSupplyNat;
if (numFtsos > 0 && !fallbackMode) {
uint256 votePowerBlock = rewardEpochs[rewardEpochs.length - 1].votepowerBlock;
circulatingSupplyNat = supply.getCirculatingSupplyAtCached(votePowerBlock);
}
for (uint256 i = 0; i < numFtsos; i++) {
IIFtso ftso = ftsos[i];
if (settings.changed) {
ftso.configureEpochs(
settings.maxVotePowerNatThresholdFraction,
settings.maxVotePowerAssetThresholdFraction,
settings.lowAssetUSDThreshold,
settings.highAssetUSDThreshold,
settings.highAssetTurnoutThresholdBIPS,
settings.lowNatTurnoutThresholdBIPS,
settings.trustedAddresses
);
}
try ftso.initializeCurrentEpochStateForReveal(
circulatingSupplyNat,
fallbackMode || ftsoInFallbackMode[ftso]) {
} catch Error(string memory message) {
_initializeCurrentEpochStateForRevealFailed(ftso, message);
} catch {
_initializeCurrentEpochStateForRevealFailed(ftso, ERR_INIT_EPOCH_REVEAL_FAIL);
}
}
settings.changed = false;
// Advance price epoch id and end-time
uint256 currentPriceEpochId = _getCurrentPriceEpochId();
lastUnprocessedPriceEpoch = currentPriceEpochId;
lastUnprocessedPriceEpochRevealEnds = _getPriceEpochRevealEndTime(currentPriceEpochId);
priceEpochInitialized = true;
}
function _initializeCurrentEpochStateForRevealFailed(IIFtso ftso, string memory message) internal {
emit InitializingCurrentEpochStateForRevealFailed(ftso, _getCurrentPriceEpochId());
addRevertError(address(ftso), message);
// if it was already called with fallback = true, just mark as not initialized, else retry
if (fallbackMode || ftsoInFallbackMode[ftso]) {
notInitializedFtsos[ftso] = true;
} else {
try ftso.initializeCurrentEpochStateForReveal(0, true) {
} catch Error(string memory message1) {
notInitializedFtsos[ftso] = true;
emit InitializingCurrentEpochStateForRevealFailed(ftso, _getCurrentPriceEpochId());
addRevertError(address(ftso), message1);
} catch {
notInitializedFtsos[ftso] = true;
emit InitializingCurrentEpochStateForRevealFailed(ftso, _getCurrentPriceEpochId());
addRevertError(address(ftso), ERR_FALLBACK_INIT_EPOCH_REVEAL_FAIL);
}
}
}
/**
* @notice Check if asset ftsos are managed by this ftso manager, revert otherwise
*/
function _checkAssetFtsosAreManaged(IIFtso[] memory _assetFtsos) internal view {
uint256 len = _assetFtsos.length;
for (uint256 i = 0; i < len; i++) {
if (!managedFtsos[_assetFtsos[i]]) {
revert(ERR_ASSET_FTSO_NOT_MANAGED);
}
}
}
/**
* @notice Check if all multi asset ftsos are managed by this ftso manager, revert otherwise
*/
function _checkMultiAssetFtsosAreManaged(IIFtso[] memory _ftsos) internal view {
uint256 len = _ftsos.length;
for (uint256 i = 0; i < len; i++) {
_checkAssetFtsosAreManaged(_ftsos[i].getAssetFtsos());
}
}
/**
* @notice Returns price epoch reveal end time.
* @param _priceEpochId The price epoch id.
* @dev half-closed interval - end time not included
*/
function _getPriceEpochRevealEndTime(uint256 _priceEpochId) internal view returns (uint256) {
return firstPriceEpochStartTs + (_priceEpochId + 1) * priceEpochDurationSeconds + revealEpochDurationSeconds;
}
/**
* @notice Returns price epoch end time.
* @param _forPriceEpochId The price epoch id of the end time to fetch.
* @dev half-closed interval - end time not included
*/
function _getPriceEpochEndTime(uint256 _forPriceEpochId) internal view returns (uint256) {
return firstPriceEpochStartTs + ((_forPriceEpochId + 1) * priceEpochDurationSeconds);
}
/**
* @notice Returns current price epoch id. The calculation in this function
* should fully match to definition of current epoch id in FTSO contracts.
*/
function _getCurrentPriceEpochId() internal view returns (uint256) {
return (block.timestamp - firstPriceEpochStartTs) / priceEpochDurationSeconds;
}
function _getFtsos() private view returns (IIFtso[] memory) {
return ftsoRegistry.getSupportedFtsos();
}
}

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_governance","internalType":"address"},{"type":"address","name":"_flareDaemon","internalType":"contract FlareDaemon"},{"type":"address","name":"_priceSubmitter","internalType":"contract IIPriceSubmitter"},{"type":"uint256","name":"_firstEpochStartTs","internalType":"uint256"},{"type":"uint256","name":"_priceEpochDurationSeconds","internalType":"uint256"},{"type":"uint256","name":"_revealEpochDurationSeconds","internalType":"uint256"},{"type":"uint256","name":"_rewardEpochsStartTs","internalType":"uint256"},{"type":"uint256","name":"_rewardEpochDurationSeconds","internalType":"uint256"},{"type":"uint256","name":"_votePowerIntervalFraction","internalType":"uint256"}]},{"type":"event","name":"CleanupBlockNumberManagerFailedForBlock","inputs":[{"type":"uint256","name":"blockNumber","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"CleanupBlockNumberManagerUnset","inputs":[],"anonymous":false},{"type":"event","name":"ClosingExpiredRewardEpochFailed","inputs":[{"type":"uint256","name":"_rewardEpoch","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ContractRevertError","inputs":[{"type":"address","name":"theContract","internalType":"address","indexed":false},{"type":"uint256","name":"atBlock","internalType":"uint256","indexed":false},{"type":"string","name":"theMessage","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"DistributingRewardsFailed","inputs":[{"type":"address","name":"ftso","internalType":"address","indexed":false},{"type":"uint256","name":"epochId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"FallbackMode","inputs":[{"type":"bool","name":"fallbackMode","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"FinalizingPriceEpochFailed","inputs":[{"type":"address","name":"ftso","internalType":"contract IIFtso","indexed":false},{"type":"uint256","name":"epochId","internalType":"uint256","indexed":false},{"type":"uint8","name":"failingType","internalType":"enum IFtso.PriceFinalizationType","indexed":false}],"anonymous":false},{"type":"event","name":"FtsoAdded","inputs":[{"type":"address","name":"ftso","internalType":"contract IIFtso","indexed":false},{"type":"bool","name":"add","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"FtsoFallbackMode","inputs":[{"type":"address","name":"ftso","internalType":"contract IIFtso","indexed":false},{"type":"bool","name":"fallbackMode","internalType":"bool","indexed":false}],"anonymous":false},{"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":"InitializingCurrentEpochStateForRevealFailed","inputs":[{"type":"address","name":"ftso","internalType":"contract IIFtso","indexed":false},{"type":"uint256","name":"epochId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"PriceEpochFinalized","inputs":[{"type":"address","name":"chosenFtso","internalType":"address","indexed":false},{"type":"uint256","name":"rewardEpochId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardEpochFinalized","inputs":[{"type":"uint256","name":"votepowerBlock","internalType":"uint256","indexed":false},{"type":"uint256","name":"startBlock","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_TRUSTED_ADDRESSES_LENGTH","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"activate","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"active","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addFtso","inputs":[{"type":"address","name":"_ftso","internalType":"contract IIFtso"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addRevertError","inputs":[{"type":"address","name":"revertedContract","internalType":"address"},{"type":"string","name":"message","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimGovernance","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract CleanupBlockNumberManager"}],"name":"cleanupBlockNumberManager","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"daemonize","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint192","name":"totalRevertedErrors","internalType":"uint192"},{"type":"uint64","name":"lastErrorTypeIndex","internalType":"uint64"}],"name":"errorData","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract FlareDaemon"}],"name":"flareDaemon","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IIFtsoRegistry"}],"name":"ftsoRegistry","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"priceEpochId","internalType":"uint256"},{"type":"uint256","name":"priceEpochStartTimestamp","internalType":"uint256"},{"type":"uint256","name":"priceEpochEndTimestamp","internalType":"uint256"},{"type":"uint256","name":"priceEpochRevealEndTimestamp","internalType":"uint256"},{"type":"uint256","name":"currentTimestamp","internalType":"uint256"}],"name":"getCurrentPriceEpochData","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getCurrentRewardEpoch","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"_fallbackMode","internalType":"bool"},{"type":"address[]","name":"_ftsos","internalType":"contract IIFtso[]"},{"type":"bool[]","name":"_ftsoInFallbackMode","internalType":"bool[]"}],"name":"getFallbackMode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"_ftsos","internalType":"contract IIFtso[]"}],"name":"getFtsos","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_firstPriceEpochStartTs","internalType":"uint256"},{"type":"uint256","name":"_priceEpochDurationSeconds","internalType":"uint256"},{"type":"uint256","name":"_revealEpochDurationSeconds","internalType":"uint256"}],"name":"getPriceEpochConfiguration","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IPriceSubmitter"}],"name":"getPriceSubmitter","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getRewardEpochVotePowerBlock","inputs":[{"type":"uint256","name":"_rewardEpoch","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getVotePowerIntervalFraction","inputs":[]},{"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":"address","name":"","internalType":"address"}],"name":"lastRewardedFtsoAddress","inputs":[]},{"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":"address","name":"_ftso","internalType":"contract IIFtso"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"replaceFtso","inputs":[{"type":"address","name":"_ftsoToRemove","internalType":"contract IIFtso"},{"type":"address","name":"_ftsoToAdd","internalType":"contract IIFtso"},{"type":"bool","name":"_copyCurrentPrice","internalType":"bool"},{"type":"bool","name":"_copyAssetOrAssetFtsos","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardEpochDurationSeconds","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"votepowerBlock","internalType":"uint256"},{"type":"uint256","name":"startBlock","internalType":"uint256"},{"type":"uint256","name":"startTimestamp","internalType":"uint256"}],"name":"rewardEpochs","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardEpochsStartTs","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IIFtsoRewardManager"}],"name":"rewardManager","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setContractAddresses","inputs":[{"type":"address","name":"_rewardManager","internalType":"contract IIFtsoRewardManager"},{"type":"address","name":"_ftsoRegistry","internalType":"contract IIFtsoRegistry"},{"type":"address","name":"_voterWhitelister","internalType":"contract IIVoterWhitelister"},{"type":"address","name":"_supply","internalType":"contract IISupply"},{"type":"address","name":"_cleanupBlockNumberManager","internalType":"contract CleanupBlockNumberManager"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFallbackMode","inputs":[{"type":"bool","name":"_fallbackMode","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFtsoAsset","inputs":[{"type":"address","name":"_ftso","internalType":"contract IIFtso"},{"type":"address","name":"_asset","internalType":"contract IIVPToken"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFtsoAssetFtsos","inputs":[{"type":"address","name":"_ftso","internalType":"contract IIFtso"},{"type":"address[]","name":"_assetFtsos","internalType":"contract IIFtso[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFtsoFallbackMode","inputs":[{"type":"address","name":"_ftso","internalType":"contract IIFtso"},{"type":"bool","name":"_fallbackMode","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setGovernanceParameters","inputs":[{"type":"uint256","name":"_maxVotePowerNatThresholdFraction","internalType":"uint256"},{"type":"uint256","name":"_maxVotePowerAssetThresholdFraction","internalType":"uint256"},{"type":"uint256","name":"_lowAssetUSDThreshold","internalType":"uint256"},{"type":"uint256","name":"_highAssetUSDThreshold","internalType":"uint256"},{"type":"uint256","name":"_highAssetTurnoutThresholdBIPS","internalType":"uint256"},{"type":"uint256","name":"_lowNatTurnoutThresholdBIPS","internalType":"uint256"},{"type":"uint256","name":"_rewardExpiryOffsetSeconds","internalType":"uint256"},{"type":"address[]","name":"_trustedAddresses","internalType":"address[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"maxVotePowerNatThresholdFraction","internalType":"uint256"},{"type":"uint256","name":"maxVotePowerAssetThresholdFraction","internalType":"uint256"},{"type":"uint256","name":"lowAssetUSDThreshold","internalType":"uint256"},{"type":"uint256","name":"highAssetUSDThreshold","internalType":"uint256"},{"type":"uint256","name":"highAssetTurnoutThresholdBIPS","internalType":"uint256"},{"type":"uint256","name":"lowNatTurnoutThresholdBIPS","internalType":"uint256"},{"type":"uint256","name":"rewardExpiryOffsetSeconds","internalType":"uint256"},{"type":"bool","name":"changed","internalType":"bool"},{"type":"bool","name":"initialized","internalType":"bool"}],"name":"settings","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"_lastErrorBlock","internalType":"uint256[]"},{"type":"uint256[]","name":"_numErrors","internalType":"uint256[]"},{"type":"string[]","name":"_errorString","internalType":"string[]"},{"type":"address[]","name":"_erroringContract","internalType":"address[]"},{"type":"uint256","name":"_totalRevertedErrors","internalType":"uint256"}],"name":"showLastRevertedError","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"_lastErrorBlock","internalType":"uint256[]"},{"type":"uint256[]","name":"_numErrors","internalType":"uint256[]"},{"type":"string[]","name":"_errorString","internalType":"string[]"},{"type":"address[]","name":"_erroringContract","internalType":"address[]"},{"type":"uint256","name":"_totalRevertedErrors","internalType":"uint256"}],"name":"showRevertedErrors","inputs":[{"type":"uint256","name":"startIndex","internalType":"uint256"},{"type":"uint256","name":"numErrorTypesToShow","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IISupply"}],"name":"supply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"switchToFallbackMode","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferGovernance","inputs":[{"type":"address","name":"_governance","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IIVoterWhitelister"}],"name":"voterWhitelister","inputs":[]}]
            

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106102745760003560e01c806393a7902511610151578063ce69f833116100c3578063e7a0d01e11610087578063e7a0d01e146104cf578063e7c830d4146104e2578063e847ae1e146104ea578063f2edab5a146104fd578063f937d6ad14610510578063ff882fbb1461051857610274565b8063ce69f8331461046c578063d38bfff414610481578063e06174e414610494578063e22fdece146104b1578063e371aef0146104b957610274565b8063a795f40911610115578063a795f40914610405578063a93a6f4214610418578063af946af71461042b578063c0ffe9081461043e578063c2b0d47b14610451578063c373a08e1461045957610274565b806393a79025146103b65780639d6a890f146103cf578063a1077532146103e2578063a578f55b146103ea578063a670ff87146103f257610274565b80634eac870f116101ea57806369b11ac6116101ae57806369b11ac6146103655780636b65cc341461036d5780636d0e8c34146103805780636ea0aa311461038857806385f3c9c91461039b5780639131205b146103a357610274565b80634eac870f146103305780635aa6e675146103385780635d36b1901461034057806360f2c5b21461034857806360f7ac971461035d57610274565b8063144e15911161023c578063144e1591146102c65780632663f1b4146102dd5780632b3c41a4146102f05780632fd8eb7d1461030957806338b5f869146103115780634b48dd5e1461031957610274565b806302fb0c5e14610279578063047fc9aa146102975780630e063d7d146102ac5780630f15f4c0146102b45780630f4ef8a6146102be575b600080fd5b61028161052b565b60405161028e9190614e8e565b60405180910390f35b61029f610534565b60405161028e9190614cde565b61029f610543565b6102bc610568565b005b61029f6105c8565b6102ce6105d7565b60405161028e93929190614f8f565b6102bc6102eb3660046145d4565b61063f565b6102f861069e565b60405161028e959493929190614def565b61029f6106d9565b61029f6106e8565b6103216106f7565b60405161028e93929190614e99565b61029f6107d3565b61029f6107e2565b6102bc6107f1565b6103506108b3565b60405161028e9190614f78565b61029f6108d7565b6103506108e6565b6102bc61037b366004614a2b565b6108eb565b61028161099e565b6102f8610396366004614ae1565b610aaf565b610350610e13565b6102bc6103b1366004614b25565b610e37565b6103be6110a7565b60405161028e959493929190614fa5565b6102bc6103dd3660046145d4565b61113a565b61029f611214565b610350611238565b6102bc6104003660046145d4565b61125c565b6102ce610413366004614ab1565b611486565b6102bc6104263660046148f3565b6114b9565b6102bc6104393660046149a0565b611649565b6102bc61044c3660046145f7565b61175a565b61029f611933565b6102bc6104673660046145d4565b611942565b6104746119e7565b60405161028e9190614ddc565b6102bc61048f3660046145d4565b6119f6565b61049c611ab8565b60405161028e9998979695949392919061500c565b610281611adf565b6104c1611bbd565b60405161028e929190614f56565b6102bc6104dd3660046149d4565b611bde565b6103506122db565b6102bc6104f8366004614883565b61233e565b61035061050b366004614ab1565b6123ee565b61029f612417565b6102bc610526366004614869565b61243b565b60055460ff1681565b601a546001600160a01b031681565b7f00000000000000000000000010000000000000000000000000000000000000035b90565b6000546001600160a01b031633146105b9576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b6005805460ff19166001179055565b6017546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000006143aba17f00000000000000000000000000000000000000000000000000000000000000b47f000000000000000000000000000000000000000000000000000000000000005a909192565b6000546001600160a01b03163314610690576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b61069b8160016124de565b50565b6004546060908190819081906000906106c890600160c01b90046001600160401b03166001610aaf565b945094509450945094509091929394565b6007546001600160a01b031681565b6018546001600160a01b031681565b601b54600160a81b900460ff1660608061070f612abc565b8051909250806001600160401b038111801561072a57600080fd5b50604051908082528060200260200182016040528015610754578160200160208202803683370190505b50915060005b818110156107cc57601c600085838151811061077257fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a900460ff168382815181106107b457fe5b9115156020928302919091019091015260010161075a565b5050909192565b601b546001600160a01b031681565b6000546001600160a01b031681565b6001546001600160a01b03163314610840576040805162461bcd60e51b815260206004820152600d60248201526c1b9bdd0818db185a5b585a5b9d609a1b604482015290519081900360640190fd5b600054600154604080516001600160a01b03938416815292909116602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b7f000000000000000000000000000000000000000000000000000000000000000490565b6001546001600160a01b031681565b600581565b6000546001600160a01b0316331461093c576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b60405163d0d552dd60e01b81526001600160a01b0383169063d0d552dd90610968908490600401614cde565b600060405180830381600087803b15801561098257600080fd5b505af1158015610996573d6000803e3d6000fd5b505050505050565b6000336001600160a01b037f00000000000000000000000010000000000000000000000000000000000000021614610a11576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b60055460ff16610a2357506000610565565b600654610a3757610a32612b3d565b610aa9565b601b54600160a01b900460ff168015610a5257504260125411155b15610a5f57610a32612cb2565b601b54600160a01b900460ff16158015610a7b57504260135411155b15610a9857610a88613293565b610a90613588565b610a32613717565b4260125411610aa957610aa96138a8565b50600190565b606080606080600060038054905087106040518060400160405280601081526020016f0e6e8c2e4e840d2dcc8caf040d0d2ced60831b81525090610b0f5760405162461bcd60e51b8152600401610b069190614f43565b60405180910390fd5b506003546000908888011115610b2a57600354889003610b2c565b865b9050806001600160401b0381118015610b4457600080fd5b50604051908082528060200260200182016040528015610b6e578160200160208202803683370190505b509550806001600160401b0381118015610b8757600080fd5b50604051908082528060200260200182016040528015610bb1578160200160208202803683370190505b509450806001600160401b0381118015610bca57600080fd5b50604051908082528060200260200182016040528015610bfe57816020015b6060815260200190600190039081610be95790505b509350806001600160401b0381118015610c1757600080fd5b50604051908082528060200260200182016040528015610c41578160200160208202803683370190505b50925060005b81811015610df75760006003828b0181548110610c6057fe5b6000918252602080832090910154808352600290915260409091205489519192506001600160c01b031690899084908110610c9757fe5b6020026020010181815250506002600082815260200190815260200160002060000160189054906101000a90046001600160401b03166001600160401b0316878381518110610ce257fe5b602090810291909101810191909152600082815260028083526040918290208101805483516001821615610100026000190190911692909204601f81018590048502830185019093528282529092909190830182828015610d845780601f10610d5957610100808354040283529160200191610d84565b820191906000526020600020905b815481529060010190602001808311610d6757829003601f168201915b5050505050868381518110610d9557fe5b60200260200101819052506002600082815260200190815260200160002060010160009054906101000a90046001600160a01b0316858381518110610dd657fe5b6001600160a01b039092166020928302919091019091015250600101610c47565b50506004549497939650919450926001600160c01b0316919050565b7f0000000000000000000000000000000000000000000000000000000000093a8081565b6000546001600160a01b03163314610e88576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b60408051808201909152601381527211dbdd8b881c185c985b5cc81a5b9d985b1a59606a1b602082015288610ed05760405162461bcd60e51b8152600401610b069190614f43565b5060408051808201909152601381527211dbdd8b881c185c985b5cc81a5b9d985b1a59606a1b602082015287610f195760405162461bcd60e51b8152600401610b069190614f43565b5060408051808201909152601381527211dbdd8b881c185c985b5cc81a5b9d985b1a59606a1b602082015286861015610f655760405162461bcd60e51b8152600401610b069190614f43565b5060408051808201909152601381527211dbdd8b881c185c985b5cc81a5b9d985b1a59606a1b6020820152612710851115610fb35760405162461bcd60e51b8152600401610b069190614f43565b5060408051808201909152601381527211dbdd8b881c185c985b5cc81a5b9d985b1a59606a1b60208201526127108411156110015760405162461bcd60e51b8152600401610b069190614f43565b5060408051808201909152601581527414995dd85c9908195e1c1a5c9e481a5b9d985b1a59605a1b60208201528261104c5760405162461bcd60e51b8152600401610b069190614f43565b5060058151111560405180606001604052806025815260200161519c602591399061108a5760405162461bcd60e51b8152600401610b069190614f43565b5061109d60088989898989898989613bd9565b5050505050505050565b6000806000806000806110b8613dd2565b9550507f000000000000000000000000000000000000000000000000000000006143aba17f00000000000000000000000000000000000000000000000000000000000000b4808702820195506001870102019250507f000000000000000000000000000000000000000000000000000000000000005a82019050429091929394565b600154600160a01b900460ff1615611190576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b6001805460ff60a01b1916600160a01b179055600054604080516001600160a01b039283168152918316602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a1600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b7f000000000000000000000000100000000000000000000000000000000000000281565b7f000000000000000000000000000000000000000000000000000000006145a63b81565b6000546001600160a01b031633146112ad576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b6000601860009054906101000a90046001600160a01b03166001600160a01b031663e848da30836001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561130c57600080fd5b505afa158015611320573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113489190810190614a7f565b6040518263ffffffff1660e01b81526004016113649190614f43565b60206040518083038186803b15801561137c57600080fd5b505afa158015611390573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b49190614ac9565b60195460405163d873617160e01b81529192506001600160a01b03169063d8736171906113e5908490600401614f78565b600060405180830381600087803b1580156113ff57600080fd5b505af1158015611413573d6000803e3d6000fd5b505060185460405163a670ff8760e01b81526001600160a01b03909116925063a670ff879150611447908590600401614cde565b600060405180830381600087803b15801561146157600080fd5b505af1158015611475573d6000803e3d6000fd5b5050505061148282613e25565b5050565b6006818154811061149657600080fd5b600091825260209091206003909102018054600182015460029092015490925083565b6000546001600160a01b0316331461150a576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b80516040805180820190915260168152754173736574206674736f73206c69737420656d70747960501b6020820152816115575760405162461bcd60e51b8152600401610b069190614f43565b5060005b818110156115dc5782818151811061156f57fe5b60200260200101516001600160a01b0316846001600160a01b031614156115d45760408051808201825260168152756674736f20657175616c73206173736574206674736f60501b6020820152905162461bcd60e51b8152610b069190600401614f43565b60010161155b565b506115e682613efc565b60405163098fef7160e11b81526001600160a01b0384169063131fdee290611612908590600401614ddc565b600060405180830381600087803b15801561162c57600080fd5b505af1158015611640573d6000803e3d6000fd5b50505050505050565b6000546001600160a01b0316331461169a576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b6001600160a01b0382166000908152601560209081526040918290205482518084019093526009835268139bdd08199bdd5b9960ba1b9183019190915260ff166116f75760405162461bcd60e51b8152600401610b069190614f43565b506001600160a01b0382166000908152601c602052604090819020805460ff1916831515179055517f24462ede4d3e8e5a69fecec6290d42a311016ca752216d9a3d681e284791b7ac9061174e9084908490614ee9565b60405180910390a15050565b6000828260405160200161176f929190614d0b565b60408051601f198184030181528282528051602091820120600081815260029092529190208054436001600160c01b038181166001600160401b03600160c01b80860482166001019091160291909316176001600160c01b031916919091179091559092507f1a601cf5e0efbd558b2778b7389af04741d1c49bcab104c40daa2da194593617916118039186918690614d2f565b60405180910390a1600480546001600160c01b0319811660016001600160c01b03928316810190921617909155600082815260026020526040902054600160c01b90046001600160401b0316111561185b5750611482565b6003805460018082019092557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01829055600082815260026020818152604090922092830180546001600160a01b0319166001600160a01b03881617905584516118cb9390910191850190614417565b50600354600091825260026020526040909120600101805467ffffffffffffffff60a01b1916600160a01b6000199093016001600160401b0390811684029190911791829055600480546001600160c01b03169390920416600160c01b029190911790555050565b6019546001600160a01b031681565b6000546001600160a01b03163314611993576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600180546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f1f95fb40be3a947982072902a887b521248d1d8931a39eb38f84f4d6fd758b699181900360200190a150565b60606119f1612abc565b905090565b6000546001600160a01b03163314611a47576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600054604080516001600160a01b039283168152918316602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a1600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b600854600954600a54600b54600c54600d54600e5460105460ff8082169161010090041689565b6000336001600160a01b037f00000000000000000000000010000000000000000000000000000000000000021614611b52576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b601b54600160a81b900460ff16611bb757601b805460ff60a81b1916600160a81b1790556040517f217a37a37fc40a97159886f80c3d45986e6fc4330ce6ad7283478b5e5ab705bc90611ba790600190614e8e565b60405180910390a1506001610565565b50600090565b6004546001600160c01b03811690600160c01b90046001600160401b031682565b6000546001600160a01b03163314611c2f576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b826001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015611c6857600080fd5b505afa158015611c7c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611ca49190810190614a7f565b604051602001611cb49190614f43565b60405160208183030381529060405280519060200120846001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015611d0357600080fd5b505afa158015611d17573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611d3f9190810190614a7f565b604051602001611d4f9190614f43565b60405160208183030381529060405280519060200120146040518060400160405280601781526020017f4654534f2073796d626f6c73206d757374206d6174636800000000000000000081525090611dba5760405162461bcd60e51b8152600401610b069190614f43565b506000611dc5612abc565b805190915060005b81811015611e0f57866001600160a01b0316838281518110611deb57fe5b60200260200101516001600160a01b03161415611e0757611e0f565b600101611dcd565b81811415611e4e576040805180820182526009815268139bdd08199bdd5b9960ba1b6020820152905162461bcd60e51b8152610b069190600401614f43565b8415611f2f57600080886001600160a01b031663eb91d37e6040518163ffffffff1660e01b8152600401604080518083038186803b158015611e8f57600080fd5b505afa158015611ea3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ec79190614b02565b60405163306ba25360e01b815291935091506001600160a01b0389169063306ba25390611efa9085908590600401614f81565b600060405180830381600087803b158015611f1457600080fd5b505af1158015611f28573d6000803e3d6000fd5b5050505050505b8315612100576000876001600160a01b0316635c222bad6040518163ffffffff1660e01b815260040160206040518083038186803b158015611f7057600080fd5b505afa158015611f84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa89190614a63565b90506001600160a01b0381161561201c5760405163d0d552dd60e01b81526001600160a01b0388169063d0d552dd90611fe5908490600401614cde565b600060405180830381600087803b158015611fff57600080fd5b505af1158015612013573d6000803e3d6000fd5b505050506120fe565b6000886001600160a01b03166318931c356040518163ffffffff1660e01b815260040160006040518083038186803b15801561205757600080fd5b505afa15801561206b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120939190810190614749565b8051909150156120fc5760405163098fef7160e11b81526001600160a01b0389169063131fdee2906120c9908490600401614ddc565b600060405180830381600087803b1580156120e357600080fd5b505af11580156120f7573d6000803e3d6000fd5b505050505b505b505b61210b8660006124de565b6000612115612abc565b805190915060005b818110156122c657600083828151811061213357fe5b602002602001015190508a6001600160a01b0316816001600160a01b0316141561215d57506122be565b6000816001600160a01b03166318931c356040518163ffffffff1660e01b815260040160006040518083038186803b15801561219857600080fd5b505afa1580156121ac573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526121d49190810190614749565b805190915080156122ba576000805b82811015612252578e6001600160a01b031684828151811061220157fe5b60200260200101516001600160a01b0316141561224a578d84828151811061222557fe5b60200260200101906001600160a01b031690816001600160a01b031681525050600191505b6001016121e3565b5080156122b85760405163098fef7160e11b81526001600160a01b0385169063131fdee290612285908690600401614ddc565b600060405180830381600087803b15801561229f57600080fd5b505af11580156122b3573d6000803e3d6000fd5b505050505b505b5050505b60010161211d565b506122d089613e25565b505050505050505050565b6006546040805180820190915260208082527f5265776172642065706f6368206e6f7420696e697469616c697a6564207965749082015260009190816123345760405162461bcd60e51b8152600401610b069190614f43565b5060001901905090565b6000546001600160a01b0316331461238f576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b601780546001600160a01b03199081166001600160a01b03978816179091556018805482169587169590951790945560198054851693861693909317909255601a80548416918516919091179055601b80549092169216919091179055565b6000600682815481106123fd57fe5b90600052602060002090600302016000015490505b919050565b7f000000000000000000000000100000000000000000000000000000000000000381565b6000546001600160a01b0316331461248c576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b601b805460ff60a81b1916600160a81b831515021790556040517f217a37a37fc40a97159886f80c3d45986e6fc4330ce6ad7283478b5e5ab705bc906124d3908390614e8e565b60405180910390a150565b60105460408051808201909152601b81527f476f762e20706172616d73206e6f7420696e697469616c697a65640000000000602082015290610100900460ff1661253b5760405162461bcd60e51b8152600401610b069190614f43565b506125b9826001600160a01b03166318931c356040518163ffffffff1660e01b815260040160006040518083038186803b15801561257857600080fd5b505afa15801561258c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526125b49190810190614749565b613efc565b8015612782576000826001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b1580156125fa57600080fd5b505afa15801561260e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526126369190810190614a7f565b6040516020016126469190614f43565b6040516020818303038152906040528051906020012090506000601860009054906101000a90046001600160a01b03166001600160a01b031663ce1c0e4d6040518163ffffffff1660e01b815260040160006040518083038186803b1580156126ae57600080fd5b505afa1580156126c2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526126ea91908101906147e1565b80519091505b801561277e57806001900390508282828151811061270a57fe5b60200260200101516040516020016127229190614f43565b60405160208183030381529060405280519060200120141561277957604080518082018252600d81526c105b1c9958591e481859191959609a1b6020820152905162461bcd60e51b8152610b069190600401614f43565b6126f0565b5050505b604051630bc29bcf60e21b81526001600160a01b03831690632f0a6f3c90612812907f000000000000000000000000000000000000000000000000000000006143aba1907f00000000000000000000000000000000000000000000000000000000000000b4907f000000000000000000000000000000000000000000000000000000000000005a90600401614f8f565b600060405180830381600087803b15801561282c57600080fd5b505af1158015612840573d6000803e3d6000fd5b50506006541591506128d2905057600680546001600160a01b0384169163e536f39691600019810190811061287157fe5b9060005260206000209060030201600001546040518263ffffffff1660e01b815260040161289f9190614f78565b600060405180830381600087803b1580156128b957600080fd5b505af11580156128cd573d6000803e3d6000fd5b505050505b600854600954600a54600b54600c54600d5460405163f7dba1f560e01b81526001600160a01b0389169663f7dba1f596612919969195909491939092600f90600401614fc8565b600060405180830381600087803b15801561293357600080fd5b505af1158015612947573d6000803e3d6000fd5b5050601b546001600160a01b038086166000908152601660209081526040808320805460ff600160a01b90970496909616151560ff19968716179055601590915280822080549094166001179093556018549251630998fc6d60e21b815290945091169150632663f1b4906129c0908690600401614cde565b602060405180830381600087803b1580156129da57600080fd5b505af11580156129ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a129190614ac9565b90508115612a7d57601954604051630d15c16960e21b81526001600160a01b039091169063345705a490612a4a908490600401614f78565b600060405180830381600087803b158015612a6457600080fd5b505af1158015612a78573d6000803e3d6000fd5b505050505b7fa0985424f2efdcae4b57a7c84bbf0a0b19f93054f21e9eb1cfcd5a59813fe1da836001604051612aaf929190614ee9565b60405180910390a1505050565b60185460408051635200305d60e11b815290516060926001600160a01b03169163a40060ba916004808301926000929190829003018186803b158015612b0157600080fd5b505afa158015612b15573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119f19190810190614749565b7f0000000000000000000000000000000000000000000000000000000000093a80601354034210612cb0576000612b72612abc565b8051604080516060810182524360001981018252602082019081524292820192835260068054600181018255600091825283517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f60039092029182015591517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d4083015592517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d41909101559293509091905b82811015612cab57838181518110612c3757fe5b60200260200101516001600160a01b031663e536f39683600001516040518263ffffffff1660e01b8152600401612c6e9190614f78565b600060405180830381600087803b158015612c8857600080fd5b505af1158015612c9c573d6000803e3d6000fd5b50505050806001019050612c23565b505050505b565b6000612cbc612abc565b80519091508015801590612cda5750601b54600160a81b900460ff16155b156131ae576007546000906001600160a01b0316612d2e57814442604051602001612d06929190614f81565b6040516020818303038152906040528051906020012060001c81612d2657fe5b069050612e04565b6000805b83811015612dca57848181518110612d4657fe5b60200260200101516001600160a01b031663d89601fd6040518163ffffffff1660e01b815260040160206040518083038186803b158015612d8657600080fd5b505afa158015612d9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dbe9190614ac9565b90910190600101612d32565b50828142604051602001612ddf929190614f81565b6040516020818303038152906040528051906020012060001c81612dff57fe5b069150505b60608060008080805b87811015612f8c5760008882890181612e2257fe5b06905060008a8281518110612e3357fe5b6020908102919091018101516001600160a01b0381166000908152601690925260409091205490915060ff1615612e89576001600160a01b03166000908152601660205260409020805460ff1916905550612f84565b6011546040516340462a2d60e01b81526001600160a01b038316916340462a2d91612eba9190891590600401614f33565b600060405180830381600087803b158015612ed457600080fd5b505af1925050508015612f0957506040513d6000823e601f3d908101601f19168201604052612f06919081019061467e565b60015b612f5757612f156150e2565b80612f205750612f30565b612f2a8282613f83565b50612f52565b612f528160405180606001604052806022815260200161520f60229139613f83565b612f81565b87158015612f66575060008351115b15612f7d5791995097509550600194509250828787875b5050505b50505b600101612e0d565b506000612f976122db565b9050821561314d576017546011546001600160a01b039091169063a9b79e1790889088908890877f00000000000000000000000000000000000000000000000000000000000000b4886001612feb85613fd4565b0360068b81548110612ff957fe5b9060005260206000209060030201600001546040518a63ffffffff1660e01b815260040161302f99989796959493929190614d5f565b600060405180830381600087803b15801561304957600080fd5b505af192505050801561305a575060015b61314d576130666150e2565b8061307157506130c8565b7f175a1d13d190d6a1e14461c214b3ecf6118b828797750b7bffd7c4f2c1eba54c836011546040516130a4929190614cf2565b60405180910390a16017546130c2906001600160a01b03168261175a565b5061314d565b7f175a1d13d190d6a1e14461c214b3ecf6118b828797750b7bffd7c4f2c1eba54c826011546040516130fb929190614cf2565b60405180910390a16017546040805180820190915260208082527f756e6b6e6f776e206661696c2e206469737472696275746520726577617264739082015261314d916001600160a01b03169061175a565b600780546001600160a01b0319166001600160a01b0384161790556040517f98b050a4042fbd1b89934ef40b9342e593f15081a348af940573a0179031f4ad9061319a9084908490614cf2565b60405180910390a150505050505050613282565b60005b8181101561322f5760008382815181106131c757fe5b6020908102919091018101516001600160a01b0381166000908152601690925260409091205490915060ff161561321c576001600160a01b03166000908152601660205260409020805460ff19169055613227565b61322581614021565b505b6001016131b1565b50600780546001600160a01b03191690557f98b050a4042fbd1b89934ef40b9342e593f15081a348af940573a0179031f4ad600061326b6122db565b604051613279929190614cf2565b60405180910390a15b5050601b805460ff60a01b19169055565b600061329d612abc565b80519091504281156133465760005b82811015613344578381815181106132c057fe5b60200260200101516001600160a01b031663d89601fd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561330057600080fd5b505afa158015613314573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133389190614ac9565b909101906001016132ac565b505b806040516020016133579190614f78565b6040516020818303038152906040528051906020012060001c905060007f0000000000000000000000000000000000000000000000000000000000000004600661339f6122db565b815481106133a957fe5b9060005260206000209060030201600101544303816133c457fe5b049050806133d0575060015b60008183816133db57fe5b069050806133e7575060015b60408051606081018252438381038252602082019081524292820192835260068054600181018255600091825283517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f60039092029182015591517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d4083015592517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d4190910155905b85811015613518578681815181106134a357fe5b60200260200101516001600160a01b031663e536f39683600001516040518263ffffffff1660e01b81526004016134da9190614f78565b600060405180830381600087803b1580156134f457600080fd5b505af1158015613508573d6000803e3d6000fd5b50506001909201915061348f9050565b50805160208201516040517f1813f880dc24666c8b69c9d771a487ea620a27fde1514be3112847056c0c532292613550929091614f81565b60405180910390a15050601380547f0000000000000000000000000000000000000000000000000000000000093a8001905550505050565b60006135926122db565b600e5490915042035b816014541080156135cf5750806006601454600101815481106135ba57fe5b90600052602060002090600302016002015411155b1561148257601754601454604051636b60edf760e11b81526001600160a01b039092169163d6c1dbee9161360591600401614f78565b600060405180830381600087803b15801561361f57600080fd5b505af1925050508015613630575060015b6137095761363c6150e2565b80613647575061369c565b7fa819a21065ad87bdde9e6d398d3213e0d3634afd87aceb7092236483f5d7ca8d6014546040516136789190614f78565b60405180910390a1601754613696906001600160a01b03168261175a565b50611482565b7fa819a21065ad87bdde9e6d398d3213e0d3634afd87aceb7092236483f5d7ca8d6014546040516136cd9190614f78565b60405180910390a160175460408051606081019091526021808252613704926001600160a01b03169190615231602083013961175a565b611482565b60148054600101905561359b565b601b546001600160a01b0316613755576040517f9a880a9e2a01928f1a99d7b0e2ea1147f52e2eb381f8d9345c110932d57bce8d90600090a1612cb0565b600060066014548154811061376657fe5b6000918252602090912060039091020154601b5460405163cbc31cf760e01b81529192506001600160a01b03169063cbc31cf7906137a8908490600401614f78565b600060405180830381600087803b1580156137c257600080fd5b505af19250505080156137d3575060015b61069b576137df6150e2565b806137ea575061383d565b7f9f874ea08c7014cce74622bfe71434f81aba7598ad65126a6aea86945bdfa18d826040516138199190614f78565b60405180910390a1601b54613837906001600160a01b03168261175a565b506138a3565b7f9f874ea08c7014cce74622bfe71434f81aba7598ad65126a6aea86945bdfa18d8160405161386c9190614f78565b60405180910390a1601b54604080516060810190915260238082526138a3926001600160a01b031691906151c1602083013961175a565b61069b565b60105460ff161561393357604051639ec2b58160e01b81526001600160a01b037f00000000000000000000000010000000000000000000000000000000000000031690639ec2b5819061390090600f90600401614dc9565b600060405180830381600087803b15801561391a57600080fd5b505af115801561392e573d6000803e3d6000fd5b505050505b600061393d612abc565b80519091506000811580159061395d5750601b54600160a81b900460ff16155b15613a0f576006805460009190600019810190811061397857fe5b6000918252602090912060039091020154601a546040516237b08960e41b81529192506001600160a01b03169063037b0890906139b9908490600401614f78565b602060405180830381600087803b1580156139d357600080fd5b505af11580156139e7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a0b9190614ac9565b9150505b60005b82811015613b98576000848281518110613a2857fe5b602090810291909101015160105490915060ff1615613abb57600854600954600a54600b54600c54600d5460405163f7dba1f560e01b81526001600160a01b0388169663f7dba1f596613a88969195909491939092600f90600401614fc8565b600060405180830381600087803b158015613aa257600080fd5b505af1158015613ab6573d6000803e3d6000fd5b505050505b806001600160a01b031663f670ebe384601b60159054906101000a900460ff1680613afe57506001600160a01b0384166000908152601c602052604090205460ff165b6040518363ffffffff1660e01b8152600401613b1b929190614f33565b600060405180830381600087803b158015613b3557600080fd5b505af1925050508015613b46575060015b613b8f57613b526150e2565b80613b5d5750613b6d565b613b6782826140bd565b50613b8f565b613b8f8160405180606001604052806023815260200161527e602391396140bd565b50600101613a12565b506010805460ff191690556000613bad613dd2565b60118190559050613bbd816142ce565b6012555050601b805460ff60a01b1916600160a01b1790555050565b88548814613bf45760088901805460ff191660011790558789555b86896001015414613c175760088901805460ff1916600190811790915589018790555b85896002015414613c395760088901805460ff19166001179055600289018690555b84896003015414613c5b5760088901805460ff19166001179055600389018590555b83896004015414613c7d5760088901805460ff19166001179055600489018490555b82896005015414613c9f5760088901805460ff19166001179055600589018390555b81896006015414613cc15760088901805460ff19166001179055600689018290555b805160078a015414613cf7578051613ce29060078b019060208401906144a3565b5060088901805460ff19166001179055613db6565b60005b8151811015613db457818181518110613d0f57fe5b60200260200101516001600160a01b03168a6007018281548110613d2f57fe5b6000918252602090912001546001600160a01b031614613dac5760088a01805460ff191660011790558151829082908110613d6657fe5b60200260200101518a6007018281548110613d7d57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b600101613cfa565b505b5050506008909501805461ff0019166101001790555050505050565b60007f00000000000000000000000000000000000000000000000000000000000000b47f000000000000000000000000000000000000000000000000000000006143aba1420381613e1f57fe5b04905090565b806001600160a01b031663555989da6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613e6057600080fd5b505af1158015613e74573d6000803e3d6000fd5b5050506001600160a01b0382166000908152601c60209081526040808320805460ff199081169091556016835281842080548216905560159092529091208054909116905550613eca613ec5612abc565b61433d565b7fa0985424f2efdcae4b57a7c84bbf0a0b19f93054f21e9eb1cfcd5a59813fe1da8160006040516124d3929190614ee9565b805160005b81811015613f7e5760156000848381518110613f1957fe5b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff16613f76576040518060600160405280602681526020016152a16026913960405162461bcd60e51b8152600401610b069190614f43565b600101613f01565b505050565b7f79f4c7cc43bfb79f5a3aad0d92f75b6fed7db061bb5cc2580a01c8132711b881826011546001604051613fb993929190614f04565b60405180910390a1613fcb828261175a565b61148282614021565b7f000000000000000000000000000000000000000000000000000000006143aba1600182017f00000000000000000000000000000000000000000000000000000000000000b40201919050565b601154604051639de6f92760e01b81526001600160a01b03831691639de6f9279161404f9190600401614f78565b600060405180830381600087803b15801561406957600080fd5b505af192505050801561407a575060015b61069b576140866150e2565b80614091575061409b565b61383782826143a1565b6138a3816040518060600160405280602b81526020016151e4602b91396143a1565b7f61156899176547b8075bfa81fa2996c6057ce9c71320884b11c0179d9dc2e462826140e7613dd2565b6040516140f5929190614cf2565b60405180910390a1614107828261175a565b601b54600160a81b900460ff168061413757506001600160a01b0382166000908152601c602052604090205460ff165b15614164576001600160a01b0382166000908152601660205260409020805460ff19166001179055611482565b60405163f670ebe360e01b81526001600160a01b0383169063f670ebe39061419490600090600190600401614f33565b600060405180830381600087803b1580156141ae57600080fd5b505af19250505080156141bf575060015b611482576141cb6150e2565b806141d65750614249565b6001600160a01b0383166000908152601660205260409020805460ff191660011790557f61156899176547b8075bfa81fa2996c6057ce9c71320884b11c0179d9dc2e46283614223613dd2565b604051614231929190614cf2565b60405180910390a1614243838261175a565b50613704565b6001600160a01b0382166000908152601660205260409020805460ff191660011790557f61156899176547b8075bfa81fa2996c6057ce9c71320884b11c0179d9dc2e46282614296613dd2565b6040516142a4929190614cf2565b60405180910390a1613704826040518060600160405280602c8152602001615252602c913961175a565b7f000000000000000000000000000000000000000000000000000000006143aba1600182017f00000000000000000000000000000000000000000000000000000000000000b402017f000000000000000000000000000000000000000000000000000000000000005a01919050565b805160005b81811015613f7e5761439983828151811061435957fe5b60200260200101516001600160a01b03166318931c356040518163ffffffff1660e01b815260040160006040518083038186803b15801561257857600080fd5b600101614342565b7f79f4c7cc43bfb79f5a3aad0d92f75b6fed7db061bb5cc2580a01c8132711b8818260115460026040516143d793929190614f04565b60405180910390a16143e9828261175a565b60115460405163974d7a6b60e01b81526001600160a01b0384169163974d7a6b916109689190600401614f78565b828054600181600116156101000203166002900490600052602060002090601f01602090048101928261444d5760008555614493565b82601f1061446657805160ff1916838001178555614493565b82800160010185558215614493579182015b82811115614493578251825591602001919060010190614478565b5061449f9291506144f8565b5090565b828054828255906000526020600020908101928215614493579160200282015b8281111561449357825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906144c3565b5b8082111561449f57600081556001016144f9565b600082601f83011261451d578081fd5b8151602061453261452d83615072565b61504f565b828152818101908583018385028701840188101561454e578586fd5b855b8581101561456c57815184529284019290840190600101614550565b5090979650505050505050565b8035801515811461241257600080fd5b600082601f830112614599578081fd5b81516145a761452d8261508f565b8181528460208386010111156145bb578283fd5b6145cc8260208301602087016150b0565b949350505050565b6000602082840312156145e5578081fd5b81356145f081615186565b9392505050565b60008060408385031215614609578081fd5b823561461481615186565b915060208301356001600160401b0381111561462e578182fd5b8301601f8101851361463e578182fd5b803561464c61452d8261508f565b818152866020838501011115614660578384fd5b81602084016020830137908101602001929092525090939092509050565b600080600060608486031215614692578081fd5b83516001600160401b03808211156146a8578283fd5b818601915086601f8301126146bb578283fd5b815160206146cb61452d83615072565b82815281810190858301838502870184018c10156146e7578788fd5b8796505b848710156147125780516146fe81615186565b8352600196909601959183019183016146eb565b509189015191975090935050508082111561472b578283fd5b506147388682870161450d565b925050604084015190509250925092565b6000602080838503121561475b578182fd5b82516001600160401b03811115614770578283fd5b8301601f81018513614780578283fd5b805161478e61452d82615072565b81815283810190838501858402850186018910156147aa578687fd5b8694505b838510156147d55780516147c181615186565b8352600194909401939185019185016147ae565b50979650505050505050565b600060208083850312156147f3578182fd5b82516001600160401b03811115614808578283fd5b8301601f81018513614818578283fd5b805161482661452d82615072565b81815283810190838501865b8481101561485b576148498a888451890101614589565b84529286019290860190600101614832565b509098975050505050505050565b60006020828403121561487a578081fd5b6145f082614579565b600080600080600060a0868803121561489a578283fd5b85356148a581615186565b945060208601356148b581615186565b935060408601356148c581615186565b925060608601356148d581615186565b915060808601356148e581615186565b809150509295509295909350565b60008060408385031215614905578182fd5b823561491081615186565b91506020838101356001600160401b0381111561492b578283fd5b8401601f8101861361493b578283fd5b803561494961452d82615072565b81815283810190838501858402850186018a1015614965578687fd5b8694505b8385101561499057803561497c81615186565b835260019490940193918501918501614969565b5080955050505050509250929050565b600080604083850312156149b2578182fd5b82356149bd81615186565b91506149cb60208401614579565b90509250929050565b600080600080608085870312156149e9578182fd5b84356149f481615186565b93506020850135614a0481615186565b9250614a1260408601614579565b9150614a2060608601614579565b905092959194509250565b60008060408385031215614a3d578182fd5b8235614a4881615186565b91506020830135614a5881615186565b809150509250929050565b600060208284031215614a74578081fd5b81516145f081615186565b600060208284031215614a90578081fd5b81516001600160401b03811115614aa5578182fd5b6145cc84828501614589565b600060208284031215614ac2578081fd5b5035919050565b600060208284031215614ada578081fd5b5051919050565b60008060408385031215614af3578182fd5b50508035926020909101359150565b60008060408385031215614b14578182fd5b505080516020909101519092909150565b600080600080600080600080610100898b031215614b41578586fd5b883597506020808a0135975060408a0135965060608a0135955060808a0135945060a08a0135935060c08a0135925060e08a01356001600160401b03811115614b88578283fd5b8a01601f81018c13614b98578283fd5b8035614ba661452d82615072565b8082825284820191508484018f868786028701011115614bc4578687fd5b8694505b83851015614bef578035614bdb81615186565b835260019490940193918501918501614bc8565b5080955050505050509295985092959890939650565b6000815180845260208085019450808401835b83811015614c3d5781516001600160a01b031687529582019590820190600101614c18565b509495945050505050565b6000815480845260208085019450838352808320835b83811015614c3d5781546001600160a01b031687529582019560019182019101614c5e565b6000815180845260208085019450808401835b83811015614c3d57815187529582019590820190600101614c96565b60008151808452614cca8160208601602086016150b0565b601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03831681526040602082018190526000906145cc90830184614cb2565b600060018060a01b038516825283602083015260606040830152614d566060830184614cb2565b95945050505050565b6000610120808352614d738184018d614c05565b90508281036020840152614d87818c614c83565b604084019a909a52505060608101969096526001600160a01b0394909416608086015260a085019290925260c084015260e08301526101009091015292915050565b6000602082526145f06020830184614c48565b6000602082526145f06020830184614c05565b600060a08252614e0260a0830188614c83565b602083820381850152614e158289614c83565b848103604086015287518082529092508183019082810284018301838a01865b83811015614e6357601f19878403018552614e51838351614cb2565b94860194925090850190600101614e35565b50508681036060880152614e77818a614c05565b955050505050508260808301529695505050505050565b901515815260200190565b600084151582526020606081840152614eb56060840186614c05565b8381036040850152845180825282860191830190845b8181101561485b578351151583529284019291840191600101614ecb565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b0384168152602081018390526060810160068310614f2557fe5b826040830152949350505050565b9182521515602082015260400190565b6000602082526145f06020830184614cb2565b6001600160c01b039290921682526001600160401b0316602082015260400190565b90815260200190565b918252602082015260400190565b9283526020830191909152604082015260600190565b948552602085019390935260408401919091526060830152608082015260a00190565b60008882528760208301528660408301528560608301528460808301528360a083015260e060c0830152614fff60e0830184614c48565b9998505050505050505050565b988952602089019790975260408801959095526060870193909352608086019190915260a085015260c0840152151560e083015215156101008201526101200190565b6040518181016001600160401b038111828210171561506a57fe5b604052919050565b60006001600160401b0382111561508557fe5b5060209081020190565b60006001600160401b038211156150a257fe5b50601f01601f191660200190565b60005b838110156150cb5781810151838201526020016150b3565b83811115612cab5750506000910152565b60e01c90565b600060443d10156150f257610565565b600481823e6308c379a061510682516150dc565b1461511057610565565b6040513d600319016004823e80513d6001600160401b03816024840111818411171561513f5750505050610565565b828401925082519150808211156151595750505050610565565b503d8301602082840101111561517157505050610565565b601f01601f1916810160200160405291505090565b6001600160a01b038116811461069b57600080fdfe4d6178207472757374656420616464726573736573206c656e677468206578636565646564756e6b6e6f776e206661696c2e2073657474696e6720636c65616e757020626c6f636b756e6b6e6f776e206661696c2e2066616c6c6261636b2066696e616c697a652070726963652065706f6368756e6b6e6f776e206661696c2e2066696e616c697a652070726963652065706f6368556e6b6e6f776e206661696c207768656e20636c6f73696e672065787069726564756e6b6e6f776e206661696c2e2066616c6c6261636b20696e69742065706f636820666f722072657665616c756e6b6e6f776e206661696c2e20696e69742065706f636820666f722072657665616c4173736574204654534f206e6f74206d616e61676564206279206674736f206d616e61676572a264697066735822122031a4df8ff2e3927ffe942baa09d7ccfecacbd707bb5bbb9857ab0f5bfd8dccfd64736f6c63430007060033