Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- DistributionToDelegators
- Optimization enabled
- true
- Compiler version
- v0.7.6+commit.7338295f
- Optimization runs
- 200
- Verified at
- 2023-02-23T08:59:26.731283Z
Constructor Arguments
0000000000000000000000004598a6c05910ab914f0cbaaca1911cd337d10d290000000000000000000000001000000000000000000000000000000000000002000000000000000000000000f0de0df69d63c1f5e841f4964550c3dabad6d24e000000000000000000000000cf3007b342f9c17afbe11bf3fba278517b44c30300000000000000000000000000000000000000004e57f8ff28b15816cd6e3ac00000000000000000000000000000000000000000000000000000000064602480
Arg [0] (address) : 0x4598a6c05910ab914f0cbaaca1911cd337d10d29
Arg [1] (address) : 0x1000000000000000000000000000000000000002
Arg [2] (address) : 0xf0de0df69d63c1f5e841f4964550c3dabad6d24e
Arg [3] (address) : 0xcf3007b342f9c17afbe11bf3fba278517b44c303
Arg [4] (uint256) : 24246183166111100254035000000
Arg [5] (uint256) : 1684022400
./contracts/tokenPools/implementation/DistributionToDelegators.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "../../addressUpdater/implementation/AddressUpdatable.sol"; import "../../utils/implementation/GovernedAndFlareDaemonized.sol"; import "../../claiming/implementation/ClaimSetupManager.sol"; import "../../token/implementation/WNat.sol"; import "../../token/lib/IICombinedNatBalance.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import "../../userInterfaces/IDistributionToDelegators.sol"; import "../../utils/interface/IIRandomProvider.sol"; import "../interface/IITokenPool.sol"; import "../../genesis/implementation/DistributionTreasury.sol"; import "../../utils/implementation/AddressSet.sol"; import "../../genesis/interface/IFlareDaemonize.sol"; /** * @title Distribution to delegators * @notice A contract to manage the ongoing airdrop distribution after the initial airdrop allocation. * The remaining amount is distributed by this contract, with a set rate every 30 days * @notice The balance that will be added to this contract must initially be a part of circulating supply **/ //solhint-disable-next-line max-states-count contract DistributionToDelegators is IDistributionToDelegators, IITokenPool, GovernedAndFlareDaemonized, IFlareDaemonize, ReentrancyGuard, AddressUpdatable { using SafeMath for uint256; using SafePct for uint256; using AddressSet for AddressSet.State; // constants uint256 internal constant WEEK = 7 days; uint256 internal constant MONTH = 30 days; uint256 internal constant NUMBER_OF_VOTE_POWER_BLOCKS = 3; uint256 internal constant TOTAL_CLAIMABLE_BIPS = 8500; // 2.37% every 30 days (so total distribution takes 36 * 30 days =~ 3 years) uint256 internal constant MONTHLY_CLAIMABLE_BIPS = 237; uint256 internal constant NUMBER_OF_MONTHS = TOTAL_CLAIMABLE_BIPS / MONTHLY_CLAIMABLE_BIPS + 1; // 36 address payable internal constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD; // Errors string internal constant ERR_ADDRESS_ZERO = "address zero"; string internal constant ERR_BALANCE_TOO_LOW = "balance too low"; string internal constant ERR_IN_THE_PAST = "in the past"; string internal constant ERR_NOT_STARTED = "not started"; string internal constant ERR_ALREADY_FINISHED = "already finished"; string internal constant ERR_MONTH_EXPIRED = "month expired"; string internal constant ERR_MONTH_NOT_CLAIMABLE = "month not claimable"; string internal constant ERR_MONTH_NOT_CLAIMABLE_YET = "month not claimable yet"; string internal constant ERR_NO_MONTH_CLAIMABLE = "no month claimable"; string internal constant ERR_CLAIM_FAILED = "claim failed"; string internal constant ERR_OPT_OUT = "already opted out"; string internal constant ERR_NOT_OPT_OUT = "not opted out"; string internal constant ERR_TREASURY_ONLY = "treasury only"; string internal constant ERR_ALREADY_STARTED = "already started"; string internal constant ERR_WRONG_START_TIMESTAMP = "wrong start timestamp"; string internal constant ERR_CLAIMED_AMOUNT_TOO_SMALL = "claimed amount too small"; string internal constant ERR_RECIPIENT_ZERO = "recipient zero"; string internal constant ERR_INVALID_PARAMS = "invalid parameters"; string internal constant ERR_STOPPED = "stopped"; string internal constant ERR_NOT_STOPPED = "not stopped"; string internal constant ERR_SENDING_FUNDS_BACK = "sending funds back failed"; // storage uint256 public totalEntitlementWei; // Total wei to be distributed (all but initial airdrop) uint256 public immutable latestEntitlementStartTs; // Latest day 0 when contract starts uint256 public totalClaimedWei; // All wei already claimed uint256 public totalBurnedWei; // Amounts that were not claimed in time and expired and was burned uint256 public totalDistributableAmount;// Total amount that was pulled from Distribution treasury for // distribution. (sum of totalAvailableAmount) uint256 public entitlementStartTs; // Day 0 when contract starts // id of the first month to expire. Closed = expired and unclaimed amount will be burned uint128 internal nextMonthToExpireCandidate; // id of the next claimable month. Normally the same as current month - may be smaller if waiting for good random uint128 internal nextMonthToClaimCandidate; mapping(uint256 => uint256) public startBlockNumber; // mapping from month to first block used in randomization mapping(uint256 => uint256) public endBlockNumber; // mapping from month to last block used in randomization mapping(uint256 => uint256[]) public votePowerBlockNumbers; // mapping from month to blocks used in claiming mapping(uint256 => uint256) public totalAvailableAmount; // mapping from month to total available amount mapping(uint256 => uint256) public totalUnclaimedAmount; // mapping from month to unclaimed amount mapping(uint256 => uint256) public totalUnclaimedWeight; // mapping from month to weight of unclaimed amount mapping(address => uint256) private ownerNextClaimableMonth; // mapping from owner to next claimable month mapping(address => bool) public optOutCandidate; // indicates if user has triggered to opt out of airdrop mapping(address => bool) public optOut; // indicates if user is opted out of airdrop (confirmed by governance) address[] public optOutAddresses; // all opted out addresses (confirmed by governance) bool public stopped; bool public useGoodRandom; // both are used only together with useGoodRandom flag - 0 otherwise uint256 public maxWaitForGoodRandomSeconds; uint256 public waitingForGoodRandomSinceTs; // contracts DistributionTreasury public immutable treasury; IIRandomProvider public priceSubmitter; IICombinedNatBalance public combinedNat; WNat public wNat; ClaimSetupManager public claimSetupManager; /** * @dev This modifier ensures that this contract's balance matches the expected balance. */ modifier mustBalance { _; require (_getExpectedBalance() <= address(this).balance, ERR_BALANCE_TOO_LOW); } modifier onlyExecutorAndAllowedRecipient(address _rewardOwner, address _recipient) { _checkExecutorAndAllowedRecipient(_rewardOwner, _recipient); _; } /** * @dev This modifier ensures that the entitelment was already started */ modifier entitlementStarted { require (entitlementStartTs < block.timestamp, ERR_NOT_STARTED); _; } /** * @dev This modifier ensures that the contract is not stopped */ modifier notStopped { require (!stopped, ERR_STOPPED); _; } constructor( address _governance, FlareDaemon _flareDaemon, address _addressUpdater, DistributionTreasury _treasury, uint256 _totalEntitlementWei, uint256 _latestEntitlementStartTs ) GovernedAndFlareDaemonized(_governance, _flareDaemon) AddressUpdatable(_addressUpdater) { require(address(_treasury) != address(0), ERR_ADDRESS_ZERO); require(_latestEntitlementStartTs >= block.timestamp, ERR_IN_THE_PAST); treasury = _treasury; totalEntitlementWei = _totalEntitlementWei; latestEntitlementStartTs = _latestEntitlementStartTs; entitlementStartTs = _latestEntitlementStartTs; emit EntitlementStart(_latestEntitlementStartTs); } /** * @notice Needed in order to receive funds from DistributionTreasury */ receive() external payable { require(msg.sender == address(treasury), ERR_TREASURY_ONLY); } function stop() external onlyImmediateGovernance { stopped = true; } /** * @notice Update the totalEntitlementWei */ function updateTotalEntitlementWei() external onlyImmediateGovernance { uint256 newTotalEntitlementWei = totalDistributableAmount.add(address(treasury).balance); assert(newTotalEntitlementWei >= totalEntitlementWei); totalEntitlementWei = newTotalEntitlementWei; } /** * @notice Start the distribution contract at _entitlementStartTs timestamp * @param _entitlementStartTs point in time when we start */ function setEntitlementStart(uint256 _entitlementStartTs) external onlyGovernance { require(entitlementStartTs > block.timestamp, ERR_ALREADY_STARTED); require(_entitlementStartTs >= block.timestamp - 2 * WEEK && _entitlementStartTs <= latestEntitlementStartTs, ERR_WRONG_START_TIMESTAMP); entitlementStartTs = _entitlementStartTs; emit EntitlementStart(_entitlementStartTs); } /** * @notice Method to opt-out of receiving airdrop rewards */ function optOutOfAirdrop() external override { require(!optOutCandidate[msg.sender], ERR_OPT_OUT); optOutCandidate[msg.sender] = true; // emit opt out event emit AccountOptOut(msg.sender, false); } /** * @notice Confirm opt out addresses * @param _optOutAddresses addresses to opt out */ function confirmOptOutOfAirdrop(address[] calldata _optOutAddresses) external onlyGovernance { uint256 len = _optOutAddresses.length; for (uint256 i = 0; i < len; i++) { address optOutAddress = _optOutAddresses[i]; require(optOutCandidate[optOutAddress], ERR_NOT_OPT_OUT); _checkOptOut(optOutAddress); optOut[optOutAddress] = true; optOutAddresses.push(optOutAddress); // emit opt out event emit AccountOptOut(optOutAddress, true); } } /** * @notice Runs task triggered by Daemon. * The tasks include the following * - setting start block number for the month * - setting end block number for the month * - calculating random blocks and weight + polling funds from treasury contract */ function daemonize() external override onlyFlareDaemon mustBalance nonReentrant returns(bool) { if (entitlementStartTs > block.timestamp || nextMonthToExpireCandidate >= NUMBER_OF_MONTHS) return false; uint256 diffSec = block.timestamp.sub(entitlementStartTs); uint256 currentMonth = diffSec.div(MONTH); uint256 remainingSec = diffSec - currentMonth * MONTH; uint256 currentWeek = remainingSec.div(WEEK); // if not the first week, which is left out for claiming, update start block if (currentWeek > 0 && currentMonth < NUMBER_OF_MONTHS && startBlockNumber[currentMonth] == 0) { startBlockNumber[currentMonth] = block.number; } // update ending block - sets to first block in new month if (currentMonth > 0 && currentMonth <= NUMBER_OF_MONTHS && endBlockNumber[currentMonth - 1] == 0) { endBlockNumber[currentMonth - 1] = block.number; } // expire old month uint256 cleanupBlockNumber = wNat.cleanupBlockNumber(); uint256 blockNumber = startBlockNumber[nextMonthToExpireCandidate]; if (blockNumber > 0 && blockNumber < cleanupBlockNumber) { uint256 toBurnWei = Math.min(totalUnclaimedAmount[nextMonthToExpireCandidate], address(this).balance); nextMonthToExpireCandidate++; // Any to burn? if (toBurnWei > 0) { // Accumulate what we are about to burn totalBurnedWei = totalBurnedWei.add(toBurnWei); //slither-disable-next-line arbitrary-send-eth BURN_ADDRESS.transfer(toBurnWei); } } // enable claiming for previous month if (currentMonth > 0 && currentMonth <= NUMBER_OF_MONTHS && nextMonthToClaimCandidate == currentMonth - 1 && !stopped) { if (_updateVotePowerBlocksAndWeight(currentMonth - 1)) { _updateDistributableAmount(currentMonth - 1); // claim amount if random is ok } } return true; } /** * @notice Allow governance to switch to good random only * @param _useGoodRandom flag indicating using good random or not * @param _maxWaitForGoodRandomSeconds max time in seconds to wait for the good random and if there is no after given time, distribution should proceed anyway */ function setUseGoodRandom(bool _useGoodRandom, uint256 _maxWaitForGoodRandomSeconds) external onlyGovernance { if (_useGoodRandom) { require(_maxWaitForGoodRandomSeconds > 0 && _maxWaitForGoodRandomSeconds <= 7 days, ERR_INVALID_PARAMS); } else { require(_maxWaitForGoodRandomSeconds == 0, ERR_INVALID_PARAMS); // reset start waiting timestamp waitingForGoodRandomSinceTs = 0; } useGoodRandom = _useGoodRandom; maxWaitForGoodRandomSeconds = _maxWaitForGoodRandomSeconds; emit UseGoodRandomSet(_useGoodRandom, _maxWaitForGoodRandomSeconds); } /** * Enable sending funds back to treasury contract in case distribution was stopped */ function sendFundsBackToTreasury() external onlyGovernance { require(stopped, ERR_NOT_STOPPED); /* solhint-disable avoid-low-level-calls */ //slither-disable-next-line arbitrary-send-eth (bool success, ) = address(treasury).call{value: address(this).balance}(""); /* solhint-enable avoid-low-level-calls */ require(success, ERR_SENDING_FUNDS_BACK); } /** * @notice Allows the sender to claim or wrap rewards for reward owner. * @notice The caller does not have to be the owner, but must be approved by the owner to claim on his behalf, * this approval is done by calling `setClaimExecutors`. * @notice It is actually safe for this to be called by anybody (nothing can be stolen), but by limiting who can * call, we allow the owner to control the timing of the calls. * @notice Reward owner can claim to any `_recipient`, while the executor can only claim to the reward owner, * reward owners's personal delegation account or one of the addresses set by `setAllowedClaimRecipients`. * @param _rewardOwner address of the reward owner * @param _recipient address to transfer funds to * @param _month last month to claim for * @param _wrap should reward be wrapped immediately * @return _rewardAmount amount of total claimed rewards */ function claim( address _rewardOwner, address _recipient, uint256 _month, bool _wrap ) external override entitlementStarted notStopped mustBalance nonReentrant onlyExecutorAndAllowedRecipient(_rewardOwner, _recipient) returns (uint256 _rewardAmount) { _rewardAmount = _claimOrWrap(_rewardOwner, _recipient, _month, _wrap); } /** * @notice Allows batch claiming for the list of '_rewardOwners' up to given '_month'. * @notice If reward owner has enabled delegation account, rewards are also claimed for that delegation account and * total claimed amount is sent to that delegation account, otherwise claimed amount is sent to owner's account. * @notice Claimed amount is automatically wrapped. * @notice Method can be used by reward owner or executor. If executor is registered with fee > 0, * then fee is paid to executor for each claimed address from the list. * @param _rewardOwners list of reward owners to claim for * @param _month last month to claim for */ //slither-disable-next-line reentrancy-eth // guarded by nonReentrant function autoClaim(address[] calldata _rewardOwners, uint256 _month) external override entitlementStarted notStopped mustBalance nonReentrant { for (uint256 i = 0; i < _rewardOwners.length; i++) { _checkNonzeroRecipient(_rewardOwners[i]); } uint256 monthToExpireNext = getMonthToExpireNext(); _checkIsMonthClaimable(monthToExpireNext, _month); (address[] memory claimAddresses, uint256 executorFeeValue) = claimSetupManager.getAutoClaimAddressesAndExecutorFee(msg.sender, _rewardOwners); uint256 totalClaimedWeiTemp; for (uint256 i = 0; i < _rewardOwners.length; i++) { address rewardOwner = _rewardOwners[i]; address claimAddress = claimAddresses[i]; uint256 rewardAmount = 0; if (!optOut[rewardOwner]) { // claim for owner rewardAmount += _claim(rewardOwner, claimAddress, monthToExpireNext, _month); } if (rewardOwner != claimAddress) { // claim for PDA - cannot be opt out rewardAmount += _claim(claimAddress, claimAddress, monthToExpireNext, _month); } totalClaimedWeiTemp += rewardAmount; rewardAmount = rewardAmount.sub(executorFeeValue, ERR_CLAIMED_AMOUNT_TOO_SMALL); _transferOrWrap(claimAddress, rewardAmount, true); } // Update grand total claimed totalClaimedWei = totalClaimedWei.add(totalClaimedWeiTemp); // send fees to executor _transferOrWrap(msg.sender, executorFeeValue.mul(_rewardOwners.length), false); } /** * @notice Return token pool supply data * @return _lockedFundsWei Foundation locked funds (wei) * @return _totalInflationAuthorizedWei Total inflation authorized amount (wei) * @return _totalClaimedWei Total claimed amount (wei) */ function getTokenPoolSupplyData() external view override returns (uint256 _lockedFundsWei, uint256 _totalInflationAuthorizedWei, uint256 _totalClaimedWei) { // This is the total amount of tokens that are actually already in circulating supply _lockedFundsWei = stopped ? totalClaimedWei.add(totalBurnedWei).add(address(this).balance) : totalEntitlementWei; // We will never increase this balance since distribution funds are taken from genesis // amounts and not from inflation. _totalInflationAuthorizedWei = 0; // What was actually already added to circulating supply _totalClaimedWei = totalClaimedWei.add(totalBurnedWei); } /** * @notice get claimable amount of wei for requesting account for specified month * @param _month month of interest * @return _amountWei amount of wei available for this account and provided month */ function getClaimableAmount(uint256 _month) external view override entitlementStarted returns(uint256 _amountWei) { _checkOptOut(msg.sender); _checkIsMonthClaimable(getMonthToExpireNext(), _month); (, _amountWei) = _getClaimableWei(msg.sender, _month); } /** * @notice get claimable amount of wei for account for specified month * @param _account the address of an account we want to get the claimable amount of wei * @param _month month of interest * @return _amountWei amount of wei available for provided account and month */ function getClaimableAmountOf(address _account, uint256 _month) external view override entitlementStarted returns(uint256 _amountWei) { _checkOptOut(_account); _checkIsMonthClaimable(getMonthToExpireNext(), _month); (, _amountWei) = _getClaimableWei(_account, _month); } /** * @notice Returns claimable months - reverts if none * @return _startMonth first claimable month * @return _endMonth last claimable month */ function getClaimableMonths() external view override returns(uint256 _startMonth, uint256 _endMonth) { require(nextMonthToClaimCandidate > 0, ERR_NO_MONTH_CLAIMABLE); _startMonth = getMonthToExpireNext(); _endMonth = nextMonthToClaimCandidate - 1; require(_startMonth <= _endMonth && _startMonth < NUMBER_OF_MONTHS, ERR_ALREADY_FINISHED); } /** * @notice Returns the next claimable month for '_rewardOwner'. * @param _rewardOwner address of the reward owner */ function nextClaimableMonth(address _rewardOwner) external view override returns (uint256) { return _nextClaimableMonth(_rewardOwner, getMonthToExpireNext()); } function switchToFallbackMode() external view override onlyFlareDaemon returns (bool) { // do nothing - there is no fallback mode in DistributionToDelegators return false; } /** * @notice Implement this function for updating daemonized contracts through AddressUpdater. */ function getContractName() external pure override returns (string memory) { return "DistributionToDelegators"; } /** * @notice Returns the current month * @return _currentMonth Current month, 0 before entitlementStartTs */ function getCurrentMonth() public view override returns (uint256 _currentMonth) { (, uint256 diffSec) = block.timestamp.trySub(entitlementStartTs); return diffSec.div(MONTH); } /** * @notice Returns the month that will expire next * @return _monthToExpireNext Month that will expire next, 36 when last month expired */ function getMonthToExpireNext() public view override returns (uint256 _monthToExpireNext) { uint256 cleanupBlockNumber = wNat.cleanupBlockNumber(); uint256 blockNumber = startBlockNumber[nextMonthToExpireCandidate]; if (blockNumber > 0 && blockNumber < cleanupBlockNumber) return nextMonthToExpireCandidate + 1; return nextMonthToExpireCandidate; } /////////////////////////////////////////////////////////////////////////////////////////////// // Update contracts /** * @notice Implementation of the AddressUpdatable abstract method. */ function _updateContractAddresses( bytes32[] memory _contractNameHashes, address[] memory _contractAddresses ) internal override { wNat = WNat(payable(_getContractAddress(_contractNameHashes, _contractAddresses, "WNat"))); claimSetupManager = ClaimSetupManager( _getContractAddress(_contractNameHashes, _contractAddresses, "ClaimSetupManager")); priceSubmitter = IIRandomProvider( _getContractAddress(_contractNameHashes, _contractAddresses, "PriceSubmitter")); combinedNat = IICombinedNatBalance( _getContractAddress(_contractNameHashes, _contractAddresses, "CombinedNat")); } /////////////////////////////////////////////////////////////////////////////////////////////// // Helpers /** * @notice Method for claiming unlocked airdrop amounts for specified month * @param _rewardOwner address of the owner of airdrop rewards * @param _recipient address representing the recipient of the reward * @param _month last month of interest * @return _claimedWei claimed amount */ function _claimOrWrap( address _rewardOwner, address _recipient, uint256 _month, bool _wrap ) internal returns(uint256 _claimedWei) { _checkNonzeroRecipient(_recipient); _checkOptOut(_rewardOwner); uint256 monthToExpireNext = getMonthToExpireNext(); _checkIsMonthClaimable(monthToExpireNext, _month); _claimedWei = _claim(_rewardOwner, _recipient, monthToExpireNext, _month); // Update grand total claimed totalClaimedWei = totalClaimedWei.add(_claimedWei); _transferOrWrap(_recipient, _claimedWei, _wrap); } /** * @notice Transfers or wrap (deposit) `_rewardAmount` to `_recipient`. * @param _recipient address representing the reward recipient * @param _rewardAmount number representing the amount to transfer * @param _wrap should reward be wrapped immediately * @dev Uses low level call to transfer funds. */ function _transferOrWrap(address _recipient, uint256 _rewardAmount, bool _wrap) internal { if (_rewardAmount > 0) { if (_wrap) { // transfer total amount (state is updated and events are emitted in _claimReward) //slither-disable-next-line arbitrary-send-eth // amount always calculated by _claimReward wNat.depositTo{value: _rewardAmount}(_recipient); } else { // transfer total amount (state is updated and events are emitted in _claimReward) /* solhint-disable avoid-low-level-calls */ //slither-disable-next-line arbitrary-send-eth // amount always calculated by _claimReward (bool success, ) = _recipient.call{value: _rewardAmount}(""); /* solhint-enable avoid-low-level-calls */ require(success, ERR_CLAIM_FAILED); } } } /** * @notice Calculate and pull the distributable amount for the specified month * @param _month month of interest * @dev Every 30 days from initial day 1/36 of the total amount is unlocked and becomes available for claiming */ function _updateDistributableAmount(uint256 _month) internal { // maximal claimable bips for this month uint256 claimBIPS = Math.min((_month + 1).mul(MONTHLY_CLAIMABLE_BIPS), TOTAL_CLAIMABLE_BIPS); // what can be distributed minus what was already distributed till now uint256 amountWei = Math.min(Math.min( totalEntitlementWei.mulDiv(claimBIPS, TOTAL_CLAIMABLE_BIPS) - totalDistributableAmount, treasury.MAX_PULL_AMOUNT_WEI()), address(treasury).balance); // update total values totalAvailableAmount[_month] = amountWei; totalUnclaimedAmount[_month] = amountWei; totalDistributableAmount += amountWei; // enable claims for current month nextMonthToClaimCandidate = uint128(_month + 1); // max _month is 35 // pull funds treasury.pullFunds(amountWei); } /** * @notice Calculate random vote power blocks and weight for the specified month * @param _month month of interest * @return info if successfully calculated - random ok */ function _updateVotePowerBlocksAndWeight(uint256 _month) internal returns (bool) { uint256 random; if (useGoodRandom) { bool goodRandom; (random, goodRandom) = priceSubmitter.getCurrentRandomWithQuality(); if (!goodRandom) { if (waitingForGoodRandomSinceTs == 0) { // random is not good for the first time - set start waiting timestamp waitingForGoodRandomSinceTs = block.timestamp; return false; // wait } else if (waitingForGoodRandomSinceTs + maxWaitForGoodRandomSeconds <= block.timestamp) { // we have waited long enough - reset start waiting timestamp and proceed waitingForGoodRandomSinceTs = 0; } else { return false; // wait } } else { waitingForGoodRandomSinceTs = 0; // we got a good random - reset start waiting timestamp } } else { random = block.timestamp + priceSubmitter.getCurrentRandom(); } uint256 startBlock = startBlockNumber[_month]; uint256 endBlock = endBlockNumber[_month]; // no underflow as endBlock is set later as startBlock uint256 slotSize = (endBlock - startBlock) / NUMBER_OF_VOTE_POWER_BLOCKS; uint256[] memory votePowerBlocks = new uint256[](NUMBER_OF_VOTE_POWER_BLOCKS); for (uint256 i = 0; i < NUMBER_OF_VOTE_POWER_BLOCKS; i++) { random = uint256(keccak256(abi.encode(random, i))); //slither-disable-next-line weak-prng uint256 votePowerBlock = startBlock + i * slotSize + random % slotSize; votePowerBlocks[i] = votePowerBlock; } votePowerBlockNumbers[_month] = votePowerBlocks; totalUnclaimedWeight[_month] = _calculateUnclaimedWeight(votePowerBlocks); return true; } function _claim( address _rewardOwner, address _recipient, uint256 _monthToExpireNext, uint256 _month ) internal returns (uint256 _claimedWei) { for (uint256 month = _nextClaimableMonth(_rewardOwner, _monthToExpireNext); month <= _month; month++) { (uint256 weight, uint256 claimableWei) = _getClaimableWei(_rewardOwner, month); if (claimableWei > 0) { totalUnclaimedAmount[month] = totalUnclaimedAmount[month].sub(claimableWei); totalUnclaimedWeight[month] = totalUnclaimedWeight[month].sub(weight); _claimedWei += claimableWei; // Emit the claim event emit AccountClaimed(_rewardOwner, _recipient, month, claimableWei); } } if (ownerNextClaimableMonth[_rewardOwner] < _month + 1) { ownerNextClaimableMonth[_rewardOwner] = _month + 1; } } function _checkIsMonthClaimable(uint256 _monthToExpireNext, uint256 _month) internal view { require(_monthToExpireNext <= _month, ERR_MONTH_EXPIRED); require(_month < NUMBER_OF_MONTHS, ERR_MONTH_NOT_CLAIMABLE); // it may not be yet claimable if first block in new month or if waiting for good random require(_month < nextMonthToClaimCandidate, ERR_MONTH_NOT_CLAIMABLE_YET); } function _checkOptOut(address _account) internal view { require(!optOut[_account], ERR_OPT_OUT); } /** * @notice Get the total unclaimed weight for the specified vote power blocks * @param _votePowerBlocks array of vote power blocks of interest * @return _amountWei unclaimed weight of wei at vote power blocks */ function _calculateUnclaimedWeight(uint256[] memory _votePowerBlocks) internal view returns (uint256 _amountWei) { for (uint256 i = 0; i < NUMBER_OF_VOTE_POWER_BLOCKS; i++) { _amountWei += combinedNat.totalSupplyAt(_votePowerBlocks[i]); } uint256 len = optOutAddresses.length; while (len > 0) { len--; address optOutAddress = optOutAddresses[len]; for (uint256 i = 0; i < NUMBER_OF_VOTE_POWER_BLOCKS; i++) { _amountWei -= combinedNat.balanceOfAt(optOutAddress, _votePowerBlocks[i]); } } } function _nextClaimableMonth(address _owner, uint256 _monthToExpireNext) internal view returns (uint256) { return Math.max(ownerNextClaimableMonth[_owner], _monthToExpireNext); } /** * @notice Get weight and claimable amount for users account for the specified month * @param _owner address of interest * @param _month month of interest * @dev Every 30 days from initial day 1/36 of the amount is released */ function _getClaimableWei(address _owner, uint256 _month) internal view returns(uint256 _weight, uint256 _claimableWei) { if (ownerNextClaimableMonth[_owner] > _month) { return (0, 0); } uint256 unclaimedAmount = totalUnclaimedAmount[_month]; if (unclaimedAmount == 0) { return (0, 0); } uint256[] memory votePowerBlocks = votePowerBlockNumbers[_month]; for (uint256 i = 0; i < NUMBER_OF_VOTE_POWER_BLOCKS; i++) { _weight += combinedNat.balanceOfAt(_owner, votePowerBlocks[i]); } if (_weight == 0) { return (0, 0); } uint256 unclaimedWeight = totalUnclaimedWeight[_month]; if (_weight == unclaimedWeight) { return (_weight, unclaimedAmount); } assert(_weight < unclaimedWeight); return (_weight, unclaimedAmount.mulDiv(_weight, unclaimedWeight)); } function _checkExecutorAndAllowedRecipient(address _rewardOwner, address _recipient) private view { if (msg.sender == _rewardOwner) { return; } claimSetupManager.checkExecutorAndAllowedRecipient(msg.sender, _rewardOwner, _recipient); } /** * @notice Compute the expected balance of this contract. * @param _balanceExpectedWei The computed balance expected. */ function _getExpectedBalance() private view returns(uint256 _balanceExpectedWei) { return stopped ? 0 : totalDistributableAmount.sub(totalClaimedWei).sub(totalBurnedWei); } function _checkNonzeroRecipient(address _address) private pure { require(_address != address(0), ERR_RECIPIENT_ZERO); } }
./contracts/userInterfaces/IDelegationAccount.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import "./IClaimSetupManager.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IDelegationAccount { event DelegateFtso(address to, uint256 bips); event RevokeFtso(address to, uint256 blockNumber); event UndelegateAllFtso(); event DelegateGovernance(address to); event UndelegateGovernance(); event WithdrawToOwner(uint256 amount); event ExternalTokenTransferred(IERC20 token, uint256 amount); event ExecutorFeePaid(address executor, uint256 amount); event Initialize(address owner, IClaimSetupManager manager); }
./contracts/userInterfaces/IFtsoManager.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import "../ftso/interface/IIFtso.sol"; import "../genesis/interface/IFtsoManagerGenesis.sol"; interface IFtsoManager is IFtsoManagerGenesis { 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); event AccruingUnearnedRewardsFailed(uint256 epochId); function active() external view returns (bool); function getCurrentRewardEpoch() external view returns (uint256); function getRewardEpochVotePowerBlock(uint256 _rewardEpoch) external view returns (uint256); function getRewardEpochToExpireNext() 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 getRewardEpochConfiguration() external view returns ( uint256 _firstRewardEpochStartTs, uint256 _rewardEpochDurationSeconds ); function getFallbackMode() external view returns ( bool _fallbackMode, IIFtso[] memory _ftsos, bool[] memory _ftsoInFallbackMode ); }
./contracts/governance/implementation/GovernedBase.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "../../userInterfaces/IGovernanceSettings.sol"; /** * @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 { struct TimelockedCall { uint256 allowedAfterTimestamp; bytes encodedCall; } // solhint-disable-next-line const-name-snakecase IGovernanceSettings public constant governanceSettings = IGovernanceSettings(0x1000000000000000000000000000000000000007); address private initialGovernance; bool private initialised; bool public productionMode; bool private executing; mapping(bytes4 => TimelockedCall) public timelockedCalls; event GovernanceCallTimelocked(bytes4 selector, uint256 allowedAfterTimestamp, bytes encodedCall); event TimelockedGovernanceCallExecuted(bytes4 selector, uint256 timestamp); event TimelockedGovernanceCallCanceled(bytes4 selector, uint256 timestamp); event GovernanceInitialised(address initialGovernance); event GovernedProductionModeEntered(address governanceSettings); modifier onlyGovernance { if (executing || !productionMode) { _beforeExecute(); _; } else { _recordTimelockedCall(msg.data); } } modifier onlyImmediateGovernance () { _checkOnlyGovernance(); _; } constructor(address _initialGovernance) { if (_initialGovernance != address(0)) { initialise(_initialGovernance); } } /** * @notice Execute the timelocked governance calls once the timelock period expires. * @dev Only executor can call this method. * @param _selector The method selector (only one timelocked call per method is stored). */ function executeGovernanceCall(bytes4 _selector) external { require(governanceSettings.isExecutor(msg.sender), "only executor"); TimelockedCall storage call = timelockedCalls[_selector]; require(call.allowedAfterTimestamp != 0, "timelock: invalid selector"); require(block.timestamp >= call.allowedAfterTimestamp, "timelock: not allowed yet"); bytes memory encodedCall = call.encodedCall; delete timelockedCalls[_selector]; executing = true; //solhint-disable-next-line avoid-low-level-calls (bool success,) = address(this).call(encodedCall); executing = false; emit TimelockedGovernanceCallExecuted(_selector, block.timestamp); _passReturnOrRevert(success); } /** * Cancel a timelocked governance call before it has been executed. * @dev Only governance can call this method. * @param _selector The method selector. */ function cancelGovernanceCall(bytes4 _selector) external onlyImmediateGovernance { require(timelockedCalls[_selector].allowedAfterTimestamp != 0, "timelock: invalid selector"); emit TimelockedGovernanceCallCanceled(_selector, block.timestamp); delete timelockedCalls[_selector]; } /** * Enter the production mode after all the initial governance settings have been set. * This enables timelocks and the governance is afterwards obtained by calling * governanceSettings.getGovernanceAddress(). */ function switchToProductionMode() external { _checkOnlyGovernance(); require(!productionMode, "already in production mode"); initialGovernance = address(0); productionMode = true; emit GovernedProductionModeEntered(address(governanceSettings)); } /** * @notice Initialize the governance address if not first initialized. */ function initialise(address _initialGovernance) public virtual { require(initialised == false, "initialised != false"); initialised = true; initialGovernance = _initialGovernance; emit GovernanceInitialised(_initialGovernance); } /** * Returns the current effective governance address. */ function governance() public view returns (address) { return productionMode ? governanceSettings.getGovernanceAddress() : initialGovernance; } function _beforeExecute() private { if (executing) { // can only be run from executeGovernanceCall(), where we check that only executor can call // make sure nothing else gets executed, even in case of reentrancy assert(msg.sender == address(this)); executing = false; } else { // must be called with: productionMode=false // must check governance in this case _checkOnlyGovernance(); } } function _recordTimelockedCall(bytes calldata _data) private { _checkOnlyGovernance(); bytes4 selector; //solhint-disable-next-line no-inline-assembly assembly { selector := calldataload(_data.offset) } uint256 timelock = governanceSettings.getTimelock(); uint256 allowedAt = block.timestamp + timelock; timelockedCalls[selector] = TimelockedCall({ allowedAfterTimestamp: allowedAt, encodedCall: _data }); emit GovernanceCallTimelocked(selector, allowedAt, _data); } function _checkOnlyGovernance() private view { require(msg.sender == governance(), "only governance"); } function _passReturnOrRevert(bool _success) private pure { // pass exact return or revert data - needs to be done in assembly //solhint-disable-next-line no-inline-assembly assembly { let size := returndatasize() let ptr := mload(0x40) mstore(0x40, add(ptr, size)) returndatacopy(ptr, 0, size) if _success { return(ptr, size) } revert(ptr, size) } } }
@openzeppelin/contracts/utils/Context.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
./contracts/token/implementation/VPContract.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../governance/implementation/GovernedBase.sol"; import "./Delegatable.sol"; import "../interface/IIVPContract.sol"; import "../interface/IIVPToken.sol"; import "../../userInterfaces/IVPToken.sol"; contract VPContract is IIVPContract, Delegatable { using SafeMath for uint256; /** * 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. */ IVPToken public immutable override ownerToken; /** * 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. */ bool public immutable override isReplacement; // The block number when vote power for an address was first set. // Reading vote power before this block would return incorrect result and must revert. mapping (address => uint256) private votePowerInitializationBlock; // Vote power cache for past blocks when vote power was not initialized. // Reading vote power at that block would return incorrect result, so cache must be set by some other means. // No need for revocation info, since there can be no delegations at such block. mapping (bytes32 => uint256) private uninitializedVotePowerCache; string constant private ALREADY_EXPLICIT_MSG = "Already delegated explicitly"; string constant private ALREADY_PERCENT_MSG = "Already delegated by percentage"; string constant internal VOTE_POWER_NOT_INITIALIZED = "Vote power not initialized"; /** * All external methods in VPContract can only be executed by the owner token. */ modifier onlyOwnerToken { require(msg.sender == address(ownerToken), "only owner token"); _; } modifier onlyPercent(address sender) { // If a delegate cannot be added by percentage, revert. require(_canDelegateByPct(sender), ALREADY_EXPLICIT_MSG); _; } modifier onlyExplicit(address sender) { // If a delegate cannot be added by explicit amount, revert. require(_canDelegateByAmount(sender), ALREADY_PERCENT_MSG); _; } /** * Construct VPContract for given VPToken. */ constructor(IVPToken _ownerToken, bool _isReplacement) { require(address(_ownerToken) != address(0), "VPContract must belong to a VPToken"); ownerToken = _ownerToken; isReplacement = _isReplacement; } /** * 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. * The method can be called only by the owner token. * @param _blockNumber The new cleanup block number. */ function setCleanupBlockNumber(uint256 _blockNumber) external override onlyOwnerToken { _setCleanupBlockNumber(_blockNumber); } /** * Set the contract that is allowed to call history cleaning methods. * The method can be called only by the owner token. */ function setCleanerContract(address _cleanerContract) external override onlyOwnerToken { _setCleanerContract(_cleanerContract); } /** * 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 override onlyOwnerToken { if (_from == address(0)) { // mint new vote power _initializeVotePower(_to, _toBalance); _mintVotePower(_to, _toBalance, _amount); } else if (_to == address(0)) { // burn vote power _initializeVotePower(_from, _fromBalance); _burnVotePower(_from, _fromBalance, _amount); } else { // transmit vote power _to receiver _initializeVotePower(_from, _fromBalance); _initializeVotePower(_to, _toBalance); _transmitVotePower(_from, _to, _fromBalance, _toBalance, _amount); } } /** * @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 cumulative - every call resets the delegation value (and value of 0 revokes delegation). **/ function delegate( address _from, address _to, uint256 _balance, uint256 _bips ) external override onlyOwnerToken onlyPercent(_from) { _initializeVotePower(_from, _balance); if (!_votePowerInitialized(_to)) { _initializeVotePower(_to, ownerToken.balanceOf(_to)); } _delegateByPercentage(_from, _to, _balance, _bips); } /** * @notice Explicitly delegate `_amount` 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 _amount An explicit vote power amount to be delegated. * Not cumulative - every call resets the delegation value (and value of 0 undelegates `to`). **/ function delegateExplicit( address _from, address _to, uint256 _balance, uint _amount ) external override onlyOwnerToken onlyExplicit(_from) { _initializeVotePower(_from, _balance); if (!_votePowerInitialized(_to)) { _initializeVotePower(_to, ownerToken.balanceOf(_to)); } _delegateByAmount(_from, _to, _balance, _amount); } /** * @notice Revoke all delegation from `_from` to `_to` 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 _to 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 _to, uint256 _balance, uint _blockNumber ) external override onlyOwnerToken { // ASSERT: if there was a delegation, _from and _to must be initialized if (!isReplacement || (_votePowerInitializedAt(_from, _blockNumber) && _votePowerInitializedAt(_to, _blockNumber))) { _revokeDelegationAt(_from, _to, _balance, _blockNumber); } } /** * @notice Undelegate all voting power for delegates of `_from` * 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 override onlyOwnerToken onlyPercent(_from) { if (_hasAnyDelegations(_from)) { // ASSERT: since there were delegations, _from and its targets must be initialized _undelegateAllByPercentage(_from, _balance); } } /** * @notice Undelegate all explicit vote power by amount delegates for `_from`. * 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 override onlyOwnerToken onlyExplicit(_from) returns (uint256) { if (_hasAnyDelegations(_from)) { // ASSERT: since there were delegations, _from and its targets must be initialized return _undelegateAllByAmount(_from, _delegateAddresses); } return 0; } /** * @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 override returns(uint256) { if (!isReplacement || _votePowerInitializedAt(_who, _blockNumber)) { // use standard method return _votePowerOfAtCached(_who, _blockNumber); } else { // use uninitialized vote power cache bytes32 key = keccak256(abi.encode(_who, _blockNumber)); uint256 cached = uninitializedVotePowerCache[key]; if (cached != 0) { return cached - 1; // safe, cached != 0 } uint256 balance = ownerToken.balanceOfAt(_who, _blockNumber); uninitializedVotePowerCache[key] = balance.add(1); return balance; } } /** * Get the current cleanup block number. */ function cleanupBlockNumber() external view override returns (uint256) { return _cleanupBlockNumber(); } /** * @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 override returns(uint256) { if (_votePowerInitialized(_who)) { return _votePowerOf(_who); } else { return ownerToken.balanceOf(_who); } } /** * @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) public view override returns(uint256) { if (!isReplacement || _votePowerInitializedAt(_who, _blockNumber)) { return _votePowerOfAt(_who, _blockNumber); } else { return ownerToken.balanceOfAt(_who, _blockNumber); } } /** * @notice Get the vote power of `_who` at block `_blockNumber`, ignoring revocation information (and cache). * @param _who The address to get voting power. * @param _blockNumber The block number at which to fetch. * @return Vote power of `_who` at `_blockNumber`. Result doesn't change if vote power is revoked. */ function votePowerOfAtIgnoringRevocation(address _who, uint256 _blockNumber) external view override returns(uint256) { if (!isReplacement || _votePowerInitializedAt(_who, _blockNumber)) { return _votePowerOfAtIgnoringRevocation(_who, _blockNumber); } else { return ownerToken.balanceOfAt(_who, _blockNumber); } } /** * 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 _votePowers A list of vote powers corresponding to _owners. */ function batchVotePowerOfAt( address[] memory _owners, uint256 _blockNumber ) external view override returns(uint256[] memory _votePowers) { _votePowers = _batchVotePowerOfAt(_owners, _blockNumber); // zero results might not have been initialized if (isReplacement) { for (uint256 i = 0; i < _votePowers.length; i++) { if (_votePowers[i] == 0 && !_votePowerInitializedAt(_owners[i], _blockNumber)) { _votePowers[i] = ownerToken.balanceOfAt(_owners[i], _blockNumber); } } } } /** * @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 override returns (uint256) { // ASSERT: if the result is nonzero, _from and _to are initialized return _votePowerFromTo(_from, _to, _balance); } /** * @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 override returns (uint256) { // ASSERT: if the result is nonzero, _from and _to were initialized at _blockNumber return _votePowerFromToAt(_from, _to, _balance, _blockNumber); } /** * @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 override returns (uint256) { return uint256(_delegationModeOf(_who)); } /** * @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 override returns (uint256) { if (_votePowerInitialized(_owner)) { return _undelegatedVotePowerOf(_owner, _balance); } else { // ASSERT: there are no delegations return _balance; } } /** * @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 override returns (uint256) { if (_votePowerInitialized(_owner)) { return _undelegatedVotePowerOfAt(_owner, _balance, _blockNumber); } else { // ASSERT: there were no delegations at _blockNumber return _balance; } } /** * @notice Get the vote power delegation `_delegateAddresses` * and `pcts` of an `_owner`. Returned in two separate positional arrays. * Also returns the count of delegates and delegation mode. * @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 override returns ( address[] memory _delegateAddresses, uint256[] memory _bips, uint256 _count, uint256 _delegationMode ) { // ASSERT: either _owner is initialized or there are no delegations return delegatesOfAt(_owner, block.number); } /** * @notice Get the vote power delegation `delegationAddresses` * and `_bips` of an `_owner`. Returned in two separate positional arrays. * Also returns the count of delegates and delegation mode. * @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 ) public view override returns ( address[] memory _delegateAddresses, uint256[] memory _bips, uint256 _count, uint256 _delegationMode ) { // ASSERT: either _owner was initialized or there were no delegations DelegationMode mode = _delegationModeOf(_owner); if (mode == DelegationMode.PERCENTAGE) { // Get the vote power delegation for the _owner (_delegateAddresses, _bips) = _percentageDelegatesOfAt(_owner, _blockNumber); } else if (mode == DelegationMode.NOTSET) { _delegateAddresses = new address[](0); _bips = new uint256[](0); } else { revert ("delegatesOf does not work in AMOUNT delegation mode"); } _count = _delegateAddresses.length; _delegationMode = uint256(mode); } /** * Initialize vote power to current balance if not initialized already. * @param _owner The address to initialize voting power. * @param _balance The owner's current balance. */ function _initializeVotePower(address _owner, uint256 _balance) internal { if (!isReplacement) return; if (_owner == address(0)) return; // 0 address is special (usually marks no source/dest - no init needed) if (votePowerInitializationBlock[_owner] == 0) { // consistency check - no delegations should be made from or to owner before vote power is initialized // (that would be dangerous, because vote power would have been delegated incorrectly) assert(_votePowerOf(_owner) == 0 && !_hasAnyDelegations(_owner)); _mintVotePower(_owner, 0, _balance); votePowerInitializationBlock[_owner] = block.number.add(1); } } /** * Has the vote power of `_owner` been initialized? * @param _owner The address to check. * @return true if vote power of _owner is initialized */ function _votePowerInitialized(address _owner) internal view returns (bool) { if (!isReplacement) return true; return votePowerInitializationBlock[_owner] != 0; } /** * Was vote power of `_owner` initialized at some block? * @param _owner The address to check. * @param _blockNumber The block for which we want to check. * @return true if vote power of _owner was initialized at _blockNumber */ function _votePowerInitializedAt(address _owner, uint256 _blockNumber) internal view returns (bool) { if (!isReplacement) return true; uint256 initblock = votePowerInitializationBlock[_owner]; return initblock != 0 && initblock - 1 <= _blockNumber; } }
./contracts/genesis/interface/IFtsoGenesis.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IFtsoGenesis { /** * @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 * @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 _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); }
./contracts/userInterfaces/IVPToken.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IGovernanceVotePower} from "./IGovernanceVotePower.sol"; import {IVPContractEvents} from "./IVPContractEvents.sol"; 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 cumulative - every call resets the delegation value (and value of 0 undelegates `to`). **/ function delegate(address _to, uint256 _bips) external; /** * @notice Undelegate all percentage delegations from the sender and then delegate corresponding * `_bips` percentage of voting power from the sender to each member of `_delegatees`. * @param _delegatees The addresses of the new recipients. * @param _bips The percentages of voting power to be delegated expressed in basis points (1/100 of one percent). * Total of all `_bips` values must be at most 10000. **/ function batchDelegate(address[] memory _delegatees, uint256[] memory _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 cumulative - 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 vote power of `_owner` at block `_blockNumber`, ignoring revocation information (and cache). * @param _owner The address to get voting power. * @param _blockNumber The block number at which to fetch. * @return Vote power of `_owner` at `_blockNumber`. Result doesn't change if vote power is revoked. */ function votePowerOfAtIgnoringRevocation(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); }
./contracts/userInterfaces/IGovernanceSettings.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; /** * A special contract that holds Flare governance address. * This contract enables updating governance address and timelock only by hard forking the network, * meaning only by updating validator code. */ interface IGovernanceSettings { /** * Get the governance account address. * The governance address can only be changed by a hardfork. */ function getGovernanceAddress() external view returns (address); /** * Get the time in seconds that must pass between a governance call and execution. * The timelock value can only be changed by a hardfork. */ function getTimelock() external view returns (uint256); /** * Get the addresses of the accounts that are allowed to execute the timelocked governance calls * once the timelock period expires. * Executors can be changed without a hardfork, via a normal governance call. */ function getExecutors() external view returns (address[] memory); /** * Check whether an address is one of the executors. */ function isExecutor(address _address) external view returns (bool); }
./contracts/token/lib/CheckPointHistory.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "@openzeppelin/contracts/math/Math.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/utils/SafeCast.sol"; /** * @title Check Point History library * @notice A contract to manage checkpoints as of a given block. * @dev Store value history by block number with detachable state. **/ library CheckPointHistory { using SafeMath for uint256; using SafeCast for uint256; /** * @dev `CheckPoint` is the structure that attaches a block number to a * given value; the block number attached is the one that last changed the * value **/ struct CheckPoint { // `value` is the amount of tokens at a specific block number uint192 value; // `fromBlock` is the block number that the value was generated from uint64 fromBlock; } struct CheckPointHistoryState { // `checkpoints` is an array that tracks values at non-contiguous block numbers mapping(uint256 => CheckPoint) checkpoints; // `checkpoints` before `startIndex` have been deleted // INVARIANT: checkpoints.endIndex == 0 || startIndex < checkpoints.endIndex (strict!) // startIndex and endIndex are both less then fromBlock, so 64 bits is enough uint64 startIndex; // the index AFTER last uint64 endIndex; } /** * @notice Binary search of _checkpoints array. * @param _checkpoints An array of CheckPoint to search. * @param _startIndex Smallest possible index to be returned. * @param _blockNumber The block number to search for. */ function _indexOfGreatestBlockLessThan( mapping(uint256 => CheckPoint) storage _checkpoints, uint256 _startIndex, uint256 _endIndex, uint256 _blockNumber ) private view returns (uint256 index) { // Binary search of the value by given block number in the array uint256 min = _startIndex; uint256 max = _endIndex.sub(1); while (max > min) { uint256 mid = (max.add(min).add(1)).div(2); if (_checkpoints[mid].fromBlock <= _blockNumber) { min = mid; } else { max = mid.sub(1); } } return min; } /** * @notice Queries the value at a specific `_blockNumber` * @param _self A CheckPointHistoryState instance to manage. * @param _blockNumber The block number of the value active at that time * @return _value The value at `_blockNumber` **/ function valueAt( CheckPointHistoryState storage _self, uint256 _blockNumber ) internal view returns (uint256 _value) { uint256 historyCount = _self.endIndex; // No _checkpoints, return 0 if (historyCount == 0) return 0; // Shortcut for the actual value (extra optimized for current block, to save one storage read) // historyCount - 1 is safe, since historyCount != 0 if (_blockNumber >= block.number || _blockNumber >= _self.checkpoints[historyCount - 1].fromBlock) { return _self.checkpoints[historyCount - 1].value; } // guard values at start uint256 startIndex = _self.startIndex; if (_blockNumber < _self.checkpoints[startIndex].fromBlock) { // reading data before `startIndex` is only safe before first cleanup require(startIndex == 0, "CheckPointHistory: reading from cleaned-up block"); return 0; } // Find the block with number less than or equal to block given uint256 index = _indexOfGreatestBlockLessThan(_self.checkpoints, startIndex, _self.endIndex, _blockNumber); return _self.checkpoints[index].value; } /** * @notice Queries the value at `block.number` * @param _self A CheckPointHistoryState instance to manage. * @return _value The value at `block.number` **/ function valueAtNow(CheckPointHistoryState storage _self) internal view returns (uint256 _value) { uint256 historyCount = _self.endIndex; // No _checkpoints, return 0 if (historyCount == 0) return 0; // Return last value return _self.checkpoints[historyCount - 1].value; } /** * @notice Writes the value at the current block. * @param _self A CheckPointHistoryState instance to manage. * @param _value Value to write. **/ function writeValue( CheckPointHistoryState storage _self, uint256 _value ) internal { uint256 historyCount = _self.endIndex; if (historyCount == 0) { // checkpoints array empty, push new CheckPoint _self.checkpoints[0] = CheckPoint({ fromBlock: block.number.toUint64(), value: _toUint192(_value) }); _self.endIndex = 1; } else { // historyCount - 1 is safe, since historyCount != 0 CheckPoint storage lastCheckpoint = _self.checkpoints[historyCount - 1]; uint256 lastBlock = lastCheckpoint.fromBlock; // slither-disable-next-line incorrect-equality if (block.number == lastBlock) { // If last check point is the current block, just update lastCheckpoint.value = _toUint192(_value); } else { // we should never have future blocks in history assert (block.number > lastBlock); // push new CheckPoint _self.checkpoints[historyCount] = CheckPoint({ fromBlock: block.number.toUint64(), value: _toUint192(_value) }); _self.endIndex = uint64(historyCount + 1); // 64 bit safe, because historyCount <= block.number } } } /** * Delete at most `_count` of the oldest checkpoints. * At least one checkpoint at or before `_cleanupBlockNumber` will remain * (unless the history was empty to start with). */ function cleanupOldCheckpoints( CheckPointHistoryState storage _self, uint256 _count, uint256 _cleanupBlockNumber ) internal returns (uint256) { if (_cleanupBlockNumber == 0) return 0; // optimization for when cleaning is not enabled uint256 length = _self.endIndex; if (length == 0) return 0; uint256 startIndex = _self.startIndex; // length - 1 is safe, since length != 0 (check above) uint256 endIndex = Math.min(startIndex.add(_count), length - 1); // last element can never be deleted uint256 index = startIndex; // we can delete `checkpoint[index]` while the next checkpoint is at `_cleanupBlockNumber` or before while (index < endIndex && _self.checkpoints[index + 1].fromBlock <= _cleanupBlockNumber) { delete _self.checkpoints[index]; index++; } if (index > startIndex) { // index is the first not deleted index _self.startIndex = index.toUint64(); } return index - startIndex; // safe: index >= startIndex at start and then increases } // SafeCast lib is missing cast to uint192 function _toUint192(uint256 _value) internal pure returns (uint192) { require(_value < 2**192, "value doesn't fit in 192 bits"); return uint192(_value); } }
./contracts/governance/implementation/Governed.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import { GovernedBase } from "./GovernedBase.sol"; /** * @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"); } }
./contracts/token/interface/IIVPToken.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import "../../userInterfaces/IVPToken.sol"; import "../../userInterfaces/IGovernanceVotePower.sol"; import "./IIVPContract.sol"; import "./IIGovernanceVotePower.sol"; import "./IICleanable.sol"; interface IIVPToken is IVPToken, IICleanable { /** * Set the contract that is allowed to set cleanupBlockNumber. * Usually this will be an instance of CleanupBlockNumberManager. */ function setCleanupBlockNumberManager(address _cleanupBlockNumberManager) external; /** * 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); }
./contracts/utils/implementation/GovernedAndFlareDaemonized.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import { FlareDaemon } from "../../genesis/implementation/FlareDaemon.sol"; import { Governed } from "../../governance/implementation/Governed.sol"; 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; } }
./contracts/genesis/interface/IFtsoManagerGenesis.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IFtsoManagerGenesis { function getCurrentPriceEpochId() external view returns (uint256 _priceEpochId); }
./contracts/tokenPools/interface/IITokenPool.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IITokenPool { /** * @notice Return token pool supply data * @return _lockedFundsWei Funds that are intentionally locked in the token pool * and not part of circulating supply * @return _totalInflationAuthorizedWei Total inflation authorized amount (wei) * @return _totalClaimedWei Total claimed amount (wei) */ function getTokenPoolSupplyData() external returns ( uint256 _lockedFundsWei, uint256 _totalInflationAuthorizedWei, uint256 _totalClaimedWei ); }
./contracts/token/interface/IIGovernanceVotePower.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import "../../userInterfaces/IVPToken.sol"; import "../../userInterfaces/IGovernanceVotePower.sol"; interface IIGovernanceVotePower is IGovernanceVotePower { /** * Event triggered when an delegator's balance changes. * * Note: the event is always emitted from `GovernanceVotePower`. */ event DelegateVotesChanged( address indexed delegate, uint256 previousBalance, uint256 newBalance ); /** * Event triggered when an account delegates to another account. * * Note: the event is always emitted from `GovernanceVotePower`. */ event DelegateChanged( address indexed delegator, address indexed fromDelegate, address indexed toDelegate ); /** * 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); function getCleanupBlockNumber() external view returns(uint256); }
./contracts/utils/implementation/AddressSet.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; library AddressSet { struct State { address[] list; mapping (address => uint256) index; } function add(State storage _state, address _address) internal { if (_state.index[_address] != 0) return; _state.list.push(_address); _state.index[_address] = _state.list.length; } function remove(State storage _state, address _address) internal { uint256 position = _state.index[_address]; if (position == 0) return; if (position < _state.list.length) { address addressToMove = _state.list[_state.list.length - 1]; _state.list[position - 1] = addressToMove; _state.index[addressToMove] = position; } _state.list.pop(); delete _state.index[_address]; } function addAll(State storage _state, address[] memory _addresses) internal { for (uint256 i = 0; i < _addresses.length; i++) { add(_state, _addresses[i]); } } function replaceAll(State storage _state, address[] memory _addresses) internal { clear(_state); addAll(_state, _addresses); } function clear(State storage _state) internal { while (_state.list.length > 0) { delete _state.index[_state.list[_state.list.length - 1]]; _state.list.pop(); } } }
./contracts/userInterfaces/IClaimSetupManager.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import "./IDelegationAccount.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IClaimSetupManager { event DelegationAccountCreated(address owner, IDelegationAccount delegationAccount); event DelegationAccountUpdated(address owner, IDelegationAccount delegationAccount, bool enabled); event ClaimExecutorsChanged(address owner, address[] executors); event AllowedClaimRecipientsChanged(address owner, address[] recipients); event ClaimExecutorFeeValueChanged(address executor, uint256 validFromRewardEpoch, uint256 feeValueWei); event ExecutorRegistered(address executor); event ExecutorUnregistered(address executor, uint256 validFromRewardEpoch); event MinFeeSet(uint256 minFeeValueWei); event MaxFeeSet(uint256 maxFeeValueWei); event RegisterExecutorFeeSet(uint256 registerExecutorFeeValueWei); event SetExecutorsExcessAmountRefunded(address owner, uint256 excessAmount); /** * @notice Sets the addresses of executors and optionally enables (creates) delegation account. * @notice If setting registered executors some fee must be paid to them. * @param _executors The new executors. All old executors will be deleted and replaced by these. */ function setAutoClaiming(address[] memory _executors, bool _enableDelegationAccount) external payable; /** * @notice Sets the addresses of executors. * @notice If setting registered executors some fee must be paid to them. * @param _executors The new executors. All old executors will be deleted and replaced by these. */ function setClaimExecutors(address[] memory _executors) external payable; /** * Set the addresses of allowed recipients. * Apart from these, the owner is always an allowed recipient. * @param _recipients The new allowed recipients. All old recipients will be deleted and replaced by these. */ function setAllowedClaimRecipients(address[] memory _recipients) external; /** * @notice Enables (creates) delegation account contract, * i.e. all airdrop and ftso rewards will be send to delegation account when using automatic claiming. * @return Address of delegation account contract. */ function enableDelegationAccount() external returns (IDelegationAccount); /** * @notice Disables delegation account contract, * i.e. all airdrop and ftso rewards will be send to owner's account when using automatic claiming. * @notice Automatic claiming will not claim airdrop and ftso rewards for delegation account anymore. * @dev Reverts if there is no delegation account */ function disableDelegationAccount() external; /** * @notice Allows executor to register and set initial fee value. * If executor was already registered before (has fee set), only update fee after `feeValueUpdateOffset`. * @notice Executor must pay fee in order to register - `registerExecutorFeeValueWei`. * @param _feeValue number representing fee value * @return Returns the reward epoch number when the setting becomes effective. */ function registerExecutor(uint256 _feeValue) external payable returns (uint256); /** * @notice Allows executor to unregister. * @return Returns the reward epoch number when the setting becomes effective. */ function unregisterExecutor() external returns (uint256); /** * @notice Allows registered executor to set (or update last scheduled) fee value. * @param _feeValue number representing fee value * @return Returns the reward epoch number when the setting becomes effective. */ function updateExecutorFeeValue(uint256 _feeValue) external returns(uint256); /** * @notice Delegate `_bips` of voting power to `_to` from msg.sender's delegation account * @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 cumulative - every call resets the delegation value (and value of 0 revokes delegation). */ function delegate(address _to, uint256 _bips) external; /** * @notice Undelegate all percentage delegations from the msg.sender's delegation account and then delegate * corresponding `_bips` percentage of voting power to each member of `_delegatees`. * @param _delegatees The addresses of the new recipients. * @param _bips The percentages of voting power to be delegated expressed in basis points (1/100 of one percent). * Total of all `_bips` values must be at most 10000. */ function batchDelegate(address[] memory _delegatees, uint256[] memory _bips) external; /** * @notice Undelegate all voting power for delegates of msg.sender's delegation account */ function undelegateAll() external; /** * @notice Revoke all delegation from msg.sender's delegation account 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 with value of 0 or undelegateAll. */ function revokeDelegationAt(address _who, uint256 _blockNumber) external; /** * @notice Delegate all governance vote power of msg.sender's delegation account to `_to`. * @param _to The address of the recipient */ function delegateGovernance(address _to) external; /** * @notice Undelegate governance vote power for delegate of msg.sender's delegation account */ function undelegateGovernance() external; /** * @notice Allows user to transfer WNat to owner's account. * @param _amount Amount of tokens to transfer */ function withdraw(uint256 _amount) external; /** * @notice Allows user to transfer balance of ERC20 tokens owned by the personal delegation contract. The main use case is to transfer tokens/NFTs that were received as part of an airdrop or register as participant in such airdrop. * @param _token Target token contract address * @param _amount Amount of tokens to transfer * @dev Reverts if target token is WNat contract - use method `withdraw` for that */ function transferExternalToken(IERC20 _token, uint256 _amount) external; /** * @notice Gets the delegation account of the `_owner`. Returns address(0) if not created yet. */ function accountToDelegationAccount(address _owner) external view returns (address); /** * @notice Gets the delegation account data for the `_owner`. Returns address(0) if not created yet. * @param _owner owner's address * @return _delegationAccount owner's delegation account address - could be address(0) * @return _enabled indicates if delegation account is enabled */ function getDelegationAccountData( address _owner ) external view returns (IDelegationAccount _delegationAccount, bool _enabled); /** * @notice Get the addresses of executors. */ function claimExecutors(address _owner) external view returns (address[] memory); /** * Get the addresses of allowed recipients. * Apart from these, the owner is always an allowed recipient. */ function allowedClaimRecipients(address _rewardOwner) external view returns (address[] memory); /** * @notice Returns info if `_executor` is allowed to execute calls for `_owner` */ function isClaimExecutor(address _owner, address _executor) external view returns(bool); /** * @notice Get registered executors */ function getRegisteredExecutors( uint256 _start, uint256 _end ) external view returns (address[] memory _registeredExecutors, uint256 _totalLength); /** * @notice Returns some info about the `_executor` * @param _executor address representing executor * @return _registered information if executor is registered * @return _currentFeeValue executor's current fee value */ function getExecutorInfo(address _executor) external view returns (bool _registered, uint256 _currentFeeValue); /** * @notice Returns the current fee value of `_executor` * @param _executor address representing executor */ function getExecutorCurrentFeeValue(address _executor) external view returns (uint256); /** * @notice Returns the fee value of `_executor` at `_rewardEpoch` * @param _executor address representing executor * @param _rewardEpoch reward epoch number */ function getExecutorFeeValue(address _executor, uint256 _rewardEpoch) external view returns (uint256); /** * @notice Returns the scheduled fee value changes of `_executor` * @param _executor address representing executor * @return _feeValue positional array of fee values * @return _validFromEpoch positional array of reward epochs the fee settings are effective from * @return _fixed positional array of boolean values indicating if settings are subjected to change */ function getExecutorScheduledFeeValueChanges(address _executor) external view returns ( uint256[] memory _feeValue, uint256[] memory _validFromEpoch, bool[] memory _fixed ); }
./contracts/governance/implementation/GovernedAtGenesis.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "./GovernedBase.sol"; /** * @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); } }
@openzeppelin/contracts/utils/SafeCast.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * 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 SafeCast { /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { require(value < 2**16, "SafeCast: value doesn\'t fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits. */ function toUint8(uint256 value) internal pure returns (uint8) { require(value < 2**8, "SafeCast: value doesn\'t fit in 8 bits"); return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v3.1._ */ function toInt128(int256 value) internal pure returns (int128) { require(value >= -2**127 && value < 2**127, "SafeCast: value doesn\'t fit in 128 bits"); return int128(value); } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v3.1._ */ function toInt64(int256 value) internal pure returns (int64) { require(value >= -2**63 && value < 2**63, "SafeCast: value doesn\'t fit in 64 bits"); return int64(value); } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v3.1._ */ function toInt32(int256 value) internal pure returns (int32) { require(value >= -2**31 && value < 2**31, "SafeCast: value doesn\'t fit in 32 bits"); return int32(value); } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v3.1._ */ function toInt16(int256 value) internal pure returns (int16) { require(value >= -2**15 && value < 2**15, "SafeCast: value doesn\'t fit in 16 bits"); return int16(value); } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits. * * _Available since v3.1._ */ function toInt8(int256 value) internal pure returns (int8) { require(value >= -2**7 && value < 2**7, "SafeCast: value doesn\'t fit in 8 bits"); return int8(value); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { require(value < 2**255, "SafeCast: value doesn't fit in an int256"); return int256(value); } }
./contracts/token/lib/CheckPointHistoryCache.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "@openzeppelin/contracts/math/SafeMath.sol"; import "./CheckPointHistory.sol"; library CheckPointHistoryCache { using SafeMath for uint256; using CheckPointHistory for CheckPointHistory.CheckPointHistoryState; struct CacheState { // mapping blockNumber => (value + 1) mapping(uint256 => uint256) cache; } function valueAt( CacheState storage _self, CheckPointHistory.CheckPointHistoryState storage _checkPointHistory, uint256 _blockNumber ) internal returns (uint256 _value, bool _cacheCreated) { // is it in cache? uint256 cachedValue = _self.cache[_blockNumber]; if (cachedValue != 0) { return (cachedValue - 1, false); // safe, cachedValue != 0 } // read from _checkPointHistory uint256 historyValue = _checkPointHistory.valueAt(_blockNumber); _self.cache[_blockNumber] = historyValue.add(1); // store to cache (add 1 to differentiate from empty) return (historyValue, true); } function deleteAt( CacheState storage _self, uint256 _blockNumber ) internal returns (uint256 _deleted) { if (_self.cache[_blockNumber] != 0) { _self.cache[_blockNumber] = 0; return 1; } return 0; } }
./contracts/token/implementation/VPToken.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "./CheckPointable.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../utils/implementation/SafePct.sol"; import "../../userInterfaces/IVPToken.sol"; import "../../userInterfaces/IVPContractEvents.sol"; import "../interface/IIVPToken.sol"; import "../interface/IIVPContract.sol"; import "../interface/IIGovernanceVotePower.sol"; import "../../userInterfaces/IGovernanceVotePower.sol"; import "../../governance/implementation/Governed.sol"; /** * @title Vote Power Token * @dev An ERC20 token to enable the holder to delegate voting power * equal 1-1 to their balance, with history tracking by block. **/ contract VPToken is IIVPToken, ERC20, CheckPointable, Governed { using SafeMath for uint256; using SafePct for uint256; // the VPContract to use for reading vote powers and delegations IIVPContract private readVpContract; // the VPContract to use for writing vote powers and delegations // normally same as `readVpContract` except during switch // when reading happens from the old and writing goes to the new VPContract IIVPContract private writeVpContract; // the contract to use for governance vote power and delegation // here only to properly update governance vp during transfers - // all actual operations go directly to governance vp contract IIGovernanceVotePower private governanceVP; // the contract that is allowed to set cleanupBlockNumber // usually this will be an instance of CleanupBlockNumberManager address public cleanupBlockNumberManager; /** * When true, the argument to `setWriteVpContract` must be a vpContract * with `isReplacement` set to `true`. To be used for creating the correct VPContract. */ bool public vpContractInitialized = false; /** * Event used to track history of VPToken -> VPContract / GovernanceVotePower * associations (e.g. by external cleaners). * @param _contractType 0 = read VPContract, 1 = write VPContract, 2 = governance vote power * @param _oldContractAddress vote power contract address before change * @param _newContractAddress vote power contract address after change */ event VotePowerContractChanged(uint256 _contractType, address _oldContractAddress, address _newContractAddress); constructor( address _governance, //slither-disable-next-line shadowing-local string memory _name, //slither-disable-next-line shadowing-local string memory _symbol ) Governed(_governance) ERC20(_name, _symbol) { /* empty block */ } /** * @dev Should be compatible with ERC20 method */ function name() public view override(ERC20, IVPToken) returns (string memory) { return ERC20.name(); } /** * @dev Should be compatible with ERC20 method */ function symbol() public view override(ERC20, IVPToken) returns (string memory) { return ERC20.symbol(); } /** * @dev Should be compatible with ERC20 method */ function decimals() public view override(ERC20, IVPToken) returns (uint8) { return ERC20.decimals(); } /** * @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(uint256 _blockNumber) public view override(CheckPointable, IVPToken) returns(uint256) { return CheckPointable.totalSupplyAt(_blockNumber); } /** * @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, uint256 _blockNumber ) public view override(CheckPointable, IVPToken) returns (uint256) { return CheckPointable.balanceOfAt(_owner, _blockNumber); } /** * @notice Delegate `_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 cumulative - every call resets the delegation value (and value of 0 revokes delegation). **/ function delegate(address _to, uint256 _bips) external override { // Get the current balance of sender and delegate by percentage _to recipient _checkWriteVpContract().delegate(msg.sender, _to, balanceOf(msg.sender), _bips); } /** * @notice Undelegate all percentage delegations from the sender and then delegate corresponding * `_bips` percentage of voting power from the sender to each member of `_delegatees`. * @param _delegatees The addresses of the new recipients. * @param _bips The percentages of voting power to be delegated expressed in basis points (1/100 of one percent). * Total of all `_bips` values must be at most 10000. **/ function batchDelegate(address[] memory _delegatees, uint256[] memory _bips) external override { require(_delegatees.length == _bips.length, "Array length mismatch"); IIVPContract vpContract = _checkWriteVpContract(); uint256 balance = balanceOf(msg.sender); vpContract.undelegateAll(msg.sender, balance); for (uint256 i = 0; i < _delegatees.length; i++) { vpContract.delegate(msg.sender, _delegatees[i], balance, _bips[i]); } } /** * @notice 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 cumulative - every call resets the delegation value (and value of 0 revokes delegation). **/ function delegateExplicit(address _to, uint256 _amount) external override { _checkWriteVpContract().delegateExplicit(msg.sender, _to, balanceOf(msg.sender), _amount); } /** * @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 override returns(uint256) { return _checkReadVpContract().undelegatedVotePowerOf(_owner, balanceOf(_owner)); } /** * @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 unallocated vote power of `_owner` */ function undelegatedVotePowerOfAt(address _owner, uint256 _blockNumber) external view override returns (uint256) { return _checkReadVpContract() .undelegatedVotePowerOfAt(_owner, balanceOfAt(_owner, _blockNumber), _blockNumber); } /** * @notice Undelegate all voting power for delegates of `msg.sender` **/ function undelegateAll() external override { _checkWriteVpContract().undelegateAll(msg.sender, balanceOf(msg.sender)); } /** * @notice Undelegate all explicit vote power by amount delegates for `msg.sender`. * @param _delegateAddresses Explicit delegation does not store delegatees' addresses, * so the caller must supply them. * @return _remainingDelegation The amount still delegated (in case the list of delegates was incomplete). */ function undelegateAllExplicit( address[] memory _delegateAddresses ) external override returns (uint256 _remainingDelegation) { return _checkWriteVpContract().undelegateAllExplicit(msg.sender, _delegateAddresses); } /** * @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. */ function revokeDelegationAt(address _who, uint256 _blockNumber) public override { IIVPContract writeVPC = writeVpContract; IIVPContract readVPC = readVpContract; if (address(writeVPC) != address(0)) { writeVPC.revokeDelegationAt(msg.sender, _who, balanceOfAt(msg.sender, _blockNumber), _blockNumber); } if (address(readVPC) != address(writeVPC) && address(readVPC) != address(0)) { try readVPC.revokeDelegationAt(msg.sender, _who, balanceOfAt(msg.sender, _blockNumber), _blockNumber) { } catch { // do nothing } } } /** * @notice Get current delegated vote power `_from` delegator delegated `_to` delegatee. * @param _from Address of delegator * @param _to Address of delegatee * @return votePower The delegated vote power. */ function votePowerFromTo( address _from, address _to ) external view override returns(uint256) { return _checkReadVpContract().votePowerFromTo(_from, _to, balanceOf(_from)); } /** * @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, uint256 _blockNumber ) external view override returns(uint256) { return _checkReadVpContract().votePowerFromToAt(_from, _to, balanceOfAt(_from, _blockNumber), _blockNumber); } /** * @notice Get the current total vote power. * @return The current total vote power (sum of all accounts' vote powers). */ function totalVotePower() external view override returns(uint256) { return totalSupply(); } /** * @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(uint256 _blockNumber) external view override returns(uint256) { return totalSupplyAt(_blockNumber); } /** * @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) public override returns(uint256) { return _totalSupplyAtCached(_blockNumber); } /** * @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 override returns (uint256) { return _checkReadVpContract().delegationModeOf(_who); } /** * @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 override returns(uint256) { return _checkReadVpContract().votePowerOf(_owner); } /** * @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 override returns(uint256) { return _checkReadVpContract().votePowerOfAt(_owner, _blockNumber); } /** * @notice Get the vote power of `_owner` at block `_blockNumber`, ignoring revocation information (and cache). * @param _owner The address to get voting power. * @param _blockNumber The block number at which to fetch. * @return Vote power of `_owner` at `_blockNumber`. Result doesn't change if vote power is revoked. */ function votePowerOfAtIgnoringRevocation(address _owner, uint256 _blockNumber) external view override returns(uint256) { return _checkReadVpContract().votePowerOfAtIgnoringRevocation(_owner, _blockNumber); } /** * 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 override returns(uint256[] memory) { return _checkReadVpContract().batchVotePowerOfAt(_owners, _blockNumber); } /** * @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) public override returns(uint256) { return _checkReadVpContract().votePowerOfAtCached(_owner, _blockNumber); } /** * @notice Get the vote power delegation `delegationAddresses` * and `_bips` of `_who`. 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 override returns ( address[] memory _delegateAddresses, uint256[] memory _bips, uint256 _count, uint256 _delegationMode ) { return _checkReadVpContract().delegatesOf(_owner); } /** * @notice Get the vote power delegation `delegationAddresses` * and `pcts` of `_who`. 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 override returns ( address[] memory _delegateAddresses, uint256[] memory _bips, uint256 _count, uint256 _delegationMode ) { return _checkReadVpContract().delegatesOfAt(_owner, _blockNumber); } // Update vote power and balance checkpoints before balances are modified. This is implemented // in the _beforeTokenTransfer hook, which is executed for _mint, _burn, and _transfer operations. function _beforeTokenTransfer( address _from, address _to, uint256 _amount ) internal virtual override(ERC20) { require(_from != _to, "Cannot transfer to self"); uint256 fromBalance = _from != address(0) ? balanceOf(_from) : 0; uint256 toBalance = _to != address(0) ? balanceOf(_to) : 0; // update vote powers IIVPContract vpc = writeVpContract; if (address(vpc) != address(0)) { vpc.updateAtTokenTransfer(_from, _to, fromBalance, toBalance, _amount); } else if (!vpContractInitialized) { // transfers without vpcontract are allowed, but after they are made // any added vpcontract must have isReplacement set vpContractInitialized = true; } // update governance vote powers IIGovernanceVotePower gvp = governanceVP; if (address(gvp) != address(0)) { gvp.updateAtTokenTransfer(_from, _to, fromBalance, toBalance, _amount); } // update balance history _updateBalanceHistoryAtTransfer(_from, _to, _amount); } /** * Call from governance to set read VpContract on token, e.g. * `vpToken.setReadVpContract(new VPContract(vpToken))` * Read VPContract must be set before any of the VPToken delegation or vote power reading methods are called, * otherwise they will revert. * NOTE: If readVpContract differs from writeVpContract all reads will be "frozen" and will not reflect * changes (not even revokes; they may or may not reflect balance transfers). * @param _vpContract Read vote power contract to be used by this token. */ function setReadVpContract(IIVPContract _vpContract) external onlyGovernance { if (address(_vpContract) != address(0)) { require(address(_vpContract.ownerToken()) == address(this), "VPContract not owned by this token"); // set contract's cleanup block _vpContract.setCleanupBlockNumber(_cleanupBlockNumber()); } emit VotePowerContractChanged(0, address(readVpContract), address(_vpContract)); readVpContract = _vpContract; } /** * Call from governance to set write VpContract on token, e.g. * `vpToken.setWriteVpContract(new VPContract(vpToken))` * Write VPContract must be set before any of the VPToken delegation modifying methods are called, * otherwise they will revert. * @param _vpContract Write vote power contract to be used by this token. */ function setWriteVpContract(IIVPContract _vpContract) external onlyGovernance { if (address(_vpContract) != address(0)) { require(address(_vpContract.ownerToken()) == address(this), "VPContract not owned by this token"); require(!vpContractInitialized || _vpContract.isReplacement(), "VPContract not configured for replacement"); // set contract's cleanup block _vpContract.setCleanupBlockNumber(_cleanupBlockNumber()); // once a non-null vpcontract is set, every other has to have isReplacement flag set vpContractInitialized = true; } emit VotePowerContractChanged(1, address(writeVpContract), address(_vpContract)); writeVpContract = _vpContract; } /** * Return read vpContract, ensuring that it is not zero. */ function _checkReadVpContract() internal view returns (IIVPContract) { IIVPContract vpc = readVpContract; require(address(vpc) != address(0), "Token missing read VPContract"); return vpc; } /** * Return write vpContract, ensuring that it is not zero. */ function _checkWriteVpContract() internal view returns (IIVPContract) { IIVPContract vpc = writeVpContract; require(address(vpc) != address(0), "Token missing write VPContract"); return vpc; } /** * Return vpContract use for reading, may be zero. */ function _getReadVpContract() internal view returns (IIVPContract) { return readVpContract; } /** * Return vpContract use for writing, may be zero. */ function _getWriteVpContract() internal view returns (IIVPContract) { return writeVpContract; } /** * Returns VPContract event interface used for readonly operations (view methods). */ function readVotePowerContract() external view override returns (IVPContractEvents) { return readVpContract; } /** * Returns VPContract event interface used for state changing operations (non-view methods). */ function writeVotePowerContract() external view override returns (IVPContractEvents) { return writeVpContract; } /** * 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 override { require(msg.sender == cleanupBlockNumberManager, "only cleanup block manager"); _setCleanupBlockNumber(_blockNumber); if (address(readVpContract) != address(0)) { readVpContract.setCleanupBlockNumber(_blockNumber); } if (address(writeVpContract) != address(0) && address(writeVpContract) != address(readVpContract)) { writeVpContract.setCleanupBlockNumber(_blockNumber); } if (address(governanceVP) != address(0)) { governanceVP.setCleanupBlockNumber(_blockNumber); } } /** * Get the current cleanup block number. */ function cleanupBlockNumber() external view override returns (uint256) { return _cleanupBlockNumber(); } /** * Set the contract that is allowed to set cleanupBlockNumber. * Usually this will be an instance of CleanupBlockNumberManager. */ function setCleanupBlockNumberManager(address _cleanupBlockNumberManager) external override onlyGovernance { cleanupBlockNumberManager = _cleanupBlockNumberManager; } /** * Set the contract that is allowed to call history cleaning methods. */ function setCleanerContract(address _cleanerContract) external override onlyGovernance { _setCleanerContract(_cleanerContract); if (address(readVpContract) != address(0)) { readVpContract.setCleanerContract(_cleanerContract); } if (address(writeVpContract) != address(0) && address(writeVpContract) != address(readVpContract)) { writeVpContract.setCleanerContract(_cleanerContract); } if (address(governanceVP) != address(0)) { governanceVP.setCleanerContract(_cleanerContract); } } /** * 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 override onlyGovernance { require(address(_governanceVotePower.ownerToken()) == address(this), "Governance vote power contract does not belong to this token."); emit VotePowerContractChanged(2, address(governanceVP), address(_governanceVotePower)); governanceVP = _governanceVotePower; } /** * When set, allows token owners to participate in governance voting * and delegate governance vote power. */ function governanceVotePower() external view override returns (IGovernanceVotePower) { return governanceVP; } }
./contracts/token/lib/IICombinedNatBalance.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IICombinedNatBalance { /** * @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); }
./contracts/claiming/implementation/CloneFactory.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; /* The MIT License (MIT) Copyright (c) 2018 Murray Software, LLC. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ //solhint-disable max-line-length //solhint-disable no-inline-assembly contract CloneFactory { function createClone(address target) internal returns (address result) { bytes20 targetBytes = bytes20(target); assembly { let clone := mload(0x40) mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(clone, 0x14), targetBytes) mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) result := create(0, clone, 0x37) } } function isClone(address target, address query) internal view returns (bool result) { bytes20 targetBytes = bytes20(target); assembly { let clone := mload(0x40) mstore(clone, 0x363d3d373d3d3d363d7300000000000000000000000000000000000000000000) mstore(add(clone, 0xa), targetBytes) mstore(add(clone, 0x1e), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) let other := add(clone, 0x40) extcodecopy(query, other, 0, 0x2d) result := and( eq(mload(clone), mload(other)), eq(mload(add(clone, 0xd)), mload(add(other, 0xd))) ) } } }
./contracts/genesis/implementation/FlareDaemon.sol
// SPDX-License-Identifier: MIT // 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; pragma abicoder v2; import "../../governance/implementation/GovernedAtGenesis.sol"; import "../../addressUpdater/implementation/AddressUpdatable.sol"; import "../interface/IInflationGenesis.sol"; import "../interface/IFlareDaemonize.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../utils/implementation/SafePct.sol"; /** * @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, AddressUpdatable { 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_ALREADY_SET = "already set"; 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 - 60 million native token uint256 internal constant MAX_MINTING_REQUEST_DEFAULT = 60000000 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 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)) AddressUpdatable(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[] memory _registrations) external onlyGovernance { _registerToDaemonize(_registrations); } /** * @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 address udpater contract. * @param _addressUpdater The address updater contract. */ function setAddressUpdater(address _addressUpdater) external onlyGovernance { require(getAddressUpdater() == address(0), ERR_ALREADY_SET); setAddressUpdaterValue(_addressUpdater); } /** * @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 onlySystemTrigger returns (uint256 _toMintWei) { return triggerInternal(); } 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 AddressUpdatable abstract method - updates Inflation and daemonized contracts. * @dev It also sets `maxMintingRequestWei` if it was not set before. */ function _updateContractAddresses( bytes32[] memory _contractNameHashes, address[] memory _contractAddresses ) internal override { IInflationGenesis _inflation = IInflationGenesis( _getContractAddress(_contractNameHashes, _contractAddresses, "Inflation")); emit InflationSet(_inflation, inflation); inflation = _inflation; if (maxMintingRequestWei == 0) { maxMintingRequestWei = MAX_MINTING_REQUEST_DEFAULT; } uint256 len = daemonizeContracts.length; if (len == 0) { return; } Registration[] memory registrations = new Registration[](len); for (uint256 i = 0; i < len; i++) { IFlareDaemonize daemonizeContract = daemonizeContracts[i]; registrations[i].daemonizedContract = IFlareDaemonize( _getContractAddress(_contractNameHashes, _contractAddresses, daemonizeContract.getContractName())); registrations[i].gasLimit = gasLimits[daemonizeContract]; } _registerToDaemonize(registrations); } /** * @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-eth // 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-eth // 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; } // Update balance lastBalance = address(this).balance; // 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); } } 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 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[] memory _registrations) internal { // 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 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); } }
./contracts/token/implementation/Delegatable.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "../lib/PercentageDelegation.sol"; import "../lib/ExplicitDelegation.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../utils/implementation/SafePct.sol"; import "../lib/VotePower.sol"; import "../lib/VotePowerCache.sol"; import "../../userInterfaces/IVPContractEvents.sol"; /** * @title Delegateable ERC20 behavior * @notice An ERC20 Delegateable behavior to delegate voting power * of a token to delegates. This contract orchestrates interaction between * managing a delegation and the vote power allocations that result. **/ contract Delegatable is IVPContractEvents { using PercentageDelegation for PercentageDelegation.DelegationState; using ExplicitDelegation for ExplicitDelegation.DelegationState; using SafeMath for uint256; using SafePct for uint256; using VotePower for VotePower.VotePowerState; using VotePowerCache for VotePowerCache.CacheState; enum DelegationMode { NOTSET, PERCENTAGE, AMOUNT } // The number of history cleanup steps executed for every write operation. // It is more than 1 to make as certain as possible that all history gets cleaned eventually. uint256 private constant CLEANUP_COUNT = 2; string constant private UNDELEGATED_VP_TOO_SMALL_MSG = "Undelegated vote power too small"; // Map that tracks delegation mode of each address. mapping(address => DelegationMode) private delegationModes; // `percentageDelegations` is the map that tracks the percentage voting power delegation of each address. // Explicit delegations are tracked directly through votePower. mapping(address => PercentageDelegation.DelegationState) private percentageDelegations; mapping(address => ExplicitDelegation.DelegationState) private explicitDelegations; // `votePower` tracks all voting power balances VotePower.VotePowerState private votePower; // `votePower` tracks all voting power balances VotePowerCache.CacheState private votePowerCache; // Historic data for the blocks before `cleanupBlockNumber` can be erased, // history before that block should never be used since it can be inconsistent. uint256 private cleanupBlockNumber; // Address of the contract that is allowed to call methods for history cleaning. address public cleanerContract; /** * Emitted when a vote power cache entry is created. * Allows history cleaners to track vote power cache cleanup opportunities off-chain. */ event CreatedVotePowerCache(address _owner, uint256 _blockNumber); // Most history cleanup opportunities can be deduced from standard events: // Transfer(from, to, amount): // - vote power checkpoints for `from` (if nonzero) and `to` (if nonzero) // - vote power checkpoints for percentage delegatees of `from` and `to` are also created, // but they don't have to be checked since Delegate events are also emitted in case of // percentage delegation vote power change due to delegators balance change // - Note: Transfer event is emitted from VPToken but vote power checkpoint delegationModes // must be called on its writeVotePowerContract // Delegate(from, to, priorVP, newVP): // - vote power checkpoints for `from` and `to` // - percentage delegation checkpoint for `from` (if `from` uses percentage delegation mode) // - explicit delegation checkpoint from `from` to `to` (if `from` uses explicit delegation mode) // Revoke(from, to, vp, block): // - vote power cache for `from` and `to` at `block` // - revocation cache block from `from` to `to` at `block` /** * Reading from history is not allowed before `cleanupBlockNumber`, since data before that * might have been deleted and is thus unreliable. */ modifier notBeforeCleanupBlock(uint256 _blockNumber) { require(_blockNumber >= cleanupBlockNumber, "Delegatable: reading from cleaned-up block"); _; } /** * History cleaning methods can be called only from the cleaner address. */ modifier onlyCleaner { require(msg.sender == cleanerContract, "Only cleaner contract"); _; } /** * @notice (Un)Allocate `_owner` vote power of `_amount` across owner delegate * vote power percentages. * @param _owner The address of the vote power owner. * @param _priorBalance The owner's balance before change. * @param _newBalance The owner's balance after change. * @dev precondition: delegationModes[_owner] == DelegationMode.PERCENTAGE */ function _allocateVotePower(address _owner, uint256 _priorBalance, uint256 _newBalance) private { // Get the voting delegation for the _owner PercentageDelegation.DelegationState storage delegation = percentageDelegations[_owner]; // Track total owner vp change uint256 ownerVpAdd = _newBalance; uint256 ownerVpSub = _priorBalance; // Iterate over the delegates (uint256 length, mapping(uint256 => DelegationHistory.Delegation) storage delegations) = delegation.getDelegationsRaw(); for (uint256 i = 0; i < length; i++) { DelegationHistory.Delegation storage dlg = delegations[i]; address delegatee = dlg.delegate; uint256 value = dlg.value; // Compute the delegated vote power for the delegatee uint256 priorValue = _priorBalance.mulDiv(value, PercentageDelegation.MAX_BIPS); uint256 newValue = _newBalance.mulDiv(value, PercentageDelegation.MAX_BIPS); ownerVpAdd = ownerVpAdd.add(priorValue); ownerVpSub = ownerVpSub.add(newValue); // could optimize next lines by checking that priorValue != newValue, but that can only happen // for the transfer of 0 amount, which is prevented by the calling function votePower.changeValue(delegatee, newValue, priorValue); votePower.cleanupOldCheckpoints(delegatee, CLEANUP_COUNT, cleanupBlockNumber); emit Delegate(_owner, delegatee, priorValue, newValue); } // (ownerVpAdd - ownerVpSub) is how much the owner vp changes - will be 0 if delegation is 100% if (ownerVpAdd != ownerVpSub) { votePower.changeValue(_owner, ownerVpAdd, ownerVpSub); votePower.cleanupOldCheckpoints(_owner, CLEANUP_COUNT, cleanupBlockNumber); } } /** * @notice Burn `_amount` of vote power for `_owner`. * @param _owner The address of the _owner vote power to burn. * @param _ownerCurrentBalance The current token balance of the owner (which is their allocatable vote power). * @param _amount The amount of vote power to burn. */ function _burnVotePower(address _owner, uint256 _ownerCurrentBalance, uint256 _amount) internal { // revert with the same error as ERC20 in case transfer exceeds balance uint256 newOwnerBalance = _ownerCurrentBalance.sub(_amount, "ERC20: transfer amount exceeds balance"); if (delegationModes[_owner] == DelegationMode.PERCENTAGE) { // for PERCENTAGE delegation: reduce owner vote power allocations _allocateVotePower(_owner, _ownerCurrentBalance, newOwnerBalance); } else { // for AMOUNT delegation: is there enough unallocated VP _to burn if explicitly delegated? require(_isTransmittable(_owner, _ownerCurrentBalance, _amount), UNDELEGATED_VP_TOO_SMALL_MSG); // burn vote power votePower.changeValue(_owner, 0, _amount); votePower.cleanupOldCheckpoints(_owner, CLEANUP_COUNT, cleanupBlockNumber); } } /** * @notice Get whether `_owner` current delegation can be delegated by percentage. * @param _owner Address of delegation to check. * @return True if delegation can be delegated by percentage. */ function _canDelegateByPct(address _owner) internal view returns(bool) { // Get the delegation mode. DelegationMode delegationMode = delegationModes[_owner]; // Return true if delegation is safe _to store percents, which can also // apply if there is not delegation mode set. return delegationMode == DelegationMode.NOTSET || delegationMode == DelegationMode.PERCENTAGE; } /** * @notice Get whether `_owner` current delegation can be delegated by amount. * @param _owner Address of delegation to check. * @return True if delegation can be delegated by amount. */ function _canDelegateByAmount(address _owner) internal view returns(bool) { // Get the delegation mode. DelegationMode delegationMode = delegationModes[_owner]; // Return true if delegation is safe to store explicit amounts, which can also // apply if there is not delegation mode set. return delegationMode == DelegationMode.NOTSET || delegationMode == DelegationMode.AMOUNT; } /** * @notice Delegate `_amount` of voting power to `_to` from `_from` * @param _from The address of the delegator * @param _to The address of the recipient * @param _senderCurrentBalance The senders current balance (not their voting power) * @param _amount The amount of voting power to be delegated **/ function _delegateByAmount( address _from, address _to, uint256 _senderCurrentBalance, uint256 _amount ) internal virtual { require (_to != address(0), "Cannot delegate to zero"); require (_to != _from, "Cannot delegate to self"); require (_canDelegateByAmount(_from), "Cannot delegate by amount"); // Get the vote power delegation for the sender ExplicitDelegation.DelegationState storage delegation = explicitDelegations[_from]; // the prior value uint256 priorAmount = delegation.getDelegatedValue(_to); // Delegate new power if (_amount < priorAmount) { // Prior amount is greater, just reduce the delegated amount. // subtraction is safe since _amount < priorAmount votePower.undelegate(_from, _to, priorAmount - _amount); } else { // Is there enough undelegated vote power? uint256 availableAmount = _undelegatedVotePowerOf(_from, _senderCurrentBalance).add(priorAmount); require(availableAmount >= _amount, UNDELEGATED_VP_TOO_SMALL_MSG); // Increase the delegated amount of vote power. // subtraction is safe since _amount >= priorAmount votePower.delegate(_from, _to, _amount - priorAmount); } votePower.cleanupOldCheckpoints(_from, CLEANUP_COUNT, cleanupBlockNumber); votePower.cleanupOldCheckpoints(_to, CLEANUP_COUNT, cleanupBlockNumber); // Add/replace delegate delegation.addReplaceDelegate(_to, _amount); delegation.cleanupOldCheckpoints(_to, CLEANUP_COUNT, cleanupBlockNumber); // update mode if needed if (delegationModes[_from] != DelegationMode.AMOUNT) { delegationModes[_from] = DelegationMode.AMOUNT; } // emit event for delegation change emit Delegate(_from, _to, priorAmount, _amount); } /** * @notice Delegate `_bips` of voting power to `_to` from `_from` * @param _from The address of the delegator * @param _to The address of the recipient * @param _senderCurrentBalance The senders current balance (not their voting power) * @param _bips The percentage of voting power in basis points (1/100 of 1 percent) to be delegated **/ function _delegateByPercentage( address _from, address _to, uint256 _senderCurrentBalance, uint256 _bips ) internal virtual { require (_to != address(0), "Cannot delegate to zero"); require (_to != _from, "Cannot delegate to self"); require (_canDelegateByPct(_from), "Cannot delegate by percentage"); // Get the vote power delegation for the sender PercentageDelegation.DelegationState storage delegation = percentageDelegations[_from]; // Get prior percent for delegate if exists uint256 priorBips = delegation.getDelegatedValue(_to); uint256 reverseVotePower = 0; uint256 newVotePower = 0; // Add/replace delegate delegation.addReplaceDelegate(_to, _bips); delegation.cleanupOldCheckpoints(CLEANUP_COUNT, cleanupBlockNumber); // First, back out old voting power percentage, if not zero if (priorBips != 0) { reverseVotePower = _senderCurrentBalance.mulDiv(priorBips, PercentageDelegation.MAX_BIPS); } // Calculate the new vote power if (_bips != 0) { newVotePower = _senderCurrentBalance.mulDiv(_bips, PercentageDelegation.MAX_BIPS); } // Delegate new power if (newVotePower < reverseVotePower) { // subtraction is safe since newVotePower < reverseVotePower votePower.undelegate(_from, _to, reverseVotePower - newVotePower); } else { // subtraction is safe since newVotePower >= reverseVotePower votePower.delegate(_from, _to, newVotePower - reverseVotePower); } votePower.cleanupOldCheckpoints(_from, CLEANUP_COUNT, cleanupBlockNumber); votePower.cleanupOldCheckpoints(_to, CLEANUP_COUNT, cleanupBlockNumber); // update mode if needed if (delegationModes[_from] != DelegationMode.PERCENTAGE) { delegationModes[_from] = DelegationMode.PERCENTAGE; } // emit event for delegation change emit Delegate(_from, _to, reverseVotePower, newVotePower); } /** * @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 */ function _delegationModeOf(address _who) internal view returns (DelegationMode) { return delegationModes[_who]; } /** * @notice Get the vote power delegation `delegationAddresses` * and `_bips` 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) */ function _percentageDelegatesOfAt( address _owner, uint256 _blockNumber ) internal view notBeforeCleanupBlock(_blockNumber) returns ( address[] memory _delegateAddresses, uint256[] memory _bips ) { PercentageDelegation.DelegationState storage delegation = percentageDelegations[_owner]; address[] memory allDelegateAddresses; uint256[] memory allBips; (allDelegateAddresses, allBips) = delegation.getDelegationsAt(_blockNumber); // delete revoked addresses for (uint256 i = 0; i < allDelegateAddresses.length; i++) { if (votePowerCache.revokedFromToAt(_owner, allDelegateAddresses[i], _blockNumber)) { allBips[i] = 0; } } uint256 length = 0; for (uint256 i = 0; i < allDelegateAddresses.length; i++) { if (allBips[i] != 0) length++; } _delegateAddresses = new address[](length); _bips = new uint256[](length); uint256 destIndex = 0; for (uint256 i = 0; i < allDelegateAddresses.length; i++) { if (allBips[i] != 0) { _delegateAddresses[destIndex] = allDelegateAddresses[i]; _bips[destIndex] = allBips[i]; destIndex++; } } } /** * @notice Checks if enough undelegated vote power exists to allow a token * transfer to occur if vote power is explicitly delegated. * @param _owner The address of transmittable vote power to check. * @param _ownerCurrentBalance The current balance of `_owner`. * @param _amount The amount to check. * @return True is `_amount` is transmittable. */ function _isTransmittable( address _owner, uint256 _ownerCurrentBalance, uint256 _amount ) private view returns(bool) { // Only proceed if we have a delegation by _amount if (delegationModes[_owner] == DelegationMode.AMOUNT) { // Return true if there is enough vote power _to cover the transfer return _undelegatedVotePowerOf(_owner, _ownerCurrentBalance) >= _amount; } else { // Not delegated by _amount, so transfer always allowed return true; } } /** * @notice Mint `_amount` of vote power for `_owner`. * @param _owner The address of the owner to receive new vote power. * @param _amount The amount of vote power to mint. */ function _mintVotePower(address _owner, uint256 _ownerCurrentBalance, uint256 _amount) internal { if (delegationModes[_owner] == DelegationMode.PERCENTAGE) { // Allocate newly minted vote power over delegates _allocateVotePower(_owner, _ownerCurrentBalance, _ownerCurrentBalance.add(_amount)); } else { votePower.changeValue(_owner, _amount, 0); votePower.cleanupOldCheckpoints(_owner, CLEANUP_COUNT, cleanupBlockNumber); } } /** * @notice Revoke the vote power of `_to` at block `_blockNumber` * @param _from The address of the delegator * @param _to The delegatee address of vote power to revoke. * @param _senderBalanceAt The sender's balance at the block to be revoked. * @param _blockNumber The block number at which to revoke. */ function _revokeDelegationAt( address _from, address _to, uint256 _senderBalanceAt, uint256 _blockNumber ) internal notBeforeCleanupBlock(_blockNumber) { require(_blockNumber < block.number, "Revoke is only for the past, use undelegate for the present"); // Get amount revoked uint256 votePowerRevoked = _votePowerFromToAtNoRevokeCheck(_from, _to, _senderBalanceAt, _blockNumber); // Revoke vote power votePowerCache.revokeAt(votePower, _from, _to, votePowerRevoked, _blockNumber); // Emit revoke event emit Revoke(_from, _to, votePowerRevoked, _blockNumber); } /** * @notice Transmit `_amount` of vote power `_from` address `_to` address. * @param _from The address of the sender. * @param _to The address of the receiver. * @param _fromCurrentBalance The current token balance of the transmitter. * @param _toCurrentBalance The current token balance of the receiver. * @param _amount The amount of vote power to transmit. */ function _transmitVotePower( address _from, address _to, uint256 _fromCurrentBalance, uint256 _toCurrentBalance, uint256 _amount ) internal { _burnVotePower(_from, _fromCurrentBalance, _amount); _mintVotePower(_to, _toCurrentBalance, _amount); } /** * @notice Undelegate all vote power by percentage for `delegation` of `_who`. * @param _from The address of the delegator * @param _senderCurrentBalance The current balance of message sender. * precondition: delegationModes[_who] == DelegationMode.PERCENTAGE */ function _undelegateAllByPercentage(address _from, uint256 _senderCurrentBalance) internal { DelegationMode delegationMode = delegationModes[_from]; if (delegationMode == DelegationMode.NOTSET) return; require(delegationMode == DelegationMode.PERCENTAGE, "undelegateAll can only be used in percentage delegation mode"); PercentageDelegation.DelegationState storage delegation = percentageDelegations[_from]; // Iterate over the delegates (address[] memory delegates, uint256[] memory _bips) = delegation.getDelegations(); for (uint256 i = 0; i < delegates.length; i++) { address to = delegates[i]; // Compute vote power to be reversed for the delegate uint256 reverseVotePower = _senderCurrentBalance.mulDiv(_bips[i], PercentageDelegation.MAX_BIPS); // Transmit vote power back to _owner votePower.undelegate(_from, to, reverseVotePower); votePower.cleanupOldCheckpoints(_from, CLEANUP_COUNT, cleanupBlockNumber); votePower.cleanupOldCheckpoints(to, CLEANUP_COUNT, cleanupBlockNumber); // Emit vote power reversal event emit Delegate(_from, to, reverseVotePower, 0); } // Clear delegates delegation.clear(); delegation.cleanupOldCheckpoints(CLEANUP_COUNT, cleanupBlockNumber); } /** * @notice Undelegate all vote power by amount delegates for `_from`. * @param _from The address of the delegator * @param _delegateAddresses Explicit delegation does not store delegatees' addresses, * so the caller must supply them. */ function _undelegateAllByAmount( address _from, address[] memory _delegateAddresses ) internal returns (uint256 _remainingDelegation) { DelegationMode delegationMode = delegationModes[_from]; if (delegationMode == DelegationMode.NOTSET) return 0; require(delegationMode == DelegationMode.AMOUNT, "undelegateAllExplicit can only be used in explicit delegation mode"); ExplicitDelegation.DelegationState storage delegation = explicitDelegations[_from]; // Iterate over the delegates for (uint256 i = 0; i < _delegateAddresses.length; i++) { address to = _delegateAddresses[i]; // Compute vote power _to be reversed for the delegate uint256 reverseVotePower = delegation.getDelegatedValue(to); if (reverseVotePower == 0) continue; // Transmit vote power back _to _owner votePower.undelegate(_from, to, reverseVotePower); votePower.cleanupOldCheckpoints(_from, CLEANUP_COUNT, cleanupBlockNumber); votePower.cleanupOldCheckpoints(to, CLEANUP_COUNT, cleanupBlockNumber); // change delagation delegation.addReplaceDelegate(to, 0); delegation.cleanupOldCheckpoints(to, CLEANUP_COUNT, cleanupBlockNumber); // Emit vote power reversal event emit Delegate(_from, to, reverseVotePower, 0); } return delegation.getDelegatedTotal(); } /** * @notice Check if the `_owner` has made any delegations. * @param _owner The address of owner to get delegated vote power. * @return The total delegated vote power at block. */ function _hasAnyDelegations(address _owner) internal view returns(bool) { DelegationMode delegationMode = delegationModes[_owner]; if (delegationMode == DelegationMode.NOTSET) { return false; } else if (delegationMode == DelegationMode.AMOUNT) { return explicitDelegations[_owner].getDelegatedTotal() > 0; } else { // delegationMode == DelegationMode.PERCENTAGE return percentageDelegations[_owner].getCount() > 0; } } /** * @notice Get the total delegated vote power of `_owner` at some block. * @param _owner The address of owner to get delegated vote power. * @param _ownerBalanceAt The balance of the owner at that block (not their vote power). * @param _blockNumber The block number at which to fetch. * @return _votePower The total delegated vote power at block. */ function _delegatedVotePowerOfAt( address _owner, uint256 _ownerBalanceAt, uint256 _blockNumber ) internal view notBeforeCleanupBlock(_blockNumber) returns(uint256 _votePower) { // Get the vote power delegation for the _owner DelegationMode delegationMode = delegationModes[_owner]; if (delegationMode == DelegationMode.NOTSET) { return 0; } else if (delegationMode == DelegationMode.AMOUNT) { return explicitDelegations[_owner].getDelegatedTotalAt(_blockNumber); } else { // delegationMode == DelegationMode.PERCENTAGE return percentageDelegations[_owner].getDelegatedTotalAmountAt(_ownerBalanceAt, _blockNumber); } } /** * @notice Get the undelegated vote power of `_owner` at some block. * @param _owner The address of owner to get undelegated vote power. * @param _ownerBalanceAt The balance of the owner at that block (not their vote power). * @param _blockNumber The block number at which to fetch. * @return _votePower The undelegated vote power at block. */ function _undelegatedVotePowerOfAt( address _owner, uint256 _ownerBalanceAt, uint256 _blockNumber ) internal view notBeforeCleanupBlock(_blockNumber) returns(uint256 _votePower) { // Return the current balance less delegations or zero if negative uint256 delegated = _delegatedVotePowerOfAt(_owner, _ownerBalanceAt, _blockNumber); bool overflow; uint256 result; (overflow, result) = _ownerBalanceAt.trySub(delegated); return result; } /** * @notice Get the undelegated vote power of `_owner`. * @param _owner The address of owner to get undelegated vote power. * @param _ownerCurrentBalance The current balance of the owner (not their vote power). * @return _votePower The undelegated vote power. */ function _undelegatedVotePowerOf( address _owner, uint256 _ownerCurrentBalance ) internal view returns(uint256 _votePower) { return _undelegatedVotePowerOfAt(_owner, _ownerCurrentBalance, block.number); } /** * @notice Get current delegated vote power `_from` delegator delegated `_to` delegatee. * @param _from Address of delegator * @param _to Address of delegatee * @return _votePower The delegated vote power. */ function _votePowerFromTo( address _from, address _to, uint256 _currentFromBalance ) internal view returns(uint256 _votePower) { DelegationMode delegationMode = delegationModes[_from]; if (delegationMode == DelegationMode.NOTSET) { return 0; } else if (delegationMode == DelegationMode.PERCENTAGE) { uint256 _bips = percentageDelegations[_from].getDelegatedValue(_to); return _currentFromBalance.mulDiv(_bips, PercentageDelegation.MAX_BIPS); } else { // delegationMode == DelegationMode.AMOUNT return explicitDelegations[_from].getDelegatedValue(_to); } } /** * @notice Get delegated the vote power `_from` delegator delegated `_to` delegatee at `_blockNumber`. * @param _from Address of delegator * @param _to Address of delegatee * @param _fromBalanceAt From's balance at the block `_blockNumber`. * @param _blockNumber The block number at which to fetch. * @return _votePower The delegated vote power. */ function _votePowerFromToAt( address _from, address _to, uint256 _fromBalanceAt, uint256 _blockNumber ) internal view notBeforeCleanupBlock(_blockNumber) returns(uint256 _votePower) { // if revoked, return 0 if (votePowerCache.revokedFromToAt(_from, _to, _blockNumber)) return 0; return _votePowerFromToAtNoRevokeCheck(_from, _to, _fromBalanceAt, _blockNumber); } /** * @notice Get delegated the vote power `_from` delegator delegated `_to` delegatee at `_blockNumber`. * Private use only - ignores revocations. * @param _from Address of delegator * @param _to Address of delegatee * @param _fromBalanceAt From's balance at the block `_blockNumber`. * @param _blockNumber The block number at which to fetch. * @return _votePower The delegated vote power. */ function _votePowerFromToAtNoRevokeCheck( address _from, address _to, uint256 _fromBalanceAt, uint256 _blockNumber ) private view returns(uint256 _votePower) { // assumed: notBeforeCleanupBlock(_blockNumber) DelegationMode delegationMode = delegationModes[_from]; if (delegationMode == DelegationMode.NOTSET) { return 0; } else if (delegationMode == DelegationMode.PERCENTAGE) { uint256 _bips = percentageDelegations[_from].getDelegatedValueAt(_to, _blockNumber); return _fromBalanceAt.mulDiv(_bips, PercentageDelegation.MAX_BIPS); } else { // delegationMode == DelegationMode.AMOUNT return explicitDelegations[_from].getDelegatedValueAt(_to, _blockNumber); } } /** * @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) internal view returns(uint256) { return votePower.votePowerOfAtNow(_who); } /** * @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 ) internal view notBeforeCleanupBlock(_blockNumber) returns(uint256) { // read cached value for past blocks to respect revocations (and possibly get a cache speedup) if (_blockNumber < block.number) { return votePowerCache.valueOfAtReadonly(votePower, _who, _blockNumber); } else { return votePower.votePowerOfAtNow(_who); } } /** * @notice Get the vote power of `_who` at block `_blockNumber`, ignoring revocation information (and cache). * @param _who The address to get voting power. * @param _blockNumber The block number at which to fetch. * @return Vote power of `_who` at `_blockNumber`. Result doesn't change if vote power is revoked. */ function _votePowerOfAtIgnoringRevocation( address _who, uint256 _blockNumber ) internal view notBeforeCleanupBlock(_blockNumber) returns(uint256) { return votePower.votePowerOfAt(_who, _blockNumber); } /** * Return vote powers for several addresses in a batch. * Only works for past blocks. * @param _owners The list of addresses to fetch vote power of. * @param _blockNumber The block number at which to fetch. * @return _votePowers A list of vote powers corresponding to _owners. */ function _batchVotePowerOfAt( address[] memory _owners, uint256 _blockNumber ) internal view notBeforeCleanupBlock(_blockNumber) returns(uint256[] memory _votePowers) { require(_blockNumber < block.number, "Can only be used for past blocks"); _votePowers = new uint256[](_owners.length); for (uint256 i = 0; i < _owners.length; i++) { // read through cache, much faster if it has been set _votePowers[i] = votePowerCache.valueOfAtReadonly(votePower, _owners[i], _blockNumber); } } /** * @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 ) internal notBeforeCleanupBlock(_blockNumber) returns(uint256) { require(_blockNumber < block.number, "Can only be used for past blocks"); (uint256 vp, bool createdCache) = votePowerCache.valueOfAt(votePower, _who, _blockNumber); if (createdCache) emit CreatedVotePowerCache(_who, _blockNumber); return vp; } /** * Set the cleanup block number. */ function _setCleanupBlockNumber(uint256 _blockNumber) internal { require(_blockNumber >= cleanupBlockNumber, "Cleanup block number must never decrease"); require(_blockNumber < block.number, "Cleanup block must be in the past"); cleanupBlockNumber = _blockNumber; } /** * Get the cleanup block number. */ function _cleanupBlockNumber() internal view returns (uint256) { return cleanupBlockNumber; } /** * Set the contract that is allowed to call history cleaning methods. */ function _setCleanerContract(address _cleanerContract) internal { cleanerContract = _cleanerContract; } // history cleanup methods /** * Delete vote power checkpoints that expired (i.e. are before `cleanupBlockNumber`). * Method can only be called from the `cleanerContract` (which may be a proxy to external cleaners). * @param _owner vote power owner account address * @param _count maximum number of checkpoints to delete * @return the number of checkpoints deleted */ function votePowerHistoryCleanup(address _owner, uint256 _count) external onlyCleaner returns (uint256) { return votePower.cleanupOldCheckpoints(_owner, _count, cleanupBlockNumber); } /** * Delete vote power cache entry that expired (i.e. is before `cleanupBlockNumber`). * Method can only be called from the `cleanerContract` (which may be a proxy to external cleaners). * @param _owner vote power owner account address * @param _blockNumber the block number for which total supply value was cached * @return the number of cache entries deleted (always 0 or 1) */ function votePowerCacheCleanup(address _owner, uint256 _blockNumber) external onlyCleaner returns (uint256) { require(_blockNumber < cleanupBlockNumber, "No cleanup after cleanup block"); return votePowerCache.deleteValueAt(_owner, _blockNumber); } /** * Delete revocation entry that expired (i.e. is before `cleanupBlockNumber`). * Method can only be called from the `cleanerContract` (which may be a proxy to external cleaners). * @param _from the delegator address * @param _to the delegatee address * @param _blockNumber the block number for which total supply value was cached * @return the number of revocation entries deleted (always 0 or 1) */ function revocationCleanup( address _from, address _to, uint256 _blockNumber ) external onlyCleaner returns (uint256) { require(_blockNumber < cleanupBlockNumber, "No cleanup after cleanup block"); return votePowerCache.deleteRevocationAt(_from, _to, _blockNumber); } /** * Delete percentage delegation checkpoints that expired (i.e. are before `cleanupBlockNumber`). * Method can only be called from the `cleanerContract` (which may be a proxy to external cleaners). * @param _owner balance owner account address * @param _count maximum number of checkpoints to delete * @return the number of checkpoints deleted */ function percentageDelegationHistoryCleanup(address _owner, uint256 _count) external onlyCleaner returns (uint256) { return percentageDelegations[_owner].cleanupOldCheckpoints(_count, cleanupBlockNumber); } /** * Delete explicit delegation checkpoints that expired (i.e. are before `cleanupBlockNumber`). * Method can only be called from the `cleanerContract` (which may be a proxy to external cleaners). * @param _from the delegator address * @param _to the delegatee address * @param _count maximum number of checkpoints to delete * @return the number of checkpoints deleted */ function explicitDelegationHistoryCleanup(address _from, address _to, uint256 _count) external onlyCleaner returns (uint256) { return explicitDelegations[_from].cleanupOldCheckpoints(_to, _count, cleanupBlockNumber); } }
./contracts/token/implementation/CheckPointable.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "../lib/CheckPointHistory.sol"; import "../lib/CheckPointsByAddress.sol"; import "../lib/CheckPointHistoryCache.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; /** * @title Check Pointable ERC20 Behavior * @notice ERC20 behavior which adds balance check point features. **/ abstract contract CheckPointable { using CheckPointHistory for CheckPointHistory.CheckPointHistoryState; using CheckPointsByAddress for CheckPointsByAddress.CheckPointsByAddressState; using CheckPointHistoryCache for CheckPointHistoryCache.CacheState; using SafeMath for uint256; // The number of history cleanup steps executed for every write operation. // It is more than 1 to make as certain as possible that all history gets cleaned eventually. uint256 private constant CLEANUP_COUNT = 2; // Private member variables CheckPointsByAddress.CheckPointsByAddressState private balanceHistory; CheckPointHistory.CheckPointHistoryState private totalSupply; CheckPointHistoryCache.CacheState private totalSupplyCache; // Historic data for the blocks before `cleanupBlockNumber` can be erased, // history before that block should never be used since it can be inconsistent. uint256 private cleanupBlockNumber; // Address of the contract that is allowed to call methods for history cleaning. address public cleanerContract; /** * Emitted when a total supply cache entry is created. * Allows history cleaners to track total supply cache cleanup opportunities off-chain. */ event CreatedTotalSupplyCache(uint256 _blockNumber); // Most cleanup opportunities can be deduced from standard event // Transfer(from, to, amount): // - balance history for `from` (if nonzero) and `to` (if nonzero) // - total supply history when either `from` or `to` is zero modifier notBeforeCleanupBlock(uint256 _blockNumber) { require(_blockNumber >= cleanupBlockNumber, "CheckPointable: reading from cleaned-up block"); _; } modifier onlyCleaner { require(msg.sender == cleanerContract, "Only cleaner contract"); _; } /** * @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 _balance The balance at `_blockNumber`. **/ function balanceOfAt(address _owner, uint256 _blockNumber) public virtual view notBeforeCleanupBlock(_blockNumber) returns (uint256 _balance) { return balanceHistory.valueOfAt(_owner, _blockNumber); } /** * @notice Burn current token `amount` for `owner` of checkpoints at current block. * @param _owner The address of the owner to burn tokens. * @param _amount The amount to burn. */ function _burnForAtNow(address _owner, uint256 _amount) internal virtual { uint256 newBalance = balanceOfAt(_owner, block.number).sub(_amount, "Burn too big for owner"); balanceHistory.writeValue(_owner, newBalance); balanceHistory.cleanupOldCheckpoints(_owner, CLEANUP_COUNT, cleanupBlockNumber); totalSupply.writeValue(totalSupplyAt(block.number).sub(_amount, "Burn too big for total supply")); totalSupply.cleanupOldCheckpoints(CLEANUP_COUNT, cleanupBlockNumber); } /** * @notice Mint current token `amount` for `owner` of checkpoints at current block. * @param _owner The address of the owner to burn tokens. * @param _amount The amount to burn. */ function _mintForAtNow(address _owner, uint256 _amount) internal virtual { uint256 newBalance = balanceOfAt(_owner, block.number).add(_amount); balanceHistory.writeValue(_owner, newBalance); balanceHistory.cleanupOldCheckpoints(_owner, CLEANUP_COUNT, cleanupBlockNumber); totalSupply.writeValue(totalSupplyAt(block.number).add(_amount)); totalSupply.cleanupOldCheckpoints(CLEANUP_COUNT, cleanupBlockNumber); } /** * @notice Total amount of tokens at a specific `_blockNumber`. * @param _blockNumber The block number when the _totalSupply is queried * @return _totalSupply The total amount of tokens at `_blockNumber` **/ function totalSupplyAt(uint256 _blockNumber) public virtual view notBeforeCleanupBlock(_blockNumber) returns(uint256 _totalSupply) { return totalSupply.valueAt(_blockNumber); } /** * @notice Total amount of tokens at a specific `_blockNumber`. * @param _blockNumber The block number when the _totalSupply is queried * @return _totalSupply The total amount of tokens at `_blockNumber` **/ function _totalSupplyAtCached(uint256 _blockNumber) internal notBeforeCleanupBlock(_blockNumber) returns(uint256 _totalSupply) { // use cache only for the past (the value will never change) require(_blockNumber < block.number, "Can only be used for past blocks"); (uint256 value, bool cacheCreated) = totalSupplyCache.valueAt(totalSupply, _blockNumber); if (cacheCreated) emit CreatedTotalSupplyCache(_blockNumber); return value; } /** * @notice Transmit token `_amount` `_from` address `_to` address of checkpoints at current block. * @param _from The address of the sender. * @param _to The address of the receiver. * @param _amount The amount to transmit. */ function _transmitAtNow(address _from, address _to, uint256 _amount) internal virtual { balanceHistory.transmit(_from, _to, _amount); balanceHistory.cleanupOldCheckpoints(_from, CLEANUP_COUNT, cleanupBlockNumber); balanceHistory.cleanupOldCheckpoints(_to, CLEANUP_COUNT, cleanupBlockNumber); } /** * Set the cleanup block number. */ function _setCleanupBlockNumber(uint256 _blockNumber) internal { require(_blockNumber >= cleanupBlockNumber, "Cleanup block number must never decrease"); require(_blockNumber < block.number, "Cleanup block must be in the past"); cleanupBlockNumber = _blockNumber; } /** * Get the cleanup block number. */ function _cleanupBlockNumber() internal view returns (uint256) { return cleanupBlockNumber; } /** * @notice Update history at token transfer, the CheckPointable part of `_beforeTokenTransfer` hook. * @param _from The address of the sender. * @param _to The address of the receiver. * @param _amount The amount to transmit. */ function _updateBalanceHistoryAtTransfer(address _from, address _to, uint256 _amount) internal virtual { if (_from == address(0)) { // mint checkpoint balance data for transferee _mintForAtNow(_to, _amount); } else if (_to == address(0)) { // burn checkpoint data for transferer _burnForAtNow(_from, _amount); } else { // transfer checkpoint balance data _transmitAtNow(_from, _to, _amount); } } // history cleanup methods /** * Set the contract that is allowed to call history cleaning methods. */ function _setCleanerContract(address _cleanerContract) internal { cleanerContract = _cleanerContract; } /** * Delete balance checkpoints that expired (i.e. are before `cleanupBlockNumber`). * Method can only be called from the `cleanerContract` (which may be a proxy to external cleaners). * @param _owner balance owner account address * @param _count maximum number of checkpoints to delete * @return the number of checkpoints deleted */ function balanceHistoryCleanup(address _owner, uint256 _count) external onlyCleaner returns (uint256) { return balanceHistory.cleanupOldCheckpoints(_owner, _count, cleanupBlockNumber); } /** * Delete total supply checkpoints that expired (i.e. are before `cleanupBlockNumber`). * Method can only be called from the `cleanerContract` (which may be a proxy to external cleaners). * @param _count maximum number of checkpoints to delete * @return the number of checkpoints deleted */ function totalSupplyHistoryCleanup(uint256 _count) external onlyCleaner returns (uint256) { return totalSupply.cleanupOldCheckpoints(_count, cleanupBlockNumber); } /** * Delete total supply cache entry that expired (i.e. is before `cleanupBlockNumber`). * Method can only be called from the `cleanerContract` (which may be a proxy to external cleaners). * @param _blockNumber the block number for which total supply value was cached * @return the number of cache entries deleted (always 0 or 1) */ function totalSupplyCacheCleanup(uint256 _blockNumber) external onlyCleaner returns (uint256) { require(_blockNumber < cleanupBlockNumber, "No cleanup after cleanup block"); return totalSupplyCache.deleteAt(_blockNumber); } }
./contracts/genesis/interface/IInflationGenesis.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; 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; }
./contracts/addressUpdater/interface/IIAddressUpdatable.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IIAddressUpdatable { /** * @notice Updates contract addresses - should be called only from AddressUpdater contract * @param _contractNameHashes list of keccak256(abi.encode(...)) contract names * @param _contractAddresses list of contract addresses corresponding to the contract names */ function updateContractAddresses( bytes32[] memory _contractNameHashes, address[] memory _contractAddresses ) external; }
./contracts/utils/implementation/SafePct.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol"; /** * @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)); } }
./contracts/ftso/interface/IIFtso.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import "../../genesis/interface/IFtsoGenesis.sol"; import "../../userInterfaces/IFtso.sol"; import "../../token/interface/IIVPToken.sol"; 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 fallbackFinalizePriceEpoch(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 _submitPeriodSeconds, uint256 _revealPeriodSeconds ) 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 ftso manager address */ function ftsoManager() external view returns (address); /** * @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); }
./contracts/claiming/implementation/ClaimSetupManager.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "./CloneFactory.sol"; import "../interface/IIClaimSetupManager.sol"; import "../interface/IIDelegationAccount.sol"; import "../../userInterfaces/IFtsoManager.sol"; import "../../governance/implementation/Governed.sol"; import "../../addressUpdater/implementation/AddressUpdatable.sol"; import "../../utils/implementation/AddressSet.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; contract ClaimSetupManager is IIClaimSetupManager, Governed, AddressUpdatable, CloneFactory, ReentrancyGuard { using AddressSet for AddressSet.State; struct ExecutorFee { // used for storing executor fee settings uint256 value; // fee value (value between `minFeeValueWei` and `maxFeeValueWei`) uint256 validFromEpoch; // id of the reward epoch from which the value is valid } struct DelegationAccountData { // used for storing data about delegation account IIDelegationAccount delegationAccount; // delegation account address bool enabled; // indicates if delegation account is enabled } string internal constant ERR_EXECUTOR_FEE_INVALID = "invalid executor fee value"; string internal constant ERR_TRANSFER_FAILURE = "transfer failed"; string internal constant ERR_FEE_INVALID = "invalid fee value"; string internal constant ERR_VALUE_ZERO = "value zero"; string internal constant ERR_MIN_FEE_INVALID = "invalid min fee value"; string internal constant ERR_MAX_FEE_INVALID = "invalid max fee value"; string internal constant ERR_ADDRESS_ZERO = "address zero"; string internal constant ERR_NOT_REGISTERED = "not registered"; string internal constant ERR_ALREADY_REGISTERED = "already registered"; string internal constant ERR_REWARD_EPOCH_INVALID = "invalid reward epoch"; string internal constant ERR_FEE_UPDATE_FAILED = "fee can not be updated"; string internal constant ERR_NO_DELEGATION_ACCOUNT = "no delegation account"; string internal constant ERR_LIBRARY_ADDRESS_NOT_SET_YET = "library address not set yet"; string internal constant ERR_CREATE_CLONE = "clone not successfully created"; string internal constant ERR_ONLY_OWNER_OR_EXECUTOR = "only owner or executor"; string internal constant ERR_RECIPIENT_NOT_ALLOWED = "recipient not allowed"; string internal constant ERR_WRONG_WNAT_ADDRESS = "wrong wNat address"; address payable constant internal BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD; uint256 public immutable feeValueUpdateOffset; // fee value update timelock measured in reward epochs uint256 public minFeeValueWei; // min value for fee uint256 public maxFeeValueWei; // max value for fee uint256 public registerExecutorFeeValueWei; // fee value that executor must pay to register IFtsoManager public ftsoManager; WNat public override wNat; IGovernanceVotePower public governanceVP; address public libraryAddress; // mapping owner address => delegation account address mapping(address => DelegationAccountData) private ownerToDelegationAccountData; mapping(address => address) private delegationAccountToOwner; // mapping owner address => executor set mapping(address => AddressSet.State) private ownerClaimExecutorSet; // mapping owner address => claim recipient address mapping(address => AddressSet.State) private ownerAllowedClaimRecipientSet; // mapping executor address => executor fees mapping(address => ExecutorFee[]) private claimExecutorFees; AddressSet.State private registeredExecutors; modifier onlyOwnerOrExecutor(address _executor, address[] memory _owners) { _checkOnlyOwnerOrExecutor(_executor, _owners); _; } constructor( address _governance, address _addressUpdater, uint256 _feeValueUpdateOffset, uint256 _minFeeValueWei, uint256 _maxFeeValueWei, uint256 _registerExecutorFeeValueWei ) Governed(_governance) AddressUpdatable(_addressUpdater) { require(_feeValueUpdateOffset > 0, ERR_VALUE_ZERO); require(_maxFeeValueWei > _minFeeValueWei, ERR_MAX_FEE_INVALID); require(_registerExecutorFeeValueWei > 0, ERR_VALUE_ZERO); feeValueUpdateOffset = _feeValueUpdateOffset; minFeeValueWei = _minFeeValueWei; maxFeeValueWei = _maxFeeValueWei; emit MinFeeSet(_minFeeValueWei); emit MaxFeeSet(_maxFeeValueWei); registerExecutorFeeValueWei = _registerExecutorFeeValueWei; emit RegisterExecutorFeeSet(_registerExecutorFeeValueWei); } /** * @notice Sets the addresses of executors and optionally enables (creates) delegation account. * @notice If setting registered executors some fee must be paid to them. * @param _executors The new executors. All old executors will be deleted and replaced by these. */ function setAutoClaiming(address[] memory _executors, bool _enableDelegationAccount) external payable override nonReentrant { _setClaimExecutors(_executors); if (_enableDelegationAccount) { _createOrEnableDelegationAccount(); } } /** * @notice Sets the addresses of executors. * @notice If setting registered executors some fee must be paid to them. * @param _executors The new executors. All old executors will be deleted and replaced by these. */ function setClaimExecutors(address[] memory _executors) external payable override nonReentrant { _setClaimExecutors(_executors); } /** * @notice Enables (creates) delegation account contract, * i.e. all airdrop and ftso rewards will be send to delegation account when using automatic claiming. * @return Address of delegation account contract. */ function enableDelegationAccount() external override returns (IDelegationAccount) { return _createOrEnableDelegationAccount(); } /** * @notice Disables delegation account contract, * i.e. all airdrop and ftso rewards will be send to owner's account when using automatic claiming. * @notice Automatic claiming will not claim airdrop and ftso rewards for delegation account anymore. * @dev Reverts if there is no delegation account */ function disableDelegationAccount() external override { DelegationAccountData storage delegationAccountData = ownerToDelegationAccountData[msg.sender]; IIDelegationAccount delegationAccount = delegationAccountData.delegationAccount; require(address(delegationAccount) != address(0), ERR_NO_DELEGATION_ACCOUNT); delegationAccountData.enabled = false; uint256 amount = wNat.balanceOf(address(delegationAccount)); if (amount > 0) { delegationAccount.withdraw(wNat, amount); } emit DelegationAccountUpdated(msg.sender, delegationAccount, false); } /** * @notice Allows executor to register and set initial fee value from current reward epoch on. * If executor was already registered before (has fee set), only update fee value after `feeValueUpdateOffset`. * @notice Executor must pay fee in order to register - `registerExecutorFeeValueWei`. * @param _feeValue number representing fee value - zero value is allowed * @return Returns the reward epoch number when the setting becomes effective. */ function registerExecutor(uint256 _feeValue) external payable override returns (uint256) { require(registeredExecutors.index[msg.sender] == 0, ERR_ALREADY_REGISTERED); require(registerExecutorFeeValueWei == msg.value, ERR_EXECUTOR_FEE_INVALID); //slither-disable-next-line arbitrary-send-eth BURN_ADDRESS.transfer(msg.value); // add and emit event registeredExecutors.add(msg.sender); emit ExecutorRegistered(msg.sender); // check last executor fee change uint256 currentRewardEpoch = ftsoManager.getCurrentRewardEpoch(); ExecutorFee[] storage efs = claimExecutorFees[msg.sender]; if (efs.length == 0 || efs[efs.length - 1].validFromEpoch < currentRewardEpoch) { // if registering for the first time or after a while, sets the fee value from current epoch on require( _feeValue >= minFeeValueWei, ERR_FEE_INVALID); require( _feeValue <= maxFeeValueWei, ERR_FEE_INVALID); efs.push(ExecutorFee({value: _feeValue, validFromEpoch: currentRewardEpoch})); emit ClaimExecutorFeeValueChanged(msg.sender, currentRewardEpoch, _feeValue); return currentRewardEpoch; } else { return _updateExecutorFeeValue(currentRewardEpoch, _feeValue); } } /** * @notice Allows executor to unregister. * @return _validFromEpoch Returns the reward epoch number when the setting becomes effective. */ function unregisterExecutor() external override returns (uint256 _validFromEpoch) { require(registeredExecutors.index[msg.sender] != 0, ERR_NOT_REGISTERED); // remove from registered registeredExecutors.remove(msg.sender); // set fee to 0 (after `feeValueUpdateOffset` - to prevent immediate new registration) _validFromEpoch = _updateExecutorFeeValue(ftsoManager.getCurrentRewardEpoch(), 0); // emit event emit ExecutorUnregistered(msg.sender, _validFromEpoch); } /** * @notice Allows registered executor to set (or update last scheduled) fee value. * @param _feeValue number representing fee value - zero value is allowed * @return Returns the reward epoch number when the setting becomes effective. */ function updateExecutorFeeValue( uint256 _feeValue ) external override returns (uint256) { require(registeredExecutors.index[msg.sender] != 0, ERR_NOT_REGISTERED); return _updateExecutorFeeValue(ftsoManager.getCurrentRewardEpoch(), _feeValue); } /** * @notice Delegate `_bips` of voting power to `_to` from msg.sender's delegation account * @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 cumulative - every call resets the delegation value (and value of 0 revokes delegation). */ function delegate(address _to, uint256 _bips) external override { _getDelegationAccount(msg.sender).delegate(wNat, _to, _bips); } /** * @notice Undelegate all percentage delegations from the msg.sender's delegation account and then delegate * corresponding `_bips` percentage of voting power to each member of `_delegatees`. * @param _delegatees The addresses of the new recipients. * @param _bips The percentages of voting power to be delegated expressed in basis points (1/100 of one percent). * Total of all `_bips` values must be at most 10000. */ function batchDelegate(address[] memory _delegatees, uint256[] memory _bips) external override { _getDelegationAccount(msg.sender).batchDelegate(wNat, _delegatees, _bips); } /** * @notice Undelegate all voting power for delegates of msg.sender's delegation account */ function undelegateAll() external override { _getDelegationAccount(msg.sender).undelegateAll(wNat); } /** * @notice Revoke all delegation from msg.sender's delegation account 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 with value of 0 or undelegateAll. */ function revokeDelegationAt(address _who, uint256 _blockNumber) external override { _getDelegationAccount(msg.sender).revokeDelegationAt(wNat, _who, _blockNumber); } /** * @notice Delegate all governance vote power of msg.sender's delegation account to `_to`. * @param _to The address of the recipient */ function delegateGovernance(address _to) external override { _getDelegationAccount(msg.sender).delegateGovernance(governanceVP, _to); } /** * @notice Undelegate governance vote power for delegate of msg.sender's delegation account */ function undelegateGovernance() external override { _getDelegationAccount(msg.sender).undelegateGovernance(governanceVP); } /** * @notice Allows user to transfer WNat to owner's account. * @param _amount Amount of tokens to transfer */ function withdraw(uint256 _amount) external override { _getDelegationAccount(msg.sender).withdraw(wNat, _amount); } /** * @notice Allows user to transfer balance of ERC20 tokens owned by the personal delegation contract. The main use case is to transfer tokens/NFTs that were received as part of an airdrop or register as participant in such airdrop. * @param _token Target token contract address * @param _amount Amount of tokens to transfer * @dev Reverts if target token is WNat contract - use method `withdraw` for that */ function transferExternalToken(IERC20 _token, uint256 _amount) external override nonReentrant { _getDelegationAccount(msg.sender).transferExternalToken(wNat, _token, _amount); } /** * @notice Sets new min fee value which must be higher than 0. * @dev Only governance can call this. */ function setMinFeeValueWei(uint256 _minFeeValueWei) external override onlyGovernance { require(_minFeeValueWei < maxFeeValueWei, ERR_MIN_FEE_INVALID); minFeeValueWei = _minFeeValueWei; emit MinFeeSet(_minFeeValueWei); } /** * @notice Sets new max fee value which must be higher than min fee value. * @dev Only governance can call this. */ function setMaxFeeValueWei(uint256 _maxFeeValueWei) external override onlyGovernance { require(_maxFeeValueWei > minFeeValueWei, ERR_MAX_FEE_INVALID); maxFeeValueWei = _maxFeeValueWei; emit MaxFeeSet(_maxFeeValueWei); } /** * @notice Sets new register executor fee value which must be higher than 0. * @dev Only governance can call this. */ function setRegisterExecutorFeeValueWei(uint256 _registerExecutorFeeValueWei) external override onlyGovernance { require(_registerExecutorFeeValueWei > 0, ERR_VALUE_ZERO); registerExecutorFeeValueWei = _registerExecutorFeeValueWei; emit RegisterExecutorFeeSet(_registerExecutorFeeValueWei); } /** * Set the addresses of allowed recipients. * Apart from these, the owner is always an allowed recipient. * @param _recipients The new allowed recipients. All old recipients will be deleted and replaced by these. */ function setAllowedClaimRecipients(address[] memory _recipients) external override { ownerAllowedClaimRecipientSet[msg.sender].replaceAll(_recipients); emit AllowedClaimRecipientsChanged(msg.sender, _recipients); } /** * @notice Sets new library address. * @dev Only governance can call this. */ function setLibraryAddress(address _libraryAddress) external override onlyGovernance { require(_libraryAddress != address(0), ERR_ADDRESS_ZERO); libraryAddress = _libraryAddress; emit SetLibraryAddress(libraryAddress); } /** * @notice Gets the delegation account of the `_owner`. Returns address(0) if not created yet. */ function accountToDelegationAccount(address _owner) external view override returns (address) { return address(_getDelegationAccount(_owner)); } /** * @notice Gets the delegation account data for the `_owner`. Returns address(0) if not created yet. * @param _owner owner's address * @return _delegationAccount owner's delegation account address - could be address(0) * @return _enabled indicates if delegation account is enabled */ function getDelegationAccountData( address _owner ) external view override returns (IDelegationAccount _delegationAccount, bool _enabled) { DelegationAccountData storage delegationAccountData = ownerToDelegationAccountData[_owner]; _delegationAccount = delegationAccountData.delegationAccount; _enabled = delegationAccountData.enabled; } /** * @notice Gets the delegation accounts for the `_owners`. Returns owner address if not created yet or not enabled. * @param _executor executor's address * @param _owners owners' addresses * @return _recipients addresses for claiming (PDA or owner) * @return _executorFeeValue executor's fee value */ function getAutoClaimAddressesAndExecutorFee( address _executor, address[] calldata _owners ) external view override onlyOwnerOrExecutor(_executor, _owners) returns ( address[] memory _recipients, uint256 _executorFeeValue ) { uint256 len = _owners.length; _recipients = new address[](len); while (len > 0) { len--; address owner = _owners[len]; DelegationAccountData storage delegationAccountData = ownerToDelegationAccountData[owner]; if (delegationAccountData.enabled) { _recipients[len] = address(delegationAccountData.delegationAccount); } else { _recipients[len] = owner; } } _executorFeeValue = getExecutorCurrentFeeValue(_executor); } /** * @notice Checks if executor can claim for given address and send funds to recipient address */ function checkExecutorAndAllowedRecipient(address _executor, address _claimFor, address _recipient) external view override { // checks if _executor is claiming for his account or his PDA account - allow any _recipient if (_claimFor == _executor || _claimFor == address(_getDelegationAccount(_executor))) { return; } // if claiming for PDA, use owner settings address owner = delegationAccountToOwner[_claimFor]; if (owner != address(0)) { _claimFor = owner; } // checks if _executor is allowed executor require(ownerClaimExecutorSet[_claimFor].index[_executor] != 0, ERR_ONLY_OWNER_OR_EXECUTOR); // checks if _recipient is allowed recipient require(_recipient == _claimFor || ownerAllowedClaimRecipientSet[_claimFor].index[_recipient] != 0 || _recipient == address(_getDelegationAccount(_claimFor)), ERR_RECIPIENT_NOT_ALLOWED); } /** * @notice Returns info if `_executor` is allowed to execute calls for `_owner` */ function isClaimExecutor(address _owner, address _executor) external view override returns(bool) { return ownerClaimExecutorSet[_owner].index[_executor] != 0; } /** * @notice Get registered executors */ function getRegisteredExecutors( uint256 _start, uint256 _end ) external view override returns (address[] memory _registeredExecutors, uint256 _totalLength) { address[] storage executors = registeredExecutors.list; _totalLength = executors.length; _end = Math.min(_end, _totalLength); _start = Math.min(_start, _end); _registeredExecutors = new address[](_end - _start); for (uint256 i = _start; i < _end; i++) { _registeredExecutors[i - _start] = executors[i]; } } /** * @notice Get the addresses of executors. */ function claimExecutors(address _owner) external view override returns (address[] memory) { return ownerClaimExecutorSet[_owner].list; } /** * Get the addresses of allowed recipients. * Apart from these, the owner is always an allowed recipient. */ function allowedClaimRecipients(address _owner) external view override returns (address[] memory) { return ownerAllowedClaimRecipientSet[_owner].list; } /** * @notice Returns the fee value of `_executor` at `_rewardEpoch` * @param _executor address representing executor * @param _rewardEpoch reward epoch number */ function getExecutorFeeValue(address _executor, uint256 _rewardEpoch) external view override returns (uint256) { require(_rewardEpoch <= ftsoManager.getCurrentRewardEpoch() + feeValueUpdateOffset, ERR_REWARD_EPOCH_INVALID); return _getExecutorFeeValue(_executor, _rewardEpoch); } /** * @notice Returns the scheduled fee value changes of `_executor` * @param _executor address representing executor * @return _feeValue positional array of fee values * @return _validFromEpoch positional array of reward epochs the fee settings are effective from * @return _fixed positional array of boolean values indicating if settings are subjected to change */ function getExecutorScheduledFeeValueChanges(address _executor) external view override returns ( uint256[] memory _feeValue, uint256[] memory _validFromEpoch, bool[] memory _fixed ) { ExecutorFee[] storage efs = claimExecutorFees[_executor]; if (efs.length > 0) { uint256 currentEpoch = ftsoManager.getCurrentRewardEpoch(); uint256 position = efs.length; while (position > 0 && efs[position - 1].validFromEpoch > currentEpoch) { position--; } uint256 count = efs.length - position; if (count > 0) { _feeValue = new uint256[](count); _validFromEpoch = new uint256[](count); _fixed = new bool[](count); for (uint256 i = 0; i < count; i++) { _feeValue[i] = efs[i + position].value; _validFromEpoch[i] = efs[i + position].validFromEpoch; _fixed[i] = (_validFromEpoch[i] - currentEpoch) != feeValueUpdateOffset; } } } } /** * @notice Returns some info about the `_executor` * @param _executor address representing executor * @return _registered information if executor is registered * @return _currentFeeValue executor's current fee value */ function getExecutorInfo(address _executor) external view override returns ( bool _registered, uint256 _currentFeeValue ) { _registered = registeredExecutors.index[_executor] != 0; _currentFeeValue = getExecutorCurrentFeeValue(_executor); } /** * @notice Returns the current fee value of `_executor` * @param _executor address representing executor */ function getExecutorCurrentFeeValue(address _executor) public view override returns (uint256) { return _getExecutorFeeValue(_executor, ftsoManager.getCurrentRewardEpoch()); } /** * @notice Sets the addresses of executors. * @notice If setting registered executors some fee must be paid to them. * @param _executors The new executors. All old executors will be deleted and replaced by these. */ function _setClaimExecutors(address[] memory _executors) internal { // pay fee to new executors uint256 totalExecutorsFee = 0; for (uint256 i = 0; i < _executors.length; i++) { address executor = _executors[i]; if (ownerClaimExecutorSet[msg.sender].index[executor] != 0) { continue; // current executor - fee already paid } uint256 executorFee = getExecutorCurrentFeeValue(executor); if (executorFee > 0) { totalExecutorsFee += executorFee; /* solhint-disable avoid-low-level-calls */ //slither-disable-next-line arbitrary-send-eth (bool success, ) = executor.call{value: executorFee}(""); //nonReentrant /* solhint-enable avoid-low-level-calls */ require(success, ERR_TRANSFER_FAILURE); } } require (totalExecutorsFee <= msg.value, ERR_EXECUTOR_FEE_INVALID); // replace executors ownerClaimExecutorSet[msg.sender].replaceAll(_executors); emit ClaimExecutorsChanged(msg.sender, _executors); // refund excess amount if (msg.value > totalExecutorsFee) { /* solhint-disable avoid-low-level-calls */ //slither-disable-next-line arbitrary-send-eth (bool success, ) = msg.sender.call{value: msg.value - totalExecutorsFee}(""); //nonReentrant /* solhint-enable avoid-low-level-calls */ require(success, ERR_TRANSFER_FAILURE); emit SetExecutorsExcessAmountRefunded(msg.sender, msg.value - totalExecutorsFee); } } /** * @notice Creates (enables) delegation account contract, * i.e. all airdrop and ftso rewards will be send to delegation account when using automatic claiming. * @return Address of delegation account contract. */ function _createOrEnableDelegationAccount() internal returns (IDelegationAccount) { DelegationAccountData storage delegationAccountData = _getOrCreateDelegationAccountData(); IIDelegationAccount delegationAccount = delegationAccountData.delegationAccount; delegationAccountData.enabled = true; emit DelegationAccountUpdated(msg.sender, delegationAccount, true); return delegationAccount; } /** * @notice Returns the delegation account data. If there is none it creates a new one. */ function _getOrCreateDelegationAccountData() internal returns (DelegationAccountData storage) { DelegationAccountData storage delegationAccountData = ownerToDelegationAccountData[msg.sender]; if (address(delegationAccountData.delegationAccount) != address(0)) { return delegationAccountData; } require(libraryAddress != address(0), ERR_LIBRARY_ADDRESS_NOT_SET_YET); // create delegation account IIDelegationAccount delegationAccount = IIDelegationAccount(payable(createClone(libraryAddress))); require(_isContract(address(delegationAccount)), ERR_CREATE_CLONE); delegationAccount.initialize(msg.sender, this); delegationAccountData.delegationAccount = delegationAccount; delegationAccountToOwner[address(delegationAccount)] = msg.sender; emit DelegationAccountCreated(msg.sender, delegationAccount); return delegationAccountData; } /** * @notice Implementation of the AddressUpdatable abstract method. */ function _updateContractAddresses( bytes32[] memory _contractNameHashes, address[] memory _contractAddresses ) internal override { ftsoManager = IFtsoManager(_getContractAddress(_contractNameHashes, _contractAddresses, "FtsoManager")); WNat newWNat = WNat(payable(_getContractAddress(_contractNameHashes, _contractAddresses, "WNat"))); if (address(wNat) == address(0)) { wNat = newWNat; } else if (newWNat != wNat) { revert(ERR_WRONG_WNAT_ADDRESS); } governanceVP = wNat.governanceVotePower(); } /** * @notice Allows executor to set (or update last scheduled) fee value. * @param _currentRewardEpoch current reward epoch number * @param _feeValue number representing fee value * @return _validFromEpoch Returns the reward epoch number when the setting becomes effective. */ function _updateExecutorFeeValue( uint256 _currentRewardEpoch, uint256 _feeValue ) internal returns (uint256 _validFromEpoch) { require(_feeValue >= minFeeValueWei, ERR_FEE_INVALID); require(_feeValue <= maxFeeValueWei, ERR_FEE_INVALID); _validFromEpoch = _currentRewardEpoch + feeValueUpdateOffset; ExecutorFee[] storage efs = claimExecutorFees[msg.sender]; // determine whether to update the last setting or add a new one uint256 position = efs.length; assert(position > 0); // this method can be called only after executor is registered uint256 lastValidFromEpoch = efs[position - 1].validFromEpoch; // do not allow updating the settings in the past - should never happen // (this can only happen if the current reward epoch is smaller than some previous one) require(_validFromEpoch >= lastValidFromEpoch, ERR_FEE_UPDATE_FAILED); if (_validFromEpoch == lastValidFromEpoch) { // update efs[position - 1].value = _feeValue; } else { // add efs.push(ExecutorFee({value: _feeValue, validFromEpoch: _validFromEpoch})); } emit ClaimExecutorFeeValueChanged(msg.sender, _validFromEpoch, _feeValue); } /** * @notice Returns delegation account for `_owner`. * @param _owner owner's address */ function _getDelegationAccount(address _owner) internal view returns (IIDelegationAccount) { return ownerToDelegationAccountData[_owner].delegationAccount; } /** * @notice Returns fee value setting for `_executor` at specified `_rewardEpoch`. * @param _executor address representing executor * @param _rewardEpoch reward epoch number */ function _getExecutorFeeValue( address _executor, uint256 _rewardEpoch ) internal view returns (uint256) { ExecutorFee[] storage efs = claimExecutorFees[_executor]; uint256 index = efs.length; while (index > 0) { index--; if (_rewardEpoch >= efs[index].validFromEpoch) { return efs[index].value; } } return 0; } /** * @notice Checks if caller is owner or executor for all addresses `_owners`. */ function _checkOnlyOwnerOrExecutor(address _executor, address[] memory _owners) internal view { for (uint256 i = 0; i < _owners.length; i++) { require(_executor == _owners[i] || ownerClaimExecutorSet[_owners[i]].index[_executor] != 0, ERR_ONLY_OWNER_OR_EXECUTOR); } } function _isContract(address _addr) private view returns (bool){ uint32 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(_addr) } return (size > 0); } }
./contracts/token/interface/IICleanable.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; 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; /** * Get the current cleanup block number. */ function cleanupBlockNumber() external view returns (uint256); }
@openzeppelin/contracts/utils/ReentrancyGuard.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor () internal { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
./contracts/genesis/implementation/DistributionTreasury.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "../../governance/implementation/Governed.sol"; /** * @title Distribution treasury * @notice A contract used to hold funds until the distribution plan is chosen. */ contract DistributionTreasury is Governed { // How often can the distribution contract pull funds - 29 days constant uint256 internal constant MAX_PULL_FREQUENCY_SEC = 29 days; uint256 public constant MAX_PULL_AMOUNT_WEI = 725000000 ether; // Errors string internal constant ERR_DISTRIBUTION_ONLY = "distribution only"; string internal constant ERR_TOO_OFTEN = "too often"; string internal constant ERR_TOO_MUCH = "too much"; string internal constant ERR_SEND_FUNDS_FAILED = "send funds failed"; string internal constant ERR_ADDRESS_ZERO = "address zero"; string internal constant ERR_ONLY_GOVERNANCE_OR_DISTRIBUTION = "only governance or distribution"; // Storage address public distribution; uint256 public lastPullTs; modifier onlyDistribution { require (msg.sender == distribution, ERR_DISTRIBUTION_ONLY); _; } constructor(address _governance) Governed(_governance) { /* empty block */ } /** * @notice Needed in order to receive funds from governance address or from distibution (if stopped) */ receive() external payable { require(msg.sender == governance() || msg.sender == distribution, ERR_ONLY_GOVERNANCE_OR_DISTRIBUTION); } /** * @notice Sets distribution contract address. * @param _distribution Distribution contract address. */ function setDistributionContract(address _distribution) external onlyGovernance { require(_distribution != address(0), ERR_ADDRESS_ZERO); distribution = _distribution; } /** * @notice Moves funds to the distribution contract (once per month) * @param _amountWei The amount of wei to pull to distribution contract */ function pullFunds(uint256 _amountWei) external onlyDistribution { // this also serves as reentrancy guard, since any re-entry will happen in the same block require(lastPullTs + MAX_PULL_FREQUENCY_SEC <= block.timestamp, ERR_TOO_OFTEN); require(_amountWei <= MAX_PULL_AMOUNT_WEI, ERR_TOO_MUCH); lastPullTs = block.timestamp; _sendFunds(msg.sender, _amountWei); } function _sendFunds(address _recipient, uint256 _amountWei) internal { /* solhint-disable avoid-low-level-calls */ //slither-disable-next-line arbitrary-send-eth (bool success, ) = _recipient.call{value: _amountWei}(""); /* solhint-enable avoid-low-level-calls */ require(success, ERR_SEND_FUNDS_FAILED); } }
./contracts/userInterfaces/IWNat.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IWNat { /** * @notice Deposit native token and mint WNAT ERC20. */ function deposit() external payable; /** * @notice Withdraw native token and burn WNAT ERC20. * @param _amount The amount to withdraw. */ function withdraw(uint256 _amount) external; /** * @notice Deposit native token from msg.sender and mint WNAT ERC20. * @param _recipient An address to receive minted WNAT. */ function depositTo(address _recipient) external payable; /** * @notice Withdraw WNAT from an owner and send NAT to msg.sender given an allowance. * @param _owner An address spending the native tokens. * @param _amount The amount to spend. * * Requirements: * * - `_owner` must have a balance of at least `_amount`. * - the caller must have allowance for `_owners`'s tokens of at least * `_amount`. */ function withdrawFrom(address _owner, uint256 _amount) external; }
./contracts/token/implementation/WNat.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "./VPToken.sol"; import "./VPContract.sol"; import "../../userInterfaces/IWNat.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; /** * @title Wrapped Native token * @notice Accept native token deposits and mint ERC20 WNAT (wrapped native) tokens 1-1. * @dev Attribution: https://rinkeby.etherscan.io/address/0xc778417e063141139fce010982780140aa0cd5ab#code */ contract WNat is VPToken, IWNat { using SafeMath for uint256; event Deposit(address indexed dst, uint amount); event Withdrawal(address indexed src, uint amount); /** * Construct an ERC20 token. */ constructor(address _governance, string memory _name, string memory _symbol) VPToken(_governance, _name, _symbol) { } receive() external payable { deposit(); } /** * @notice Withdraw WNAT from an owner and send native tokens to msg.sender given an allowance. * @param owner An address spending the Native tokens. * @param amount The amount to spend. * * Requirements: * * - `owner` must have a balance of at least `amount`. * - the caller must have allowance for `owners`'s tokens of at least * `amount`. */ function withdrawFrom(address owner, uint256 amount) external override { // Reduce senders allowance _approve(owner, msg.sender, allowance(owner, msg.sender).sub(amount, "allowance below zero")); // Burn the owners balance _burn(owner, amount); // Emit withdraw event emit Withdrawal(owner, amount); // Move value to sender (last statement, to prevent reentrancy) msg.sender.transfer(amount); } /** * @notice Deposit Native from msg.sender and mints WNAT ERC20 to recipient address. * @param recipient An address to receive minted WNAT. */ function depositTo(address recipient) external payable override { require(recipient != address(0), "Cannot deposit to zero address"); // Mint WNAT _mint(recipient, msg.value); // Emit deposit event emit Deposit(recipient, msg.value); } /** * @notice Deposit Native and mint wNat ERC20. */ function deposit() public payable override { // Mint WNAT _mint(msg.sender, msg.value); // Emit deposit event emit Deposit(msg.sender, msg.value); } /** * @notice Withdraw Native and burn WNAT ERC20. * @param amount The amount to withdraw. */ function withdraw(uint256 amount) external override { // Burn WNAT tokens _burn(msg.sender, amount); // Emit withdrawal event emit Withdrawal(msg.sender, amount); // Send Native to sender (last statement, to prevent reentrancy) msg.sender.transfer(amount); } }
@openzeppelin/contracts/math/Math.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } }
./contracts/token/lib/VotePower.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "./CheckPointHistory.sol"; import "./CheckPointsByAddress.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; /** * @title Vote power library * @notice A library to record delegate vote power balances by delegator * and delegatee. **/ library VotePower { using CheckPointHistory for CheckPointHistory.CheckPointHistoryState; using CheckPointsByAddress for CheckPointsByAddress.CheckPointsByAddressState; using SafeMath for uint256; /** * @dev `VotePowerState` is state structure used by this library to manage vote * power amounts by delegator and it's delegates. */ struct VotePowerState { // `votePowerByAddress` is the map that tracks the voting power balance // of each address, by block. CheckPointsByAddress.CheckPointsByAddressState votePowerByAddress; } /** * @notice This modifier checks that both addresses are non-zero. * @param _delegator A delegator address. * @param _delegatee A delegatee address. */ modifier addressesNotZero(address _delegator, address _delegatee) { // Both addresses cannot be zero assert(!(_delegator == address(0) && _delegatee == address(0))); _; } /** * @notice Delegate vote power `_amount` to `_delegatee` address from `_delegator` address. * @param _delegator Delegator address * @param _delegatee Delegatee address * @param _amount The _amount of vote power to send from _delegator to _delegatee * @dev Amount recorded at the current block. **/ function delegate( VotePowerState storage _self, address _delegator, address _delegatee, uint256 _amount ) internal addressesNotZero(_delegator, _delegatee) { // Shortcut if (_amount == 0) { return; } // Transmit vote power _self.votePowerByAddress.transmit(_delegator, _delegatee, _amount); } /** * @notice Change the current vote power value. * @param _owner Address of vote power owner. * @param _add The amount to add to the vote power. * @param _sub The amount to subtract from the vote power. */ function changeValue( VotePowerState storage _self, address _owner, uint256 _add, uint256 _sub ) internal { assert(_owner != address(0)); if (_add == _sub) return; uint256 value = _self.votePowerByAddress.valueOfAtNow(_owner); value = value.add(_add).sub(_sub); _self.votePowerByAddress.writeValue(_owner, value); } /** * @notice Undelegate vote power `_amount` from `_delegatee` address * to `_delegator` address * @param _delegator Delegator address * @param _delegatee Delegatee address * @param _amount The amount of vote power recovered by delegator from delegatee **/ function undelegate( VotePowerState storage _self, address _delegator, address _delegatee, uint256 _amount ) internal addressesNotZero(_delegator, _delegatee) { // Shortcut if (_amount == 0) { return; } // Recover vote power _self.votePowerByAddress.transmit(_delegatee, _delegator, _amount); } /** * Delete at most `_count` of the oldest checkpoints. * At least one checkpoint at or before `_cleanupBlockNumber` will remain * (unless the history was empty to start with). */ function cleanupOldCheckpoints( VotePowerState storage _self, address _owner, uint256 _count, uint256 _cleanupBlockNumber ) internal returns (uint256) { return _self.votePowerByAddress.cleanupOldCheckpoints(_owner, _count, _cleanupBlockNumber); } /** * @notice Get the vote power of `_who` at `_blockNumber`. * @param _self A VotePowerState instance to manage. * @param _who Address to get vote power. * @param _blockNumber Block number of the block to fetch vote power. * @return _votePower The fetched vote power. */ function votePowerOfAt( VotePowerState storage _self, address _who, uint256 _blockNumber ) internal view returns(uint256 _votePower) { return _self.votePowerByAddress.valueOfAt(_who, _blockNumber); } /** * @notice Get the current vote power of `_who`. * @param _self A VotePowerState instance to manage. * @param _who Address to get vote power. * @return _votePower The fetched vote power. */ function votePowerOfAtNow( VotePowerState storage _self, address _who ) internal view returns(uint256 _votePower) { return _self.votePowerByAddress.valueOfAtNow(_who); } }
@openzeppelin/contracts/math/SafeMath.sol
// SPDX-License-Identifier: MIT 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; } }
./contracts/claiming/interface/IIClaimSetupManager.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import "../../userInterfaces/IClaimSetupManager.sol"; import "../../token/implementation/WNat.sol"; interface IIClaimSetupManager is IClaimSetupManager { event SetLibraryAddress(address libraryAddress); function setLibraryAddress(address _libraryAddress) external; function setMinFeeValueWei(uint256 _minFeeValueWei) external; function setMaxFeeValueWei(uint256 _maxFeeValueWei) external; function setRegisterExecutorFeeValueWei(uint256 _registerExecutorFeeValueWei) external; function wNat() external view returns(WNat); function getAutoClaimAddressesAndExecutorFee(address _executor, address[] memory _owners) external view returns (address[] memory _claimAddresses, uint256 _executorFeeValue); function checkExecutorAndAllowedRecipient(address _executor, address _owner, address _recipient) external view; }
@openzeppelin/contracts/token/ERC20/ERC20.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "../../utils/Context.sol"; import "./IERC20.sol"; import "../../math/SafeMath.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ constructor (string memory name_, string memory symbol_) public { _name = name_; _symbol = symbol_; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Sets {decimals} to a value other than the default one of 18. * * WARNING: This function should only be called from the constructor. Most * applications that interact with token contracts will not expect * {decimals} to ever change, and may work incorrectly if it does. */ function _setupDecimals(uint8 decimals_) internal virtual { _decimals = decimals_; } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } }
./contracts/userInterfaces/IDistributionToDelegators.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; pragma abicoder v2; interface IDistributionToDelegators { // Events event UseGoodRandomSet(bool useGoodRandom, uint256 maxWaitForGoodRandomSeconds); event EntitlementStart(uint256 entitlementStartTs); event AccountClaimed(address indexed whoClaimed, address indexed sentTo, uint256 month, uint256 amountWei); event AccountOptOut(address indexed theAccount, bool confirmed); // Methods /** * @notice Allows the sender to claim or wrap rewards for reward owner. * @notice The caller does not have to be the owner, but must be approved by the owner to claim on his behalf, * this approval is done by calling `setClaimExecutors`. * @notice It is actually safe for this to be called by anybody (nothing can be stolen), but by limiting who can * call, we allow the owner to control the timing of the calls. * @notice Reward owner can claim to any `_recipient`, while the executor can only claim to the reward owner, * reward owners's personal delegation account or one of the addresses set by `setAllowedClaimRecipients`. * @param _rewardOwner address of the reward owner * @param _recipient address to transfer funds to * @param _month last month to claim for * @param _wrap should reward be wrapped immediately * @return _rewardAmount amount of total claimed rewards */ function claim(address _rewardOwner, address _recipient, uint256 _month, bool _wrap) external returns(uint256 _rewardAmount); /** * @notice Allows batch claiming for the list of '_rewardOwners' up to given '_month'. * @notice If reward owner has enabled delegation account, rewards are also claimed for that delegation account and * total claimed amount is sent to that delegation account, otherwise claimed amount is sent to owner's account. * @notice Claimed amount is automatically wrapped. * @notice Method can be used by reward owner or executor. If executor is registered with fee > 0, * then fee is paid to executor for each claimed address from the list. * @param _rewardOwners list of reward owners to claim for * @param _month last month to claim for */ function autoClaim(address[] calldata _rewardOwners, uint256 _month) external; /** * @notice Method to opt-out of receiving airdrop rewards */ function optOutOfAirdrop() external; /** * @notice Returns the next claimable month for '_rewardOwner'. * @param _rewardOwner address of the reward owner */ function nextClaimableMonth(address _rewardOwner) external view returns (uint256); /** * @notice get claimable amount of wei for requesting account for specified month * @param _month month of interest * @return _amountWei amount of wei available for this account and provided month */ function getClaimableAmount(uint256 _month) external view returns(uint256 _amountWei); /** * @notice get claimable amount of wei for account for specified month * @param _account the address of an account we want to get the claimable amount of wei * @param _month month of interest * @return _amountWei amount of wei available for provided account and month */ function getClaimableAmountOf(address _account, uint256 _month) external view returns(uint256 _amountWei); /** * @notice Returns the current month * @return _currentMonth Current month, 0 before entitlementStartTs */ function getCurrentMonth() external view returns (uint256 _currentMonth); /** * @notice Returns the month that will expire next * @return _monthToExpireNext Month that will expire next, 36 when last month expired */ function getMonthToExpireNext() external view returns (uint256 _monthToExpireNext); /** * @notice Returns claimable months - reverts if none * @return _startMonth first claimable month * @return _endMonth last claimable month */ function getClaimableMonths() external view returns(uint256 _startMonth, uint256 _endMonth); }
./contracts/addressUpdater/implementation/AddressUpdatable.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "../interface/IIAddressUpdatable.sol"; abstract contract AddressUpdatable is IIAddressUpdatable { // https://docs.soliditylang.org/en/v0.8.7/contracts.html#constant-and-immutable-state-variables // No storage slot is allocated bytes32 internal constant ADDRESS_STORAGE_POSITION = keccak256("flare.diamond.AddressUpdatable.ADDRESS_STORAGE_POSITION"); modifier onlyAddressUpdater() { require (msg.sender == getAddressUpdater(), "only address updater"); _; } constructor(address _addressUpdater) { setAddressUpdaterValue(_addressUpdater); } function getAddressUpdater() public view returns (address _addressUpdater) { // Only direct constants are allowed in inline assembly, so we assign it here bytes32 position = ADDRESS_STORAGE_POSITION; // solhint-disable-next-line no-inline-assembly assembly { _addressUpdater := sload(position) } } /** * @notice external method called from AddressUpdater only */ function updateContractAddresses( bytes32[] memory _contractNameHashes, address[] memory _contractAddresses ) external override onlyAddressUpdater { // update addressUpdater address setAddressUpdaterValue(_getContractAddress(_contractNameHashes, _contractAddresses, "AddressUpdater")); // update all other addresses _updateContractAddresses(_contractNameHashes, _contractAddresses); } /** * @notice virtual method that a contract extending AddressUpdatable must implement */ function _updateContractAddresses( bytes32[] memory _contractNameHashes, address[] memory _contractAddresses ) internal virtual; /** * @notice helper method to get contract address * @dev it reverts if contract name does not exist */ function _getContractAddress( bytes32[] memory _nameHashes, address[] memory _addresses, string memory _nameToFind ) internal pure returns(address) { bytes32 nameHash = keccak256(abi.encode(_nameToFind)); address a = address(0); for (uint256 i = 0; i < _nameHashes.length; i++) { if (nameHash == _nameHashes[i]) { a = _addresses[i]; break; } } require(a != address(0), "address zero"); return a; } function setAddressUpdaterValue(address _addressUpdater) internal { // Only direct constants are allowed in inline assembly, so we assign it here bytes32 position = ADDRESS_STORAGE_POSITION; // solhint-disable-next-line no-inline-assembly assembly { sstore(position, _addressUpdater) } } }
./contracts/token/lib/DelegationHistory.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "@openzeppelin/contracts/math/Math.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/utils/SafeCast.sol"; import "../../utils/implementation/SafePct.sol"; /** * @title DelegationHistory library * @notice A contract to manage checkpoints as of a given block. * @dev Store value history by block number with detachable state. **/ library DelegationHistory { using SafeMath for uint256; using SafePct for uint256; using SafeCast for uint256; uint256 public constant MAX_DELEGATES_BY_PERCENT = 2; string private constant MAX_DELEGATES_MSG = "Max delegates exceeded"; struct Delegation { address delegate; uint16 value; // delegations[0] will also hold length and blockNumber to save 1 slot of storage per checkpoint // for all other indexes these fields will be 0 // also, when checkpoint is empty, `length` will automatically be 0, which is ok uint64 fromBlock; uint8 length; // length is limited to MAX_DELEGATES_BY_PERCENT which fits in 8 bits } /** * @dev `CheckPoint` is the structure that attaches a block number to a * given value; the block number attached is the one that last changed the * value **/ struct CheckPoint { // the list of delegations at the time mapping(uint256 => Delegation) delegations; } struct CheckPointHistoryState { // `checkpoints` is an array that tracks delegations at non-contiguous block numbers mapping(uint256 => CheckPoint) checkpoints; // `checkpoints` before `startIndex` have been deleted // INVARIANT: checkpoints.length == 0 || startIndex < checkpoints.length (strict!) uint64 startIndex; uint64 length; } /** * @notice Queries the value at a specific `_blockNumber` * @param _self A CheckPointHistoryState instance to manage. * @param _delegate The delegate for which we need value. * @param _blockNumber The block number of the value active at that time * @return _value The value of the `_delegate` at `_blockNumber` **/ function valueOfAt( CheckPointHistoryState storage _self, address _delegate, uint256 _blockNumber ) internal view returns (uint256 _value) { (bool found, uint256 index) = _findGreatestBlockLessThan(_self, _blockNumber); if (!found) return 0; return _getValueForDelegate(_self.checkpoints[index], _delegate); } /** * @notice Queries the value at `block.number` * @param _self A CheckPointHistoryState instance to manage. * @param _delegate The delegate for which we need value. * @return _value The value at `block.number` **/ function valueOfAtNow( CheckPointHistoryState storage _self, address _delegate ) internal view returns (uint256 _value) { uint256 length = _self.length; if (length == 0) return 0; return _getValueForDelegate(_self.checkpoints[length - 1], _delegate); } /** * @notice Writes the value at the current block. * @param _self A CheckPointHistoryState instance to manage. * @param _delegate The delegate tu update. * @param _value The new value to set for this delegate (value `0` deletes `_delegate` from the list). **/ function writeValue( CheckPointHistoryState storage _self, address _delegate, uint256 _value ) internal { uint256 historyCount = _self.length; if (historyCount == 0) { // checkpoints array empty, push new CheckPoint if (_value != 0) { CheckPoint storage cp = _self.checkpoints[historyCount]; _self.length = SafeCast.toUint64(historyCount + 1); cp.delegations[0] = Delegation({ delegate: _delegate, value: _value.toUint16(), fromBlock: block.number.toUint64(), length: 1 }); } } else { // historyCount - 1 is safe, since historyCount != 0 CheckPoint storage lastCheckpoint = _self.checkpoints[historyCount - 1]; uint256 lastBlock = lastCheckpoint.delegations[0].fromBlock; // slither-disable-next-line incorrect-equality if (block.number == lastBlock) { // If last check point is the current block, just update _updateDelegates(lastCheckpoint, _delegate, _value); } else { // we should never have future blocks in history assert(block.number > lastBlock); // last check point block is before CheckPoint storage cp = _self.checkpoints[historyCount]; _self.length = SafeCast.toUint64(historyCount + 1); _copyAndUpdateDelegates(cp, lastCheckpoint, _delegate, _value); cp.delegations[0].fromBlock = block.number.toUint64(); } } } /** * Get all percentage delegations active at a time. * @param _self A CheckPointHistoryState instance to manage. * @param _blockNumber The block number to query. * @return _delegates The active percentage delegates at the time. * @return _values The delegates' values at the time. **/ function delegationsAt( CheckPointHistoryState storage _self, uint256 _blockNumber ) internal view returns ( address[] memory _delegates, uint256[] memory _values ) { (bool found, uint256 index) = _findGreatestBlockLessThan(_self, _blockNumber); if (!found) { return (new address[](0), new uint256[](0)); } // copy delegates and values to memory arrays // (to prevent caller updating the stored value) CheckPoint storage cp = _self.checkpoints[index]; uint256 length = cp.delegations[0].length; _delegates = new address[](length); _values = new uint256[](length); for (uint256 i = 0; i < length; i++) { Delegation storage dlg = cp.delegations[i]; _delegates[i] = dlg.delegate; _values[i] = dlg.value; } } /** * Get all percentage delegations active now. * @param _self A CheckPointHistoryState instance to manage. * @return _delegates The active percentage delegates. * @return _values The delegates' values. **/ function delegationsAtNow( CheckPointHistoryState storage _self ) internal view returns (address[] memory _delegates, uint256[] memory _values) { return delegationsAt(_self, block.number); } /** * Get all percentage delegations active now. * @param _self A CheckPointHistoryState instance to manage. * @return _length The number of delegations. * @return _delegations . **/ function delegationsAtNowRaw( CheckPointHistoryState storage _self ) internal view returns ( uint256 _length, mapping(uint256 => Delegation) storage _delegations ) { uint256 length = _self.length; if (length == 0) { return (0, _self.checkpoints[0].delegations); } CheckPoint storage cp = _self.checkpoints[length - 1]; return (cp.delegations[0].length, cp.delegations); } /** * Get the number of delegations. * @param _self A CheckPointHistoryState instance to query. * @param _blockNumber The block number to query. * @return _count Count of delegations at the time. **/ function countAt( CheckPointHistoryState storage _self, uint256 _blockNumber ) internal view returns (uint256 _count) { (bool found, uint256 index) = _findGreatestBlockLessThan(_self, _blockNumber); if (!found) return 0; return _self.checkpoints[index].delegations[0].length; } /** * Get the sum of all delegation values. * @param _self A CheckPointHistoryState instance to query. * @param _blockNumber The block number to query. * @return _total Total delegation value at the time. **/ function totalValueAt( CheckPointHistoryState storage _self, uint256 _blockNumber ) internal view returns (uint256 _total) { (bool found, uint256 index) = _findGreatestBlockLessThan(_self, _blockNumber); if (!found) return 0; CheckPoint storage cp = _self.checkpoints[index]; uint256 length = cp.delegations[0].length; _total = 0; for (uint256 i = 0; i < length; i++) { _total = _total.add(cp.delegations[i].value); } } /** * Get the sum of all delegation values. * @param _self A CheckPointHistoryState instance to query. * @return _total Total delegation value at the time. **/ function totalValueAtNow( CheckPointHistoryState storage _self ) internal view returns (uint256 _total) { return totalValueAt(_self, block.number); } /** * Get the sum of all delegation values, every one scaled by `_mul/_div`. * @param _self A CheckPointHistoryState instance to query. * @param _mul The multiplier. * @param _div The divisor. * @param _blockNumber The block number to query. * @return _total Total scaled delegation value at the time. **/ function scaledTotalValueAt( CheckPointHistoryState storage _self, uint256 _mul, uint256 _div, uint256 _blockNumber ) internal view returns (uint256 _total) { (bool found, uint256 index) = _findGreatestBlockLessThan(_self, _blockNumber); if (!found) return 0; CheckPoint storage cp = _self.checkpoints[index]; uint256 length = cp.delegations[0].length; _total = 0; for (uint256 i = 0; i < length; i++) { _total = _total.add(uint256(cp.delegations[i].value).mulDiv(_mul, _div)); } } /** * Clear all delegations at this moment. * @param _self A CheckPointHistoryState instance to manage. */ function clear(CheckPointHistoryState storage _self) internal { uint256 historyCount = _self.length; if (historyCount > 0) { // add an empty checkpoint CheckPoint storage cp = _self.checkpoints[historyCount]; _self.length = SafeCast.toUint64(historyCount + 1); // create empty checkpoint = only set fromBlock cp.delegations[0] = Delegation({ delegate: address(0), value: 0, fromBlock: block.number.toUint64(), length: 0 }); } } /** * Delete at most `_count` of the oldest checkpoints. * At least one checkpoint at or before `_cleanupBlockNumber` will remain * (unless the history was empty to start with). */ function cleanupOldCheckpoints( CheckPointHistoryState storage _self, uint256 _count, uint256 _cleanupBlockNumber ) internal returns (uint256) { if (_cleanupBlockNumber == 0) return 0; // optimization for when cleaning is not enabled uint256 length = _self.length; if (length == 0) return 0; uint256 startIndex = _self.startIndex; // length - 1 is safe, since length != 0 (check above) uint256 endIndex = Math.min(startIndex.add(_count), length - 1); // last element can never be deleted uint256 index = startIndex; // we can delete `checkpoint[index]` while the next checkpoint is at `_cleanupBlockNumber` or before while (index < endIndex && _self.checkpoints[index + 1].delegations[0].fromBlock <= _cleanupBlockNumber) { CheckPoint storage cp = _self.checkpoints[index]; uint256 cplength = cp.delegations[0].length; for (uint256 i = 0; i < cplength; i++) { delete cp.delegations[i]; } index++; } if (index > startIndex) { // index is the first not deleted index _self.startIndex = SafeCast.toUint64(index); } return index - startIndex; // safe: index = startIndex at start and increases in loop } ///////////////////////////////////////////////////////////////////////////////// // helper functions for writeValueAt function _copyAndUpdateDelegates( CheckPoint storage _cp, CheckPoint storage _orig, address _delegate, uint256 _value ) private { uint256 length = _orig.delegations[0].length; bool updated = false; uint256 newlength = 0; for (uint256 i = 0; i < length; i++) { Delegation memory origDlg = _orig.delegations[i]; if (origDlg.delegate == _delegate) { // copy delegate, but with new value newlength = _appendDelegate(_cp, origDlg.delegate, _value, newlength); updated = true; } else { // just copy the delegate with original value newlength = _appendDelegate(_cp, origDlg.delegate, origDlg.value, newlength); } } if (!updated) { // delegate is not in the original list, so add it newlength = _appendDelegate(_cp, _delegate, _value, newlength); } // safe - newlength <= length + 1 <= MAX_DELEGATES_BY_PERCENT _cp.delegations[0].length = uint8(newlength); } function _updateDelegates(CheckPoint storage _cp, address _delegate, uint256 _value) private { uint256 length = _cp.delegations[0].length; uint256 i = 0; while (i < length && _cp.delegations[i].delegate != _delegate) ++i; if (i < length) { if (_value != 0) { _cp.delegations[i].value = _value.toUint16(); } else { _deleteDelegate(_cp, i, length - 1); // length - 1 is safe: 0 <= i < length _cp.delegations[0].length = uint8(length - 1); } } else { uint256 newlength = _appendDelegate(_cp, _delegate, _value, length); _cp.delegations[0].length = uint8(newlength); // safe - length <= MAX_DELEGATES_BY_PERCENT } } function _appendDelegate(CheckPoint storage _cp, address _delegate, uint256 _value, uint256 _length) private returns (uint256) { if (_value != 0) { require(_length < MAX_DELEGATES_BY_PERCENT, MAX_DELEGATES_MSG); Delegation storage dlg = _cp.delegations[_length]; dlg.delegate = _delegate; dlg.value = _value.toUint16(); // for delegations[0], fromBlock and length are assigned outside return _length + 1; } return _length; } function _deleteDelegate(CheckPoint storage _cp, uint256 _index, uint256 _last) private { Delegation storage dlg = _cp.delegations[_index]; Delegation storage lastDlg = _cp.delegations[_last]; if (_index < _last) { dlg.delegate = lastDlg.delegate; dlg.value = lastDlg.value; } lastDlg.delegate = address(0); lastDlg.value = 0; } ///////////////////////////////////////////////////////////////////////////////// // helper functions for querying /** * @notice Binary search of _checkpoints array. * @param _checkpoints An array of CheckPoint to search. * @param _startIndex Smallest possible index to be returned. * @param _blockNumber The block number to search for. */ function _binarySearchGreatestBlockLessThan( mapping(uint256 => CheckPoint) storage _checkpoints, uint256 _startIndex, uint256 _endIndex, uint256 _blockNumber ) private view returns (uint256 _index) { // Binary search of the value by given block number in the array uint256 min = _startIndex; uint256 max = _endIndex.sub(1); while (max > min) { uint256 mid = (max.add(min).add(1)).div(2); if (_checkpoints[mid].delegations[0].fromBlock <= _blockNumber) { min = mid; } else { max = mid.sub(1); } } return min; } /** * @notice Binary search of _checkpoints array. Extra optimized for the common case when we are * searching for the last block. * @param _self The state to query. * @param _blockNumber The block number to search for. * @return _found true if value was found (only `false` if `_blockNumber` is before first * checkpoint or the checkpoint array is empty) * @return _index index of the newest block with number less than or equal `_blockNumber` */ function _findGreatestBlockLessThan( CheckPointHistoryState storage _self, uint256 _blockNumber ) private view returns ( bool _found, uint256 _index ) { uint256 startIndex = _self.startIndex; uint256 historyCount = _self.length; if (historyCount == 0) { _found = false; } else if (_blockNumber >= _self.checkpoints[historyCount - 1].delegations[0].fromBlock) { _found = true; _index = historyCount - 1; // safe, historyCount != 0 in this branch } else if (_blockNumber < _self.checkpoints[startIndex].delegations[0].fromBlock) { // reading data before `_startIndex` is only safe before first cleanup require(startIndex == 0, "DelegationHistory: reading from cleaned-up block"); _found = false; } else { _found = true; _index = _binarySearchGreatestBlockLessThan(_self.checkpoints, startIndex, historyCount, _blockNumber); } } /** * Find delegate and return its value or 0 if not found. */ function _getValueForDelegate(CheckPoint storage _cp, address _delegate) internal view returns (uint256) { uint256 length = _cp.delegations[0].length; for (uint256 i = 0; i < length; i++) { Delegation storage dlg = _cp.delegations[i]; if (dlg.delegate == _delegate) { return dlg.value; } } return 0; // _delegate not found } }
./contracts/genesis/interface/IFlareDaemonize.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; /// 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); /// Implement this function for updating daemonized contracts through AddressUpdater. function getContractName() external view returns (string memory); }
./contracts/token/lib/CheckPointsByAddress.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "./CheckPointHistory.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; /** * @title Check Points By Address library * @notice A contract to manage checkpoint history for a collection of addresses. * @dev Store value history by address, and then by block number. **/ library CheckPointsByAddress { using SafeMath for uint256; using CheckPointHistory for CheckPointHistory.CheckPointHistoryState; struct CheckPointsByAddressState { // `historyByAddress` is the map that stores the check point history of each address mapping(address => CheckPointHistory.CheckPointHistoryState) historyByAddress; } /** /** * @notice Send `amount` value to `to` address from `from` address. * @param _self A CheckPointsByAddressState instance to manage. * @param _from Address of the history of from values * @param _to Address of the history of to values * @param _amount The amount of value to be transferred **/ function transmit( CheckPointsByAddressState storage _self, address _from, address _to, uint256 _amount ) internal { // Shortcut if (_amount == 0) return; // Both from and to can never be zero assert(!(_from == address(0) && _to == address(0))); // Update transferer value if (_from != address(0)) { // Compute the new from balance uint256 newValueFrom = valueOfAtNow(_self, _from).sub(_amount); writeValue(_self, _from, newValueFrom); } // Update transferee value if (_to != address(0)) { // Compute the new to balance uint256 newValueTo = valueOfAtNow(_self, _to).add(_amount); writeValue(_self, _to, newValueTo); } } /** * @notice Queries the value of `_owner` at a specific `_blockNumber`. * @param _self A CheckPointsByAddressState instance to manage. * @param _owner The address from which the value will be retrieved. * @param _blockNumber The block number to query for the then current value. * @return The value at `_blockNumber` for `_owner`. **/ function valueOfAt( CheckPointsByAddressState storage _self, address _owner, uint256 _blockNumber ) internal view returns (uint256) { // Get history for _owner CheckPointHistory.CheckPointHistoryState storage history = _self.historyByAddress[_owner]; // Return value at given block return history.valueAt(_blockNumber); } /** * @notice Get the value of the `_owner` at the current `block.number`. * @param _self A CheckPointsByAddressState instance to manage. * @param _owner The address of the value is being requested. * @return The value of `_owner` at the current block. **/ function valueOfAtNow(CheckPointsByAddressState storage _self, address _owner) internal view returns (uint256) { // Get history for _owner CheckPointHistory.CheckPointHistoryState storage history = _self.historyByAddress[_owner]; // Return value at now return history.valueAtNow(); } /** * @notice Writes the `value` at the current block number for `_owner`. * @param _self A CheckPointsByAddressState instance to manage. * @param _owner The address of `_owner` to write. * @param _value The value to write. * @dev Sender must be the owner of the contract. **/ function writeValue( CheckPointsByAddressState storage _self, address _owner, uint256 _value ) internal { // Get history for _owner CheckPointHistory.CheckPointHistoryState storage history = _self.historyByAddress[_owner]; // Write the value history.writeValue(_value); } /** * Delete at most `_count` of the oldest checkpoints. * At least one checkpoint at or before `_cleanupBlockNumber` will remain * (unless the history was empty to start with). */ function cleanupOldCheckpoints( CheckPointsByAddressState storage _self, address _owner, uint256 _count, uint256 _cleanupBlockNumber ) internal returns (uint256) { if (_owner != address(0)) { return _self.historyByAddress[_owner].cleanupOldCheckpoints(_count, _cleanupBlockNumber); } return 0; } }
./contracts/token/lib/VotePowerCache.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../lib/VotePower.sol"; /** * @title Vote power library * @notice A library to record delegate vote power balances by delegator * and delegatee. **/ library VotePowerCache { using SafeMath for uint256; using VotePower for VotePower.VotePowerState; struct RevocationCacheRecord { // revoking delegation only affects cached value therefore we have to track // the revocation in order not to revoke twice // mapping delegatee => revokedValue mapping(address => uint256) revocations; } /** * @dev `CacheState` is state structure used by this library to manage vote * power amounts by delegator and it's delegates. */ struct CacheState { // map keccak256([address, _blockNumber]) -> (value + 1) mapping(bytes32 => uint256) valueCache; // map keccak256([address, _blockNumber]) -> RevocationCacheRecord mapping(bytes32 => RevocationCacheRecord) revocationCache; } /** * @notice Get the cached value at given block. If there is no cached value, original * value is returned and stored to cache. Cache never gets stale, because original * value can never change in a past block. * @param _self A VotePowerCache instance to manage. * @param _votePower A VotePower instance to read from if cache is empty. * @param _who Address to get vote power. * @param _blockNumber Block number of the block to fetch vote power. * precondition: _blockNumber < block.number */ function valueOfAt( CacheState storage _self, VotePower.VotePowerState storage _votePower, address _who, uint256 _blockNumber ) internal returns (uint256 _value, bool _createdCache) { bytes32 key = keccak256(abi.encode(_who, _blockNumber)); // is it in cache? uint256 cachedValue = _self.valueCache[key]; if (cachedValue != 0) { return (cachedValue - 1, false); // safe, cachedValue != 0 } // read from _votePower uint256 votePowerValue = _votePower.votePowerOfAt(_who, _blockNumber); _writeCacheValue(_self, key, votePowerValue); return (votePowerValue, true); } /** * @notice Get the cached value at given block. If there is no cached value, original * value is returned. Cache is never modified. * @param _self A VotePowerCache instance to manage. * @param _votePower A VotePower instance to read from if cache is empty. * @param _who Address to get vote power. * @param _blockNumber Block number of the block to fetch vote power. * precondition: _blockNumber < block.number */ function valueOfAtReadonly( CacheState storage _self, VotePower.VotePowerState storage _votePower, address _who, uint256 _blockNumber ) internal view returns (uint256 _value) { bytes32 key = keccak256(abi.encode(_who, _blockNumber)); // is it in cache? uint256 cachedValue = _self.valueCache[key]; if (cachedValue != 0) { return cachedValue - 1; // safe, cachedValue != 0 } // read from _votePower return _votePower.votePowerOfAt(_who, _blockNumber); } /** * @notice Delete cached value for `_who` at given block. * Only used for history cleanup. * @param _self A VotePowerCache instance to manage. * @param _who Address to get vote power. * @param _blockNumber Block number of the block to fetch vote power. * @return _deleted The number of cache items deleted (always 0 or 1). * precondition: _blockNumber < cleanupBlockNumber */ function deleteValueAt( CacheState storage _self, address _who, uint256 _blockNumber ) internal returns (uint256 _deleted) { bytes32 key = keccak256(abi.encode(_who, _blockNumber)); if (_self.valueCache[key] != 0) { delete _self.valueCache[key]; return 1; } return 0; } /** * @notice Revoke vote power delegation from `from` to `to` at given block. * Updates cached values for the block, so they are the only vote power values respecting revocation. * @dev Only delegatees cached value is changed, delegator doesn't get the vote power back; so * the revoked vote power is forfeit for as long as this vote power block is in use. This is needed to * prevent double voting. * @param _self A VotePowerCache instance to manage. * @param _votePower A VotePower instance to read from if cache is empty. * @param _from The delegator. * @param _to The delegatee. * @param _revokedValue Value of delegation is not stored here, so it must be supplied by caller. * @param _blockNumber Block number of the block to modify. * precondition: _blockNumber < block.number */ function revokeAt( CacheState storage _self, VotePower.VotePowerState storage _votePower, address _from, address _to, uint256 _revokedValue, uint256 _blockNumber ) internal { if (_revokedValue == 0) return; bytes32 keyFrom = keccak256(abi.encode(_from, _blockNumber)); if (_self.revocationCache[keyFrom].revocations[_to] != 0) { revert("Already revoked"); } // read values and prime cacheOf (uint256 valueTo,) = valueOfAt(_self, _votePower, _to, _blockNumber); // write new values bytes32 keyTo = keccak256(abi.encode(_to, _blockNumber)); _writeCacheValue(_self, keyTo, valueTo.sub(_revokedValue, "Revoked value too large")); // mark as revoked _self.revocationCache[keyFrom].revocations[_to] = _revokedValue; } /** * @notice Delete revocation from `_from` to `_to` at block `_blockNumber`. * Only used for history cleanup. * @param _self A VotePowerCache instance to manage. * @param _from The delegator. * @param _to The delegatee. * @param _blockNumber Block number of the block to modify. * precondition: _blockNumber < cleanupBlockNumber */ function deleteRevocationAt( CacheState storage _self, address _from, address _to, uint256 _blockNumber ) internal returns (uint256 _deleted) { bytes32 keyFrom = keccak256(abi.encode(_from, _blockNumber)); RevocationCacheRecord storage revocationRec = _self.revocationCache[keyFrom]; uint256 value = revocationRec.revocations[_to]; if (value != 0) { delete revocationRec.revocations[_to]; return 1; } return 0; } /** * @notice Returns true if `from` has revoked vote pover delgation of `to` in block `_blockNumber`. * @param _self A VotePowerCache instance to manage. * @param _from The delegator. * @param _to The delegatee. * @param _blockNumber Block number of the block to fetch result. * precondition: _blockNumber < block.number */ function revokedFromToAt( CacheState storage _self, address _from, address _to, uint256 _blockNumber ) internal view returns (bool revoked) { bytes32 keyFrom = keccak256(abi.encode(_from, _blockNumber)); return _self.revocationCache[keyFrom].revocations[_to] != 0; } function _writeCacheValue(CacheState storage _self, bytes32 _key, uint256 _value) private { // store to cacheOf (add 1 to differentiate from empty) _self.valueCache[_key] = _value.add(1); } }
./contracts/token/interface/IIVPContract.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import "../../userInterfaces/IVPToken.sol"; import "../../userInterfaces/IVPContractEvents.sol"; import "./IICleanable.sol"; 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 cumulative - 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 cumulative - 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); /** * @notice Get the vote power of `_who` at block `_blockNumber`, ignoring revocation information (and cache). * @param _who The address to get voting power. * @param _blockNumber The block number at which to fetch. * @return Vote power of `_who` at `_blockNumber`. Result doesn't change if vote power is revoked. */ function votePowerOfAtIgnoringRevocation(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); }
./contracts/claiming/interface/IIDelegationAccount.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; import "../../userInterfaces/IDelegationAccount.sol"; import "../interface/IIClaimSetupManager.sol"; interface IIDelegationAccount is IDelegationAccount { /** * Initialization of a new deployed contract * @param _owner contract owner address * @param _manager contract manager address */ function initialize(address _owner, IIClaimSetupManager _manager) external; function delegate(WNat _wNat, address _to, uint256 _bips) external; function batchDelegate(WNat _wNat, address[] memory _delegatees, uint256[] memory _bips) external; function undelegateAll(WNat _wNat) external; function revokeDelegationAt(WNat _wNat, address _who, uint256 _blockNumber) external; function delegateGovernance(IGovernanceVotePower _governanceVP, address _to) external; function undelegateGovernance(IGovernanceVotePower _governanceVP) external; function withdraw(WNat _wNat, uint256 _amount) external; function transferExternalToken(WNat _wNat, IERC20 _token, uint256 _amount) external; }
./contracts/userInterfaces/IFtso.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IFtso { enum PriceFinalizationType { // initial state NOT_FINALIZED, // median calculation used to find price WEIGHTED_MEDIAN, // low turnout - price calculated from median of trusted addresses TRUSTED_ADDRESSES, // low turnout + no votes from trusted addresses - price copied from previous epoch PREVIOUS_PRICE_COPIED, // price calculated from median of trusted addresses - triggered due to an exception TRUSTED_ADDRESSES_EXCEPTION, // previous price copied - triggered due to an exception PREVIOUS_PRICE_COPIED_EXCEPTION } event PriceRevealed( address indexed voter, uint256 indexed epochId, uint256 price, 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 _firstEpochStartTs First epoch start timestamp * @return _submitPeriodSeconds Submit period in seconds * @return _revealPeriodSeconds Reveal period in seconds */ function getPriceEpochConfiguration() external view returns ( uint256 _firstEpochStartTs, uint256 _submitPeriodSeconds, uint256 _revealPeriodSeconds ); /** * @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 asset price and number of decimals * @return _price Price in USD multiplied by ASSET_PRICE_USD_DECIMALS * @return _timestamp Time when price was updated for the last time * @return _assetPriceUsdDecimals Number of decimals used for USD price */ function getCurrentPriceWithDecimals() external view returns ( uint256 _price, uint256 _timestamp, uint256 _assetPriceUsdDecimals ); /** * @notice Returns current asset price calculated from trusted providers * @return _price Price in USD multiplied by ASSET_PRICE_USD_DECIMALS * @return _timestamp Time when price was updated for the last time */ function getCurrentPriceFromTrustedProviders() external view returns (uint256 _price, uint256 _timestamp); /** * @notice Returns current asset price calculated from trusted providers and number of decimals * @return _price Price in USD multiplied by ASSET_PRICE_USD_DECIMALS * @return _timestamp Time when price was updated for the last time * @return _assetPriceUsdDecimals Number of decimals used for USD price */ function getCurrentPriceWithDecimalsFromTrustedProviders() external view returns ( uint256 _price, uint256 _timestamp, uint256 _assetPriceUsdDecimals ); /** * @notice Returns current asset price details * @return _price Price in USD multiplied by ASSET_PRICE_USD_DECIMALS * @return _priceTimestamp Time when price was updated for the last time * @return _priceFinalizationType Finalization type when price was updated for the last time * @return _lastPriceEpochFinalizationTimestamp Time when last price epoch was finalized * @return _lastPriceEpochFinalizationType Finalization type of last finalized price epoch */ function getCurrentPriceDetails() external view returns ( uint256 _price, uint256 _priceTimestamp, PriceFinalizationType _priceFinalizationType, uint256 _lastPriceEpochFinalizationTimestamp, PriceFinalizationType _lastPriceEpochFinalizationType ); /** * @notice Returns current random number */ function getCurrentRandom() external view returns (uint256); }
./contracts/userInterfaces/IVPContractEvents.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; 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); }
./contracts/token/lib/PercentageDelegation.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "./CheckPointHistory.sol"; import "./DelegationHistory.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../utils/implementation/SafePct.sol"; /** * @title PercentageDelegation library * @notice Only handles percentage delegation * @notice A library to manage a group of _delegates for allocating voting power by a delegator. **/ library PercentageDelegation { using CheckPointHistory for CheckPointHistory.CheckPointHistoryState; using DelegationHistory for DelegationHistory.CheckPointHistoryState; using SafeMath for uint256; using SafePct for uint256; uint256 public constant MAX_BIPS = 10000; string private constant MAX_BIPS_MSG = "Max delegation bips exceeded"; /** * @dev `DelegationState` is the state structure used by this library to contain/manage * a grouing of _delegates (a PercentageDelegation) for a delegator. */ struct DelegationState { // percentages by _delegates DelegationHistory.CheckPointHistoryState delegation; } /** * @notice Add or replace an existing _delegate with allocated vote power in basis points. * @param _self A DelegationState instance to manage. * @param _delegate The address of the _delegate to add/replace * @param _bips Allocation of the delegation specified in basis points (1/100 of 1 percent) * @dev If you send a `_bips` of zero, `_delegate` will be deleted if one * exists in the delegation; if zero and `_delegate` does not exist, it will not be added. */ function addReplaceDelegate( DelegationState storage _self, address _delegate, uint256 _bips ) internal { // Check for max delegation basis points assert(_bips <= MAX_BIPS); // Change the delegate's percentage _self.delegation.writeValue(_delegate, _bips); // check the total require(_self.delegation.totalValueAtNow() <= MAX_BIPS, MAX_BIPS_MSG); } /** * @notice Get the total of the explicit vote power delegation bips of all delegates at given block. * @param _self A DelegationState instance to manage. * @param _blockNumber The block to query. * @return _totalBips The total vote power bips delegated. */ function getDelegatedTotalAt( DelegationState storage _self, uint256 _blockNumber ) internal view returns (uint256 _totalBips) { return _self.delegation.totalValueAt(_blockNumber); } /** * @notice Get the total of the bips vote power delegation bips of all _delegates. * @param _self A DelegationState instance to manage. * @return _totalBips The total vote power bips delegated. */ function getDelegatedTotal( DelegationState storage _self ) internal view returns (uint256 _totalBips) { return _self.delegation.totalValueAtNow(); } /** * @notice Given a _delegate address, return the bips of the vote power delegation. * @param _self A DelegationState instance to manage. * @param _delegate The delegate address to find. * @param _blockNumber The block to query. * @return _bips The percent of vote power allocated to the delegate address. */ function getDelegatedValueAt( DelegationState storage _self, address _delegate, uint256 _blockNumber ) internal view returns (uint256 _bips) { return _self.delegation.valueOfAt(_delegate, _blockNumber); } /** * @notice Given a delegate address, return the bips of the vote power delegation. * @param _self A DelegationState instance to manage. * @param _delegate The delegate address to find. * @return _bips The percent of vote power allocated to the delegate address. */ function getDelegatedValue( DelegationState storage _self, address _delegate ) internal view returns (uint256 _bips) { return _self.delegation.valueOfAtNow(_delegate); } /** * @notice Returns lists of delegate addresses and corresponding values at given block. * @param _self A DelegationState instance to manage. * @param _blockNumber The block to query. * @return _delegates Positional array of delegation addresses. * @return _values Positional array of delegation percents specified in basis points (1/100 or 1 percent) */ function getDelegationsAt( DelegationState storage _self, uint256 _blockNumber ) internal view returns ( address[] memory _delegates, uint256[] memory _values ) { return _self.delegation.delegationsAt(_blockNumber); } /** * @notice Returns lists of delegate addresses and corresponding values. * @param _self A DelegationState instance to manage. * @return _delegates Positional array of delegation addresses. * @return _values Positional array of delegation percents specified in basis points (1/100 or 1 percent) */ function getDelegations( DelegationState storage _self ) internal view returns ( address[] memory _delegates, uint256[] memory _values ) { return _self.delegation.delegationsAtNow(); } /** * Get all percentage delegations active now. * @param _self A CheckPointHistoryState instance to manage. * @return _length The number of delegations. * @return _delegations . **/ function getDelegationsRaw( DelegationState storage _self ) internal view returns ( uint256 _length, mapping(uint256 => DelegationHistory.Delegation) storage _delegations ) { return _self.delegation.delegationsAtNowRaw(); } /** * Get the number of delegations. * @param _self A DelegationState instance to manage. * @param _blockNumber The block number to query. * @return _count Count of delegations at the time. **/ function getCountAt( DelegationState storage _self, uint256 _blockNumber ) internal view returns (uint256 _count) { return _self.delegation.countAt(_blockNumber); } /** * Get the number of delegations. * @param _self A DelegationState instance to manage. * @return _count Count of delegations at the time. **/ function getCount( DelegationState storage _self ) internal view returns (uint256 _count) { return _self.delegation.countAt(block.number); } /** * @notice Get the total amount (absolute) of the vote power delegation of all delegates. * @param _self A DelegationState instance to manage. * @param _balance Owner's balance. * @return _totalAmount The total vote power amount delegated. */ function getDelegatedTotalAmountAt( DelegationState storage _self, uint256 _balance, uint256 _blockNumber ) internal view returns (uint256 _totalAmount) { return _self.delegation.scaledTotalValueAt(_balance, MAX_BIPS, _blockNumber); } /** * @notice Clears all delegates. * @param _self A DelegationState instance to manage. * @dev Delegation mode remains PERCENTAGE, even though the delgation is now empty. */ function clear(DelegationState storage _self) internal { _self.delegation.clear(); } /** * Delete at most `_count` of the oldest checkpoints. * At least one checkpoint at or before `_cleanupBlockNumber` will remain * (unless the history was empty to start with). */ function cleanupOldCheckpoints( DelegationState storage _self, uint256 _count, uint256 _cleanupBlockNumber ) internal returns (uint256) { return _self.delegation.cleanupOldCheckpoints(_count, _cleanupBlockNumber); } }
./contracts/token/lib/ExplicitDelegation.sol
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "./CheckPointsByAddress.sol"; import "./CheckPointHistory.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../utils/implementation/SafePct.sol"; /** * @title ExplicitDelegation library * @notice A library to manage a group of delegates for allocating voting power by a delegator. **/ library ExplicitDelegation { using CheckPointHistory for CheckPointHistory.CheckPointHistoryState; using CheckPointsByAddress for CheckPointsByAddress.CheckPointsByAddressState; using SafeMath for uint256; using SafePct for uint256; /** * @dev `DelegationState` is the state structure used by this library to contain/manage * a grouing of delegates (a ExplicitDelegation) for a delegator. */ struct DelegationState { CheckPointHistory.CheckPointHistoryState delegatedTotal; // `delegatedVotePower` is a map of delegators pointing to a map of delegates // containing a checkpoint history of delegated vote power balances. CheckPointsByAddress.CheckPointsByAddressState delegatedVotePower; } /** * @notice Add or replace an existing _delegate with new vote power (explicit). * @param _self A DelegationState instance to manage. * @param _delegate The address of the _delegate to add/replace * @param _amount Allocation of the delegation as explicit amount */ function addReplaceDelegate( DelegationState storage _self, address _delegate, uint256 _amount ) internal { uint256 prevAmount = _self.delegatedVotePower.valueOfAtNow(_delegate); uint256 newTotal = _self.delegatedTotal.valueAtNow().sub(prevAmount, "Total < 0").add(_amount); _self.delegatedVotePower.writeValue(_delegate, _amount); _self.delegatedTotal.writeValue(newTotal); } /** * Delete at most `_count` of the oldest checkpoints. * At least one checkpoint at or before `_cleanupBlockNumber` will remain * (unless the history was empty to start with). */ function cleanupOldCheckpoints( DelegationState storage _self, address _owner, uint256 _count, uint256 _cleanupBlockNumber ) internal returns(uint256 _deleted) { _deleted = _self.delegatedTotal.cleanupOldCheckpoints(_count, _cleanupBlockNumber); // safe: cleanupOldCheckpoints always returns the number of deleted elements which is small, so no owerflow _deleted += _self.delegatedVotePower.cleanupOldCheckpoints(_owner, _count, _cleanupBlockNumber); } /** * @notice Get the _total of the explicit vote power delegation amount. * @param _self A DelegationState instance to manage. * @param _blockNumber The block to query. * @return _total The _total vote power amount delegated. */ function getDelegatedTotalAt( DelegationState storage _self, uint256 _blockNumber ) internal view returns (uint256 _total) { return _self.delegatedTotal.valueAt(_blockNumber); } /** * @notice Get the _total of the explicit vote power delegation amount. * @param _self A DelegationState instance to manage. * @return _total The total vote power amount delegated. */ function getDelegatedTotal( DelegationState storage _self ) internal view returns (uint256 _total) { return _self.delegatedTotal.valueAtNow(); } /** * @notice Given a delegate address, return the explicit amount of the vote power delegation. * @param _self A DelegationState instance to manage. * @param _delegate The _delegate address to find. * @param _blockNumber The block to query. * @return _value The percent of vote power allocated to the _delegate address. */ function getDelegatedValueAt( DelegationState storage _self, address _delegate, uint256 _blockNumber ) internal view returns (uint256 _value) { return _self.delegatedVotePower.valueOfAt(_delegate, _blockNumber); } /** * @notice Given a delegate address, return the explicit amount of the vote power delegation. * @param _self A DelegationState instance to manage. * @param _delegate The _delegate address to find. * @return _value The percent of vote power allocated to the _delegate address. */ function getDelegatedValue( DelegationState storage _self, address _delegate ) internal view returns (uint256 _value) { return _self.delegatedVotePower.valueOfAtNow(_delegate); } }
./contracts/utils/interface/IIRandomProvider.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; interface IIRandomProvider { function chillNonrevealingDataProviders(uint256 _finalizingPriceEpochId, uint256 _currentPriceEpochId) external; function getCurrentRandom() external view returns(uint256 _currentRandom); function getCurrentRandomWithQuality() external view returns(uint256 _currentRandom, bool _goodRandom); }
@openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT 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); }
./contracts/userInterfaces/IGovernanceVotePower.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9; 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 of `msg.sender``. **/ 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 _votePower Governance vote power of `_who` at `_blockNumber`. */ function votePowerOfAt(address _who, uint256 _blockNumber) external view returns(uint256); /** * @notice Get the vote power of `account` at the current block. * @param account The address to get voting power. * @return Vote power of `account` at the current block number. */ function getVotes(address account) external view returns (uint256); /** * @notice Get the delegate's address of `_who` at block `_blockNumber` * @param _who The address to get delegate's address. * @param _blockNumber The block number at which to fetch. * @return Delegate's address of `_who` at `_blockNumber`. */ function getDelegateOfAt(address _who, uint256 _blockNumber) external view returns (address); /** * @notice Get the delegate's address of `_who` at the current block. * @param _who The address to get delegate's address. * @return Delegate's address of `_who` at the current block number. */ function getDelegateOfAtNow(address _who) external view returns (address); }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_governance","internalType":"address"},{"type":"address","name":"_flareDaemon","internalType":"contract FlareDaemon"},{"type":"address","name":"_addressUpdater","internalType":"address"},{"type":"address","name":"_treasury","internalType":"contract DistributionTreasury"},{"type":"uint256","name":"_totalEntitlementWei","internalType":"uint256"},{"type":"uint256","name":"_latestEntitlementStartTs","internalType":"uint256"}]},{"type":"event","name":"AccountClaimed","inputs":[{"type":"address","name":"whoClaimed","internalType":"address","indexed":true},{"type":"address","name":"sentTo","internalType":"address","indexed":true},{"type":"uint256","name":"month","internalType":"uint256","indexed":false},{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"AccountOptOut","inputs":[{"type":"address","name":"theAccount","internalType":"address","indexed":true},{"type":"bool","name":"confirmed","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"EntitlementStart","inputs":[{"type":"uint256","name":"entitlementStartTs","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"GovernanceCallTimelocked","inputs":[{"type":"bytes4","name":"selector","internalType":"bytes4","indexed":false},{"type":"uint256","name":"allowedAfterTimestamp","internalType":"uint256","indexed":false},{"type":"bytes","name":"encodedCall","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"GovernanceInitialised","inputs":[{"type":"address","name":"initialGovernance","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"GovernedProductionModeEntered","inputs":[{"type":"address","name":"governanceSettings","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"TimelockedGovernanceCallCanceled","inputs":[{"type":"bytes4","name":"selector","internalType":"bytes4","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"TimelockedGovernanceCallExecuted","inputs":[{"type":"bytes4","name":"selector","internalType":"bytes4","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"UseGoodRandomSet","inputs":[{"type":"bool","name":"useGoodRandom","internalType":"bool","indexed":false},{"type":"uint256","name":"maxWaitForGoodRandomSeconds","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"autoClaim","inputs":[{"type":"address[]","name":"_rewardOwners","internalType":"address[]"},{"type":"uint256","name":"_month","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelGovernanceCall","inputs":[{"type":"bytes4","name":"_selector","internalType":"bytes4"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"_rewardAmount","internalType":"uint256"}],"name":"claim","inputs":[{"type":"address","name":"_rewardOwner","internalType":"address"},{"type":"address","name":"_recipient","internalType":"address"},{"type":"uint256","name":"_month","internalType":"uint256"},{"type":"bool","name":"_wrap","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ClaimSetupManager"}],"name":"claimSetupManager","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IICombinedNatBalance"}],"name":"combinedNat","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"confirmOptOutOfAirdrop","inputs":[{"type":"address[]","name":"_optOutAddresses","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"daemonize","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"endBlockNumber","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"entitlementStartTs","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeGovernanceCall","inputs":[{"type":"bytes4","name":"_selector","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract FlareDaemon"}],"name":"flareDaemon","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"_addressUpdater","internalType":"address"}],"name":"getAddressUpdater","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_amountWei","internalType":"uint256"}],"name":"getClaimableAmount","inputs":[{"type":"uint256","name":"_month","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_amountWei","internalType":"uint256"}],"name":"getClaimableAmountOf","inputs":[{"type":"address","name":"_account","internalType":"address"},{"type":"uint256","name":"_month","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_startMonth","internalType":"uint256"},{"type":"uint256","name":"_endMonth","internalType":"uint256"}],"name":"getClaimableMonths","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"getContractName","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_currentMonth","internalType":"uint256"}],"name":"getCurrentMonth","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_monthToExpireNext","internalType":"uint256"}],"name":"getMonthToExpireNext","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_lockedFundsWei","internalType":"uint256"},{"type":"uint256","name":"_totalInflationAuthorizedWei","internalType":"uint256"},{"type":"uint256","name":"_totalClaimedWei","internalType":"uint256"}],"name":"getTokenPoolSupplyData","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"governance","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IGovernanceSettings"}],"name":"governanceSettings","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialise","inputs":[{"type":"address","name":"_initialGovernance","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"latestEntitlementStartTs","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxWaitForGoodRandomSeconds","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"nextClaimableMonth","inputs":[{"type":"address","name":"_rewardOwner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"optOut","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"optOutAddresses","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"optOutCandidate","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"optOutOfAirdrop","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IIRandomProvider"}],"name":"priceSubmitter","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"productionMode","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"sendFundsBackToTreasury","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setEntitlementStart","inputs":[{"type":"uint256","name":"_entitlementStartTs","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setUseGoodRandom","inputs":[{"type":"bool","name":"_useGoodRandom","internalType":"bool"},{"type":"uint256","name":"_maxWaitForGoodRandomSeconds","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"startBlockNumber","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"stop","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"stopped","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"switchToFallbackMode","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"switchToProductionMode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"allowedAfterTimestamp","internalType":"uint256"},{"type":"bytes","name":"encodedCall","internalType":"bytes"}],"name":"timelockedCalls","inputs":[{"type":"bytes4","name":"","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalAvailableAmount","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalBurnedWei","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalClaimedWei","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalDistributableAmount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalEntitlementWei","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalUnclaimedAmount","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalUnclaimedWeight","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract DistributionTreasury"}],"name":"treasury","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateContractAddresses","inputs":[{"type":"bytes32[]","name":"_contractNameHashes","internalType":"bytes32[]"},{"type":"address[]","name":"_contractAddresses","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateTotalEntitlementWei","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"useGoodRandom","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"votePowerBlockNumbers","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract WNat"}],"name":"wNat","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"waitingForGoodRandomSinceTs","inputs":[]},{"type":"receive","stateMutability":"payable"}]
Contract Creation Code
0x60e06040523480156200001157600080fd5b50604051620049c2380380620049c2833981810160405260c08110156200003757600080fd5b508051602082015160408301516060840151608085015160a090950151939492939192909183868681806001600160a01b038116156200007c576200007c81620002ce565b506001600160a01b038116620000cc576040805162461bcd60e51b815260206004820152601060248201526f5f676f7665726e616e6365207a65726f60801b604482015290519081900360640190fd5b506001600160a01b0381166200011d576040805162461bcd60e51b8152602060048201526011602482015270666c617265206461656d6f6e207a65726f60781b604482015290519081900360640190fd5b60601b6001600160601b0319166080525060016002556200013e8162000391565b5060408051808201909152600c81526b61646472657373207a65726f60a01b60208201526001600160a01b038416620001f85760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015620001bc578181015183820152602001620001a2565b50505050905090810190601f168015620001ea5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060408051808201909152600b81526a1a5b881d1a19481c185cdd60aa1b6020820152428210156200026d5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315620001bc578181015183820152602001620001a2565b506001600160601b0319606084901b1660c052600382905560a081905260078190556040805182815290517f6887b4fbe6e282072c586eed840058a3507439898b1521541253e5a78a41c69b9181900360200190a1505050505050620003b5565b600054600160a01b900460ff16156200032e576040805162461bcd60e51b815260206004820152601460248201527f696e697469616c6973656420213d2066616c7365000000000000000000000000604482015290519081900360640190fd5b60008054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b03831690811790915560408051918252517f9789733827840833afc031fb2ef9ab6894271f77bad2085687cf4ae5c7bee4db916020908290030190a150565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e771955565b60805160601c60a05160c05160601c6145ad620004156000398061036d5280610f5252806116d15280611ddf528061387452806138fe52806139925250806126ef5280612b7b5250806117f352806124505280612a5352506145ad6000f3fe6080604052600436106103395760003560e01c8063a1077532116101ab578063ddd1b67e116100f7578063f1e01c2211610095578063f5a983831161006f578063f5a9838314610d0a578063f5f5ba7214610d1f578063f937d6ad14610da9578063f94fcc6d14610dbe57610419565b8063f1e01c2214610cb6578063f2325e3814610ce0578063f2a1f76714610cf557610419565b8063e28ef1f7116100d1578063e28ef1f714610c23578063e4c1e96c14610c4d578063e60eb6ff14610c77578063f12d31ae14610c8c57610419565b8063ddd1b67e14610be4578063e17f212e14610bf9578063e22fdece14610c0e57610419565b8063b0b742ac11610164578063c4db96191161013e578063c4db961914610b5d578063cb063fa214610b72578063d461048314610b87578063d9d065c114610bba57610419565b8063b0b742ac14610ae8578063b23b6ef114610afd578063b2c1219214610b1257610419565b8063a107753214610932578063a90a38e114610947578063aa7579ac14610979578063ae6771611461098e578063af3267fe146109a3578063b00c0b76146109b857610419565b806361a30370116102855780637d8ca242116102235780638dc305fa116101fd5780638dc305fa1461085a5780639d6a890f146108d55780639edbf007146109085780639f71043e1461091d57610419565b80637d8ca242146107f15780638635f8981461081b57806389e6faa61461083057610419565b806367fc40291161025f57806367fc4029146106e05780636d0e8c341461071457806374e6310e1461072957806375f12b21146107dc57610419565b806361a303701461068c57806361d027b3146106b657806362354e03146106cb57610419565b8063257a7ee2116102f257806333cd2400116102cc57806333cd2400146105cb5780635267a15d146106125780635aa6e675146106435780635ff270791461065857610419565b8063257a7ee21461052f5780632dafdbbf1461055f5780632e6584521461059257610419565b8063023666481461041e57806302573715146104455780630732d2ea1461047357806307da68f51461048a57806315c29c5b1461049f578063220c1c16146104b457610419565b366104195760408051808201909152600d81526c7472656173757279206f6e6c7960981b6020820152336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146104165760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156103db5781810151838201526020016103c3565b50505050905090810190601f1680156104085780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50005b600080fd5b34801561042a57600080fd5b50610433610df1565b60408051918252519081900360200190f35b34801561045157600080fd5b5061045a610df7565b6040805192835260208301919091528051918290030190f35b34801561047f57600080fd5b50610488610f36565b005b34801561049657600080fd5b50610488610f8b565b3480156104ab57600080fd5b50610433610fa2565b3480156104c057600080fd5b50610488600480360360208110156104d757600080fd5b810190602081018135600160201b8111156104f157600080fd5b82018360208201111561050357600080fd5b803590602001918460208302840111600160201b8311171561052457600080fd5b509092509050610fa8565b34801561053b57600080fd5b506104336004803603604081101561055257600080fd5b508035906020013561114d565b34801561056b57600080fd5b5061057461117e565b60408051938452602084019290925282820152519081900360600190f35b34801561059e57600080fd5b50610433600480360360408110156105b557600080fd5b506001600160a01b0381351690602001356111dc565b3480156105d757600080fd5b506105fe600480360360208110156105ee57600080fd5b50356001600160a01b0316611280565b604080519115158252519081900360200190f35b34801561061e57600080fd5b50610627611295565b604080516001600160a01b039092168252519081900360200190f35b34801561064f57600080fd5b506106276112ba565b34801561066457600080fd5b506104886004803603602081101561067b57600080fd5b50356001600160e01b031916611350565b34801561069857600080fd5b50610627600480360360208110156106af57600080fd5b50356116a5565b3480156106c257600080fd5b506106276116cf565b3480156106d757600080fd5b506106276116f3565b3480156106ec57600080fd5b506104886004803603602081101561070357600080fd5b50356001600160e01b0319166116fe565b34801561072057600080fd5b506105fe6117e6565b34801561073557600080fd5b5061075d6004803603602081101561074c57600080fd5b50356001600160e01b031916611bdf565b6040518083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156107a0578181015183820152602001610788565b50505050905090810190601f1680156107cd5780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b3480156107e857600080fd5b506105fe611c85565b3480156107fd57600080fd5b506104336004803603602081101561081457600080fd5b5035611c8e565b34801561082757600080fd5b50610488611d2b565b34801561083c57600080fd5b506104336004803603602081101561085357600080fd5b5035611eda565b34801561086657600080fd5b506104886004803603604081101561087d57600080fd5b810190602081018135600160201b81111561089757600080fd5b8201836020820111156108a957600080fd5b803590602001918460208302840111600160201b831117156108ca57600080fd5b919350915035611eec565b3480156108e157600080fd5b50610488600480360360208110156108f857600080fd5b50356001600160a01b0316612380565b34801561091457600080fd5b50610627612439565b34801561092957600080fd5b50610433612448565b34801561093e57600080fd5b5061062761244e565b34801561095357600080fd5b506104886004803603604081101561096a57600080fd5b50803515159060200135612472565b34801561098557600080fd5b50610433612611565b34801561099a57600080fd5b506104336126ed565b3480156109af57600080fd5b50610433612711565b3480156109c457600080fd5b50610488600480360360408110156109db57600080fd5b810190602081018135600160201b8111156109f557600080fd5b820183602082011115610a0757600080fd5b803590602001918460208302840111600160201b83111715610a2857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b811115610a7757600080fd5b820183602082011115610a8957600080fd5b803590602001918460208302840111600160201b83111715610aaa57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550612717945050505050565b348015610af457600080fd5b506106276127be565b348015610b0957600080fd5b506104336127cd565b348015610b1e57600080fd5b5061043360048036036080811015610b3557600080fd5b506001600160a01b0381358116916020810135909116906040810135906060013515156127d3565b348015610b6957600080fd5b506106276129c3565b348015610b7e57600080fd5b506105fe6129d2565b348015610b9357600080fd5b506105fe60048036036020811015610baa57600080fd5b50356001600160a01b03166129e0565b348015610bc657600080fd5b5061043360048036036020811015610bdd57600080fd5b50356129f5565b348015610bf057600080fd5b50610433612a07565b348015610c0557600080fd5b506105fe612a36565b348015610c1a57600080fd5b506105fe612a46565b348015610c2f57600080fd5b5061048860048036036020811015610c4657600080fd5b5035612abf565b348015610c5957600080fd5b5061043360048036036020811015610c7057600080fd5b5035612c64565b348015610c8357600080fd5b50610433612c76565b348015610c9857600080fd5b5061043360048036036020811015610caf57600080fd5b5035612c7c565b348015610cc257600080fd5b5061043360048036036020811015610cd957600080fd5b5035612c8e565b348015610cec57600080fd5b50610433612ca0565b348015610d0157600080fd5b50610488612ca6565b348015610d1657600080fd5b50610488612d81565b348015610d2b57600080fd5b50610d34612e3b565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610d6e578181015183820152602001610d56565b50505050905090810190601f168015610d9b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b348015610db557600080fd5b50610627612e72565b348015610dca57600080fd5b5061043360048036036020811015610de157600080fd5b50356001600160a01b0316612e81565b60055481565b6008546040805180820190915260128152716e6f206d6f6e746820636c61696d61626c6560701b6020820152600091829190600160801b90046001600160801b0316610e845760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b50610e8d612611565b6008549092506000196001600160801b03600160801b909204821601169050808211801590610ebc5750602482105b6040518060400160405280601081526020016f185b1c9958591e48199a5b9a5cda195960821b81525090610f315760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b509091565b610f3e612e9c565b600654600090610f78906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001631612efb565b9050600354811015610f8657fe5b600355565b610f93612e9c565b6013805460ff19166001179055565b60145481565b600054600160b01b900460ff1680610fca5750600054600160a81b900460ff16155b1561113e57610fd7612f5e565b8060005b81811015611137576000848483818110610ff157fe5b602090810292909201356001600160a01b0316600081815260108452604090819020548151808301909252600d82526c1b9bdd081bdc1d1959081bdd5d609a1b948201949094529093509160ff16905061108c5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b5061109681612f93565b6001600160a01b0381166000818152601160209081526040808320805460ff1916600190811790915560128054808301825594527fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec344490930180546001600160a01b031916851790558051928352517f82b45541b9ba7a8fe574a801f120df904cff6cde36bee6c217c9514949aa0cb89281900390910190a250600101610fdb565b5050611149565b611149600036613023565b5050565b600b602052816000526040600020818154811061116957600080fd5b90600052602060002001600091509150505481565b6013546000908190819060ff16611197576003546111b8565b6111b8476111b2600554600454612efb90919063ffffffff16565b90612efb565b9250600091506111d5600554600454612efb90919063ffffffff16565b9050909192565b600042600754106040518060400160405280600b81526020016a1b9bdd081cdd185c9d195960aa1b815250906112535760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b5061125d83612f93565b61126e611268612611565b836131a6565b6112788383613329565b949350505050565b60106020526000908152604090205460ff1681565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e77195490565b60008054600160a81b900460ff166112dd576000546001600160a01b031661134a565b60076001609c1b016001600160a01b031663732524946040518163ffffffff1660e01b815260040160206040518083038186803b15801561131d57600080fd5b505afa158015611331573d6000803e3d6000fd5b505050506040513d602081101561134757600080fd5b50515b90505b90565b60408051630debfda360e41b8152336004820152905160076001609c1b019163debfda30916024808301926020929190829003018186803b15801561139457600080fd5b505afa1580156113a8573d6000803e3d6000fd5b505050506040513d60208110156113be57600080fd5b5051611401576040805162461bcd60e51b815260206004820152600d60248201526c37b7363c9032bc32b1baba37b960991b604482015290519081900360640190fd5b6001600160e01b031981166000908152600160205260409020805461146d576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b80544210156114c3576040805162461bcd60e51b815260206004820152601960248201527f74696d656c6f636b3a206e6f7420616c6c6f7765642079657400000000000000604482015290519081900360640190fd5b6000816001018054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561155d5780601f106115325761010080835404028352916020019161155d565b820191906000526020600020905b81548152906001019060200180831161154057829003601f168201915b5050506001600160e01b0319861660009081526001602081905260408220828155949550909250611591915083018261443b565b50506000805460ff60b01b1916600160b01b178155604051825130918491819060208401908083835b602083106115d95780518252601f1990920191602091820191016115ba565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461163b576040519150601f19603f3d011682016040523d82523d6000602084013e611640565b606091505b50506000805460ff60b01b19169055604080516001600160e01b03198716815242602082015281519293507fa7326b57fc9cfe267aaea5e7f0b01757154d265620a0585819416ee9ddd2c438929081900390910190a161169f816134e4565b50505050565b601281815481106116b557600080fd5b6000918252602090912001546001600160a01b0316905081565b7f000000000000000000000000000000000000000000000000000000000000000081565b60076001609c1b0181565b611706612e9c565b6001600160e01b03198116600090815260016020526040902054611771576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b604080516001600160e01b03198316815242602082015281517f7735b2391c38a81419c513e30ca578db7158eadd7101511b23e221c654d19cf8929181900390910190a16001600160e01b031981166000908152600160208190526040822082815591906117e19083018261443b565b505050565b6000336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611859576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b6002805414156118b0576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b600280556007544210806118d2575060085460246001600160801b0390911610155b156118df57506000611b57565b60006118f66007544261350190919063ffffffff16565b905060006119078262278d0061355e565b905062278d008102820360006119208262093a8061355e565b90506000811180156119325750602483105b801561194a5750600083815260096020526040902054155b156119615760008381526009602052604090204390555b600083118015611972575060248311155b801561198f575060001983016000908152600a6020526040902054155b156119ab5760001983016000908152600a602052604090204390555b6018546040805163deea13e760e01b815290516000926001600160a01b03169163deea13e7916004808301926020929190829003018186803b1580156119f057600080fd5b505afa158015611a04573d6000803e3d6000fd5b505050506040513d6020811015611a1a57600080fd5b50516008546001600160801b03166000908152600960205260409020549091508015801590611a4857508181105b15611ae8576008546001600160801b03166000908152600d6020526040812054611a7290476135c5565b600880546001600160801b03808216600101166fffffffffffffffffffffffffffffffff1990911617905590508015611ae657600554611ab29082612efb565b60055560405161dead9082156108fc029083906000818181858888f19350505050158015611ae4573d6000803e3d6000fd5b505b505b600085118015611af9575060248511155b8015611b1b57506008546001600160801b03600160801b909104166000198601145b8015611b2a575060135460ff16155b15611b4c57611b3b600186036135db565b15611b4c57611b4c60018603613830565b600196505050505050505b600160025547611b656139f4565b11156040518060400160405280600f81526020016e62616c616e636520746f6f206c6f7760881b81525090611bdb5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b5090565b600160208181526000928352604092839020805481840180548651600296821615610100026000190190911695909504601f81018590048502860185019096528585529094919392909190830182828015611c7b5780601f10611c5057610100808354040283529160200191611c7b565b820191906000526020600020905b815481529060010190602001808311611c5e57829003601f168201915b5050505050905082565b60135460ff1681565b600042600754106040518060400160405280600b81526020016a1b9bdd081cdd185c9d195960aa1b81525090611d055760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b50611d0f33612f93565b611d1a611268612611565b611d243383613329565b9392505050565b600054600160b01b900460ff1680611d4d5750600054600160a81b900460ff16155b15611ecd57611d5a612f5e565b60135460408051808201909152600b81526a1b9bdd081cdd1bdc1c195960aa1b60208201529060ff16611dce5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b506040516000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169047908381818185875af1925050503d8060008114611e3a576040519150601f19603f3d011682016040523d82523d6000602084013e611e3f565b606091505b50509050806040518060400160405280601981526020017f73656e64696e672066756e6473206261636b206661696c65640000000000000081525090611ec65760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b5050611ed8565b611ed8600036613023565b565b600a6020526000908152604090205481565b42600754106040518060400160405280600b81526020016a1b9bdd081cdd185c9d195960aa1b81525090611f615760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b506013546040805180820190915260078152661cdd1bdc1c195960ca1b60208201529060ff1615611fd35760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b5060028054141561202b576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002805560005b828110156120665761205e84848381811061204957fe5b905060200201356001600160a01b0316613a29565b600101612032565b506000612071612611565b905061207d81836131a6565b6019546040805163712441d960e11b81523360048201818152602483019384526044830188905260009485946001600160a01b039091169363e24883b293928b928b92606401846020850280828437600081840152601f19601f82011690508083019250505094505050505060006040518083038186803b15801561210157600080fd5b505afa158015612115573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604090815281101561213e57600080fd5b8101908080516040519392919084600160201b82111561215d57600080fd5b90830190602082018581111561217257600080fd5b82518660208202830111600160201b8211171561218e57600080fd5b82525081516020918201928201910280838360005b838110156121bb5781810151838201526020016121a3565b50505050919091016040525060200151929450919250600091508190505b868110156122d15760008888838181106121ef57fe5b905060200201356001600160a01b03169050600085838151811061220f57fe5b6020908102919091018101516001600160a01b03841660009081526011909252604082205490925060ff1661224c5761224a83838a8c613aa3565b015b816001600160a01b0316836001600160a01b0316146122735761227182838a8c613aa3565b015b60408051808201909152601881527f636c61696d656420616d6f756e7420746f6f20736d616c6c00000000000000006020820152948101946122b89082908890613bc5565b90506122c682826001613c1f565b5050506001016121d9565b506004546122df9082612efb565b6004556122f7336122f08489613d67565b6000613c1f565b505060016002555047905061230a6139f4565b11156040518060400160405280600f81526020016e62616c616e636520746f6f206c6f7760881b8152509061169f5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b600054600160a01b900460ff16156123d6576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b60008054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b03831690811790915560408051918252517f9789733827840833afc031fb2ef9ab6894271f77bad2085687cf4ae5c7bee4db916020908290030190a150565b6018546001600160a01b031681565b60045481565b7f000000000000000000000000000000000000000000000000000000000000000081565b600054600160b01b900460ff16806124945750600054600160a81b900460ff16155b1561113e576124a1612f5e565b8115612537576000811180156124ba575062093a808111155b60405180604001604052806012815260200171696e76616c696420706172616d657465727360701b815250906125315760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b506125b4565b604080518082019091526012815271696e76616c696420706172616d657465727360701b602082015281156125ad5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b5060006015555b6013805461ff001916610100841515908102919091179091556014829055604080519182526020820183905280517f5c9bf067f2a8b23128e64d5ce119251f51d6c0c24e0d7bf430c2dd77df3ec0929281900390910190a1611149565b600080601860009054906101000a90046001600160a01b03166001600160a01b031663deea13e76040518163ffffffff1660e01b815260040160206040518083038186803b15801561266257600080fd5b505afa158015612676573d6000803e3d6000fd5b505050506040513d602081101561268c57600080fd5b50516008546001600160801b031660009081526009602052604090205490915080158015906126ba57508181105b156126da5750506008546001600160801b0390811660010116905061134d565b50506008546001600160801b0316905090565b7f000000000000000000000000000000000000000000000000000000000000000081565b60065481565b61271f611295565b6001600160a01b0316336001600160a01b03161461277b576040805162461bcd60e51b815260206004820152601460248201527337b7363c9030b2323932b9b9903ab83230ba32b960611b604482015290519081900360640190fd5b6127b46127af83836040518060400160405280600e81526020016d20b2323932b9b9aab83230ba32b960911b815250613dc0565b613eed565b6111498282613f11565b6017546001600160a01b031681565b60155481565b600042600754106040518060400160405280600b81526020016a1b9bdd081cdd185c9d195960aa1b8152509061284a5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b506013546040805180820190915260078152661cdd1bdc1c195960ca1b60208201529060ff16156128bc5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b50600280541415612914576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002805584846129248282614061565b612930878787876140ee565b6001600255925047915061294490506139f4565b11156040518060400160405280600f81526020016e62616c616e636520746f6f206c6f7760881b815250906129ba5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b50949350505050565b6019546001600160a01b031681565b601354610100900460ff1681565b60116020526000908152604090205460ff1681565b600d6020526000908152604090205481565b600080612a1f6007544261414290919063ffffffff16565b9150612a3090508162278d0061355e565b91505090565b600054600160a81b900460ff1681565b6000336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612ab9576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b50600090565b600054600160b01b900460ff1680612ae15750600054600160a81b900460ff16155b15612c5657612aee612f5e565b42600754116040518060400160405280600f81526020016e185b1c9958591e481cdd185c9d1959608a1b81525090612b675760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b50621274ff1942018110801590612b9e57507f00000000000000000000000000000000000000000000000000000000000000008111155b60405180604001604052806015815260200174077726f6e672073746172742074696d657374616d7605c1b81525090612c185760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b5060078190556040805182815290517f6887b4fbe6e282072c586eed840058a3507439898b1521541253e5a78a41c69b9181900360200190a1612c61565b612c61600036613023565b50565b600c6020526000908152604090205481565b60075481565b600e6020526000908152604090205481565b60096020526000908152604090205481565b60035481565b336000908152601060209081526040918290205482518084019093526011835270185b1c9958591e481bdc1d1959081bdd5d607a1b9183019190915260ff1615612d315760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b50336000818152601060209081526040808320805460ff191660011790558051928352517f82b45541b9ba7a8fe574a801f120df904cff6cde36bee6c217c9514949aa0cb89281900390910190a2565b612d89612e9c565b600054600160a81b900460ff1615612de8576040805162461bcd60e51b815260206004820152601a60248201527f616c726561647920696e2070726f64756374696f6e206d6f6465000000000000604482015290519081900360640190fd5b60008054600161ff0160a01b031916600160a81b1790556040805160076001609c1b01815290517f83af113638b5422f9e977cebc0aaf0eaf2188eb9a8baae7f9d46c42b33a1560c9181900360200190a1565b60408051808201909152601881527f446973747269627574696f6e546f44656c656761746f72730000000000000000602082015290565b6016546001600160a01b031681565b6000612e9482612e8f612611565b614164565b90505b919050565b612ea46112ba565b6001600160a01b0316336001600160a01b031614611ed8576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600082820183811015612f55576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b600054600160b01b900460ff1615612f8b57333014612f7957fe5b6000805460ff60b01b19169055611ed8565b611ed8612e9c565b6001600160a01b03811660009081526011602081815260409283902054835180850190945291835270185b1c9958591e481bdc1d1959081bdd5d607a1b9083015260ff16156111495760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b61302b612e9c565b600082359050600060076001609c1b016001600160a01b0316636221a54b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561307357600080fd5b505afa158015613087573d6000803e3d6000fd5b505050506040513d602081101561309d57600080fd5b505160408051808201825242830180825282516020601f89018190048102820181019094528781529394509290918281019190889088908190840183828082843760009201829052509390945250506001600160e01b031986168152600160208181526040909220845181558483015180519194506131219392850192019061447f565b509050507fed948300a3694aa01d4a6b258bfd664350193d770c0b51f8387277f6d83ea3b68382878760405180856001600160e01b0319168152602001848152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f191690920182900397509095505050505050a15050505050565b60408051808201909152600d81526c1b5bdb9d1a08195e1c1a5c9959609a1b6020820152818311156132195760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b506040805180820190915260138152726d6f6e7468206e6f7420636c61696d61626c6560681b6020820152602482106132935760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b5060085460408051808201909152601781527f6d6f6e7468206e6f7420636c61696d61626c6520796574000000000000000000602082015290600160801b90046001600160801b031682106117e15760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b6001600160a01b0382166000908152600f60205260408120548190831015613356575060009050806134dd565b6000838152600d6020526040902054806133775760008092509250506134dd565b6000848152600b60209081526040808320805482518185028101850190935280835291929091908301828280156133cd57602002820191906000526020600020905b8154815260200190600101908083116133b9575b5050505050905060005b600381101561348a5760175482516001600160a01b0390911690634ee2cd7e90899085908590811061340557fe5b60200260200101516040518363ffffffff1660e01b815260040180836001600160a01b031681526020018281526020019250505060206040518083038186803b15801561345157600080fd5b505afa158015613465573d6000803e3d6000fd5b505050506040513d602081101561347b57600080fd5b505194909401936001016133d7565b508361349e576000809350935050506134dd565b6000858152600e6020526040902054848114156134c057509091506134dd9050565b8085106134c957fe5b846134d5848284614187565b945094505050505b9250929050565b3d604051818101604052816000823e82156134fd578181f35b8181fd5b600082821115613558576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60008082116135b4576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b8183816135bd57fe5b049392505050565b60008183106135d45781612f55565b5090919050565b6013546000908190610100900460ff16156136b6576016546040805163a978fb6b60e01b815281516000936001600160a01b03169263a978fb6b9260048082019391829003018186803b15801561363157600080fd5b505afa158015613645573d6000803e3d6000fd5b505050506040513d604081101561365b57600080fd5b5080516020909101519092509050806136aa5760155461368357505042601555506000612e97565b42601454601554011161369a5760006015556136a5565b600092505050612e97565b6136b0565b60006015555b50613735565b601660009054906101000a90046001600160a01b03166001600160a01b031663d89601fd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561370457600080fd5b505afa158015613718573d6000803e3d6000fd5b505050506040513d602081101561372e57600080fd5b5051420190505b600083815260096020908152604080832054600a909252808320548151600380825260808201909352929390928484038390049281602001602082028036833701905050905060005b60038110156137e95760408051602080820198909852808201839052815180820383018152606090910190915280519601959095209460008387816137bf57fe5b068483028701019050808383815181106137d557fe5b60209081029190910101525060010161377e565b506000878152600b60209081526040909120825161380992840190614507565b506138138161428d565b6000888152600e6020526040902055506001945050505050919050565b600061384b6138436001840160ed613d67565b6121346135c5565b9050600061392c6138fc600654613871856121346003546141879092919063ffffffff16565b037f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166329d71f6d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156138cb57600080fd5b505afa1580156138df573d6000803e3d6000fd5b505050506040513d60208110156138f557600080fd5b50516135c5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316316135c5565b6000848152600c60209081526040808320849055600d9091528082208390556006805484019055600880546001600160801b03600189018116600160801b029116179055805163ec8d877760e01b81526004810184905290519293506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263ec8d87779260248084019391929182900301818387803b1580156139d757600080fd5b505af11580156139eb573d6000803e3d6000fd5b50505050505050565b60135460009060ff16612ab957613a24600554613a1e60045460065461350190919063ffffffff16565b90613501565b61134a565b60408051808201909152600e81526d726563697069656e74207a65726f60901b60208201526001600160a01b0382166111495760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b600080613ab08685614164565b90505b828111613b7b57600080613ac78884613329565b90925090508015613b71576000838152600d6020526040902054613aeb9082613501565b6000848152600d6020908152604080832093909355600e90522054613b109083613501565b6000848152600e60209081526040918290209290925580518581529182018390528051958301956001600160a01b03808b1693908c16927fbdb59bec3f0c77052f6645d7365d5008c0affb5d51489a220d01bb1af96897b092918290030190a35b5050600101613ab3565b506001600160a01b0385166000908152600f6020526040902054600183011115611278576001600160a01b0385166000908152600f60205260409020600183019055949350505050565b60008184841115613c175760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b505050900390565b81156117e1578015613c9a576018546040805163b760faf960e01b81526001600160a01b0386811660048301529151919092169163b760faf991859160248082019260009290919082900301818588803b158015613c7c57600080fd5b505af1158015613c90573d6000803e3d6000fd5b50505050506117e1565b6040516000906001600160a01b0385169084908381818185875af1925050503d8060008114613ce5576040519150601f19603f3d011682016040523d82523d6000602084013e613cea565b606091505b50509050806040518060400160405280600c81526020016b18db185a5b4819985a5b195960a21b81525090613d605760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b5050505050565b600082613d7657506000612f58565b82820282848281613d8357fe5b0414612f555760405162461bcd60e51b81526004018080602001828103825260218152602001806145576021913960400191505060405180910390fd5b600080826040516020018080602001828103825283818151815260200191508051906020019080838360005b83811015613e04578181015183820152602001613dec565b50505050905090810190601f168015613e315780820380516001836020036101000a031916815260200191505b50925050506040516020818303038152906040528051906020012090506000805b8651811015613e9957868181518110613e6757fe5b6020026020010151831415613e9157858181518110613e8257fe5b60200260200101519150613e99565b600101613e52565b506001600160a01b038116613ee4576040805162461bcd60e51b815260206004820152600c60248201526b61646472657373207a65726f60a01b604482015290519081900360640190fd5b95945050505050565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e771955565b613f3882826040518060400160405280600481526020016315d3985d60e21b815250613dc0565b601860006101000a8154816001600160a01b0302191690836001600160a01b03160217905550613f9282826040518060400160405280601181526020017021b630b4b6a9b2ba3ab826b0b730b3b2b960791b815250613dc0565b601960006101000a8154816001600160a01b0302191690836001600160a01b03160217905550613fe982826040518060400160405280600e81526020016d283934b1b2a9bab136b4ba3a32b960911b815250613dc0565b601660006101000a8154816001600160a01b0302191690836001600160a01b0316021790555061403d82826040518060400160405280600b81526020016a10dbdb589a5b995913985d60aa1b815250613dc0565b601780546001600160a01b0319166001600160a01b03929092169190911790555050565b336001600160a01b038316141561407757611149565b6019546040805163ce2caa5760e01b81523360048201526001600160a01b03858116602483015284811660448301529151919092169163ce2caa57916064808301926000929190829003018186803b1580156140d257600080fd5b505afa1580156140e6573d6000803e3d6000fd5b505050505050565b60006140f984613a29565b61410285612f93565b600061410c612611565b905061411881856131a6565b61412486868387613aa3565b6004549092506141349083612efb565b6004556129ba858385613c1f565b60008083831115614158575060009050806134dd565b50600193919092039150565b6001600160a01b0382166000908152600f6020526040812054612f55908361442b565b60008082116141d0576040805162461bcd60e51b815260206004820152601060248201526f4469766973696f6e206279207a65726f60801b604482015290519081900360640190fd5b836141dd57506000611d24565b838302838582816141ea57fe5b041415614203578281816141fa57fe5b04915050611d24565b600083868161420e57fe5b049050600084878161421c57fe5b069050600085878161422a57fe5b049050600086888161423857fe5b0690506142806142528861424c8685613d67565b9061355e565b6111b261425f8686613d67565b6111b261426c8987613d67565b6111b28d61427a8c8b613d67565b90613d67565b9998505050505050505050565b6000805b60038110156143325760175483516001600160a01b039091169063981b24d0908590849081106142bd57fe5b60200260200101516040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156142f957600080fd5b505afa15801561430d573d6000803e3d6000fd5b505050506040513d602081101561432357600080fd5b50519190910190600101614291565b506012545b80156144255780806001900391505060006012828154811061435557fe5b60009182526020822001546001600160a01b031691505b600381101561441e5760175485516001600160a01b0390911690634ee2cd7e90849088908590811061439a57fe5b60200260200101516040518363ffffffff1660e01b815260040180836001600160a01b031681526020018281526020019250505060206040518083038186803b1580156143e657600080fd5b505afa1580156143fa573d6000803e3d6000fd5b505050506040513d602081101561441057600080fd5b50519093039260010161436c565b5050614337565b50919050565b6000818310156135d45781612f55565b50805460018160011615610100020316600290046000825580601f106144615750612c61565b601f016020900490600052602060002090810190612c619190614541565b828054600181600116156101000203166002900490600052602060002090601f0160209004810192826144b557600085556144fb565b82601f106144ce57805160ff19168380011785556144fb565b828001600101855582156144fb579182015b828111156144fb5782518255916020019190600101906144e0565b50611bdb929150614541565b8280548282559060005260206000209081019282156144fb57916020028201828111156144fb5782518255916020019190600101906144e0565b5b80821115611bdb576000815560010161454256fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a26469706673582212202b7a96e33877ad4add6a3e5eade68e93d98c565135721ee0a077fa7bef4c166c64736f6c634300070600330000000000000000000000004598a6c05910ab914f0cbaaca1911cd337d10d290000000000000000000000001000000000000000000000000000000000000002000000000000000000000000f0de0df69d63c1f5e841f4964550c3dabad6d24e000000000000000000000000cf3007b342f9c17afbe11bf3fba278517b44c30300000000000000000000000000000000000000004e57f8ff28b15816cd6e3ac00000000000000000000000000000000000000000000000000000000064602480
Deployed ByteCode
0x6080604052600436106103395760003560e01c8063a1077532116101ab578063ddd1b67e116100f7578063f1e01c2211610095578063f5a983831161006f578063f5a9838314610d0a578063f5f5ba7214610d1f578063f937d6ad14610da9578063f94fcc6d14610dbe57610419565b8063f1e01c2214610cb6578063f2325e3814610ce0578063f2a1f76714610cf557610419565b8063e28ef1f7116100d1578063e28ef1f714610c23578063e4c1e96c14610c4d578063e60eb6ff14610c77578063f12d31ae14610c8c57610419565b8063ddd1b67e14610be4578063e17f212e14610bf9578063e22fdece14610c0e57610419565b8063b0b742ac11610164578063c4db96191161013e578063c4db961914610b5d578063cb063fa214610b72578063d461048314610b87578063d9d065c114610bba57610419565b8063b0b742ac14610ae8578063b23b6ef114610afd578063b2c1219214610b1257610419565b8063a107753214610932578063a90a38e114610947578063aa7579ac14610979578063ae6771611461098e578063af3267fe146109a3578063b00c0b76146109b857610419565b806361a30370116102855780637d8ca242116102235780638dc305fa116101fd5780638dc305fa1461085a5780639d6a890f146108d55780639edbf007146109085780639f71043e1461091d57610419565b80637d8ca242146107f15780638635f8981461081b57806389e6faa61461083057610419565b806367fc40291161025f57806367fc4029146106e05780636d0e8c341461071457806374e6310e1461072957806375f12b21146107dc57610419565b806361a303701461068c57806361d027b3146106b657806362354e03146106cb57610419565b8063257a7ee2116102f257806333cd2400116102cc57806333cd2400146105cb5780635267a15d146106125780635aa6e675146106435780635ff270791461065857610419565b8063257a7ee21461052f5780632dafdbbf1461055f5780632e6584521461059257610419565b8063023666481461041e57806302573715146104455780630732d2ea1461047357806307da68f51461048a57806315c29c5b1461049f578063220c1c16146104b457610419565b366104195760408051808201909152600d81526c7472656173757279206f6e6c7960981b6020820152336001600160a01b037f000000000000000000000000cf3007b342f9c17afbe11bf3fba278517b44c30316146104165760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156103db5781810151838201526020016103c3565b50505050905090810190601f1680156104085780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50005b600080fd5b34801561042a57600080fd5b50610433610df1565b60408051918252519081900360200190f35b34801561045157600080fd5b5061045a610df7565b6040805192835260208301919091528051918290030190f35b34801561047f57600080fd5b50610488610f36565b005b34801561049657600080fd5b50610488610f8b565b3480156104ab57600080fd5b50610433610fa2565b3480156104c057600080fd5b50610488600480360360208110156104d757600080fd5b810190602081018135600160201b8111156104f157600080fd5b82018360208201111561050357600080fd5b803590602001918460208302840111600160201b8311171561052457600080fd5b509092509050610fa8565b34801561053b57600080fd5b506104336004803603604081101561055257600080fd5b508035906020013561114d565b34801561056b57600080fd5b5061057461117e565b60408051938452602084019290925282820152519081900360600190f35b34801561059e57600080fd5b50610433600480360360408110156105b557600080fd5b506001600160a01b0381351690602001356111dc565b3480156105d757600080fd5b506105fe600480360360208110156105ee57600080fd5b50356001600160a01b0316611280565b604080519115158252519081900360200190f35b34801561061e57600080fd5b50610627611295565b604080516001600160a01b039092168252519081900360200190f35b34801561064f57600080fd5b506106276112ba565b34801561066457600080fd5b506104886004803603602081101561067b57600080fd5b50356001600160e01b031916611350565b34801561069857600080fd5b50610627600480360360208110156106af57600080fd5b50356116a5565b3480156106c257600080fd5b506106276116cf565b3480156106d757600080fd5b506106276116f3565b3480156106ec57600080fd5b506104886004803603602081101561070357600080fd5b50356001600160e01b0319166116fe565b34801561072057600080fd5b506105fe6117e6565b34801561073557600080fd5b5061075d6004803603602081101561074c57600080fd5b50356001600160e01b031916611bdf565b6040518083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156107a0578181015183820152602001610788565b50505050905090810190601f1680156107cd5780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b3480156107e857600080fd5b506105fe611c85565b3480156107fd57600080fd5b506104336004803603602081101561081457600080fd5b5035611c8e565b34801561082757600080fd5b50610488611d2b565b34801561083c57600080fd5b506104336004803603602081101561085357600080fd5b5035611eda565b34801561086657600080fd5b506104886004803603604081101561087d57600080fd5b810190602081018135600160201b81111561089757600080fd5b8201836020820111156108a957600080fd5b803590602001918460208302840111600160201b831117156108ca57600080fd5b919350915035611eec565b3480156108e157600080fd5b50610488600480360360208110156108f857600080fd5b50356001600160a01b0316612380565b34801561091457600080fd5b50610627612439565b34801561092957600080fd5b50610433612448565b34801561093e57600080fd5b5061062761244e565b34801561095357600080fd5b506104886004803603604081101561096a57600080fd5b50803515159060200135612472565b34801561098557600080fd5b50610433612611565b34801561099a57600080fd5b506104336126ed565b3480156109af57600080fd5b50610433612711565b3480156109c457600080fd5b50610488600480360360408110156109db57600080fd5b810190602081018135600160201b8111156109f557600080fd5b820183602082011115610a0757600080fd5b803590602001918460208302840111600160201b83111715610a2857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b811115610a7757600080fd5b820183602082011115610a8957600080fd5b803590602001918460208302840111600160201b83111715610aaa57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550612717945050505050565b348015610af457600080fd5b506106276127be565b348015610b0957600080fd5b506104336127cd565b348015610b1e57600080fd5b5061043360048036036080811015610b3557600080fd5b506001600160a01b0381358116916020810135909116906040810135906060013515156127d3565b348015610b6957600080fd5b506106276129c3565b348015610b7e57600080fd5b506105fe6129d2565b348015610b9357600080fd5b506105fe60048036036020811015610baa57600080fd5b50356001600160a01b03166129e0565b348015610bc657600080fd5b5061043360048036036020811015610bdd57600080fd5b50356129f5565b348015610bf057600080fd5b50610433612a07565b348015610c0557600080fd5b506105fe612a36565b348015610c1a57600080fd5b506105fe612a46565b348015610c2f57600080fd5b5061048860048036036020811015610c4657600080fd5b5035612abf565b348015610c5957600080fd5b5061043360048036036020811015610c7057600080fd5b5035612c64565b348015610c8357600080fd5b50610433612c76565b348015610c9857600080fd5b5061043360048036036020811015610caf57600080fd5b5035612c7c565b348015610cc257600080fd5b5061043360048036036020811015610cd957600080fd5b5035612c8e565b348015610cec57600080fd5b50610433612ca0565b348015610d0157600080fd5b50610488612ca6565b348015610d1657600080fd5b50610488612d81565b348015610d2b57600080fd5b50610d34612e3b565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610d6e578181015183820152602001610d56565b50505050905090810190601f168015610d9b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b348015610db557600080fd5b50610627612e72565b348015610dca57600080fd5b5061043360048036036020811015610de157600080fd5b50356001600160a01b0316612e81565b60055481565b6008546040805180820190915260128152716e6f206d6f6e746820636c61696d61626c6560701b6020820152600091829190600160801b90046001600160801b0316610e845760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b50610e8d612611565b6008549092506000196001600160801b03600160801b909204821601169050808211801590610ebc5750602482105b6040518060400160405280601081526020016f185b1c9958591e48199a5b9a5cda195960821b81525090610f315760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b509091565b610f3e612e9c565b600654600090610f78906001600160a01b037f000000000000000000000000cf3007b342f9c17afbe11bf3fba278517b44c3031631612efb565b9050600354811015610f8657fe5b600355565b610f93612e9c565b6013805460ff19166001179055565b60145481565b600054600160b01b900460ff1680610fca5750600054600160a81b900460ff16155b1561113e57610fd7612f5e565b8060005b81811015611137576000848483818110610ff157fe5b602090810292909201356001600160a01b0316600081815260108452604090819020548151808301909252600d82526c1b9bdd081bdc1d1959081bdd5d609a1b948201949094529093509160ff16905061108c5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b5061109681612f93565b6001600160a01b0381166000818152601160209081526040808320805460ff1916600190811790915560128054808301825594527fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec344490930180546001600160a01b031916851790558051928352517f82b45541b9ba7a8fe574a801f120df904cff6cde36bee6c217c9514949aa0cb89281900390910190a250600101610fdb565b5050611149565b611149600036613023565b5050565b600b602052816000526040600020818154811061116957600080fd5b90600052602060002001600091509150505481565b6013546000908190819060ff16611197576003546111b8565b6111b8476111b2600554600454612efb90919063ffffffff16565b90612efb565b9250600091506111d5600554600454612efb90919063ffffffff16565b9050909192565b600042600754106040518060400160405280600b81526020016a1b9bdd081cdd185c9d195960aa1b815250906112535760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b5061125d83612f93565b61126e611268612611565b836131a6565b6112788383613329565b949350505050565b60106020526000908152604090205460ff1681565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e77195490565b60008054600160a81b900460ff166112dd576000546001600160a01b031661134a565b60076001609c1b016001600160a01b031663732524946040518163ffffffff1660e01b815260040160206040518083038186803b15801561131d57600080fd5b505afa158015611331573d6000803e3d6000fd5b505050506040513d602081101561134757600080fd5b50515b90505b90565b60408051630debfda360e41b8152336004820152905160076001609c1b019163debfda30916024808301926020929190829003018186803b15801561139457600080fd5b505afa1580156113a8573d6000803e3d6000fd5b505050506040513d60208110156113be57600080fd5b5051611401576040805162461bcd60e51b815260206004820152600d60248201526c37b7363c9032bc32b1baba37b960991b604482015290519081900360640190fd5b6001600160e01b031981166000908152600160205260409020805461146d576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b80544210156114c3576040805162461bcd60e51b815260206004820152601960248201527f74696d656c6f636b3a206e6f7420616c6c6f7765642079657400000000000000604482015290519081900360640190fd5b6000816001018054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561155d5780601f106115325761010080835404028352916020019161155d565b820191906000526020600020905b81548152906001019060200180831161154057829003601f168201915b5050506001600160e01b0319861660009081526001602081905260408220828155949550909250611591915083018261443b565b50506000805460ff60b01b1916600160b01b178155604051825130918491819060208401908083835b602083106115d95780518252601f1990920191602091820191016115ba565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461163b576040519150601f19603f3d011682016040523d82523d6000602084013e611640565b606091505b50506000805460ff60b01b19169055604080516001600160e01b03198716815242602082015281519293507fa7326b57fc9cfe267aaea5e7f0b01757154d265620a0585819416ee9ddd2c438929081900390910190a161169f816134e4565b50505050565b601281815481106116b557600080fd5b6000918252602090912001546001600160a01b0316905081565b7f000000000000000000000000cf3007b342f9c17afbe11bf3fba278517b44c30381565b60076001609c1b0181565b611706612e9c565b6001600160e01b03198116600090815260016020526040902054611771576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b604080516001600160e01b03198316815242602082015281517f7735b2391c38a81419c513e30ca578db7158eadd7101511b23e221c654d19cf8929181900390910190a16001600160e01b031981166000908152600160208190526040822082815591906117e19083018261443b565b505050565b6000336001600160a01b037f00000000000000000000000010000000000000000000000000000000000000021614611859576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b6002805414156118b0576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b600280556007544210806118d2575060085460246001600160801b0390911610155b156118df57506000611b57565b60006118f66007544261350190919063ffffffff16565b905060006119078262278d0061355e565b905062278d008102820360006119208262093a8061355e565b90506000811180156119325750602483105b801561194a5750600083815260096020526040902054155b156119615760008381526009602052604090204390555b600083118015611972575060248311155b801561198f575060001983016000908152600a6020526040902054155b156119ab5760001983016000908152600a602052604090204390555b6018546040805163deea13e760e01b815290516000926001600160a01b03169163deea13e7916004808301926020929190829003018186803b1580156119f057600080fd5b505afa158015611a04573d6000803e3d6000fd5b505050506040513d6020811015611a1a57600080fd5b50516008546001600160801b03166000908152600960205260409020549091508015801590611a4857508181105b15611ae8576008546001600160801b03166000908152600d6020526040812054611a7290476135c5565b600880546001600160801b03808216600101166fffffffffffffffffffffffffffffffff1990911617905590508015611ae657600554611ab29082612efb565b60055560405161dead9082156108fc029083906000818181858888f19350505050158015611ae4573d6000803e3d6000fd5b505b505b600085118015611af9575060248511155b8015611b1b57506008546001600160801b03600160801b909104166000198601145b8015611b2a575060135460ff16155b15611b4c57611b3b600186036135db565b15611b4c57611b4c60018603613830565b600196505050505050505b600160025547611b656139f4565b11156040518060400160405280600f81526020016e62616c616e636520746f6f206c6f7760881b81525090611bdb5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b5090565b600160208181526000928352604092839020805481840180548651600296821615610100026000190190911695909504601f81018590048502860185019096528585529094919392909190830182828015611c7b5780601f10611c5057610100808354040283529160200191611c7b565b820191906000526020600020905b815481529060010190602001808311611c5e57829003601f168201915b5050505050905082565b60135460ff1681565b600042600754106040518060400160405280600b81526020016a1b9bdd081cdd185c9d195960aa1b81525090611d055760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b50611d0f33612f93565b611d1a611268612611565b611d243383613329565b9392505050565b600054600160b01b900460ff1680611d4d5750600054600160a81b900460ff16155b15611ecd57611d5a612f5e565b60135460408051808201909152600b81526a1b9bdd081cdd1bdc1c195960aa1b60208201529060ff16611dce5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b506040516000906001600160a01b037f000000000000000000000000cf3007b342f9c17afbe11bf3fba278517b44c303169047908381818185875af1925050503d8060008114611e3a576040519150601f19603f3d011682016040523d82523d6000602084013e611e3f565b606091505b50509050806040518060400160405280601981526020017f73656e64696e672066756e6473206261636b206661696c65640000000000000081525090611ec65760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b5050611ed8565b611ed8600036613023565b565b600a6020526000908152604090205481565b42600754106040518060400160405280600b81526020016a1b9bdd081cdd185c9d195960aa1b81525090611f615760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b506013546040805180820190915260078152661cdd1bdc1c195960ca1b60208201529060ff1615611fd35760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b5060028054141561202b576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002805560005b828110156120665761205e84848381811061204957fe5b905060200201356001600160a01b0316613a29565b600101612032565b506000612071612611565b905061207d81836131a6565b6019546040805163712441d960e11b81523360048201818152602483019384526044830188905260009485946001600160a01b039091169363e24883b293928b928b92606401846020850280828437600081840152601f19601f82011690508083019250505094505050505060006040518083038186803b15801561210157600080fd5b505afa158015612115573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604090815281101561213e57600080fd5b8101908080516040519392919084600160201b82111561215d57600080fd5b90830190602082018581111561217257600080fd5b82518660208202830111600160201b8211171561218e57600080fd5b82525081516020918201928201910280838360005b838110156121bb5781810151838201526020016121a3565b50505050919091016040525060200151929450919250600091508190505b868110156122d15760008888838181106121ef57fe5b905060200201356001600160a01b03169050600085838151811061220f57fe5b6020908102919091018101516001600160a01b03841660009081526011909252604082205490925060ff1661224c5761224a83838a8c613aa3565b015b816001600160a01b0316836001600160a01b0316146122735761227182838a8c613aa3565b015b60408051808201909152601881527f636c61696d656420616d6f756e7420746f6f20736d616c6c00000000000000006020820152948101946122b89082908890613bc5565b90506122c682826001613c1f565b5050506001016121d9565b506004546122df9082612efb565b6004556122f7336122f08489613d67565b6000613c1f565b505060016002555047905061230a6139f4565b11156040518060400160405280600f81526020016e62616c616e636520746f6f206c6f7760881b8152509061169f5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b600054600160a01b900460ff16156123d6576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b60008054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b03831690811790915560408051918252517f9789733827840833afc031fb2ef9ab6894271f77bad2085687cf4ae5c7bee4db916020908290030190a150565b6018546001600160a01b031681565b60045481565b7f000000000000000000000000100000000000000000000000000000000000000281565b600054600160b01b900460ff16806124945750600054600160a81b900460ff16155b1561113e576124a1612f5e565b8115612537576000811180156124ba575062093a808111155b60405180604001604052806012815260200171696e76616c696420706172616d657465727360701b815250906125315760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b506125b4565b604080518082019091526012815271696e76616c696420706172616d657465727360701b602082015281156125ad5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b5060006015555b6013805461ff001916610100841515908102919091179091556014829055604080519182526020820183905280517f5c9bf067f2a8b23128e64d5ce119251f51d6c0c24e0d7bf430c2dd77df3ec0929281900390910190a1611149565b600080601860009054906101000a90046001600160a01b03166001600160a01b031663deea13e76040518163ffffffff1660e01b815260040160206040518083038186803b15801561266257600080fd5b505afa158015612676573d6000803e3d6000fd5b505050506040513d602081101561268c57600080fd5b50516008546001600160801b031660009081526009602052604090205490915080158015906126ba57508181105b156126da5750506008546001600160801b0390811660010116905061134d565b50506008546001600160801b0316905090565b7f000000000000000000000000000000000000000000000000000000006460248081565b60065481565b61271f611295565b6001600160a01b0316336001600160a01b03161461277b576040805162461bcd60e51b815260206004820152601460248201527337b7363c9030b2323932b9b9903ab83230ba32b960611b604482015290519081900360640190fd5b6127b46127af83836040518060400160405280600e81526020016d20b2323932b9b9aab83230ba32b960911b815250613dc0565b613eed565b6111498282613f11565b6017546001600160a01b031681565b60155481565b600042600754106040518060400160405280600b81526020016a1b9bdd081cdd185c9d195960aa1b8152509061284a5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b506013546040805180820190915260078152661cdd1bdc1c195960ca1b60208201529060ff16156128bc5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b50600280541415612914576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002805584846129248282614061565b612930878787876140ee565b6001600255925047915061294490506139f4565b11156040518060400160405280600f81526020016e62616c616e636520746f6f206c6f7760881b815250906129ba5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b50949350505050565b6019546001600160a01b031681565b601354610100900460ff1681565b60116020526000908152604090205460ff1681565b600d6020526000908152604090205481565b600080612a1f6007544261414290919063ffffffff16565b9150612a3090508162278d0061355e565b91505090565b600054600160a81b900460ff1681565b6000336001600160a01b037f00000000000000000000000010000000000000000000000000000000000000021614612ab9576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b50600090565b600054600160b01b900460ff1680612ae15750600054600160a81b900460ff16155b15612c5657612aee612f5e565b42600754116040518060400160405280600f81526020016e185b1c9958591e481cdd185c9d1959608a1b81525090612b675760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b50621274ff1942018110801590612b9e57507f00000000000000000000000000000000000000000000000000000000646024808111155b60405180604001604052806015815260200174077726f6e672073746172742074696d657374616d7605c1b81525090612c185760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b5060078190556040805182815290517f6887b4fbe6e282072c586eed840058a3507439898b1521541253e5a78a41c69b9181900360200190a1612c61565b612c61600036613023565b50565b600c6020526000908152604090205481565b60075481565b600e6020526000908152604090205481565b60096020526000908152604090205481565b60035481565b336000908152601060209081526040918290205482518084019093526011835270185b1c9958591e481bdc1d1959081bdd5d607a1b9183019190915260ff1615612d315760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b50336000818152601060209081526040808320805460ff191660011790558051928352517f82b45541b9ba7a8fe574a801f120df904cff6cde36bee6c217c9514949aa0cb89281900390910190a2565b612d89612e9c565b600054600160a81b900460ff1615612de8576040805162461bcd60e51b815260206004820152601a60248201527f616c726561647920696e2070726f64756374696f6e206d6f6465000000000000604482015290519081900360640190fd5b60008054600161ff0160a01b031916600160a81b1790556040805160076001609c1b01815290517f83af113638b5422f9e977cebc0aaf0eaf2188eb9a8baae7f9d46c42b33a1560c9181900360200190a1565b60408051808201909152601881527f446973747269627574696f6e546f44656c656761746f72730000000000000000602082015290565b6016546001600160a01b031681565b6000612e9482612e8f612611565b614164565b90505b919050565b612ea46112ba565b6001600160a01b0316336001600160a01b031614611ed8576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600082820183811015612f55576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b600054600160b01b900460ff1615612f8b57333014612f7957fe5b6000805460ff60b01b19169055611ed8565b611ed8612e9c565b6001600160a01b03811660009081526011602081815260409283902054835180850190945291835270185b1c9958591e481bdc1d1959081bdd5d607a1b9083015260ff16156111495760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b61302b612e9c565b600082359050600060076001609c1b016001600160a01b0316636221a54b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561307357600080fd5b505afa158015613087573d6000803e3d6000fd5b505050506040513d602081101561309d57600080fd5b505160408051808201825242830180825282516020601f89018190048102820181019094528781529394509290918281019190889088908190840183828082843760009201829052509390945250506001600160e01b031986168152600160208181526040909220845181558483015180519194506131219392850192019061447f565b509050507fed948300a3694aa01d4a6b258bfd664350193d770c0b51f8387277f6d83ea3b68382878760405180856001600160e01b0319168152602001848152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f191690920182900397509095505050505050a15050505050565b60408051808201909152600d81526c1b5bdb9d1a08195e1c1a5c9959609a1b6020820152818311156132195760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b506040805180820190915260138152726d6f6e7468206e6f7420636c61696d61626c6560681b6020820152602482106132935760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b5060085460408051808201909152601781527f6d6f6e7468206e6f7420636c61696d61626c6520796574000000000000000000602082015290600160801b90046001600160801b031682106117e15760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b6001600160a01b0382166000908152600f60205260408120548190831015613356575060009050806134dd565b6000838152600d6020526040902054806133775760008092509250506134dd565b6000848152600b60209081526040808320805482518185028101850190935280835291929091908301828280156133cd57602002820191906000526020600020905b8154815260200190600101908083116133b9575b5050505050905060005b600381101561348a5760175482516001600160a01b0390911690634ee2cd7e90899085908590811061340557fe5b60200260200101516040518363ffffffff1660e01b815260040180836001600160a01b031681526020018281526020019250505060206040518083038186803b15801561345157600080fd5b505afa158015613465573d6000803e3d6000fd5b505050506040513d602081101561347b57600080fd5b505194909401936001016133d7565b508361349e576000809350935050506134dd565b6000858152600e6020526040902054848114156134c057509091506134dd9050565b8085106134c957fe5b846134d5848284614187565b945094505050505b9250929050565b3d604051818101604052816000823e82156134fd578181f35b8181fd5b600082821115613558576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60008082116135b4576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b8183816135bd57fe5b049392505050565b60008183106135d45781612f55565b5090919050565b6013546000908190610100900460ff16156136b6576016546040805163a978fb6b60e01b815281516000936001600160a01b03169263a978fb6b9260048082019391829003018186803b15801561363157600080fd5b505afa158015613645573d6000803e3d6000fd5b505050506040513d604081101561365b57600080fd5b5080516020909101519092509050806136aa5760155461368357505042601555506000612e97565b42601454601554011161369a5760006015556136a5565b600092505050612e97565b6136b0565b60006015555b50613735565b601660009054906101000a90046001600160a01b03166001600160a01b031663d89601fd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561370457600080fd5b505afa158015613718573d6000803e3d6000fd5b505050506040513d602081101561372e57600080fd5b5051420190505b600083815260096020908152604080832054600a909252808320548151600380825260808201909352929390928484038390049281602001602082028036833701905050905060005b60038110156137e95760408051602080820198909852808201839052815180820383018152606090910190915280519601959095209460008387816137bf57fe5b068483028701019050808383815181106137d557fe5b60209081029190910101525060010161377e565b506000878152600b60209081526040909120825161380992840190614507565b506138138161428d565b6000888152600e6020526040902055506001945050505050919050565b600061384b6138436001840160ed613d67565b6121346135c5565b9050600061392c6138fc600654613871856121346003546141879092919063ffffffff16565b037f000000000000000000000000cf3007b342f9c17afbe11bf3fba278517b44c3036001600160a01b03166329d71f6d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156138cb57600080fd5b505afa1580156138df573d6000803e3d6000fd5b505050506040513d60208110156138f557600080fd5b50516135c5565b7f000000000000000000000000cf3007b342f9c17afbe11bf3fba278517b44c3036001600160a01b0316316135c5565b6000848152600c60209081526040808320849055600d9091528082208390556006805484019055600880546001600160801b03600189018116600160801b029116179055805163ec8d877760e01b81526004810184905290519293506001600160a01b037f000000000000000000000000cf3007b342f9c17afbe11bf3fba278517b44c303169263ec8d87779260248084019391929182900301818387803b1580156139d757600080fd5b505af11580156139eb573d6000803e3d6000fd5b50505050505050565b60135460009060ff16612ab957613a24600554613a1e60045460065461350190919063ffffffff16565b90613501565b61134a565b60408051808201909152600e81526d726563697069656e74207a65726f60901b60208201526001600160a01b0382166111495760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b600080613ab08685614164565b90505b828111613b7b57600080613ac78884613329565b90925090508015613b71576000838152600d6020526040902054613aeb9082613501565b6000848152600d6020908152604080832093909355600e90522054613b109083613501565b6000848152600e60209081526040918290209290925580518581529182018390528051958301956001600160a01b03808b1693908c16927fbdb59bec3f0c77052f6645d7365d5008c0affb5d51489a220d01bb1af96897b092918290030190a35b5050600101613ab3565b506001600160a01b0385166000908152600f6020526040902054600183011115611278576001600160a01b0385166000908152600f60205260409020600183019055949350505050565b60008184841115613c175760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b505050900390565b81156117e1578015613c9a576018546040805163b760faf960e01b81526001600160a01b0386811660048301529151919092169163b760faf991859160248082019260009290919082900301818588803b158015613c7c57600080fd5b505af1158015613c90573d6000803e3d6000fd5b50505050506117e1565b6040516000906001600160a01b0385169084908381818185875af1925050503d8060008114613ce5576040519150601f19603f3d011682016040523d82523d6000602084013e613cea565b606091505b50509050806040518060400160405280600c81526020016b18db185a5b4819985a5b195960a21b81525090613d605760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156103db5781810151838201526020016103c3565b5050505050565b600082613d7657506000612f58565b82820282848281613d8357fe5b0414612f555760405162461bcd60e51b81526004018080602001828103825260218152602001806145576021913960400191505060405180910390fd5b600080826040516020018080602001828103825283818151815260200191508051906020019080838360005b83811015613e04578181015183820152602001613dec565b50505050905090810190601f168015613e315780820380516001836020036101000a031916815260200191505b50925050506040516020818303038152906040528051906020012090506000805b8651811015613e9957868181518110613e6757fe5b6020026020010151831415613e9157858181518110613e8257fe5b60200260200101519150613e99565b600101613e52565b506001600160a01b038116613ee4576040805162461bcd60e51b815260206004820152600c60248201526b61646472657373207a65726f60a01b604482015290519081900360640190fd5b95945050505050565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e771955565b613f3882826040518060400160405280600481526020016315d3985d60e21b815250613dc0565b601860006101000a8154816001600160a01b0302191690836001600160a01b03160217905550613f9282826040518060400160405280601181526020017021b630b4b6a9b2ba3ab826b0b730b3b2b960791b815250613dc0565b601960006101000a8154816001600160a01b0302191690836001600160a01b03160217905550613fe982826040518060400160405280600e81526020016d283934b1b2a9bab136b4ba3a32b960911b815250613dc0565b601660006101000a8154816001600160a01b0302191690836001600160a01b0316021790555061403d82826040518060400160405280600b81526020016a10dbdb589a5b995913985d60aa1b815250613dc0565b601780546001600160a01b0319166001600160a01b03929092169190911790555050565b336001600160a01b038316141561407757611149565b6019546040805163ce2caa5760e01b81523360048201526001600160a01b03858116602483015284811660448301529151919092169163ce2caa57916064808301926000929190829003018186803b1580156140d257600080fd5b505afa1580156140e6573d6000803e3d6000fd5b505050505050565b60006140f984613a29565b61410285612f93565b600061410c612611565b905061411881856131a6565b61412486868387613aa3565b6004549092506141349083612efb565b6004556129ba858385613c1f565b60008083831115614158575060009050806134dd565b50600193919092039150565b6001600160a01b0382166000908152600f6020526040812054612f55908361442b565b60008082116141d0576040805162461bcd60e51b815260206004820152601060248201526f4469766973696f6e206279207a65726f60801b604482015290519081900360640190fd5b836141dd57506000611d24565b838302838582816141ea57fe5b041415614203578281816141fa57fe5b04915050611d24565b600083868161420e57fe5b049050600084878161421c57fe5b069050600085878161422a57fe5b049050600086888161423857fe5b0690506142806142528861424c8685613d67565b9061355e565b6111b261425f8686613d67565b6111b261426c8987613d67565b6111b28d61427a8c8b613d67565b90613d67565b9998505050505050505050565b6000805b60038110156143325760175483516001600160a01b039091169063981b24d0908590849081106142bd57fe5b60200260200101516040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156142f957600080fd5b505afa15801561430d573d6000803e3d6000fd5b505050506040513d602081101561432357600080fd5b50519190910190600101614291565b506012545b80156144255780806001900391505060006012828154811061435557fe5b60009182526020822001546001600160a01b031691505b600381101561441e5760175485516001600160a01b0390911690634ee2cd7e90849088908590811061439a57fe5b60200260200101516040518363ffffffff1660e01b815260040180836001600160a01b031681526020018281526020019250505060206040518083038186803b1580156143e657600080fd5b505afa1580156143fa573d6000803e3d6000fd5b505050506040513d602081101561441057600080fd5b50519093039260010161436c565b5050614337565b50919050565b6000818310156135d45781612f55565b50805460018160011615610100020316600290046000825580601f106144615750612c61565b601f016020900490600052602060002090810190612c619190614541565b828054600181600116156101000203166002900490600052602060002090601f0160209004810192826144b557600085556144fb565b82601f106144ce57805160ff19168380011785556144fb565b828001600101855582156144fb579182015b828111156144fb5782518255916020019190600101906144e0565b50611bdb929150614541565b8280548282559060005260206000209081019282156144fb57916020028201828111156144fb5782518255916020019190600101906144e0565b5b80821115611bdb576000815560010161454256fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a26469706673582212202b7a96e33877ad4add6a3e5eade68e93d98c565135721ee0a077fa7bef4c166c64736f6c63430007060033