Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
0x60806040 | 8485474 | 1718 days ago | IN | Create: Pool | 0 ETH | 0.08602295 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract contains unverified libraries: DrawManager, FixidityLib
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Pool
Compiler Version
v0.5.10+commit.5a6ea5b1
Contract Source Code (Solidity Standard Json-Input format)
/** Copyright 2019 PoolTogether LLC This file is part of PoolTogether. PoolTogether is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation under version 3 of the License. PoolTogether is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with PoolTogether. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.5.10; import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts-ethereum-package/contracts/utils/ReentrancyGuard.sol"; import "@openzeppelin/contracts-ethereum-package/contracts/access/Roles.sol"; import "./compound/ICErc20.sol"; import "./DrawManager.sol"; import "fixidity/contracts/FixidityLib.sol"; import "@openzeppelin/upgrades/contracts/Initializable.sol"; /** * @title The Pool contract * @author Brendan Asselstine * @notice This contract allows users to pool deposits into Compound and win the accrued interest in periodic draws. * Funds are immediately deposited and withdrawn from the Compound cToken contract. * Draws go through three stages: open, committed and rewarded in that order. * Only one draw is ever in the open stage. Users deposits are always added to the open draw. Funds in the open Draw are that user's open balance. * When a Draw is committed, the funds in it are moved to a user's committed total and the total committed balance of all users is updated. * When a Draw is rewarded, the gross winnings are the accrued interest since the last reward (if any). A winner is selected with their chances being * proportional to their committed balance vs the total committed balance of all users. * * * With the above in mind, there is always an open draw and possibly a committed draw. The progression is: * * Step 1: Draw 1 Open * Step 2: Draw 2 Open | Draw 1 Committed * Step 3: Draw 3 Open | Draw 2 Committed | Draw 1 Rewarded * Step 4: Draw 4 Open | Draw 3 Committed | Draw 2 Rewarded * Step 5: Draw 5 Open | Draw 4 Committed | Draw 3 Rewarded * Step X: ... */ contract Pool is Initializable, ReentrancyGuard { using DrawManager for DrawManager.State; using SafeMath for uint256; using Roles for Roles.Role; uint256 private constant ETHER_IN_WEI = 1000000000000000000; /** * Emitted when a user deposits into the Pool. * @param sender The purchaser of the tickets * @param amount The size of the deposit */ event Deposited(address indexed sender, uint256 amount); /** * Emitted when Sponsors have deposited into the Pool * @param sender The purchaser of the tickets * @param amount The size of the deposit */ event SponsorshipDeposited(address indexed sender, uint256 amount); /** * Emitted when an admin has been added to the Pool. * @param admin The admin that was added */ event AdminAdded(address indexed admin); /** * Emitted when an admin has been removed from the Pool. * @param admin The admin that was removed */ event AdminRemoved(address indexed admin); /** * Emitted when a user withdraws from the pool. * @param sender The user that is withdrawing from the pool * @param amount The amount that the user withdrew */ event Withdrawn(address indexed sender, uint256 amount); /** * Emitted when a new draw is opened for deposit. * @param drawId The draw id * @param feeBeneficiary The fee beneficiary for this draw * @param secretHash The committed secret hash * @param feeFraction The fee fraction of the winnings to be given to the beneficiary */ event Opened( uint256 indexed drawId, address indexed feeBeneficiary, bytes32 secretHash, uint256 feeFraction ); /** * Emitted when a draw is committed. * @param drawId The draw id */ event Committed( uint256 indexed drawId ); /** * Emitted when a draw is rewarded. * @param drawId The draw id * @param winner The address of the winner * @param entropy The entropy used to select the winner * @param winnings The net winnings given to the winner * @param fee The fee being given to the draw beneficiary */ event Rewarded( uint256 indexed drawId, address indexed winner, bytes32 entropy, uint256 winnings, uint256 fee ); /** * Emitted when the fee fraction is changed. Takes effect on the next draw. * @param feeFraction The next fee fraction encoded as a fixed point 18 decimal */ event NextFeeFractionChanged(uint256 feeFraction); /** * Emitted when the next fee beneficiary changes. Takes effect on the next draw. * @param feeBeneficiary The next fee beneficiary */ event NextFeeBeneficiaryChanged(address indexed feeBeneficiary); /** * Emitted when an admin pauses the contract */ event Paused(address indexed sender); /** * Emitted when an admin unpauses the contract */ event Unpaused(address indexed sender); struct Draw { uint256 feeFraction; //fixed point 18 address feeBeneficiary; uint256 openedBlock; bytes32 secretHash; } /** * The Compound cToken that this Pool is bound to. */ ICErc20 public cToken; /** * The fee beneficiary to use for subsequent Draws. */ address public nextFeeBeneficiary; /** * The fee fraction to use for subsequent Draws. */ uint256 public nextFeeFraction; /** * The total of all balances */ uint256 public accountedBalance; /** * The total deposits and winnings for each user. */ mapping (address => uint256) balances; /** * A mapping of draw ids to Draw structures */ mapping(uint256 => Draw) draws; /** * A structure that is used to manage the user's odds of winning. */ DrawManager.State drawState; /** * A structure containing the administrators */ Roles.Role admins; /** * Whether the contract is paused */ bool public paused; /** * @notice Initializes a new Pool contract. * @param _owner The owner of the Pool. They are able to change settings and are set as the owner of new lotteries. * @param _cToken The Compound Finance MoneyMarket contract to supply and withdraw tokens. * @param _feeFraction The fraction of the gross winnings that should be transferred to the owner as the fee. Is a fixed point 18 number. * @param _feeBeneficiary The address that will receive the fee fraction */ function init ( address _owner, address _cToken, uint256 _feeFraction, address _feeBeneficiary ) public initializer { require(_owner != address(0), "owner cannot be the null address"); require(_cToken != address(0), "money market address is zero"); cToken = ICErc20(_cToken); _addAdmin(_owner); _setNextFeeFraction(_feeFraction); _setNextFeeBeneficiary(_feeBeneficiary); } /** * @notice Opens a new Draw. * @param _secretHash The secret hash to commit to the Draw. */ function open(bytes32 _secretHash) internal { drawState.openNextDraw(); draws[drawState.openDrawIndex] = Draw(nextFeeFraction, nextFeeBeneficiary, block.number, _secretHash); emit Opened( drawState.openDrawIndex, nextFeeBeneficiary, _secretHash, nextFeeFraction ); } /** * @notice Commits the current draw. */ function commit() internal { uint256 drawId = currentOpenDrawId(); emit Committed(drawId); } /** * @notice Commits the current open draw, if any, and opens the next draw using the passed hash. Really this function is only called twice: * the first after Pool contract creation and the second immediately after. * Can only be called by an admin. * May fire the Committed event, and always fires the Open event. * @param nextSecretHash The secret hash to use to open a new Draw */ function openNextDraw(bytes32 nextSecretHash) public onlyAdmin unlessPaused { require(currentCommittedDrawId() == 0, "there is a committed draw"); if (currentOpenDrawId() != 0) { commit(); } open(nextSecretHash); } /** * @notice Rewards the current committed draw using the passed secret, commits the current open draw, and opens the next draw using the passed secret hash. * Can only be called by an admin. * Fires the Rewarded event, the Committed event, and the Open event. * @param nextSecretHash The secret hash to use to open a new Draw * @param lastSecret The secret to reveal to reward the current committed Draw. */ function rewardAndOpenNextDraw(bytes32 nextSecretHash, bytes32 lastSecret, bytes32 _salt) public onlyAdmin unlessPaused { require(currentCommittedDrawId() != 0, "a draw has not been committed"); reward(lastSecret, _salt); commit(); open(nextSecretHash); } /** * @notice Rewards the winner for the current committed Draw using the passed secret. * The gross winnings are calculated by subtracting the accounted balance from the current underlying cToken balance. * A winner is calculated using the revealed secret and a hash of the Draw's opened block and the gross winnings. * If there is a winner (i.e. any eligible users) then winner's balance is updated with their net winnings. * The draw beneficiary's balance is updated with the fee. * The accounted balance is updated to include the fee and, if there was a winner, the net winnings. * Fires the Rewarded event. * @param _secret The secret to reveal for the current committed Draw */ function reward(bytes32 _secret, bytes32 _salt) internal { uint256 drawId = currentCommittedDrawId(); Draw storage draw = draws[drawId]; require(draw.secretHash == keccak256(abi.encodePacked(_secret, _salt)), "secret does not match"); // Calculate the gross winnings uint256 underlyingBalance = balance(); uint256 grossWinnings = underlyingBalance.sub(accountedBalance); // derive entropy from the revealed secret and the hash of the openedBlock and gross winnings bytes32 entropy = _secret ^ keccak256(abi.encodePacked(draw.openedBlock, grossWinnings)); // Select the winner using the hash as entropy address winningAddress = calculateWinner(entropy); // Calculate the beneficiary fee uint256 fee = calculateFee(draw.feeFraction, grossWinnings); // Update balance of the beneficiary balances[draw.feeBeneficiary] = balances[draw.feeBeneficiary].add(fee); // Calculate the net winnings uint256 netWinnings = grossWinnings.sub(fee); // If there is a winner who is to receive non-zero winnings if (winningAddress != address(0) && netWinnings != 0) { // Update balance of the winner balances[winningAddress] = balances[winningAddress].add(netWinnings); // Enter their winnings into the next draw drawState.deposit(winningAddress, netWinnings); // Updated the accounted total accountedBalance = underlyingBalance; } else { // Only account for the fee accountedBalance = accountedBalance.add(fee); } // Destroy the draw now that it's complete delete draws[drawId]; emit Rewarded( drawId, winningAddress, entropy, netWinnings, fee ); } /** * @notice Calculate the beneficiary fee using the passed fee fraction and gross winnings. * @param _feeFraction The fee fraction, between 0 and 1, represented as a 18 point fixed number. * @param _grossWinnings The gross winnings to take a fraction of. */ function calculateFee(uint256 _feeFraction, uint256 _grossWinnings) internal pure returns (uint256) { int256 grossWinningsFixed = FixidityLib.newFixed(int256(_grossWinnings)); int256 feeFixed = FixidityLib.multiply(grossWinningsFixed, FixidityLib.newFixed(int256(_feeFraction), uint8(18))); return uint256(FixidityLib.fromFixed(feeFixed)); } /** * @notice Allows a user to deposit a sponsorship amount. The deposit is transferred into the cToken. * Sponsorships allow a user to contribute to the pool without becoming eligible to win. They can withdraw their sponsorship at any time. * The deposit will immediately be added to Compound and the interest will contribute to the next draw. * @param _amount The amount of the token underlying the cToken to deposit. */ function depositSponsorship(uint256 _amount) public nonReentrant unlessPaused { // Deposit the funds _deposit(_amount); emit SponsorshipDeposited(msg.sender, _amount); } /** * @notice Deposits into the pool under the current open Draw. The deposit is transferred into the cToken. * Once the open draw is committed, the deposit will be added to the user's total committed balance and increase their chances of winning * proportional to the total committed balance of all users. * @param _amount The amount of the token underlying the cToken to deposit. */ function depositPool(uint256 _amount) public requireOpenDraw nonReentrant unlessPaused { // Update the user's eligibility drawState.deposit(msg.sender, _amount); // Deposit the funds _deposit(_amount); emit Deposited(msg.sender, _amount); } /** * @notice Transfers tokens from the sender into the Compound cToken contract and updates the accountedBalance. * @param _amount The amount of the token underlying the cToken to deposit. */ function _deposit(uint256 _amount) internal { require(_amount > 0, "deposit is not greater than zero"); // Transfer the tokens into this contract require(token().transferFrom(msg.sender, address(this), _amount), "token transfer failed"); // Update the user's balance balances[msg.sender] = balances[msg.sender].add(_amount); // Update the total of this contract accountedBalance = accountedBalance.add(_amount); // Deposit into Compound require(token().approve(address(cToken), _amount), "could not approve money market spend"); require(cToken.mint(_amount) == 0, "could not supply money market"); } /** * @notice Withdraw the sender's entire balance back to them. */ function withdraw() public nonReentrant { uint balance = balances[msg.sender]; require(balance > 0, "balance has already been withdrawn"); // Update the user's balance balances[msg.sender] = 0; // Update their chances of winning drawState.withdraw(msg.sender); _withdraw(balance); } /** * @notice Transfers tokens from the cToken contract to the sender. Updates the accounted balance. */ function _withdraw(uint256 _amount) internal { require(_amount > 0, "withdrawal is not greater than zero"); // Update the total of this contract accountedBalance = accountedBalance.sub(_amount); // Withdraw from Compound and transfer require(cToken.redeemUnderlying(_amount) == 0, "could not redeem from compound"); require(token().transfer(msg.sender, _amount), "could not transfer winnings"); emit Withdrawn(msg.sender, _amount); } /** * @notice Returns the id of the current open Draw. * @return The current open Draw id */ function currentOpenDrawId() public view returns (uint256) { return drawState.openDrawIndex; } /** * @notice Returns the id of the current committed Draw. * @return The current committed Draw id */ function currentCommittedDrawId() public view returns (uint256) { if (drawState.openDrawIndex > 1) { return drawState.openDrawIndex - 1; } else { return 0; } } /** * @notice Gets information for a given draw. * @param _drawId The id of the Draw to retrieve info for. * @return Fields including: * feeFraction: the fee fraction * feeBeneficiary: the beneficiary of the fee * openedBlock: The block at which the draw was opened * secretHash: The hash of the secret committed to this draw. */ function getDraw(uint256 _drawId) public view returns ( uint256 feeFraction, address feeBeneficiary, uint256 openedBlock, bytes32 secretHash ) { Draw storage draw = draws[_drawId]; feeFraction = draw.feeFraction; feeBeneficiary = draw.feeBeneficiary; openedBlock = draw.openedBlock; secretHash = draw.secretHash; } /** * @notice Returns the total of the address's balance in committed Draws. That is, the total that contributes to their chances of winning. * @param _addr The address of the user * @return The total committed balance for the user */ function committedBalanceOf(address _addr) public view returns (uint256) { return drawState.committedBalanceOf(_addr); } /** * @notice Returns the total of the address's balance in the open Draw. That is, the total that will *eventually* contribute to their chances of winning. * @param _addr The address of the user * @return The total open balance for the user */ function openBalanceOf(address _addr) public view returns (uint256) { return drawState.openBalanceOf(_addr); } /** * @notice Returns a user's total balance, including both committed Draw balance and open Draw balance. * @param _addr The address of the user to check. * @return The users's current balance. */ function balanceOf(address _addr) public view returns (uint256) { return balances[_addr]; } /** * @notice Calculates a winner using the passed entropy for the current committed balances. * @param _entropy The entropy to use to select the winner * @return The winning address */ function calculateWinner(bytes32 _entropy) public view returns (address) { return drawState.drawWithEntropy(_entropy); } /** * @notice Returns the total committed balance. Used to compute an address's chances of winning. * @return The total committed balance. */ function committedSupply() public view returns (uint256) { return drawState.committedSupply; } /** * @notice Returns the total open balance. This balance is the number of tickets purchased for the open draw. * @return The total open balance */ function openSupply() public view returns (uint256) { return drawState.openSupply(); } /** * @notice Calculates the total estimated interest earned for the given number of blocks * @param _blocks The number of block that interest accrued for * @return The total estimated interest as a 18 point fixed decimal. */ function estimatedInterestRate(uint256 _blocks) public view returns (uint256) { return supplyRatePerBlock().mul(_blocks); } /** * @notice Convenience function to return the supplyRatePerBlock value from the money market contract. * @return The cToken supply rate per block */ function supplyRatePerBlock() public view returns (uint256) { return cToken.supplyRatePerBlock(); } /** * @notice Sets the beneficiary fee fraction for subsequent Draws. * Fires the NextFeeFractionChanged event. * Can only be called by an admin. * @param _feeFraction The fee fraction to use. * Must be between 0 and 1 and formatted as a fixed point number with 18 decimals (as in Ether). */ function setNextFeeFraction(uint256 _feeFraction) public onlyAdmin { _setNextFeeFraction(_feeFraction); } function _setNextFeeFraction(uint256 _feeFraction) internal { require(_feeFraction >= 0, "fee must be zero or greater"); require(_feeFraction <= ETHER_IN_WEI, "fee fraction must be 1 or less"); nextFeeFraction = _feeFraction; emit NextFeeFractionChanged(_feeFraction); } /** * @notice Sets the fee beneficiary for subsequent Draws. * Can only be called by admins. * @param _feeBeneficiary The beneficiary for the fee fraction. Cannot be the 0 address. */ function setNextFeeBeneficiary(address _feeBeneficiary) public onlyAdmin { _setNextFeeBeneficiary(_feeBeneficiary); } function _setNextFeeBeneficiary(address _feeBeneficiary) internal { require(_feeBeneficiary != address(0), "beneficiary should not be 0x0"); nextFeeBeneficiary = _feeBeneficiary; emit NextFeeBeneficiaryChanged(_feeBeneficiary); } /** * @notice Adds an administrator. * Can only be called by administrators. * Fires the AdminAdded event. * @param _admin The address of the admin to add */ function addAdmin(address _admin) public onlyAdmin { _addAdmin(_admin); } /** * @notice Checks whether a given address is an administrator. * @param _admin The address to check * @return True if the address is an admin, false otherwise. */ function isAdmin(address _admin) public view returns (bool) { return admins.has(_admin); } function _addAdmin(address _admin) internal { admins.add(_admin); emit AdminAdded(_admin); } /** * @notice Removes an administrator * Can only be called by an admin. * @param _admin The address of the admin to remove */ function removeAdmin(address _admin) public onlyAdmin { require(admins.has(_admin), "admin does not exist"); admins.remove(_admin); emit AdminRemoved(_admin); } /** * @notice Returns the token underlying the cToken. * @return An ERC20 token address */ function token() internal view returns (IERC20) { return IERC20(cToken.underlying()); } /** * @notice Returns the underlying balance of this contract in the cToken. * @return The cToken underlying balance for this contract. */ function balance() public returns (uint256) { return cToken.balanceOfUnderlying(address(this)); } function pause() public unlessPaused onlyAdmin { paused = true; emit Paused(msg.sender); } function unpause() public whenPaused onlyAdmin { paused = false; emit Unpaused(msg.sender); } modifier onlyAdmin() { require(admins.has(msg.sender), "must be an admin"); _; } modifier requireOpenDraw() { require(currentOpenDrawId() != 0, "there is no open draw"); _; } modifier whenPaused() { require(paused, "contract is not paused"); _; } modifier unlessPaused() { require(!paused, "contract is paused"); _; } }
/** Copyright 2019 PoolTogether LLC This file is part of PoolTogether. PoolTogether is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation under version 3 of the License. PoolTogether is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with PoolTogether. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.5.10; import "./UniformRandomNumber.sol"; import "@kleros/kleros/contracts/data-structures/SortitionSumTreeFactory.sol"; import "@openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol"; /** * @author Brendan Asselstine * @notice Tracks committed and open balances for addresses. Affords selection of an address by indexing all committed balances. * * Balances are tracked in Draws. There is always one open Draw. Deposits are always added to the open Draw. * When a new draw is opened, the previous opened draw is committed. * * The committed balance for an address is the total of their balances for committed Draws. * An address's open balance is their balance in the open Draw. */ library DrawManager { using SortitionSumTreeFactory for SortitionSumTreeFactory.SortitionSumTrees; using SafeMath for uint256; /** * The ID to use for the selection tree. */ bytes32 public constant TREE_OF_DRAWS = "TreeOfDraws"; uint8 public constant MAX_LEAVES = 10; /** * Stores information for all draws. */ struct State { /** * Each Draw stores it's address balances in a sortitionSumTree. Draw trees are indexed using the Draw index. * There is one root sortitionSumTree that stores all of the draw totals. The root tree is indexed using the constant TREE_OF_DRAWS. */ SortitionSumTreeFactory.SortitionSumTrees sortitionSumTrees; /** * Stores the first Draw index that an address deposited to. */ mapping(address => uint256) usersFirstDrawIndex; /** * Stores the last Draw index that an address deposited to. */ mapping(address => uint256) usersSecondDrawIndex; /** * Stores a mapping of Draw index => Draw total */ mapping(uint256 => uint256) drawTotals; /** * The current open Draw index */ uint256 openDrawIndex; /** * The total of committed balances */ uint256 committedSupply; } /** * @notice Opens the next Draw and commits the previous open Draw (if any). * @param self The drawState this library is attached to * @return The index of the new open Draw */ function openNextDraw(State storage self) public returns (uint256) { if (self.openDrawIndex == 0) { // If there is no previous draw, we must initialize self.sortitionSumTrees.createTree(TREE_OF_DRAWS, MAX_LEAVES); } else { // else add current draw to sortition sum trees bytes32 drawId = bytes32(self.openDrawIndex); uint256 drawTotal = self.drawTotals[self.openDrawIndex]; self.sortitionSumTrees.set(TREE_OF_DRAWS, drawTotal, drawId); self.committedSupply = self.committedSupply.add(drawTotal); } // now create a new draw uint256 drawIndex = self.openDrawIndex.add(1); self.sortitionSumTrees.createTree(bytes32(drawIndex), MAX_LEAVES); self.openDrawIndex = drawIndex; return drawIndex; } /** * @notice Deposits the given amount into the current open draw by the given user. * @param self The DrawManager state * @param _addr The address to deposit for * @param _amount The amount to deposit */ function deposit(State storage self, address _addr, uint256 _amount) public requireOpenDraw(self) { bytes32 userId = bytes32(uint256(_addr)); uint256 openDrawIndex = self.openDrawIndex; // update the current draw uint256 currentAmount = self.sortitionSumTrees.stakeOf(bytes32(openDrawIndex), userId); currentAmount = currentAmount.add(_amount); drawSet(self, openDrawIndex, currentAmount, _addr); uint256 firstDrawIndex = self.usersFirstDrawIndex[_addr]; uint256 secondDrawIndex = self.usersSecondDrawIndex[_addr]; // if this is the users first draw, set it if (firstDrawIndex == 0) { self.usersFirstDrawIndex[_addr] = openDrawIndex; // otherwise, if the first draw is not this draw } else if (firstDrawIndex != openDrawIndex) { // if a second draw does not exist if (secondDrawIndex == 0) { // set the second draw to the current draw self.usersSecondDrawIndex[_addr] = openDrawIndex; // otherwise if a second draw exists but is not the current one } else if (secondDrawIndex != openDrawIndex) { // merge it into the first draw, and update the second draw index to this one uint256 firstAmount = self.sortitionSumTrees.stakeOf(bytes32(firstDrawIndex), userId); uint256 secondAmount = self.sortitionSumTrees.stakeOf(bytes32(secondDrawIndex), userId); drawSet(self, firstDrawIndex, firstAmount.add(secondAmount), _addr); drawSet(self, secondDrawIndex, 0, _addr); self.usersSecondDrawIndex[_addr] = openDrawIndex; } } } /** * @notice Withdraws a user's committed and open draws. * @param self The DrawManager state * @param _addr The address whose balance to withdraw */ function withdraw(State storage self, address _addr) public requireOpenDraw(self) { uint256 firstDrawIndex = self.usersFirstDrawIndex[_addr]; uint256 secondDrawIndex = self.usersSecondDrawIndex[_addr]; if (firstDrawIndex != 0) { drawSet(self, firstDrawIndex, 0, _addr); } if (secondDrawIndex != 0) { drawSet(self, secondDrawIndex, 0, _addr); } } /** * @notice Returns the total balance for an address, including committed balances and the open balance. */ function balanceOf(State storage drawState, address _addr) public view returns (uint256) { return committedBalanceOf(drawState, _addr).add(openBalanceOf(drawState, _addr)); } /** * @notice Returns the total committed balance for an address. * @param self The DrawManager state * @param _addr The address whose committed balance should be returned * @return The total committed balance */ function committedBalanceOf(State storage self, address _addr) public view returns (uint256) { uint256 balance = 0; uint256 firstDrawIndex = self.usersFirstDrawIndex[_addr]; uint256 secondDrawIndex = self.usersSecondDrawIndex[_addr]; if (firstDrawIndex != 0 && firstDrawIndex != self.openDrawIndex) { balance = balance.add(self.sortitionSumTrees.stakeOf(bytes32(firstDrawIndex), bytes32(uint256(_addr)))); } if (secondDrawIndex != 0 && secondDrawIndex != self.openDrawIndex) { balance = balance.add(self.sortitionSumTrees.stakeOf(bytes32(secondDrawIndex), bytes32(uint256(_addr)))); } return balance; } /** * @notice Returns the open balance for an address * @param self The DrawManager state * @param _addr The address whose open balance should be returned * @return The open balance */ function openBalanceOf(State storage self, address _addr) public view returns (uint256) { if (self.openDrawIndex == 0) { return 0; } else { return self.sortitionSumTrees.stakeOf(bytes32(self.openDrawIndex), bytes32(uint256(_addr))); } } /** * @notice Returns the open Draw balance for the DrawManager * @param self The DrawManager state * @return The open draw total balance */ function openSupply(State storage self) public view returns (uint256) { return self.drawTotals[self.openDrawIndex]; } /** * @notice Updates the Draw balance for an address. * @param self The DrawManager state * @param _drawIndex The Draw index * @param _amount The new balance * @param _addr The address whose balance should be updated */ function drawSet(State storage self, uint256 _drawIndex, uint256 _amount, address _addr) internal { bytes32 drawId = bytes32(_drawIndex); bytes32 userId = bytes32(uint256(_addr)); uint256 oldAmount = self.sortitionSumTrees.stakeOf(drawId, userId); if (oldAmount != _amount) { // If the amount has changed // Update the Draw's balance for that address self.sortitionSumTrees.set(drawId, _amount, userId); uint256 drawTotal = self.drawTotals[_drawIndex]; if (oldAmount > _amount) { // If the amount is less than the old amount // Subtract the difference from the Draw total uint256 diffAmount = oldAmount.sub(_amount); drawTotal = drawTotal.sub(diffAmount); if (_drawIndex != self.openDrawIndex) { // If the Draw is committed, update the root tree and committed supply self.sortitionSumTrees.set(TREE_OF_DRAWS, drawTotal, drawId); self.committedSupply = self.committedSupply.sub(diffAmount); } } else { // oldAmount < _amount // if the amount is greater than the old amount // Add the difference to the Draw total uint256 diffAmount = _amount.sub(oldAmount); drawTotal = drawTotal.add(diffAmount); if (_drawIndex != self.openDrawIndex) { // If the Draw is committed, update the root tree and committed supply self.sortitionSumTrees.set(TREE_OF_DRAWS, drawTotal, drawId); self.committedSupply = self.committedSupply.add(diffAmount); } } // Update the Draw total with the new total self.drawTotals[_drawIndex] = drawTotal; } } /** * @notice Selects an address by indexing into the committed tokens using the passed token * @param self The DrawManager state * @param _token The token index to select * @return The selected address */ function draw(State storage self, uint256 _token) public view returns (address) { // If there is no one to select, just return the zero address if (self.committedSupply == 0) { return address(0); } require(_token < self.committedSupply, "token is beyond the eligible supply"); uint256 drawIndex = uint256(self.sortitionSumTrees.draw(TREE_OF_DRAWS, _token)); assert(drawIndex != 0); uint256 drawSupply = self.drawTotals[drawIndex]; assert(drawSupply > 0); uint256 drawToken = _token % drawSupply; return address(uint256(self.sortitionSumTrees.draw(bytes32(drawIndex), drawToken))); } /** * @notice Selects an address using the entropy as an index into the committed tokens * The entropy is passed into the UniformRandomNumber library to remove modulo bias. * @param self The DrawManager state * @param _entropy The random entropy to use * @return The selected address */ function drawWithEntropy(State storage self, bytes32 _entropy) public view returns (address) { return draw(self, UniformRandomNumber.uniform(uint256(_entropy), self.committedSupply)); } modifier requireOpenDraw(State storage self) { require(self.openDrawIndex > 0, "there is no open draw"); _; } }
/** Copyright 2019 PoolTogether LLC This file is part of PoolTogether. PoolTogether is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation under version 3 of the License. PoolTogether is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with PoolTogether. If not, see <https://www.gnu.org/licenses/>. */ // Migrations.sol pragma solidity 0.5.10; import "@openzeppelin/contracts-ethereum-package/contracts/ownership/Ownable.sol"; contract Migrations is Ownable { uint public last_completed_migration; function setCompleted(uint completed) public onlyOwner { last_completed_migration = completed; } function upgrade(address new_address) public onlyOwner { Migrations upgraded = Migrations(new_address); upgraded.setCompleted(last_completed_migration); } }
/** Copyright 2019 PoolTogether LLC This file is part of PoolTogether. PoolTogether is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation under version 3 of the License. PoolTogether is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with PoolTogether. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.5.10; /** * @author Brendan Asselstine * @notice A library that uses entropy to select a random number within a bound. Compensates for modulo bias. * @dev Thanks to https://medium.com/hownetworks/dont-waste-cycles-with-modulo-bias-35b6fdafcf94 */ library UniformRandomNumber { /// @notice Select a random number without modulo bias using a random seed and upper bound /// @param _entropy The seed for randomness /// @param _upperBound The upper bound of the desired number /// @return A random number less than the _upperBound function uniform(uint256 _entropy, uint256 _upperBound) internal pure returns (uint256) { if (_upperBound == 0) { return 0; } uint256 min = -_upperBound % _upperBound; uint256 random = _entropy; while (true) { if (random >= min) { break; } random = uint256(keccak256(abi.encodePacked(random))); } return random % _upperBound; } }
/** Copyright 2019 PoolTogether LLC This file is part of PoolTogether. PoolTogether is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation under version 3 of the License. PoolTogether is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with PoolTogether. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.5.10; contract ICErc20 { address public underlying; function mint(uint mintAmount) external returns (uint); function redeemUnderlying(uint redeemAmount) external returns (uint); function balanceOfUnderlying(address owner) external returns (uint); function getCash() external view returns (uint); function supplyRatePerBlock() external view returns (uint); }
/** Copyright 2019 PoolTogether LLC This file is part of PoolTogether. PoolTogether is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation under version 3 of the License. PoolTogether is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with PoolTogether. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.5.10; import "../compound/ICErc20.sol"; import "@openzeppelin/upgrades/contracts/Initializable.sol"; import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/IERC20.sol"; contract CErc20Mock is Initializable, ICErc20 { mapping(address => uint256) ownerTokenAmounts; uint __supplyRatePerBlock; function initialize (address _token, uint256 _supplyRatePerBlock) public initializer { require(_token != address(0), "token is not defined"); underlying = _token; __supplyRatePerBlock = _supplyRatePerBlock; } function mint(uint amount) external returns (uint) { ownerTokenAmounts[msg.sender] = ownerTokenAmounts[msg.sender] + amount; require(IERC20(underlying).transferFrom(msg.sender, address(this), amount), "could not transfer tokens"); return 0; } function getCash() external view returns (uint) { return IERC20(underlying).balanceOf(address(this)); } function redeemUnderlying(uint requestedAmount) external returns (uint) { require(ownerTokenAmounts[msg.sender] > 0, "you must have supplied tokens"); ownerTokenAmounts[msg.sender] = ownerTokenAmounts[msg.sender] - requestedAmount; require(IERC20(underlying).transfer(msg.sender, requestedAmount), "could not transfer tokens"); } function reward(address account) external { ownerTokenAmounts[account] = (ownerTokenAmounts[account] * 120) / 100; } function balanceOfUnderlying(address account) external returns (uint) { return ownerTokenAmounts[account]; } function supplyRatePerBlock() external view returns (uint) { return __supplyRatePerBlock; } function setSupplyRateMantissa(uint256 _supplyRatePerBlock) external { __supplyRatePerBlock = _supplyRatePerBlock; } }
/** Copyright 2019 PoolTogether LLC This file is part of PoolTogether. PoolTogether is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation under version 3 of the License. PoolTogether is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with PoolTogether. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.5.10; import "../DrawManager.sol"; contract ExposedDrawManager { using DrawManager for DrawManager.State; DrawManager.State state; function openNextDraw() public { state.openNextDraw(); } function deposit(address user, uint256 amount) public { state.deposit(user, amount); } function withdraw(address user) public { state.withdraw(user); } function balanceOf(address user) public view returns (uint256) { return state.balanceOf(user); } function committedBalanceOf(address user) public view returns (uint256) { return state.committedBalanceOf(user); } function openBalanceOf(address user) public view returns (uint256) { return state.openBalanceOf(user); } function committedSupply() public view returns (uint256) { return state.committedSupply; } function openSupply() public view returns (uint256) { return state.openSupply(); } function openDrawIndex() public view returns (uint256) { return state.openDrawIndex; } function draw(uint256 token) public view returns (address) { return state.draw(token); } function firstDrawIndex(address user) public view returns (uint256) { return state.usersFirstDrawIndex[user]; } function secondDrawIndex(address user) public view returns (uint256) { return state.usersSecondDrawIndex[user]; } function drawWithEntropy(bytes32 entropy) public view returns (address) { return state.drawWithEntropy(entropy); } }
/** Copyright 2019 PoolTogether LLC This file is part of PoolTogether. PoolTogether is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation under version 3 of the License. PoolTogether is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with PoolTogether. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity ^0.5.10; import "../UniformRandomNumber.sol"; contract ExposedUniformRandomNumber { function uniform(uint256 _entropy, uint256 _upperBound) public pure returns (uint256) { return UniformRandomNumber.uniform(_entropy, _upperBound); } }
/** Copyright 2019 PoolTogether LLC This file is part of PoolTogether. PoolTogether is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation under version 3 of the License. PoolTogether is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with PoolTogether. If not, see <https://www.gnu.org/licenses/>. */ pragma solidity 0.5.10; import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Mintable.sol"; /** * @author Brendan Asselstine * @notice An ERC20 Token contract to be used for testing the Pool contract */ contract Token is ERC20Mintable { string public constant name = "Token"; string public constant symbol = "TOK"; uint8 public constant decimals = 18; }
/** * @reviewers: [@clesaege, @unknownunknown1, @ferittuncer] * @auditors: [] * @bounties: [<14 days 10 ETH max payout>] * @deployments: [] */ pragma solidity ^0.5.0; /** * @title SortitionSumTreeFactory * @author Enrique Piqueras - <[email protected]> * @dev A factory of trees that keep track of staked values for sortition. */ library SortitionSumTreeFactory { /* Structs */ struct SortitionSumTree { uint K; // The maximum number of childs per node. // We use this to keep track of vacant positions in the tree after removing a leaf. This is for keeping the tree as balanced as possible without spending gas on moving nodes around. uint[] stack; uint[] nodes; // Two-way mapping of IDs to node indexes. Note that node index 0 is reserved for the root node, and means the ID does not have a node. mapping(bytes32 => uint) IDsToNodeIndexes; mapping(uint => bytes32) nodeIndexesToIDs; } /* Storage */ struct SortitionSumTrees { mapping(bytes32 => SortitionSumTree) sortitionSumTrees; } /* internal */ /** * @dev Create a sortition sum tree at the specified key. * @param _key The key of the new tree. * @param _K The number of children each node in the tree should have. */ function createTree(SortitionSumTrees storage self, bytes32 _key, uint _K) internal { SortitionSumTree storage tree = self.sortitionSumTrees[_key]; require(tree.K == 0, "Tree already exists."); require(_K > 1, "K must be greater than one."); tree.K = _K; tree.stack.length = 0; tree.nodes.length = 0; tree.nodes.push(0); } /** * @dev Set a value of a tree. * @param _key The key of the tree. * @param _value The new value. * @param _ID The ID of the value. * `O(log_k(n))` where * `k` is the maximum number of childs per node in the tree, * and `n` is the maximum number of nodes ever appended. */ function set(SortitionSumTrees storage self, bytes32 _key, uint _value, bytes32 _ID) internal { SortitionSumTree storage tree = self.sortitionSumTrees[_key]; uint treeIndex = tree.IDsToNodeIndexes[_ID]; if (treeIndex == 0) { // No existing node. if (_value != 0) { // Non zero value. // Append. // Add node. if (tree.stack.length == 0) { // No vacant spots. // Get the index and append the value. treeIndex = tree.nodes.length; tree.nodes.push(_value); // Potentially append a new node and make the parent a sum node. if (treeIndex != 1 && (treeIndex - 1) % tree.K == 0) { // Is first child. uint parentIndex = treeIndex / tree.K; bytes32 parentID = tree.nodeIndexesToIDs[parentIndex]; uint newIndex = treeIndex + 1; tree.nodes.push(tree.nodes[parentIndex]); delete tree.nodeIndexesToIDs[parentIndex]; tree.IDsToNodeIndexes[parentID] = newIndex; tree.nodeIndexesToIDs[newIndex] = parentID; } } else { // Some vacant spot. // Pop the stack and append the value. treeIndex = tree.stack[tree.stack.length - 1]; tree.stack.length--; tree.nodes[treeIndex] = _value; } // Add label. tree.IDsToNodeIndexes[_ID] = treeIndex; tree.nodeIndexesToIDs[treeIndex] = _ID; updateParents(self, _key, treeIndex, true, _value); } } else { // Existing node. if (_value == 0) { // Zero value. // Remove. // Remember value and set to 0. uint value = tree.nodes[treeIndex]; tree.nodes[treeIndex] = 0; // Push to stack. tree.stack.push(treeIndex); // Clear label. delete tree.IDsToNodeIndexes[_ID]; delete tree.nodeIndexesToIDs[treeIndex]; updateParents(self, _key, treeIndex, false, value); } else if (_value != tree.nodes[treeIndex]) { // New, non zero value. // Set. bool plusOrMinus = tree.nodes[treeIndex] <= _value; uint plusOrMinusValue = plusOrMinus ? _value - tree.nodes[treeIndex] : tree.nodes[treeIndex] - _value; tree.nodes[treeIndex] = _value; updateParents(self, _key, treeIndex, plusOrMinus, plusOrMinusValue); } } } /* internal Views */ /** * @dev Query the leaves of a tree. Note that if `startIndex == 0`, the tree is empty and the root node will be returned. * @param _key The key of the tree to get the leaves from. * @param _cursor The pagination cursor. * @param _count The number of items to return. * @return The index at which leaves start, the values of the returned leaves, and whether there are more for pagination. * `O(n)` where * `n` is the maximum number of nodes ever appended. */ function queryLeafs( SortitionSumTrees storage self, bytes32 _key, uint _cursor, uint _count ) internal view returns(uint startIndex, uint[] memory values, bool hasMore) { SortitionSumTree storage tree = self.sortitionSumTrees[_key]; // Find the start index. for (uint i = 0; i < tree.nodes.length; i++) { if ((tree.K * i) + 1 >= tree.nodes.length) { startIndex = i; break; } } // Get the values. uint loopStartIndex = startIndex + _cursor; values = new uint[](loopStartIndex + _count > tree.nodes.length ? tree.nodes.length - loopStartIndex : _count); uint valuesIndex = 0; for (uint j = loopStartIndex; j < tree.nodes.length; j++) { if (valuesIndex < _count) { values[valuesIndex] = tree.nodes[j]; valuesIndex++; } else { hasMore = true; break; } } } /** * @dev Draw an ID from a tree using a number. Note that this function reverts if the sum of all values in the tree is 0. * @param _key The key of the tree. * @param _drawnNumber The drawn number. * @return The drawn ID. * `O(k * log_k(n))` where * `k` is the maximum number of childs per node in the tree, * and `n` is the maximum number of nodes ever appended. */ function draw(SortitionSumTrees storage self, bytes32 _key, uint _drawnNumber) internal view returns(bytes32 ID) { SortitionSumTree storage tree = self.sortitionSumTrees[_key]; uint treeIndex = 0; uint currentDrawnNumber = _drawnNumber % tree.nodes[0]; while ((tree.K * treeIndex) + 1 < tree.nodes.length) // While it still has children. for (uint i = 1; i <= tree.K; i++) { // Loop over children. uint nodeIndex = (tree.K * treeIndex) + i; uint nodeValue = tree.nodes[nodeIndex]; if (currentDrawnNumber >= nodeValue) currentDrawnNumber -= nodeValue; // Go to the next child. else { // Pick this child. treeIndex = nodeIndex; break; } } ID = tree.nodeIndexesToIDs[treeIndex]; } /** @dev Gets a specified ID's associated value. * @param _key The key of the tree. * @param _ID The ID of the value. * @return The associated value. */ function stakeOf(SortitionSumTrees storage self, bytes32 _key, bytes32 _ID) internal view returns(uint value) { SortitionSumTree storage tree = self.sortitionSumTrees[_key]; uint treeIndex = tree.IDsToNodeIndexes[_ID]; if (treeIndex == 0) value = 0; else value = tree.nodes[treeIndex]; } /* Private */ /** * @dev Update all the parents of a node. * @param _key The key of the tree to update. * @param _treeIndex The index of the node to start from. * @param _plusOrMinus Wether to add (true) or substract (false). * @param _value The value to add or substract. * `O(log_k(n))` where * `k` is the maximum number of childs per node in the tree, * and `n` is the maximum number of nodes ever appended. */ function updateParents(SortitionSumTrees storage self, bytes32 _key, uint _treeIndex, bool _plusOrMinus, uint _value) private { SortitionSumTree storage tree = self.sortitionSumTrees[_key]; uint parentIndex = _treeIndex; while (parentIndex != 0) { parentIndex = (parentIndex - 1) / tree.K; tree.nodes[parentIndex] = _plusOrMinus ? tree.nodes[parentIndex] + _value : tree.nodes[parentIndex] - _value; } } }
pragma solidity ^0.5.2; /** * @title SafeMath * @dev Unsigned math operations with safety checks that revert on error */ library SafeMath { /** * @dev Multiplies two unsigned integers, reverts on overflow. */ function mul(uint256 a, uint256 b) internal pure returns (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-solidity/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b); return c; } /** * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a); uint256 c = a - b; return c; } /** * @dev Adds two unsigned integers, reverts on overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a); return c; } /** * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo), * reverts when dividing by zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0); return a % b; } }
pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; /** * @title Ownable * @dev The Ownable contract has an owner address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". */ contract Ownable is Initializable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ function initialize(address sender) public initializer { _owner = sender; emit OwnershipTransferred(address(0), _owner); } /** * @return the address of the owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner()); _; } /** * @return true if `msg.sender` is the owner of the contract. */ function isOwner() public view returns (bool) { return msg.sender == _owner; } /** * @dev Allows the current owner to relinquish control of the contract. * It will not be possible to call the functions with the `onlyOwner` * modifier anymore. * @notice Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0)); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } uint256[50] private ______gap; }
pragma solidity ^0.5.2; /** * @title ERC20 interface * @dev see https://eips.ethereum.org/EIPS/eip-20 */ interface IERC20 { function transfer(address to, uint256 value) external returns (bool); function approve(address spender, uint256 value) external returns (bool); function transferFrom(address from, address to, uint256 value) external returns (bool); function totalSupply() external view returns (uint256); function balanceOf(address who) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); }
pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; /** * @title Helps contracts guard against reentrancy attacks. * @author Remco Bloemen <remco@2π.com>, Eenae <[email protected]> * @dev If you mark a function `nonReentrant`, you should also * mark it `external`. */ contract ReentrancyGuard is Initializable { /// @dev counter to allow mutex lock with only one SSTORE operation uint256 private _guardCounter; function initialize() public initializer { // The counter starts at one to prevent changing it from zero to a non-zero // value, which is a more expensive operation. _guardCounter = 1; } /** * @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() { _guardCounter += 1; uint256 localCounter = _guardCounter; _; require(localCounter == _guardCounter); } uint256[50] private ______gap; }
pragma solidity ^0.5.2; /** * @title Roles * @dev Library for managing addresses assigned to a Role. */ library Roles { struct Role { mapping (address => bool) bearer; } /** * @dev give an account access to this role */ function add(Role storage role, address account) internal { require(account != address(0)); require(!has(role, account)); role.bearer[account] = true; } /** * @dev remove an account's access to this role */ function remove(Role storage role, address account) internal { require(account != address(0)); require(has(role, account)); role.bearer[account] = false; } /** * @dev check if an account has this role * @return bool */ function has(Role storage role, address account) internal view returns (bool) { require(account != address(0)); return role.bearer[account]; } }
pragma solidity ^0.5.0; /** * @title FixidityLib * @author Gadi Guy, Alberto Cuesta Canada * @notice This library provides fixed point arithmetic with protection against * overflow. * All operations are done with int256 and the operands must have been created * with any of the newFrom* functions, which shift the comma digits() to the * right and check for limits. * When using this library be sure of using maxNewFixed() as the upper limit for * creation of fixed point numbers. Use maxFixedMul(), maxFixedDiv() and * maxFixedAdd() if you want to be certain that those operations don't * overflow. */ library FixidityLib { /** * @notice Number of positions that the comma is shifted to the right. */ function digits() public pure returns(uint8) { return 24; } /** * @notice This is 1 in the fixed point units used in this library. * @dev Test fixed1() equals 10^digits() * Hardcoded to 24 digits. */ function fixed1() public pure returns(int256) { return 1000000000000000000000000; } /** * @notice The amount of decimals lost on each multiplication operand. * @dev Test mulPrecision() equals sqrt(fixed1) * Hardcoded to 24 digits. */ function mulPrecision() public pure returns(int256) { return 1000000000000; } /** * @notice Maximum value that can be represented in an int256 * @dev Test maxInt256() equals 2^255 -1 */ function maxInt256() public pure returns(int256) { return 57896044618658097711785492504343953926634992332820282019728792003956564819967; } /** * @notice Minimum value that can be represented in an int256 * @dev Test minInt256 equals (2^255) * (-1) */ function minInt256() public pure returns(int256) { return -57896044618658097711785492504343953926634992332820282019728792003956564819968; } /** * @notice Maximum value that can be converted to fixed point. Optimize for * @dev deployment. * Test maxNewFixed() equals maxInt256() / fixed1() * Hardcoded to 24 digits. */ function maxNewFixed() public pure returns(int256) { return 57896044618658097711785492504343953926634992332820282; } /** * @notice Minimum value that can be converted to fixed point. Optimize for * deployment. * @dev Test minNewFixed() equals -(maxInt256()) / fixed1() * Hardcoded to 24 digits. */ function minNewFixed() public pure returns(int256) { return -57896044618658097711785492504343953926634992332820282; } /** * @notice Maximum value that can be safely used as an addition operator. * @dev Test maxFixedAdd() equals maxInt256()-1 / 2 * Test add(maxFixedAdd(),maxFixedAdd()) equals maxFixedAdd() + maxFixedAdd() * Test add(maxFixedAdd()+1,maxFixedAdd()) throws * Test add(-maxFixedAdd(),-maxFixedAdd()) equals -maxFixedAdd() - maxFixedAdd() * Test add(-maxFixedAdd(),-maxFixedAdd()-1) throws */ function maxFixedAdd() public pure returns(int256) { return 28948022309329048855892746252171976963317496166410141009864396001978282409983; } /** * @notice Maximum negative value that can be safely in a subtraction. * @dev Test maxFixedSub() equals minInt256() / 2 */ function maxFixedSub() public pure returns(int256) { return -28948022309329048855892746252171976963317496166410141009864396001978282409984; } /** * @notice Maximum value that can be safely used as a multiplication operator. * @dev Calculated as sqrt(maxInt256()*fixed1()). * Be careful with your sqrt() implementation. I couldn't find a calculator * that would give the exact square root of maxInt256*fixed1 so this number * is below the real number by no more than 3*10**28. It is safe to use as * a limit for your multiplications, although powers of two of numbers over * this value might still work. * Test multiply(maxFixedMul(),maxFixedMul()) equals maxFixedMul() * maxFixedMul() * Test multiply(maxFixedMul(),maxFixedMul()+1) throws * Test multiply(-maxFixedMul(),maxFixedMul()) equals -maxFixedMul() * maxFixedMul() * Test multiply(-maxFixedMul(),maxFixedMul()+1) throws * Hardcoded to 24 digits. */ function maxFixedMul() public pure returns(int256) { return 240615969168004498257251713877715648331380787511296; } /** * @notice Maximum value that can be safely used as a dividend. * @dev divide(maxFixedDiv,newFixedFraction(1,fixed1())) = maxInt256(). * Test maxFixedDiv() equals maxInt256()/fixed1() * Test divide(maxFixedDiv(),multiply(mulPrecision(),mulPrecision())) = maxFixedDiv()*(10^digits()) * Test divide(maxFixedDiv()+1,multiply(mulPrecision(),mulPrecision())) throws * Hardcoded to 24 digits. */ function maxFixedDiv() public pure returns(int256) { return 57896044618658097711785492504343953926634992332820282; } /** * @notice Maximum value that can be safely used as a divisor. * @dev Test maxFixedDivisor() equals fixed1()*fixed1() - Or 10**(digits()*2) * Test divide(10**(digits()*2 + 1),10**(digits()*2)) = returns 10*fixed1() * Test divide(10**(digits()*2 + 1),10**(digits()*2 + 1)) = throws * Hardcoded to 24 digits. */ function maxFixedDivisor() public pure returns(int256) { return 1000000000000000000000000000000000000000000000000; } /** * @notice Converts an int256 to fixed point units, equivalent to multiplying * by 10^digits(). * @dev Test newFixed(0) returns 0 * Test newFixed(1) returns fixed1() * Test newFixed(maxNewFixed()) returns maxNewFixed() * fixed1() * Test newFixed(maxNewFixed()+1) fails */ function newFixed(int256 x) public pure returns (int256) { require(x <= maxNewFixed()); require(x >= minNewFixed()); return x * fixed1(); } /** * @notice Converts an int256 in the fixed point representation of this * library to a non decimal. All decimal digits will be truncated. */ function fromFixed(int256 x) public pure returns (int256) { return x / fixed1(); } /** * @notice Converts an int256 which is already in some fixed point * representation to a different fixed precision representation. * Both the origin and destination precisions must be 38 or less digits. * Origin values with a precision higher than the destination precision * will be truncated accordingly. * @dev * Test convertFixed(1,0,0) returns 1; * Test convertFixed(1,1,1) returns 1; * Test convertFixed(1,1,0) returns 0; * Test convertFixed(1,0,1) returns 10; * Test convertFixed(10,1,0) returns 1; * Test convertFixed(10,0,1) returns 100; * Test convertFixed(100,1,0) returns 10; * Test convertFixed(100,0,1) returns 1000; * Test convertFixed(1000,2,0) returns 10; * Test convertFixed(1000,0,2) returns 100000; * Test convertFixed(1000,2,1) returns 100; * Test convertFixed(1000,1,2) returns 10000; * Test convertFixed(maxInt256,1,0) returns maxInt256/10; * Test convertFixed(maxInt256,0,1) throws * Test convertFixed(maxInt256,38,0) returns maxInt256/(10**38); * Test convertFixed(1,0,38) returns 10**38; * Test convertFixed(maxInt256,39,0) throws * Test convertFixed(1,0,39) throws */ function convertFixed(int256 x, uint8 _originDigits, uint8 _destinationDigits) public pure returns (int256) { require(_originDigits <= 38 && _destinationDigits <= 38); uint8 decimalDifference; if ( _originDigits > _destinationDigits ){ decimalDifference = _originDigits - _destinationDigits; return x/(uint128(10)**uint128(decimalDifference)); } else if ( _originDigits < _destinationDigits ){ decimalDifference = _destinationDigits - _originDigits; // Cast uint8 -> uint128 is safe // Exponentiation is safe: // _originDigits and _destinationDigits limited to 38 or less // decimalDifference = abs(_destinationDigits - _originDigits) // decimalDifference < 38 // 10**38 < 2**128-1 require(x <= maxInt256()/uint128(10)**uint128(decimalDifference)); require(x >= minInt256()/uint128(10)**uint128(decimalDifference)); return x*(uint128(10)**uint128(decimalDifference)); } // _originDigits == digits()) return x; } /** * @notice Converts an int256 which is already in some fixed point * representation to that of this library. The _originDigits parameter is the * precision of x. Values with a precision higher than FixidityLib.digits() * will be truncated accordingly. */ function newFixed(int256 x, uint8 _originDigits) public pure returns (int256) { return convertFixed(x, _originDigits, digits()); } /** * @notice Converts an int256 in the fixed point representation of this * library to a different representation. The _destinationDigits parameter is the * precision of the output x. Values with a precision below than * FixidityLib.digits() will be truncated accordingly. */ function fromFixed(int256 x, uint8 _destinationDigits) public pure returns (int256) { return convertFixed(x, digits(), _destinationDigits); } /** * @notice Converts two int256 representing a fraction to fixed point units, * equivalent to multiplying dividend and divisor by 10^digits(). * @dev * Test newFixedFraction(maxFixedDiv()+1,1) fails * Test newFixedFraction(1,maxFixedDiv()+1) fails * Test newFixedFraction(1,0) fails * Test newFixedFraction(0,1) returns 0 * Test newFixedFraction(1,1) returns fixed1() * Test newFixedFraction(maxFixedDiv(),1) returns maxFixedDiv()*fixed1() * Test newFixedFraction(1,fixed1()) returns 1 * Test newFixedFraction(1,fixed1()-1) returns 0 */ function newFixedFraction( int256 numerator, int256 denominator ) public pure returns (int256) { require(numerator <= maxNewFixed()); require(denominator <= maxNewFixed()); require(denominator != 0); int256 convertedNumerator = newFixed(numerator); int256 convertedDenominator = newFixed(denominator); return divide(convertedNumerator, convertedDenominator); } /** * @notice Returns the integer part of a fixed point number. * @dev * Test integer(0) returns 0 * Test integer(fixed1()) returns fixed1() * Test integer(newFixed(maxNewFixed())) returns maxNewFixed()*fixed1() * Test integer(-fixed1()) returns -fixed1() * Test integer(newFixed(-maxNewFixed())) returns -maxNewFixed()*fixed1() */ function integer(int256 x) public pure returns (int256) { return (x / fixed1()) * fixed1(); // Can't overflow } /** * @notice Returns the fractional part of a fixed point number. * In the case of a negative number the fractional is also negative. * @dev * Test fractional(0) returns 0 * Test fractional(fixed1()) returns 0 * Test fractional(fixed1()-1) returns 10^24-1 * Test fractional(-fixed1()) returns 0 * Test fractional(-fixed1()+1) returns -10^24-1 */ function fractional(int256 x) public pure returns (int256) { return x - (x / fixed1()) * fixed1(); // Can't overflow } /** * @notice Converts to positive if negative. * Due to int256 having one more negative number than positive numbers * abs(minInt256) reverts. * @dev * Test abs(0) returns 0 * Test abs(fixed1()) returns -fixed1() * Test abs(-fixed1()) returns fixed1() * Test abs(newFixed(maxNewFixed())) returns maxNewFixed()*fixed1() * Test abs(newFixed(minNewFixed())) returns -minNewFixed()*fixed1() */ function abs(int256 x) public pure returns (int256) { if (x >= 0) { return x; } else { int256 result = -x; assert (result > 0); return result; } } /** * @notice x+y. If any operator is higher than maxFixedAdd() it * might overflow. * In solidity maxInt256 + 1 = minInt256 and viceversa. * @dev * Test add(maxFixedAdd(),maxFixedAdd()) returns maxInt256()-1 * Test add(maxFixedAdd()+1,maxFixedAdd()+1) fails * Test add(-maxFixedSub(),-maxFixedSub()) returns minInt256() * Test add(-maxFixedSub()-1,-maxFixedSub()-1) fails * Test add(maxInt256(),maxInt256()) fails * Test add(minInt256(),minInt256()) fails */ function add(int256 x, int256 y) public pure returns (int256) { int256 z = x + y; if (x > 0 && y > 0) assert(z > x && z > y); if (x < 0 && y < 0) assert(z < x && z < y); return z; } /** * @notice x-y. You can use add(x,-y) instead. * @dev Tests covered by add(x,y) */ function subtract(int256 x, int256 y) public pure returns (int256) { return add(x,-y); } /** * @notice x*y. If any of the operators is higher than maxFixedMul() it * might overflow. * @dev * Test multiply(0,0) returns 0 * Test multiply(maxFixedMul(),0) returns 0 * Test multiply(0,maxFixedMul()) returns 0 * Test multiply(maxFixedMul(),fixed1()) returns maxFixedMul() * Test multiply(fixed1(),maxFixedMul()) returns maxFixedMul() * Test all combinations of (2,-2), (2, 2.5), (2, -2.5) and (0.5, -0.5) * Test multiply(fixed1()/mulPrecision(),fixed1()*mulPrecision()) * Test multiply(maxFixedMul()-1,maxFixedMul()) equals multiply(maxFixedMul(),maxFixedMul()-1) * Test multiply(maxFixedMul(),maxFixedMul()) returns maxInt256() // Probably not to the last digits * Test multiply(maxFixedMul()+1,maxFixedMul()) fails * Test multiply(maxFixedMul(),maxFixedMul()+1) fails */ function multiply(int256 x, int256 y) public pure returns (int256) { if (x == 0 || y == 0) return 0; if (y == fixed1()) return x; if (x == fixed1()) return y; // Separate into integer and fractional parts // x = x1 + x2, y = y1 + y2 int256 x1 = integer(x) / fixed1(); int256 x2 = fractional(x); int256 y1 = integer(y) / fixed1(); int256 y2 = fractional(y); // (x1 + x2) * (y1 + y2) = (x1 * y1) + (x1 * y2) + (x2 * y1) + (x2 * y2) int256 x1y1 = x1 * y1; if (x1 != 0) assert(x1y1 / x1 == y1); // Overflow x1y1 // x1y1 needs to be multiplied back by fixed1 // solium-disable-next-line mixedcase int256 fixed_x1y1 = x1y1 * fixed1(); if (x1y1 != 0) assert(fixed_x1y1 / x1y1 == fixed1()); // Overflow x1y1 * fixed1 x1y1 = fixed_x1y1; int256 x2y1 = x2 * y1; if (x2 != 0) assert(x2y1 / x2 == y1); // Overflow x2y1 int256 x1y2 = x1 * y2; if (x1 != 0) assert(x1y2 / x1 == y2); // Overflow x1y2 x2 = x2 / mulPrecision(); y2 = y2 / mulPrecision(); int256 x2y2 = x2 * y2; if (x2 != 0) assert(x2y2 / x2 == y2); // Overflow x2y2 // result = fixed1() * x1 * y1 + x1 * y2 + x2 * y1 + x2 * y2 / fixed1(); int256 result = x1y1; result = add(result, x2y1); // Add checks for overflow result = add(result, x1y2); // Add checks for overflow result = add(result, x2y2); // Add checks for overflow return result; } /** * @notice 1/x * @dev * Test reciprocal(0) fails * Test reciprocal(fixed1()) returns fixed1() * Test reciprocal(fixed1()*fixed1()) returns 1 // Testing how the fractional is truncated * Test reciprocal(2*fixed1()*fixed1()) returns 0 // Testing how the fractional is truncated */ function reciprocal(int256 x) public pure returns (int256) { require(x != 0); return (fixed1()*fixed1()) / x; // Can't overflow } /** * @notice x/y. If the dividend is higher than maxFixedDiv() it * might overflow. You can use multiply(x,reciprocal(y)) instead. * There is a loss of precision on division for the lower mulPrecision() decimals. * @dev * Test divide(fixed1(),0) fails * Test divide(maxFixedDiv(),1) = maxFixedDiv()*(10^digits()) * Test divide(maxFixedDiv()+1,1) throws * Test divide(maxFixedDiv(),maxFixedDiv()) returns fixed1() */ function divide(int256 x, int256 y) public pure returns (int256) { if (y == fixed1()) return x; require(y != 0); require(y <= maxFixedDivisor()); return multiply(x, reciprocal(y)); } }
pragma solidity >=0.4.24 <0.6.0; /** * @title Initializable * * @dev Helper contract to support initializer functions. To use it, replace * the constructor with a function that has the `initializer` modifier. * WARNING: Unlike constructors, initializer functions must be manually * invoked. This applies both to deploying an Initializable contract, as well * as extending an Initializable contract via inheritance. * WARNING: When used with inheritance, manual care must be taken to not invoke * a parent initializer twice, or ensure that all initializers are idempotent, * because this is not dealt with automatically as with constructors. */ contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private initializing; /** * @dev Modifier to use in the initializer function of a contract. */ modifier initializer() { require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized"); bool isTopLevelCall = !initializing; if (isTopLevelCall) { initializing = true; initialized = true; } _; if (isTopLevelCall) { initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function isConstructor() private view returns (bool) { // extcodesize checks the size of the code stored in an address, and // address returns the current address. Since the code is still not // deployed when running a constructor, any checks on its code size will // yield zero, making it an effective way to detect if a contract is // under construction or not. uint256 cs; assembly { cs := extcodesize(address) } return cs == 0; } // Reserved storage space to allow for layout changes in the future. uint256[50] private ______gap; }
pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; import "./ERC20.sol"; import "../../access/roles/MinterRole.sol"; /** * @title ERC20Mintable * @dev ERC20 minting logic */ contract ERC20Mintable is Initializable, ERC20, MinterRole { function initialize(address sender) public initializer { MinterRole.initialize(sender); } /** * @dev Function to mint tokens * @param to The address that will receive the minted tokens. * @param value The amount of tokens to mint. * @return A boolean that indicates if the operation was successful. */ function mint(address to, uint256 value) public onlyMinter returns (bool) { _mint(to, value); return true; } uint256[50] private ______gap; }
pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; import "./IERC20.sol"; import "../../math/SafeMath.sol"; /** * @title Standard ERC20 token * * @dev Implementation of the basic standard token. * https://eips.ethereum.org/EIPS/eip-20 * Originally based on code by FirstBlood: * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol * * This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for * all accounts just by listening to said events. Note that this isn't required by the specification, and other * compliant implementations may not do it. */ contract ERC20 is Initializable, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowed; uint256 private _totalSupply; /** * @dev Total number of tokens in existence */ function totalSupply() public view returns (uint256) { return _totalSupply; } /** * @dev Gets the balance of the specified address. * @param owner The address to query the balance of. * @return A uint256 representing the amount owned by the passed address. */ function balanceOf(address owner) public view returns (uint256) { return _balances[owner]; } /** * @dev Function to check the amount of tokens that an owner allowed to a spender. * @param owner address The address which owns the funds. * @param spender address The address which will spend the funds. * @return A uint256 specifying the amount of tokens still available for the spender. */ function allowance(address owner, address spender) public view returns (uint256) { return _allowed[owner][spender]; } /** * @dev Transfer token to a specified address * @param to The address to transfer to. * @param value The amount to be transferred. */ function transfer(address to, uint256 value) public returns (bool) { _transfer(msg.sender, to, value); return true; } /** * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. * 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 * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. */ function approve(address spender, uint256 value) public returns (bool) { _approve(msg.sender, spender, value); return true; } /** * @dev Transfer tokens from one address to another. * Note that while this function emits an Approval event, this is not required as per the specification, * and other compliant implementations may not emit the event. * @param from address The address which you want to send tokens from * @param to address The address which you want to transfer to * @param value uint256 the amount of tokens to be transferred */ function transferFrom(address from, address to, uint256 value) public returns (bool) { _transfer(from, to, value); _approve(from, msg.sender, _allowed[from][msg.sender].sub(value)); return true; } /** * @dev Increase the amount of tokens that an owner allowed to a spender. * approve should be called when _allowed[msg.sender][spender] == 0. To increment * allowed value is better to use this function to avoid 2 calls (and wait until * the first transaction is mined) * From MonolithDAO Token.sol * Emits an Approval event. * @param spender The address which will spend the funds. * @param addedValue The amount of tokens to increase the allowance by. */ function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { _approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue)); return true; } /** * @dev Decrease the amount of tokens that an owner allowed to a spender. * approve should be called when _allowed[msg.sender][spender] == 0. To decrement * allowed value is better to use this function to avoid 2 calls (and wait until * the first transaction is mined) * From MonolithDAO Token.sol * Emits an Approval event. * @param spender The address which will spend the funds. * @param subtractedValue The amount of tokens to decrease the allowance by. */ function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { _approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue)); return true; } /** * @dev Transfer token for a specified addresses * @param from The address to transfer from. * @param to The address to transfer to. * @param value The amount to be transferred. */ function _transfer(address from, address to, uint256 value) internal { require(to != address(0)); _balances[from] = _balances[from].sub(value); _balances[to] = _balances[to].add(value); emit Transfer(from, to, value); } /** * @dev Internal function that mints an amount of the token and assigns it to * an account. This encapsulates the modification of balances such that the * proper events are emitted. * @param account The account that will receive the created tokens. * @param value The amount that will be created. */ function _mint(address account, uint256 value) internal { require(account != address(0)); _totalSupply = _totalSupply.add(value); _balances[account] = _balances[account].add(value); emit Transfer(address(0), account, value); } /** * @dev Internal function that burns an amount of the token of a given * account. * @param account The account whose tokens will be burnt. * @param value The amount that will be burnt. */ function _burn(address account, uint256 value) internal { require(account != address(0)); _totalSupply = _totalSupply.sub(value); _balances[account] = _balances[account].sub(value); emit Transfer(account, address(0), value); } /** * @dev Approve an address to spend another addresses' tokens. * @param owner The address that owns the tokens. * @param spender The address that will spend the tokens. * @param value The number of tokens that can be spent. */ function _approve(address owner, address spender, uint256 value) internal { require(spender != address(0)); require(owner != address(0)); _allowed[owner][spender] = value; emit Approval(owner, spender, value); } /** * @dev Internal function that burns an amount of the token of a given * account, deducting from the sender's allowance for said account. Uses the * internal burn function. * Emits an Approval event (reflecting the reduced allowance). * @param account The account whose tokens will be burnt. * @param value The amount that will be burnt. */ function _burnFrom(address account, uint256 value) internal { _burn(account, value); _approve(account, msg.sender, _allowed[account][msg.sender].sub(value)); } uint256[50] private ______gap; }
pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; import "../Roles.sol"; contract MinterRole is Initializable { using Roles for Roles.Role; event MinterAdded(address indexed account); event MinterRemoved(address indexed account); Roles.Role private _minters; function initialize(address sender) public initializer { if (!isMinter(sender)) { _addMinter(sender); } } modifier onlyMinter() { require(isMinter(msg.sender)); _; } function isMinter(address account) public view returns (bool) { return _minters.has(account); } function addMinter(address account) public onlyMinter { _addMinter(account); } function renounceMinter() public { _removeMinter(msg.sender); } function _addMinter(address account) internal { _minters.add(account); emit MinterAdded(account); } function _removeMinter(address account) internal { _minters.remove(account); emit MinterRemoved(account); } uint256[50] private ______gap; }
{ "optimizer": {}, "evmVersion": "constantinople", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "libraries": { "contracts/Pool.sol": { "DrawManager": "0xD215CF8D8bC151414A9c5c145fE219E746E5cE80", "FixidityLib": "0x5Ce0678E90719ff5382a57fA693394Aee468f11B" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"constant":true,"inputs":[],"name":"accountedBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"nextFeeFraction","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_admin","type":"address"}],"name":"removeAdmin","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"depositPool","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_admin","type":"address"}],"name":"isAdmin","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"currentOpenDrawId","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_feeBeneficiary","type":"address"}],"name":"setNextFeeBeneficiary","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"depositSponsorship","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"openSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_cToken","type":"address"},{"name":"_feeFraction","type":"uint256"},{"name":"_feeBeneficiary","type":"address"}],"name":"init","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_addr","type":"address"}],"name":"openBalanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"cToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_admin","type":"address"}],"name":"addAdmin","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_addr","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_blocks","type":"uint256"}],"name":"estimatedInterestRate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_addr","type":"address"}],"name":"committedBalanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"currentCommittedDrawId","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"nextSecretHash","type":"bytes32"},{"name":"lastSecret","type":"bytes32"},{"name":"_salt","type":"bytes32"}],"name":"rewardAndOpenNextDraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_feeFraction","type":"uint256"}],"name":"setNextFeeFraction","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"nextFeeBeneficiary","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_entropy","type":"bytes32"}],"name":"calculateWinner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"supplyRatePerBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"balance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_drawId","type":"uint256"}],"name":"getDraw","outputs":[{"name":"feeFraction","type":"uint256"},{"name":"feeBeneficiary","type":"address"},{"name":"openedBlock","type":"uint256"},{"name":"secretHash","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"nextSecretHash","type":"bytes32"}],"name":"openNextDraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"committedSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"SponsorshipDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"admin","type":"address"}],"name":"AdminAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"admin","type":"address"}],"name":"AdminRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"drawId","type":"uint256"},{"indexed":true,"name":"feeBeneficiary","type":"address"},{"indexed":false,"name":"secretHash","type":"bytes32"},{"indexed":false,"name":"feeFraction","type":"uint256"}],"name":"Opened","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"drawId","type":"uint256"}],"name":"Committed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"drawId","type":"uint256"},{"indexed":true,"name":"winner","type":"address"},{"indexed":false,"name":"entropy","type":"bytes32"},{"indexed":false,"name":"winnings","type":"uint256"},{"indexed":false,"name":"fee","type":"uint256"}],"name":"Rewarded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"feeFraction","type":"uint256"}],"name":"NextFeeFractionChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"feeBeneficiary","type":"address"}],"name":"NextFeeBeneficiaryChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"}],"name":"Unpaused","type":"event"}]
Contract Creation Code
60806040523480156100115760006000fd5b50610017565b613c3b806100266000396000f3fe60806040523480156100115760006000fd5b50600436106101ea5760003560e01c80637048027511610110578063944b1479116100a3578063b69ef8a811610072578063b69ef8a8146107da578063be6307c8146107f8578063c1ebb4ac14610884578063e8f099f4146108b7576101ea565b8063944b1479146106d05780639ad8bd78146106ff578063ac2defea14610749578063ae9d70b0146107bc576101ea565b80637f77fc4d116100df5780637f77fc4d1461064f5780638129fc1c1461066d578063815d85d2146106775780638456cb59146106c6576101ea565b8063704802751461051557806370a082311461055a57806377bbb757146105b357806379f08771146105f6576101ea565b80633d3d6a1a116101885780634b180da9116101575780634b180da9146103c157806350193485146104505780635c975abb146104a957806369e527da146104cb576101ea565b80633d3d6a1a146103255780633f4ba83a1461036a578063426d58e51461037457806347800068146103a3576101ea565b806323440944116101c4578063234409441461027157806324d7806c146102a0578063304c9670146102fd5780633ccfd60b1461031b576101ea565b80630937eb54146101f057806314f74b8c1461020e5780631785f53c1461022c576101ea565b60006000fd5b6101f86108d5565b6040518082815260200191505060405180910390f35b6102166108de565b6040518082815260200191505060405180910390f35b61026f600480360360208110156102435760006000fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506108e7565b005b61029e600480360360208110156102885760006000fd5b8101908080359060200190929190505050610a62565b005b6102e3600480360360208110156102b75760006000fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610cb6565b604051808215151515815260200191505060405180910390f35b610305610cdb565b6040518082815260200191505060405180910390f35b610323610cf3565b005b6103686004803603602081101561033c5760006000fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ed0565b005b610372610f72565b005b6103a16004803603602081101561038b5760006000fd5b81019080803590602001909291905050506110ea565b005b6103ab611209565b6040518082815260200191505060405180910390f35b61044e600480360360808110156103d85760006000fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506112a8565b005b610493600480360360208110156104675760006000fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611577565b6040518082815260200191505060405180910390f35b6104b161164c565b604051808215151515815260200191505060405180910390f35b6104d361165f565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6105586004803603602081101561052c5760006000fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611685565b005b61059d600480360360208110156105715760006000fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611727565b6040518082815260200191505060405180910390f35b6105e0600480360360208110156105ca5760006000fd5b810190808035906020019092919050505061177b565b6040518082815260200191505060405180910390f35b6106396004803603602081101561060d5760006000fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506117a9565b6040518082815260200191505060405180910390f35b61065761187e565b6040518082815260200191505060405180910390f35b6106756118bb565b005b6106c46004803603606081101561068e5760006000fd5b810190808035600019169060200190929190803560001916906020019092919080356000191690602001909291905050506119d5565b005b6106ce611ba9565b005b6106fd600480360360208110156106e75760006000fd5b8101908080359060200190929190505050611d22565b005b610707611dc4565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61077a600480360360208110156107605760006000fd5b810190808035600019169060200190929190505050611dea565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6107c4611e9b565b6040518082815260200191505060405180910390f35b6107e2611f4d565b6040518082815260200191505060405180910390f35b6108256004803603602081101561080f5760006000fd5b8101908080359060200190929190505050612038565b604051808581526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001838152602001826000191660001916815260200194505050505060405180910390f35b6108b56004803603602081101561089b5760006000fd5b8101908080356000191690602001909291905050506120b3565b005b6108bf61228c565b6040518082815260200191505060405180910390f35b60696000505481565b60686000505481565b6108fe3360726000506122a490919063ffffffff16565b1515610975576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f6d75737420626520616e2061646d696e0000000000000000000000000000000081526020015060200191505060405180910390fd5b61098c8160726000506122a490919063ffffffff16565b1515610a03576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f61646d696e20646f6573206e6f7420657869737400000000000000000000000081526020015060200191505060405180910390fd5b610a1a81607260005061234290919063ffffffff16565b8073ffffffffffffffffffffffffffffffffffffffff167fa3b62bc36326052d97ea62d63c3d60308ed4c3ea8ac079dd8499f1e9c4f80c0f60405160405180910390a25b5b50565b6000610a72610cdb63ffffffff16565b14151515610aeb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f7468657265206973206e6f206f70656e2064726177000000000000000000000081526020015060200191505060405180910390fd5b60016033600082828250540192505081909090555060006033600050549050607360009054906101000a900460ff16151515610b92576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f636f6e747261637420697320706175736564000000000000000000000000000081526020015060200191505060405180910390fd5b606c60005073d215cf8d8bc151414a9c5c145fe219e746e5ce8063e3451b76909133856040518463ffffffff1660e01b8152600401808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001935050505060006040518083038186803b158015610c245760006000fd5b505af4158015610c39573d600060003e3d6000fd5b50505050610c4c826123fd63ffffffff16565b3373ffffffffffffffffffffffffffffffffffffffff167f2da466a7b24304f47e87fa2e1e5a81b9831ce54fec19055ce277ca2f39ba42c4836040518082815260200191505060405180910390a25b5b60336000505481141515610cb05760006000fd5b505b5b50565b6000610ccf8260726000506122a490919063ffffffff16565b9050610cd6565b919050565b6000606c600050600401600050549050610cf0565b90565b600160336000828282505401925050819090905550600060336000505490506000606a60005060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050549050600081111515610db7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180613b706022913960400191505060405180910390fd5b6000606a60005060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050819090905550606c60005073d215cf8d8bc151414a9c5c145fe219e746e5ce80634c9b9e9c9091336040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060006040518083038186803b158015610e8e5760006000fd5b505af4158015610ea3573d600060003e3d6000fd5b50505050610eb68161293763ffffffff16565b505b60336000505481141515610ecc5760006000fd5b505b565b610ee73360726000506122a490919063ffffffff16565b1515610f5e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f6d75737420626520616e2061646d696e0000000000000000000000000000000081526020015060200191505060405180910390fd5b610f6d81612c7d63ffffffff16565b5b5b50565b607360009054906101000a900460ff161515610ff9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f636f6e7472616374206973206e6f74207061757365640000000000000000000081526020015060200191505060405180910390fd5b6110103360726000506122a490919063ffffffff16565b1515611087576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f6d75737420626520616e2061646d696e0000000000000000000000000000000081526020015060200191505060405180910390fd5b6000607360006101000a81548160ff0219169083151502179055503373ffffffffffffffffffffffffffffffffffffffff167f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa60405160405180910390a25b5b5b565b60016033600082828250540192505081909090555060006033600050549050607360009054906101000a900460ff16151515611191576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f636f6e747261637420697320706175736564000000000000000000000000000081526020015060200191505060405180910390fd5b6111a0826123fd63ffffffff16565b3373ffffffffffffffffffffffffffffffffffffffff167f6dd4ea9218ce2f17ec77769fa65225b906e99dd3f597b7e087df3bdd8f7899dd836040518082815260200191505060405180910390a25b5b603360005054811415156112045760006000fd5b505b50565b6000606c60005073d215cf8d8bc151414a9c5c145fe219e746e5ce8063ed21d6ea90916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156112615760006000fd5b505af4158015611276573d600060003e3d6000fd5b505050506040513d602081101561128d5760006000fd5b810190808051906020019092919050505090506112a5565b90565b600060019054906101000a900460ff16806112cd57506112cc612dad63ffffffff16565b5b806112e55750600060009054906101000a900460ff16155b151561133c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e815260200180613bb5602e913960400191505060405180910390fd5b6000600060019054906101000a900460ff16159050801561138e576001600060016101000a81548160ff0219169083151502179055506001600060006101000a81548160ff0219169083151502179055505b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614151515611436576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f6f776e65722063616e6e6f7420626520746865206e756c6c206164647265737381526020015060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141515156114de576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f6d6f6e6579206d61726b65742061646472657373206973207a65726f0000000081526020015060200191505060405180910390fd5b83606660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061152e85612dc563ffffffff16565b61153d83612e2363ffffffff16565b61154c82612c7d63ffffffff16565b5b801561156f576000600060016101000a81548160ff0219169083151502179055505b505b50505050565b6000606c60005073d215cf8d8bc151414a9c5c145fe219e746e5ce8063e27683ea9091846040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b1580156116035760006000fd5b505af4158015611618573d600060003e3d6000fd5b505050506040513d602081101561162f5760006000fd5b81019080805190602001909291905050509050611647565b919050565b607360009054906101000a900460ff1681565b606660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61169c3360726000506122a490919063ffffffff16565b1515611713576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f6d75737420626520616e2061646d696e0000000000000000000000000000000081526020015060200191505060405180910390fd5b61172281612dc563ffffffff16565b5b5b50565b6000606a60005060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050549050611776565b919050565b600061179d8261178f611e9b63ffffffff16565b612f6990919063ffffffff16565b90506117a4565b919050565b6000606c60005073d215cf8d8bc151414a9c5c145fe219e746e5ce80638fa1e1989091846040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b1580156118355760006000fd5b505af415801561184a573d600060003e3d6000fd5b505050506040513d60208110156118615760006000fd5b81019080805190602001909291905050509050611879565b919050565b60006001606c6000506004016000505411156118ae576001606c600050600401600050540390506118b8566118b7565b600090506118b8565b5b90565b600060019054906101000a900460ff16806118e057506118df612dad63ffffffff16565b5b806118f85750600060009054906101000a900460ff16155b151561194f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e815260200180613bb5602e913960400191505060405180910390fd5b6000600060019054906101000a900460ff1615905080156119a1576001600060016101000a81548160ff0219169083151502179055506001600060006101000a81548160ff0219169083151502179055505b600160336000508190909055505b80156119d1576000600060016101000a81548160ff0219169083151502179055505b505b565b6119ec3360726000506122a490919063ffffffff16565b1515611a63576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f6d75737420626520616e2061646d696e0000000000000000000000000000000081526020015060200191505060405180910390fd5b607360009054906101000a900460ff16151515611aeb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f636f6e747261637420697320706175736564000000000000000000000000000081526020015060200191505060405180910390fd5b6000611afb61187e63ffffffff16565b14151515611b74576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f61206472617720686173206e6f74206265656e20636f6d6d697474656400000081526020015060200191505060405180910390fd5b611b848282612fae63ffffffff16565b611b926134da63ffffffff16565b611ba18361351d63ffffffff16565b5b5b5b505050565b607360009054906101000a900460ff16151515611c31576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f636f6e747261637420697320706175736564000000000000000000000000000081526020015060200191505060405180910390fd5b611c483360726000506122a490919063ffffffff16565b1515611cbf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f6d75737420626520616e2061646d696e0000000000000000000000000000000081526020015060200191505060405180910390fd5b6001607360006101000a81548160ff0219169083151502179055503373ffffffffffffffffffffffffffffffffffffffff167f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25860405160405180910390a25b5b5b565b611d393360726000506122a490919063ffffffff16565b1515611db0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f6d75737420626520616e2061646d696e0000000000000000000000000000000081526020015060200191505060405180910390fd5b611dbf81612e2363ffffffff16565b5b5b50565b606760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000606c60005073d215cf8d8bc151414a9c5c145fe219e746e5ce80633484b6bb9091846040518363ffffffff1660e01b81526004018083815260200182600019166000191681526020019250505060206040518083038186803b158015611e525760006000fd5b505af4158015611e67573d600060003e3d6000fd5b505050506040513d6020811015611e7e5760006000fd5b81019080805190602001909291905050509050611e96565b919050565b6000606660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ae9d70b06040518163ffffffff1660e01b815260040160206040518083038186803b158015611f065760006000fd5b505afa158015611f1b573d600060003e3d6000fd5b505050506040513d6020811015611f325760006000fd5b81019080805190602001909291905050509050611f4a565b90565b6000606660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633af9e669306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015611ff15760006000fd5b505af1158015612006573d600060003e3d6000fd5b505050506040513d602081101561201d5760006000fd5b81019080805190602001909291905050509050612035565b90565b60006000600060006000606b600050600087815260200190815260200160002060005090508060000160005054945084508060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1693508350806002016000505492508250806003016000505491508150505b9193509193565b6120ca3360726000506122a490919063ffffffff16565b1515612141576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f6d75737420626520616e2061646d696e0000000000000000000000000000000081526020015060200191505060405180910390fd5b607360009054906101000a900460ff161515156121c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f636f6e747261637420697320706175736564000000000000000000000000000081526020015060200191505060405180910390fd5b60006121d961187e63ffffffff16565b141515612251576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f7468657265206973206120636f6d6d697474656420647261770000000000000081526020015060200191505060405180910390fd5b6000612261610cdb63ffffffff16565b141515612277576122766134da63ffffffff16565b5b6122868161351d63ffffffff16565b5b5b5b50565b6000606c6000506005016000505490506122a1565b90565b6000600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141515156122e35760006000fd5b8260000160005060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905061233c565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561237f5760006000fd5b61238f82826122a463ffffffff16565b151561239b5760006000fd5b60008260000160005060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505b5050565b600081111515612478576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f6465706f736974206973206e6f742067726561746572207468616e207a65726f81526020015060200191505060405180910390fd5b61248661374a63ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff166323b872dd3330846040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b1580156125415760006000fd5b505af1158015612556573d600060003e3d6000fd5b505050506040513d602081101561256d5760006000fd5b810190808051906020019092919050505015156125f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f746f6b656e207472616e73666572206661696c6564000000000000000000000081526020015060200191505060405180910390fd5b61264d81606a60005060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050546137fc90919063ffffffff16565b606a60005060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000508190909055506126b0816069600050546137fc90919063ffffffff16565b60696000508190909055506126c961374a63ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff1663095ea7b3606660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156127725760006000fd5b505af1158015612787573d600060003e3d6000fd5b505050506040513d602081101561279e5760006000fd5b81019080805190602001909291905050501515612806576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180613be36024913960400191505060405180910390fd5b6000606660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a0712d68836040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561287e5760006000fd5b505af1158015612893573d600060003e3d6000fd5b505050506040513d60208110156128aa5760006000fd5b8101908080519060200190929190505050141515612933576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f636f756c64206e6f7420737570706c79206d6f6e6579206d61726b657400000081526020015060200191505060405180910390fd5b5b50565b600081111515612992576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180613b926023913960400191505060405180910390fd5b6129aa8160696000505461382590919063ffffffff16565b60696000508190909055506000606660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663852a12e3836040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015612a2d5760006000fd5b505af1158015612a42573d600060003e3d6000fd5b505050506040513d6020811015612a595760006000fd5b8101908080519060200190929190505050141515612ae2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f636f756c64206e6f742072656465656d2066726f6d20636f6d706f756e64000081526020015060200191505060405180910390fd5b612af061374a63ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015612b775760006000fd5b505af1158015612b8c573d600060003e3d6000fd5b505050506040513d6020811015612ba35760006000fd5b81019080805190602001909291905050501515612c2b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f636f756c64206e6f74207472616e736665722077696e6e696e6773000000000081526020015060200191505060405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff167f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5826040518082815260200191505060405180910390a25b50565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515612d25576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f62656e65666963696172792073686f756c64206e6f742062652030783000000081526020015060200191505060405180910390fd5b80606760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167f4adde74fa6a2bac1c22b89b0488eb67527c033fc6110f443d1424a91a0d41d4560405160405180910390a25b50565b60006000303b905060008114915050612dc256505b90565b612ddc81607260005061384e90919063ffffffff16565b8073ffffffffffffffffffffffffffffffffffffffff167f44d6d25963f097ad14f29f06854a01f575648a1ef82f30e562ccd3889717e33960405160405180910390a25b50565b60008110151515612e9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f666565206d757374206265207a65726f206f722067726561746572000000000081526020015060200191505060405180910390fd5b670de0b6b3a76400008111151515612f22576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f666565206672616374696f6e206d7573742062652031206f72206c657373000081526020015060200191505060405180910390fd5b8060686000508190909055507f19cbde830537adec39ff348fcf33c89911750be4bc7433a01b3836d71ddb7881816040518082815260200191505060405180910390a15b50565b60006000831415612f7d5760009050612fa8565b60008284029050828482811515612f9057fe5b04141515612f9e5760006000fd5b80915050612fa856505b92915050565b6000612fbe61187e63ffffffff16565b90506000606b60005060008381526020019081526020016000206000509050838360405160200180836000191660001916815260200182600019166000191681526020019250505060405160208183030381529060405280519060200120600019168160030160005054600019161415156130a4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f73656372657420646f6573206e6f74206d61746368000000000000000000000081526020015060200191505060405180910390fd5b60006130b4611f4d63ffffffff16565b905060006130d06069600050548361382590919063ffffffff16565b9050600083600201600050548260405160200180838152602001828152602001925050506040516020818303038152906040528051906020012087189050600061311f82611dea63ffffffff16565b9050600061313a86600001600050548561390a63ffffffff16565b90506131b881606a60005060008960010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050546137fc90919063ffffffff16565b606a60005060008860010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050819090905550600061323c828661382590919063ffffffff16565b9050600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561327c575060008114155b156133e0576132d981606a60005060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050546137fc90919063ffffffff16565b606a60005060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050819090905550606c60005073d215cf8d8bc151414a9c5c145fe219e746e5ce8063e3451b76909185846040518463ffffffff1660e01b8152600401808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001935050505060006040518083038186803b1580156133b65760006000fd5b505af41580156133cb573d600060003e3d6000fd5b50505050856069600050819090905550613404565b6133f8826069600050546137fc90919063ffffffff16565b60696000508190909055505b606b6000506000898152602001908152602001600020600060008201600050600090556001820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556002820160005060009055600382016000506000905550508273ffffffffffffffffffffffffffffffffffffffff16887f39d270b67baa0bff7a394d3427e52a85d706cae15e649754ec7b54f3c9deb3f0868486604051808460001916600019168152602001838152602001828152602001935050505060405180910390a350505050505050505b5050565b60006134ea610cdb63ffffffff16565b9050807f023ad9f3cfd45bbf91919354cab651602c11b3d4267df2f095331f1e31c0c42960405160405180910390a2505b565b606c60005073d215cf8d8bc151414a9c5c145fe219e746e5ce80636290728890916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156135735760006000fd5b505af4158015613588573d600060003e3d6000fd5b505050506040513d602081101561359f5760006000fd5b81019080805190602001909291905050505060405180608001604052806068600050548152602001606760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020014381526020018260001916815260200150606b6000506000606c60005060040160005054815260200190815260200160002060005060008201518160000160005090905560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160005090905560608201518160030160005090600019169055905050606760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16606c600050600401600050547f3ba93e35d4f024f23249948504642bc624ab65bc80542daab33f8583f1b8d72f836068600050546040518083600019166000191681526020018281526020019250505060405180910390a35b50565b6000606660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636f307dc36040518163ffffffff1660e01b815260040160206040518083038186803b1580156137b55760006000fd5b505afa1580156137ca573d600060003e3d6000fd5b505050506040513d60208110156137e15760006000fd5b810190808051906020019092919050505090506137f9565b90565b6000600082840190508381101515156138155760006000fd5b8091505061381f56505b92915050565b60008282111515156138375760006000fd5b600082840390508091505061384856505b92915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561388b5760006000fd5b61389b82826122a463ffffffff16565b1515156138a85760006000fd5b60018260000160005060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505b5050565b60006000735ce0678e90719ff5382a57fa693394aee468f11b63bd5cbd62846040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561395e5760006000fd5b505af4158015613973573d600060003e3d6000fd5b505050506040513d602081101561398a5760006000fd5b810190808051906020019092919050505090506000735ce0678e90719ff5382a57fa693394aee468f11b633c4308a883735ce0678e90719ff5382a57fa693394aee468f11b63d6c1528b8960126040518363ffffffff1660e01b8152600401808381526020018260ff1660ff1681526020019250505060206040518083038186803b158015613a195760006000fd5b505af4158015613a2e573d600060003e3d6000fd5b505050506040513d6020811015613a455760006000fd5b81019080805190602001909291905050506040518363ffffffff1660e01b8152600401808381526020018281526020019250505060206040518083038186803b158015613a925760006000fd5b505af4158015613aa7573d600060003e3d6000fd5b505050506040513d6020811015613abe5760006000fd5b81019080805190602001909291905050509050735ce0678e90719ff5382a57fa693394aee468f11b630e998993826040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015613b215760006000fd5b505af4158015613b36573d600060003e3d6000fd5b505050506040513d6020811015613b4d5760006000fd5b810190808051906020019092919050505092505050613b695650505b9291505056fe62616c616e63652068617320616c7265616479206265656e2077697468647261776e7769746864726177616c206973206e6f742067726561746572207468616e207a65726f436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a6564636f756c64206e6f7420617070726f7665206d6f6e6579206d61726b6574207370656e64a265627a7a723058204f56aea8ae7585b4254f75cd16f60cfe6d95ca3c3081d15b87c30f009647b05964736f6c634300050a0032
Deployed Bytecode
0x60806040523480156100115760006000fd5b50600436106101ea5760003560e01c80637048027511610110578063944b1479116100a3578063b69ef8a811610072578063b69ef8a8146107da578063be6307c8146107f8578063c1ebb4ac14610884578063e8f099f4146108b7576101ea565b8063944b1479146106d05780639ad8bd78146106ff578063ac2defea14610749578063ae9d70b0146107bc576101ea565b80637f77fc4d116100df5780637f77fc4d1461064f5780638129fc1c1461066d578063815d85d2146106775780638456cb59146106c6576101ea565b8063704802751461051557806370a082311461055a57806377bbb757146105b357806379f08771146105f6576101ea565b80633d3d6a1a116101885780634b180da9116101575780634b180da9146103c157806350193485146104505780635c975abb146104a957806369e527da146104cb576101ea565b80633d3d6a1a146103255780633f4ba83a1461036a578063426d58e51461037457806347800068146103a3576101ea565b806323440944116101c4578063234409441461027157806324d7806c146102a0578063304c9670146102fd5780633ccfd60b1461031b576101ea565b80630937eb54146101f057806314f74b8c1461020e5780631785f53c1461022c576101ea565b60006000fd5b6101f86108d5565b6040518082815260200191505060405180910390f35b6102166108de565b6040518082815260200191505060405180910390f35b61026f600480360360208110156102435760006000fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506108e7565b005b61029e600480360360208110156102885760006000fd5b8101908080359060200190929190505050610a62565b005b6102e3600480360360208110156102b75760006000fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610cb6565b604051808215151515815260200191505060405180910390f35b610305610cdb565b6040518082815260200191505060405180910390f35b610323610cf3565b005b6103686004803603602081101561033c5760006000fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ed0565b005b610372610f72565b005b6103a16004803603602081101561038b5760006000fd5b81019080803590602001909291905050506110ea565b005b6103ab611209565b6040518082815260200191505060405180910390f35b61044e600480360360808110156103d85760006000fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506112a8565b005b610493600480360360208110156104675760006000fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611577565b6040518082815260200191505060405180910390f35b6104b161164c565b604051808215151515815260200191505060405180910390f35b6104d361165f565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6105586004803603602081101561052c5760006000fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611685565b005b61059d600480360360208110156105715760006000fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611727565b6040518082815260200191505060405180910390f35b6105e0600480360360208110156105ca5760006000fd5b810190808035906020019092919050505061177b565b6040518082815260200191505060405180910390f35b6106396004803603602081101561060d5760006000fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506117a9565b6040518082815260200191505060405180910390f35b61065761187e565b6040518082815260200191505060405180910390f35b6106756118bb565b005b6106c46004803603606081101561068e5760006000fd5b810190808035600019169060200190929190803560001916906020019092919080356000191690602001909291905050506119d5565b005b6106ce611ba9565b005b6106fd600480360360208110156106e75760006000fd5b8101908080359060200190929190505050611d22565b005b610707611dc4565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61077a600480360360208110156107605760006000fd5b810190808035600019169060200190929190505050611dea565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6107c4611e9b565b6040518082815260200191505060405180910390f35b6107e2611f4d565b6040518082815260200191505060405180910390f35b6108256004803603602081101561080f5760006000fd5b8101908080359060200190929190505050612038565b604051808581526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001838152602001826000191660001916815260200194505050505060405180910390f35b6108b56004803603602081101561089b5760006000fd5b8101908080356000191690602001909291905050506120b3565b005b6108bf61228c565b6040518082815260200191505060405180910390f35b60696000505481565b60686000505481565b6108fe3360726000506122a490919063ffffffff16565b1515610975576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f6d75737420626520616e2061646d696e0000000000000000000000000000000081526020015060200191505060405180910390fd5b61098c8160726000506122a490919063ffffffff16565b1515610a03576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f61646d696e20646f6573206e6f7420657869737400000000000000000000000081526020015060200191505060405180910390fd5b610a1a81607260005061234290919063ffffffff16565b8073ffffffffffffffffffffffffffffffffffffffff167fa3b62bc36326052d97ea62d63c3d60308ed4c3ea8ac079dd8499f1e9c4f80c0f60405160405180910390a25b5b50565b6000610a72610cdb63ffffffff16565b14151515610aeb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f7468657265206973206e6f206f70656e2064726177000000000000000000000081526020015060200191505060405180910390fd5b60016033600082828250540192505081909090555060006033600050549050607360009054906101000a900460ff16151515610b92576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f636f6e747261637420697320706175736564000000000000000000000000000081526020015060200191505060405180910390fd5b606c60005073d215cf8d8bc151414a9c5c145fe219e746e5ce8063e3451b76909133856040518463ffffffff1660e01b8152600401808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001935050505060006040518083038186803b158015610c245760006000fd5b505af4158015610c39573d600060003e3d6000fd5b50505050610c4c826123fd63ffffffff16565b3373ffffffffffffffffffffffffffffffffffffffff167f2da466a7b24304f47e87fa2e1e5a81b9831ce54fec19055ce277ca2f39ba42c4836040518082815260200191505060405180910390a25b5b60336000505481141515610cb05760006000fd5b505b5b50565b6000610ccf8260726000506122a490919063ffffffff16565b9050610cd6565b919050565b6000606c600050600401600050549050610cf0565b90565b600160336000828282505401925050819090905550600060336000505490506000606a60005060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050549050600081111515610db7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180613b706022913960400191505060405180910390fd5b6000606a60005060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050819090905550606c60005073d215cf8d8bc151414a9c5c145fe219e746e5ce80634c9b9e9c9091336040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060006040518083038186803b158015610e8e5760006000fd5b505af4158015610ea3573d600060003e3d6000fd5b50505050610eb68161293763ffffffff16565b505b60336000505481141515610ecc5760006000fd5b505b565b610ee73360726000506122a490919063ffffffff16565b1515610f5e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f6d75737420626520616e2061646d696e0000000000000000000000000000000081526020015060200191505060405180910390fd5b610f6d81612c7d63ffffffff16565b5b5b50565b607360009054906101000a900460ff161515610ff9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f636f6e7472616374206973206e6f74207061757365640000000000000000000081526020015060200191505060405180910390fd5b6110103360726000506122a490919063ffffffff16565b1515611087576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f6d75737420626520616e2061646d696e0000000000000000000000000000000081526020015060200191505060405180910390fd5b6000607360006101000a81548160ff0219169083151502179055503373ffffffffffffffffffffffffffffffffffffffff167f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa60405160405180910390a25b5b5b565b60016033600082828250540192505081909090555060006033600050549050607360009054906101000a900460ff16151515611191576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f636f6e747261637420697320706175736564000000000000000000000000000081526020015060200191505060405180910390fd5b6111a0826123fd63ffffffff16565b3373ffffffffffffffffffffffffffffffffffffffff167f6dd4ea9218ce2f17ec77769fa65225b906e99dd3f597b7e087df3bdd8f7899dd836040518082815260200191505060405180910390a25b5b603360005054811415156112045760006000fd5b505b50565b6000606c60005073d215cf8d8bc151414a9c5c145fe219e746e5ce8063ed21d6ea90916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156112615760006000fd5b505af4158015611276573d600060003e3d6000fd5b505050506040513d602081101561128d5760006000fd5b810190808051906020019092919050505090506112a5565b90565b600060019054906101000a900460ff16806112cd57506112cc612dad63ffffffff16565b5b806112e55750600060009054906101000a900460ff16155b151561133c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e815260200180613bb5602e913960400191505060405180910390fd5b6000600060019054906101000a900460ff16159050801561138e576001600060016101000a81548160ff0219169083151502179055506001600060006101000a81548160ff0219169083151502179055505b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614151515611436576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f6f776e65722063616e6e6f7420626520746865206e756c6c206164647265737381526020015060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141515156114de576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f6d6f6e6579206d61726b65742061646472657373206973207a65726f0000000081526020015060200191505060405180910390fd5b83606660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061152e85612dc563ffffffff16565b61153d83612e2363ffffffff16565b61154c82612c7d63ffffffff16565b5b801561156f576000600060016101000a81548160ff0219169083151502179055505b505b50505050565b6000606c60005073d215cf8d8bc151414a9c5c145fe219e746e5ce8063e27683ea9091846040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b1580156116035760006000fd5b505af4158015611618573d600060003e3d6000fd5b505050506040513d602081101561162f5760006000fd5b81019080805190602001909291905050509050611647565b919050565b607360009054906101000a900460ff1681565b606660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61169c3360726000506122a490919063ffffffff16565b1515611713576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f6d75737420626520616e2061646d696e0000000000000000000000000000000081526020015060200191505060405180910390fd5b61172281612dc563ffffffff16565b5b5b50565b6000606a60005060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050549050611776565b919050565b600061179d8261178f611e9b63ffffffff16565b612f6990919063ffffffff16565b90506117a4565b919050565b6000606c60005073d215cf8d8bc151414a9c5c145fe219e746e5ce80638fa1e1989091846040518363ffffffff1660e01b8152600401808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b1580156118355760006000fd5b505af415801561184a573d600060003e3d6000fd5b505050506040513d60208110156118615760006000fd5b81019080805190602001909291905050509050611879565b919050565b60006001606c6000506004016000505411156118ae576001606c600050600401600050540390506118b8566118b7565b600090506118b8565b5b90565b600060019054906101000a900460ff16806118e057506118df612dad63ffffffff16565b5b806118f85750600060009054906101000a900460ff16155b151561194f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e815260200180613bb5602e913960400191505060405180910390fd5b6000600060019054906101000a900460ff1615905080156119a1576001600060016101000a81548160ff0219169083151502179055506001600060006101000a81548160ff0219169083151502179055505b600160336000508190909055505b80156119d1576000600060016101000a81548160ff0219169083151502179055505b505b565b6119ec3360726000506122a490919063ffffffff16565b1515611a63576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f6d75737420626520616e2061646d696e0000000000000000000000000000000081526020015060200191505060405180910390fd5b607360009054906101000a900460ff16151515611aeb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f636f6e747261637420697320706175736564000000000000000000000000000081526020015060200191505060405180910390fd5b6000611afb61187e63ffffffff16565b14151515611b74576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f61206472617720686173206e6f74206265656e20636f6d6d697474656400000081526020015060200191505060405180910390fd5b611b848282612fae63ffffffff16565b611b926134da63ffffffff16565b611ba18361351d63ffffffff16565b5b5b5b505050565b607360009054906101000a900460ff16151515611c31576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f636f6e747261637420697320706175736564000000000000000000000000000081526020015060200191505060405180910390fd5b611c483360726000506122a490919063ffffffff16565b1515611cbf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f6d75737420626520616e2061646d696e0000000000000000000000000000000081526020015060200191505060405180910390fd5b6001607360006101000a81548160ff0219169083151502179055503373ffffffffffffffffffffffffffffffffffffffff167f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25860405160405180910390a25b5b5b565b611d393360726000506122a490919063ffffffff16565b1515611db0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f6d75737420626520616e2061646d696e0000000000000000000000000000000081526020015060200191505060405180910390fd5b611dbf81612e2363ffffffff16565b5b5b50565b606760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000606c60005073d215cf8d8bc151414a9c5c145fe219e746e5ce80633484b6bb9091846040518363ffffffff1660e01b81526004018083815260200182600019166000191681526020019250505060206040518083038186803b158015611e525760006000fd5b505af4158015611e67573d600060003e3d6000fd5b505050506040513d6020811015611e7e5760006000fd5b81019080805190602001909291905050509050611e96565b919050565b6000606660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ae9d70b06040518163ffffffff1660e01b815260040160206040518083038186803b158015611f065760006000fd5b505afa158015611f1b573d600060003e3d6000fd5b505050506040513d6020811015611f325760006000fd5b81019080805190602001909291905050509050611f4a565b90565b6000606660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633af9e669306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015611ff15760006000fd5b505af1158015612006573d600060003e3d6000fd5b505050506040513d602081101561201d5760006000fd5b81019080805190602001909291905050509050612035565b90565b60006000600060006000606b600050600087815260200190815260200160002060005090508060000160005054945084508060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1693508350806002016000505492508250806003016000505491508150505b9193509193565b6120ca3360726000506122a490919063ffffffff16565b1515612141576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f6d75737420626520616e2061646d696e0000000000000000000000000000000081526020015060200191505060405180910390fd5b607360009054906101000a900460ff161515156121c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f636f6e747261637420697320706175736564000000000000000000000000000081526020015060200191505060405180910390fd5b60006121d961187e63ffffffff16565b141515612251576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f7468657265206973206120636f6d6d697474656420647261770000000000000081526020015060200191505060405180910390fd5b6000612261610cdb63ffffffff16565b141515612277576122766134da63ffffffff16565b5b6122868161351d63ffffffff16565b5b5b5b50565b6000606c6000506005016000505490506122a1565b90565b6000600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141515156122e35760006000fd5b8260000160005060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905061233c565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561237f5760006000fd5b61238f82826122a463ffffffff16565b151561239b5760006000fd5b60008260000160005060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505b5050565b600081111515612478576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f6465706f736974206973206e6f742067726561746572207468616e207a65726f81526020015060200191505060405180910390fd5b61248661374a63ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff166323b872dd3330846040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b1580156125415760006000fd5b505af1158015612556573d600060003e3d6000fd5b505050506040513d602081101561256d5760006000fd5b810190808051906020019092919050505015156125f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f746f6b656e207472616e73666572206661696c6564000000000000000000000081526020015060200191505060405180910390fd5b61264d81606a60005060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050546137fc90919063ffffffff16565b606a60005060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000508190909055506126b0816069600050546137fc90919063ffffffff16565b60696000508190909055506126c961374a63ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff1663095ea7b3606660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156127725760006000fd5b505af1158015612787573d600060003e3d6000fd5b505050506040513d602081101561279e5760006000fd5b81019080805190602001909291905050501515612806576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180613be36024913960400191505060405180910390fd5b6000606660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a0712d68836040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561287e5760006000fd5b505af1158015612893573d600060003e3d6000fd5b505050506040513d60208110156128aa5760006000fd5b8101908080519060200190929190505050141515612933576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f636f756c64206e6f7420737570706c79206d6f6e6579206d61726b657400000081526020015060200191505060405180910390fd5b5b50565b600081111515612992576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180613b926023913960400191505060405180910390fd5b6129aa8160696000505461382590919063ffffffff16565b60696000508190909055506000606660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663852a12e3836040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015612a2d5760006000fd5b505af1158015612a42573d600060003e3d6000fd5b505050506040513d6020811015612a595760006000fd5b8101908080519060200190929190505050141515612ae2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f636f756c64206e6f742072656465656d2066726f6d20636f6d706f756e64000081526020015060200191505060405180910390fd5b612af061374a63ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015612b775760006000fd5b505af1158015612b8c573d600060003e3d6000fd5b505050506040513d6020811015612ba35760006000fd5b81019080805190602001909291905050501515612c2b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f636f756c64206e6f74207472616e736665722077696e6e696e6773000000000081526020015060200191505060405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff167f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5826040518082815260200191505060405180910390a25b50565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515612d25576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f62656e65666963696172792073686f756c64206e6f742062652030783000000081526020015060200191505060405180910390fd5b80606760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167f4adde74fa6a2bac1c22b89b0488eb67527c033fc6110f443d1424a91a0d41d4560405160405180910390a25b50565b60006000303b905060008114915050612dc256505b90565b612ddc81607260005061384e90919063ffffffff16565b8073ffffffffffffffffffffffffffffffffffffffff167f44d6d25963f097ad14f29f06854a01f575648a1ef82f30e562ccd3889717e33960405160405180910390a25b50565b60008110151515612e9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f666565206d757374206265207a65726f206f722067726561746572000000000081526020015060200191505060405180910390fd5b670de0b6b3a76400008111151515612f22576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f666565206672616374696f6e206d7573742062652031206f72206c657373000081526020015060200191505060405180910390fd5b8060686000508190909055507f19cbde830537adec39ff348fcf33c89911750be4bc7433a01b3836d71ddb7881816040518082815260200191505060405180910390a15b50565b60006000831415612f7d5760009050612fa8565b60008284029050828482811515612f9057fe5b04141515612f9e5760006000fd5b80915050612fa856505b92915050565b6000612fbe61187e63ffffffff16565b90506000606b60005060008381526020019081526020016000206000509050838360405160200180836000191660001916815260200182600019166000191681526020019250505060405160208183030381529060405280519060200120600019168160030160005054600019161415156130a4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f73656372657420646f6573206e6f74206d61746368000000000000000000000081526020015060200191505060405180910390fd5b60006130b4611f4d63ffffffff16565b905060006130d06069600050548361382590919063ffffffff16565b9050600083600201600050548260405160200180838152602001828152602001925050506040516020818303038152906040528051906020012087189050600061311f82611dea63ffffffff16565b9050600061313a86600001600050548561390a63ffffffff16565b90506131b881606a60005060008960010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050546137fc90919063ffffffff16565b606a60005060008860010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050819090905550600061323c828661382590919063ffffffff16565b9050600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561327c575060008114155b156133e0576132d981606a60005060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050546137fc90919063ffffffff16565b606a60005060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050819090905550606c60005073d215cf8d8bc151414a9c5c145fe219e746e5ce8063e3451b76909185846040518463ffffffff1660e01b8152600401808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001935050505060006040518083038186803b1580156133b65760006000fd5b505af41580156133cb573d600060003e3d6000fd5b50505050856069600050819090905550613404565b6133f8826069600050546137fc90919063ffffffff16565b60696000508190909055505b606b6000506000898152602001908152602001600020600060008201600050600090556001820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556002820160005060009055600382016000506000905550508273ffffffffffffffffffffffffffffffffffffffff16887f39d270b67baa0bff7a394d3427e52a85d706cae15e649754ec7b54f3c9deb3f0868486604051808460001916600019168152602001838152602001828152602001935050505060405180910390a350505050505050505b5050565b60006134ea610cdb63ffffffff16565b9050807f023ad9f3cfd45bbf91919354cab651602c11b3d4267df2f095331f1e31c0c42960405160405180910390a2505b565b606c60005073d215cf8d8bc151414a9c5c145fe219e746e5ce80636290728890916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156135735760006000fd5b505af4158015613588573d600060003e3d6000fd5b505050506040513d602081101561359f5760006000fd5b81019080805190602001909291905050505060405180608001604052806068600050548152602001606760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020014381526020018260001916815260200150606b6000506000606c60005060040160005054815260200190815260200160002060005060008201518160000160005090905560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160005090905560608201518160030160005090600019169055905050606760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16606c600050600401600050547f3ba93e35d4f024f23249948504642bc624ab65bc80542daab33f8583f1b8d72f836068600050546040518083600019166000191681526020018281526020019250505060405180910390a35b50565b6000606660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636f307dc36040518163ffffffff1660e01b815260040160206040518083038186803b1580156137b55760006000fd5b505afa1580156137ca573d600060003e3d6000fd5b505050506040513d60208110156137e15760006000fd5b810190808051906020019092919050505090506137f9565b90565b6000600082840190508381101515156138155760006000fd5b8091505061381f56505b92915050565b60008282111515156138375760006000fd5b600082840390508091505061384856505b92915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561388b5760006000fd5b61389b82826122a463ffffffff16565b1515156138a85760006000fd5b60018260000160005060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505b5050565b60006000735ce0678e90719ff5382a57fa693394aee468f11b63bd5cbd62846040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561395e5760006000fd5b505af4158015613973573d600060003e3d6000fd5b505050506040513d602081101561398a5760006000fd5b810190808051906020019092919050505090506000735ce0678e90719ff5382a57fa693394aee468f11b633c4308a883735ce0678e90719ff5382a57fa693394aee468f11b63d6c1528b8960126040518363ffffffff1660e01b8152600401808381526020018260ff1660ff1681526020019250505060206040518083038186803b158015613a195760006000fd5b505af4158015613a2e573d600060003e3d6000fd5b505050506040513d6020811015613a455760006000fd5b81019080805190602001909291905050506040518363ffffffff1660e01b8152600401808381526020018281526020019250505060206040518083038186803b158015613a925760006000fd5b505af4158015613aa7573d600060003e3d6000fd5b505050506040513d6020811015613abe5760006000fd5b81019080805190602001909291905050509050735ce0678e90719ff5382a57fa693394aee468f11b630e998993826040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015613b215760006000fd5b505af4158015613b36573d600060003e3d6000fd5b505050506040513d6020811015613b4d5760006000fd5b810190808051906020019092919050505092505050613b695650505b9291505056fe62616c616e63652068617320616c7265616479206265656e2077697468647261776e7769746864726177616c206973206e6f742067726561746572207468616e207a65726f436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a6564636f756c64206e6f7420617070726f7665206d6f6e6579206d61726b6574207370656e64a265627a7a723058204f56aea8ae7585b4254f75cd16f60cfe6d95ca3c3081d15b87c30f009647b05964736f6c634300050a0032
Deployed Bytecode Sourcemap
2420:19965:12:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;2420:19965:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5760:31;;;:::i;:::-;;;;;;;;;;;;;;;;;;;5682:30;;;:::i;:::-;;;;;;;;;;;;;;;;;;;21169:175;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;21169:175:12;;;;;;;;;;;;;;;;;;;:::i;:::-;;13196:264;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;13196:264:12;;;;;;;;;;;;;;;;;:::i;:::-;;20821:96;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;20821:96:12;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;15401:100;;;:::i;:::-;;;;;;;;;;;;;;;;;;;14393:316;;;:::i;:::-;;20008:123;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;20008:123:12;;;;;;;;;;;;;;;;;;;:::i;:::-;;21909:104;;;:::i;:::-;;12605:184;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;12605:184:12;;;;;;;;;;;;;;;;;:::i;:::-;;18348:92;;;:::i;:::-;;;;;;;;;;;;;;;;;;;6745:416;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;6745:416:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;17166:116;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;17166:116:12;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;6236:18;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;5489:21;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;20558:79;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;20558:79:12;;;;;;;;;;;;;;;;;;;:::i;:::-;;17498:97;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;17498:97:12;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;18684:129;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;18684:129:12;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;16776:126;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;16776:126:12;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;15619:185;;;:::i;:::-;;;;;;;;;;;;;;;;;;;466:214:8;;;:::i;:::-;;8819:273:12;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;8819:273:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;21804:101;;;:::i;:::-;;19401:111;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;19401:111:12;;;;;;;;;;;;;;;;;:::i;:::-;;5581:33;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;17799:126;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;17799:126:12;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;18980:105;;;:::i;:::-;;;;;;;;;;;;;;;;;;;21697:103;;;:::i;:::-;;;;;;;;;;;;;;;;;;;16168:354;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;16168:354:12;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8147:238;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;8147:238:12;;;;;;;;;;;;;;;;;;;;:::i;:::-;;18083:100;;;:::i;:::-;;;;;;;;;;;;;;;;;;;5760:31;;;;;;:::o;5682:30::-;;;;;;:::o;21169:175::-;22052:22;22063:10;22052:6;;;:10;;:22;;;;:::i;:::-;22044:51;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21237:18;21248:6;21237;;;:10;;:18;;;;:::i;:::-;21229:51;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21286:21;21300:6;21286;;;:13;;:21;;;;:::i;:::-;21332:6;21319:20;;;;;;;;;;;;22101:1;21169:175;;:::o;13196:264::-;22175:1;22152:19;:17;:19;;:::i;:::-;:24;;22144:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1106:1:8;1089:13;;:18;;;;;;;;;;;;;;;1117:20;1140:13;;;;1117:36;;22342:6:12;;;;;;;;;;;22341:7;22333:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13326:9;;;:17;;;;13344:10;13356:7;13326:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;13326:38:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;13326:38:12;;;;13396:17;13405:7;13396:8;:17;;:::i;:::-;13435:10;13425:30;;;13447:7;13425:30;;;;;;;;;;;;;;;;;;22377:1;1163::8;1198:13;;;;1182:12;:29;1174:38;;;;;;;;22208:1:12;;13196:264;;:::o;20821:96::-;20875:4;20894:18;20905:6;20894;;;:10;;:18;;;;:::i;:::-;20887:25;;;;20821:96;;;;:::o;15401:100::-;15451:7;15473:9;;;:23;;;;;15466:30;;;;15401:100;;:::o;14393:316::-;1106:1:8;1089:13;;:18;;;;;;;;;;;;;;;1117:20;1140:13;;;;1117:36;;14439:12:12;14454:8;;;:20;14463:10;14454:20;;;;;;;;;;;;;;;;;;14439:35;;14499:1;14489:7;:11;14481:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14602:1;14579:8;;;:20;14588:10;14579:20;;;;;;;;;;;;;;;;:24;;;;;;;14649:9;;;:18;;;;14668:10;14649:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;14649:30:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;14649:30:12;;;;14686:18;14696:7;14686:9;:18;;:::i;:::-;1163:1:8;;1198:13;;;;1182:12;:29;1174:38;;;;;;;;14393:316:12;;:::o;20008:123::-;22052:22;22063:10;22052:6;;;:10;;:22;;;;:::i;:::-;22044:51;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;20087:39;20110:15;20087:22;:39;;:::i;:::-;22101:1;20008:123;;:::o;21909:104::-;22254:6;;;;;;;;;;;22246:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;22052:22;22063:10;22052:6;;;:10;;:22;;;;:::i;:::-;22044:51;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21971:5;21962:6;;:14;;;;;;;;;;;;;;;;;;21997:10;21988:20;;;;;;;;;;;;22101:1;22293;21909:104;:::o;12605:184::-;1106:1:8;1089:13;;:18;;;;;;;;;;;;;;;1117:20;1140:13;;;;1117:36;;22342:6:12;;;;;;;;;;;22341:7;22333:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12714:17;12723:7;12714:8;:17;;:::i;:::-;12764:10;12743:41;;;12776:7;12743:41;;;;;;;;;;;;;;;;;;22377:1;1163::8;1198:13;;;;1182:12;:29;1174:38;;;;;;;;12605:184:12;;;:::o;18348:92::-;18391:7;18413:9;;;:20;;;;:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;18413:22:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;18413:22:12;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;18413:22:12;;;;;;;;;;;;;;;;18406:29;;;;18348:92;;:::o;6745:416::-;1024:12:9;;;;;;;;;;;:31;;;;1040:15;:13;:15;;:::i;:::-;1024:31;:47;;;;1060:11;;;;;;;;;;;1059:12;1024:47;1016:106;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1129:19;1152:12;;;;;;;;;;;1151:13;1129:35;;1174:14;1170:80;;;1213:4;1198:12;;:19;;;;;;;;;;;;;;;;;;1239:4;1225:11;;:18;;;;;;;;;;;;;;;;;;1170:80;6911:1:12;6893:20;;:6;:20;;;;6885:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6983:1;6964:21;;:7;:21;;;;6956:62;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7041:7;7024:6;;:25;;;;;;;;;;;;;;;;;;7055:17;7065:6;7055:9;:17;;:::i;:::-;7078:33;7098:12;7078:19;:33;;:::i;:::-;7117:39;7140:15;7117:22;:39;;:::i;:::-;1256:1:9;1268:14;1264:55;;;1307:5;1292:12;;:20;;;;;;;;;;;;;;;;;;1264:55;6745:416:12;;;;;;:::o;17166:116::-;17225:7;17247:9;;;:23;;;;17271:5;17247:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;17247:30:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;17247:30:12;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;17247:30:12;;;;;;;;;;;;;;;;17240:37;;;;17166:116;;;;:::o;6236:18::-;;;;;;;;;;;;;:::o;5489:21::-;;;;;;;;;;;;;:::o;20558:79::-;22052:22;22063:10;22052:6;;;:10;;:22;;;;:::i;:::-;22044:51;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;20615:17;20625:6;20615:9;:17;;:::i;:::-;22101:1;20558:79;;:::o;17498:97::-;17553:7;17575:8;;;:15;17584:5;17575:15;;;;;;;;;;;;;;;;;;17568:22;;;;17498:97;;;;:::o;18684:129::-;18753:7;18775:33;18800:7;18775:20;:18;:20;;:::i;:::-;:24;;:33;;;;:::i;:::-;18768:40;;;;18684:129;;;;:::o;16776:126::-;16840:7;16862:9;;;:28;;;;16891:5;16862:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;16862:35:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;16862:35:12;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;16862:35:12;;;;;;;;;;;;;;;;16855:42;;;;16776:126;;;;:::o;15619:185::-;15674:7;15719:1;15693:9;;;:23;;;;;:27;15689:111;;;15763:1;15737:9;;;:23;;;;;:27;15730:34;;;;15689:111;;;15792:1;15785:8;;;;15689:111;15619:185;;:::o;466:214:8:-;1024:12:9;;;;;;;;;;;:31;;;;1040:15;:13;:15;;:::i;:::-;1024:31;:47;;;;1060:11;;;;;;;;;;;1059:12;1024:47;1016:106;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1129:19;1152:12;;;;;;;;;;;1151:13;1129:35;;1174:14;1170:80;;;1213:4;1198:12;;:19;;;;;;;;;;;;;;;;;;1239:4;1225:11;;:18;;;;;;;;;;;;;;;;;;1170:80;672:1:8;656:13;;:17;;;;;;;1256:1:9;1268:14;1264:55;;;1307:5;1292:12;;:20;;;;;;;;;;;;;;;;;;1264:55;466:214:8;;:::o;8819:273:12:-;22052:22;22063:10;22052:6;;;:10;;:22;;;;:::i;:::-;22044:51;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;22342:6;;;;;;;;;;;22341:7;22333:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8981:1;8953:24;:22;:24;;:::i;:::-;:29;;8945:71;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9022:25;9029:10;9041:5;9022:6;:25;;:::i;:::-;9053:8;:6;:8;;:::i;:::-;9067:20;9072:14;9067:4;:20;;:::i;:::-;22377:1;22101;8819:273;;;;:::o;21804:101::-;22342:6;;;;;;;;;;;22341:7;22333:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;22052:22;22063:10;22052:6;;;:10;;:22;;;;:::i;:::-;22044:51;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21866:4;21857:6;;:13;;;;;;;;;;;;;;;;;;21889:10;21882:18;;;;;;;;;;;;22101:1;22377;21804:101;:::o;19401:111::-;22052:22;22063:10;22052:6;;;:10;;:22;;;;:::i;:::-;22044:51;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19474:33;19494:12;19474:19;:33;;:::i;:::-;22101:1;19401:111;;:::o;5581:33::-;;;;;;;;;;;;;:::o;17799:126::-;17863:7;17885:9;;;:25;;;;17911:8;17885:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;17885:35:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;17885:35:12;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;17885:35:12;;;;;;;;;;;;;;;;17878:42;;;;17799:126;;;;:::o;18980:105::-;19031:7;19053:6;;;;;;;;;;;:25;;;:27;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;19053:27:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;19053:27:12;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;19053:27:12;;;;;;;;;;;;;;;;19046:34;;;;18980:105;;:::o;21697:103::-;21732:7;21754:6;;;;;;;;;;;:26;;;21789:4;21754:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;21754:41:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;21754:41:12;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;21754:41:12;;;;;;;;;;;;;;;;21747:48;;;;21697:103;;:::o;16168:354::-;16228:19;16253:22;16281:19;16306:18;16335:17;16355:5;;;:14;16361:7;16355:14;;;;;;;;;;;;;16335:34;;16389:4;:16;;;;;16375:30;;;;16428:4;:19;;;;;;;;;;;;16411:36;;;;16467:4;:16;;;;;16453:30;;;;16502:4;:15;;;;;16489:28;;;;16168:354;;;;;;;:::o;8147:238::-;22052:22;22063:10;22052:6;;;:10;;:22;;;;:::i;:::-;22044:51;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;22342:6;;;;;;;;;;;22341:7;22333:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8265:1;8237:24;:22;:24;;:::i;:::-;:29;8229:67;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8329:1;8306:19;:17;:19;;:::i;:::-;:24;;8302:53;;;8340:8;:6;:8;;:::i;:::-;8302:53;8360:20;8365:14;8360:4;:20;;:::i;:::-;22377:1;22101;8147:238;;:::o;18083:100::-;18131:7;18153:9;;;:25;;;;;18146:32;;;;18083:100;;:::o;786:162:1:-;858:4;901:1;882:21;;:7;:21;;;;874:30;;;;;;;;921:4;:11;;;;:20;933:7;921:20;;;;;;;;;;;;;;;;;;;;;;;;;914:27;;;;786:162;;;;;:::o;514:184::-;612:1;593:21;;:7;:21;;;;585:30;;;;;;;;633:18;637:4;643:7;633:3;:18;;:::i;:::-;625:27;;;;;;;;686:5;663:4;:11;;;;:20;675:7;663:20;;;;;;;;;;;;;;;;:28;;;;;;;;;;;;;;;;;;514:184;;;:::o;13668:645:12:-;13736:1;13726:7;:11;13718:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13835:7;:5;:7;;:::i;:::-;:20;;;13856:10;13876:4;13883:7;13835:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;13835:56:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;13835:56:12;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;13835:56:12;;;;;;;;;;;;;;;;13827:90;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13980:33;14005:7;13980:8;;;:20;13989:10;13980:20;;;;;;;;;;;;;;;;;;:24;;:33;;;;:::i;:::-;13957:8;;;:20;13966:10;13957:20;;;;;;;;;;;;;;;;:56;;;;;;;14080:29;14101:7;14080:16;;;;:20;;:29;;;;:::i;:::-;14061:16;;:48;;;;;;;14153:7;:5;:7;;:::i;:::-;:15;;;14177:6;;;;;;;;;;;14186:7;14153:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;14153:41:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;14153:41:12;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;14153:41:12;;;;;;;;;;;;;;;;14145:90;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14273:1;14249:6;;;;;;;;;;;:11;;;14261:7;14249:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;14249:20:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;14249:20:12;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;14249:20:12;;;;;;;;;;;;;;;;:25;14241:67;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13668:645;;:::o;14827:466::-;14896:1;14886:7;:11;14878:59;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15004:29;15025:7;15004:16;;;;:20;;:29;;;;:::i;:::-;14985:16;;:48;;;;;;;15127:1;15091:6;;;;;;;;;;;:23;;;15115:7;15091:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;15091:32:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;15091:32:12;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;15091:32:12;;;;;;;;;;;;;;;;:37;15083:80;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15177:7;:5;:7;;:::i;:::-;:16;;;15194:10;15206:7;15177:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;15177:37:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;15177:37:12;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;15177:37:12;;;;;;;;;;;;;;;;15169:77;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15268:10;15258:30;;;15280:7;15258:30;;;;;;;;;;;;;;;;;;14827:466;;:::o;20135:244::-;20242:1;20215:29;;:15;:29;;;;20207:71;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;20305:15;20284:18;;:36;;;;;;;;;;;;;;;;;;20358:15;20332:42;;;;;;;;;;;;20135:244;;:::o;1409:467:9:-;1456:4;1797:10;1842:7;1830:20;1824:26;;1870:1;1864:2;:7;1857:14;;;;;1409:467;;;:::o;20921:103:12:-;20971:18;20982:6;20971;;;:10;;:18;;;;:::i;:::-;21012:6;21001:18;;;;;;;;;;;;20921:103;;:::o;19516:289::-;19606:1;19590:12;:17;;19582:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2616:19;19653:12;:28;;19645:71;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19740:12;19722:15;;:30;;;;;;;19764:36;19787:12;19764:36;;;;;;;;;;;;;;;;;;19516:289;;:::o;231:421:3:-;289:7;534:1;529;:6;525:45;;;558:1;551:8;;;;525:45;580:9;596:1;592;:5;580:17;;624:1;619;615;:5;;;;;;;;:10;607:19;;;;;;;;644:1;637:8;;;;;231:421;;;;;;:::o;9809:1717:12:-;9872:14;9889:24;:22;:24;;:::i;:::-;9872:41;;9919:17;9939:5;;;:13;9945:6;9939:13;;;;;;;;;;;;;9919:33;;10013:7;10022:5;9996:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;9996:32:12;;;9986:43;;;;;;9967:62;;;:4;:15;;;;;:62;;;;9959:96;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10098:25;10126:9;:7;:9;;:::i;:::-;10098:37;;10141:21;10165:39;10187:16;;;;10165:17;:21;;:39;;;;:::i;:::-;10141:63;;10309:15;10364:4;:16;;;;;10382:13;10347:49;;;;;;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;10347::12;;;10337:60;;;;;;10327:7;:70;10309:88;;10455:22;10480:24;10496:7;10480:15;:24;;:::i;:::-;10455:49;;10548:11;10562:45;10575:4;:16;;;;;10593:13;10562:12;:45;;:::i;:::-;10548:59;;10687:38;10721:3;10687:8;;;:29;10696:4;:19;;;;;;;;;;;;10687:29;;;;;;;;;;;;;;;;;;:33;;:38;;;;:::i;:::-;10655:8;;;:29;10664:4;:19;;;;;;;;;;;;10655:29;;;;;;;;;;;;;;;;:70;;;;;;;10766:19;10788:22;10806:3;10788:13;:17;;:22;;;;:::i;:::-;10766:44;;10911:1;10885:28;;:14;:28;;;;:48;;;;;10932:1;10917:11;:16;;10885:48;10881:460;;;11008:41;11037:11;11008:8;;;:24;11017:14;11008:24;;;;;;;;;;;;;;;;;;:28;;:41;;;;:::i;:::-;10981:8;;;:24;10990:14;10981:24;;;;;;;;;;;;;;;;:68;;;;;;;11107:9;;;:17;;;;11125:14;11141:11;11107:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;11107:46:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;11107:46:12;;;;11218:17;11199:16;;:36;;;;;;;10881:460;;;11309:25;11330:3;11309:16;;;;:20;;:25;;;;:::i;:::-;11290:16;;:44;;;;;;;10881:460;11401:5;;;:13;11407:6;11401:13;;;;;;;;;;;;11394:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11456:14;11426:95;;11442:6;11426:95;11478:7;11493:11;11512:3;11426:95;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9809:1717;;;;;;;;;;;:::o;7634:102::-;7667:14;7684:19;:17;:19;;:::i;:::-;7667:36;;7724:6;7714:17;;;;;;;;;;7634:102;;:::o;7271:308::-;7321:9;;;:22;;;;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;7321:24:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;7321:24:12;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;7321:24:12;;;;;;;;;;;;;;;;;7384:68;;;;;;;;7389:15;;;;7384:68;;;;7406:18;;;;;;;;;;;7384:68;;;;;;7426:12;7384:68;;;;7440:11;7384:68;;;;;;;;7351:5;;;:30;7357:9;;;:23;;;;;7351:30;;;;;;;;;;;;:101;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7508:18;;;;;;;;;;;7463:111;;7477:9;;;:23;;;;;7463:111;7534:11;7553:15;;;;7463:111;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7271:308;;:::o;21450:93::-;21490:6;21518;;;;;;;;;;;:17;;;:19;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;21518:19:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;21518:19:12;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;21518:19:12;;;;;;;;;;;;;;;;21504:34;;;;21450:93;;:::o;1439:145:3:-;1497:7;1516:9;1532:1;1528;:5;1516:17;;1556:1;1551;:6;;1543:15;;;;;;;;1576:1;1569:8;;;;;1439:145;;;;;;:::o;1211:::-;1269:7;1301:1;1296;:6;;1288:15;;;;;;;;1313:9;1329:1;1325;:5;1313:17;;1348:1;1341:8;;;;;1211:145;;;;;;:::o;259:181:1:-;354:1;335:21;;:7;:21;;;;327:30;;;;;;;;376:18;380:4;386:7;376:3;:18;;:::i;:::-;375:19;367:28;;;;;;;;429:4;406;:11;;;;:20;418:7;406:20;;;;;;;;;;;;;;;;:27;;;;;;;;;;;;;;;;;;259:181;;;:::o;11804:355:12:-;11895:7;11910:25;11938:11;:20;11966:14;11938:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;11938:44:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;11938:44:12;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;11938:44:12;;;;;;;;;;;;;;;;11910:72;;11988:15;12006:11;:20;12027:18;12047:11;:20;12075:12;12096:2;12047:53;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;12047:53:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;12047:53:12;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;12047:53:12;;;;;;;;;;;;;;;;12006:95;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;12006:95:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;12006:95:12;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;12006:95:12;;;;;;;;;;;;;;;;11988:113;;12122:11;:21;12144:8;12122:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;12122:31:12;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;12122:31:12;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;12122:31:12;;;;;;;;;;;;;;;;12107:47;;;;;;11804:355;;;;;;;:::o
Swarm Source
bzzr://4f56aea8ae7585b4254f75cd16f60cfe6d95ca3c3081d15b87c30f009647b059
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 25 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.