Address Details
contract
0xf54658d51a33525bE5CA67C45F81B34F56055cC1
- Contract Name
- GoodGhosting
- Creator
- 0x913503–14682a at 0xe9b730–074c26
- Balance
- 4.624222369291862546 CELO ( )
- Locked CELO Balance
- 0.00 CELO
- Voting CELO Balance
- 0.00 CELO
- Pending Unlocked Gold
- 0.00 CELO
- Tokens
-
Fetching tokens...
- Transactions
- 5,854 Transactions
- Transfers
- 15,486 Transfers
- Gas Used
- 1,202,348,603
- Last Balance Update
- 23757897
Transactions
Token Transfers
Tokens
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Write Contract
This contract has been verified via Sourcify.
View contract in Sourcify repository
- Contract name:
- GoodGhosting
- Optimization enabled
- true
- Compiler version
- v0.6.11+commit.5ef660b1
- Optimization runs
- 1500
- EVM Version
- istanbul
- Verified at
- 2022-07-24T02:12:04.853985Z
project:/contracts/GoodGhosting.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.6.11; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Pausable.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./aave/ILendingPoolAddressesProvider.sol"; import "./aave/ILendingPool.sol"; import "./aave/AToken.sol"; /// @title GoodGhosting Game Contract /// @notice Used for games deployed on Ethereum Mainnet using Aave (v2) as the underlying pool, or for games deployed on Celo using Moola (v2) as the underlying pool /// @author Francis Odisi & Viraz Malhotra contract GoodGhosting is Ownable, Pausable { using SafeMath for uint256; /// @notice Ownership Control flag bool public allowRenouncingOwnership = false; /// @notice Controls if tokens were redeemed or not from the pool bool public redeemed; /// @notice controls if admin withdrew or not the performance fee. bool public adminWithdraw; /// @notice Address of the token used for depositing into the game by players (DAI) IERC20 public immutable daiToken; /// @notice Address of the interest bearing token received when funds are transferred to the external pool AToken public immutable adaiToken; /// @notice Which Aave instance we use to swap DAI to interest bearing aDAI ILendingPoolAddressesProvider public immutable lendingPoolAddressProvider; /// @notice Lending pool address ILendingPool public lendingPool; /// @notice Defines an optional token address used to provide additional incentives to users. Accepts "0x0" adresses when no incentive token exists. IERC20 public immutable incentiveToken; /// @notice total amount of incentive tokens to be distributed among winners uint256 public totalIncentiveAmount = 0; /// @notice Controls the amount of active players in the game (ignores players that early withdraw) uint256 public activePlayersCount = 0; /// @notice Stores the total amount of net interest received in the game. uint256 public totalGameInterest; /// @notice total principal amount uint256 public totalGamePrincipal; /// @notice performance fee amount allocated to the admin uint256 public adminFeeAmount; /// @notice The amount to be paid on each segment uint256 public immutable segmentPayment; /// @notice The number of segments in the game (segment count) uint256 public immutable lastSegment; /// @notice When the game started (deployed timestamp) uint256 public immutable firstSegmentStart; /// @notice The time duration (in seconds) of each segment uint256 public immutable segmentLength; /// @notice Defines the max quantity of players allowed in the game uint256 public immutable maxPlayersCount; /// @notice winner counter to track no of winners uint256 public winnerCount = 0; /// @notice The early withdrawal fee (percentage) uint8 public immutable earlyWithdrawalFee; /// @notice The performance admin fee (percentage) uint8 public immutable customFee; struct Player { bool withdrawn; bool canRejoin; bool isWinner; address addr; uint256 mostRecentSegmentPaid; uint256 amountPaid; uint256 winnerIndex; } /// @notice Stores info about the players in the game mapping(address => Player) public players; /// @notice controls the amount deposited in each segment that was not yet transferred to the external underlying pool /// @notice list of players address[] public iterablePlayers; /// @notice list of winners address[] public winners; event JoinedGame(address indexed player, uint256 amount); event Deposit( address indexed player, uint256 indexed segment, uint256 amount ); event Withdrawal( address indexed player, uint256 amount, uint256 playerReward, uint256 playerIncentive ); event FundsRedeemedFromExternalPool( uint256 totalAmount, uint256 totalGamePrincipal, uint256 totalGameInterest, uint256 rewards, uint256 totalIncentiveAmount ); event WinnersAnnouncement(address[] winners); event EarlyWithdrawal( address indexed player, uint256 amount, uint256 totalGamePrincipal ); event AdminWithdrawal( address indexed admin, uint256 totalGameInterest, uint256 adminFeeAmount, uint256 adminIncentiveAmount ); modifier whenGameIsCompleted() { require(isGameCompleted(), "Game is not completed"); _; } modifier whenGameIsNotCompleted() { require(!isGameCompleted(), "Game is already completed"); _; } /** Creates a new instance of GoodGhosting game @param _inboundCurrency Smart contract address of inbound currency used for the game. @param _lendingPoolAddressProvider Smart contract address of the lending pool adddress provider. @param _segmentCount Number of segments in the game. @param _segmentLength Lenght of each segment, in seconds (i.e., 180 (sec) => 3 minutes). @param _segmentPayment Amount of tokens each player needs to contribute per segment (i.e. 10*10**18 equals to 10 DAI - note that DAI uses 18 decimal places). @param _earlyWithdrawalFee Fee paid by users on early withdrawals (before the game completes). Used as an integer percentage (i.e., 10 represents 10%). @param _customFee performance fee charged by admin. Used as an integer percentage (i.e., 10 represents 10%). Does not accept "decimal" fees like "0.5". @param _dataProvider id for getting the data provider contract address 0x1 to be passed. @param _maxPlayersCount max quantity of players allowed to join the game @param _incentiveToken optional token address used to provide additional incentives to users. Accepts "0x0" adresses when no incentive token exists. */ constructor( IERC20 _inboundCurrency, ILendingPoolAddressesProvider _lendingPoolAddressProvider, uint256 _segmentCount, uint256 _segmentLength, uint256 _segmentPayment, uint8 _earlyWithdrawalFee, uint8 _customFee, address _dataProvider, uint256 _maxPlayersCount, IERC20 _incentiveToken ) public { require(_customFee <= 20, "_customFee must be less than or equal to 20%"); require(_earlyWithdrawalFee <= 10, "_earlyWithdrawalFee must be less than or equal to 10%"); require(_earlyWithdrawalFee > 0, "_earlyWithdrawalFee must be greater than zero"); require(_maxPlayersCount > 0, "_maxPlayersCount must be greater than zero"); require(address(_inboundCurrency) != address(0), "invalid _inboundCurrency address"); require(address(_lendingPoolAddressProvider) != address(0), "invalid _lendingPoolAddressProvider address"); require(_segmentCount > 0, "_segmentCount must be greater than zero"); require(_segmentLength > 0, "_segmentLength must be greater than zero"); require(_segmentPayment > 0, "_segmentPayment must be greater than zero"); require(_dataProvider != address(0), "invalid _dataProvider address"); // Initializes default variables firstSegmentStart = block.timestamp; //gets current time lastSegment = _segmentCount; segmentLength = _segmentLength; segmentPayment = _segmentPayment; earlyWithdrawalFee = _earlyWithdrawalFee; customFee = _customFee; daiToken = _inboundCurrency; lendingPoolAddressProvider = _lendingPoolAddressProvider; AaveProtocolDataProvider dataProvider = AaveProtocolDataProvider(_dataProvider); // lending pool needs to be approved in v2 since it is the core contract in v2 and not lending pool core lendingPool = ILendingPool( _lendingPoolAddressProvider.getLendingPool() ); // atoken address in v2 is fetched from data provider contract (address adaiTokenAddress, , ) = dataProvider.getReserveTokensAddresses(address(_inboundCurrency)); adaiToken = AToken(adaiTokenAddress); maxPlayersCount = _maxPlayersCount; incentiveToken = _incentiveToken; } /// @notice pauses the game. This function can be called only by the contract's admin. function pause() external onlyOwner whenNotPaused { _pause(); } /// @notice unpauses the game. This function can be called only by the contract's admin. function unpause() external onlyOwner whenPaused { _unpause(); } /// @notice Renounces Ownership. function renounceOwnership() public override onlyOwner { require(allowRenouncingOwnership, "Not allowed"); super.renounceOwnership(); } /// @notice Unlocks renounceOwnership. function unlockRenounceOwnership() external onlyOwner { allowRenouncingOwnership = true; } /// @notice Allows the admin to withdraw the performance fee, if applicable. This function can be called only by the contract's admin. /// @dev Cannot be called before the game ends. function adminFeeWithdraw() external virtual onlyOwner whenGameIsCompleted { require(redeemed, "Funds not redeemed from external pool"); require(!adminWithdraw, "Admin has already withdrawn"); adminWithdraw = true; // when there are no winners, admin will be able to withdraw the // additional incentives sent to the pool, avoiding locking the funds. uint256 adminIncentiveAmount = 0; if (winnerCount == 0 && totalIncentiveAmount > 0) { adminIncentiveAmount = totalIncentiveAmount; } emit AdminWithdrawal(owner(), totalGameInterest, adminFeeAmount, adminIncentiveAmount); if (adminFeeAmount > 0) { require( IERC20(daiToken).transfer(owner(), adminFeeAmount), "Fail to transfer ER20 tokens to admin" ); } if (adminIncentiveAmount > 0) { require( IERC20(incentiveToken).transfer(owner(), adminIncentiveAmount), "Fail to transfer ER20 incentive tokens to admin" ); } } /// @notice Allows a player to join the game function joinGame() external virtual whenNotPaused { _joinGame(); } /// @notice Allows a player to withdraw funds before the game ends. An early withdrawal fee is charged. /// @dev Cannot be called after the game is completed. function earlyWithdraw() external whenNotPaused whenGameIsNotCompleted { Player storage player = players[msg.sender]; require(player.amountPaid > 0, "Player does not exist"); require(!player.withdrawn, "Player has already withdrawn"); player.withdrawn = true; activePlayersCount = activePlayersCount.sub(1); if (winnerCount > 0 && player.isWinner) { winnerCount = winnerCount.sub(uint(1)); player.isWinner = false; winners[player.winnerIndex] = address(0); } // In an early withdraw, users get their principal minus the earlyWithdrawalFee % defined in the constructor. uint256 withdrawAmount = player.amountPaid.sub( player.amountPaid.mul(earlyWithdrawalFee).div(100) ); // Decreases the totalGamePrincipal on earlyWithdraw totalGamePrincipal = totalGamePrincipal.sub(player.amountPaid); uint256 currentSegment = getCurrentSegment(); // Users that early withdraw during the first segment, are allowed to rejoin. if (currentSegment == 0) { player.canRejoin = true; } emit EarlyWithdrawal(msg.sender, withdrawAmount, totalGamePrincipal); lendingPool.withdraw(address(daiToken), withdrawAmount, address(this)); require( IERC20(daiToken).transfer(msg.sender, withdrawAmount), "Fail to transfer ERC20 tokens on early withdraw" ); } /// @notice Allows player to withdraw their funds after the game ends with no loss (fee). Winners get a share of the interest earned. function withdraw() external virtual { Player storage player = players[msg.sender]; require(player.amountPaid > 0, "Player does not exist"); require(!player.withdrawn, "Player has already withdrawn"); player.withdrawn = true; // First player to withdraw redeems everyone's funds if (!redeemed) { redeemFromExternalPool(); } uint256 payout = player.amountPaid; uint256 playerIncentive = 0; if (player.mostRecentSegmentPaid == lastSegment.sub(1)) { // Player is a winner and gets a bonus! payout = payout.add(totalGameInterest.div(winnerCount)); // If there's additional incentives, distributes them to winners if (totalIncentiveAmount > 0) { playerIncentive = totalIncentiveAmount.div(winnerCount); } } emit Withdrawal(msg.sender, payout, 0, playerIncentive); require( IERC20(daiToken).transfer(msg.sender, payout), "Fail to transfer ERC20 tokens on withdraw" ); if (playerIncentive > 0) { require( IERC20(incentiveToken).transfer(msg.sender, playerIncentive), "Fail to transfer ERC20 incentive tokens on withdraw" ); } } /// @notice Allows players to make deposits for the game segments, after joining the game. function makeDeposit() external whenNotPaused { Player storage player = players[msg.sender]; require( !player.withdrawn, "Player already withdraw from game" ); // only registered players can deposit require( player.addr == msg.sender, "Sender is not a player" ); uint256 currentSegment = getCurrentSegment(); // User can only deposit between segment 1 and segment n-1 (where n is the number of segments for the game). // Details: // Segment 0 is paid when user joins the game (the first deposit window). // Last segment doesn't accept payments, because the payment window for the last // segment happens on segment n-1 (penultimate segment). // Any segment greater than the last segment means the game is completed, and cannot // receive payments require( currentSegment > 0 && currentSegment < lastSegment, "Deposit available only between segment 1 and segment n-1 (penultimate)" ); //check if current segment is currently unpaid require( player.mostRecentSegmentPaid != currentSegment, "Player already paid current segment" ); // check if player has made payments up to the previous segment require( player.mostRecentSegmentPaid == currentSegment.sub(1), "Player didn't pay the previous segment - game over!" ); emit Deposit(msg.sender, currentSegment, segmentPayment); _transferDaiToContract(); } /// @notice gets the number of players in the game /// @return number of players function getNumberOfPlayers() external view returns (uint256) { return iterablePlayers.length; } /// @notice Redeems funds from the external pool and updates the internal accounting controls related to the game stats. /// @dev Can only be called after the game is completed. function redeemFromExternalPool() public virtual whenGameIsCompleted { require(!redeemed, "Redeem operation already happened for the game"); redeemed = true; // Withdraws funds (principal + interest + rewards) from external pool if (adaiToken.balanceOf(address(this)) > 0) { lendingPool.withdraw( address(daiToken), type(uint256).max, address(this) ); } uint256 totalBalance = IERC20(daiToken).balanceOf(address(this)); // If there's an incentive token address defined, sets the total incentive amount to be distributed among winners. if (address(incentiveToken) != address(0)) { totalIncentiveAmount = IERC20(incentiveToken).balanceOf(address(this)); } // calculates gross interest uint256 grossInterest = 0; // Sanity check to avoid reverting due to overflow in the "subtraction" below. // This could only happen in case Aave changes the 1:1 ratio between // aToken vs. Token in the future (i.e., 1 aDAI is worth less than 1 DAI) if (totalBalance > totalGamePrincipal) { grossInterest = totalBalance.sub(totalGamePrincipal); } // calculates the performance/admin fee (takes a cut - the admin percentage fee - from the pool's interest). // calculates the "gameInterest" (net interest) that will be split among winners in the game uint256 _adminFeeAmount; if (customFee > 0) { _adminFeeAmount = (grossInterest.mul(customFee)).div(100); totalGameInterest = grossInterest.sub(_adminFeeAmount); } else { _adminFeeAmount = 0; totalGameInterest = grossInterest; } // when there's no winners, admin takes all the interest + rewards if (winnerCount == 0) { adminFeeAmount = grossInterest; } else { adminFeeAmount = _adminFeeAmount; } emit FundsRedeemedFromExternalPool( totalBalance, totalGamePrincipal, totalGameInterest, 0, totalIncentiveAmount ); emit WinnersAnnouncement(winners); } /// @notice Calculates the current segment of the game. /// @return current game segment function getCurrentSegment() public view returns (uint256) { return block.timestamp.sub(firstSegmentStart).div(segmentLength); } /// @notice Checks if the game is completed or not. /// @return "true" if completeted; otherwise, "false". function isGameCompleted() public view returns (bool) { // Game is completed when the current segment is greater than "lastSegment" of the game. return getCurrentSegment() > lastSegment; } /** @dev Manages the transfer of funds from the player to the contract, recording the required accounting operations to control the user's position in the pool. */ function _transferDaiToContract() internal { require( daiToken.allowance(msg.sender, address(this)) >= segmentPayment, "You need to have allowance to do transfer DAI on the smart contract" ); uint256 currentSegment = getCurrentSegment(); players[msg.sender].mostRecentSegmentPaid = currentSegment; players[msg.sender].amountPaid = players[msg.sender].amountPaid.add( segmentPayment ); // check if this is deposit for the last segment. If yes, the player is a winner. // since both join game and deposit method call this method so having it here if (currentSegment == lastSegment.sub(1)) { winners.push(msg.sender); // array indexes start from 0 players[msg.sender].winnerIndex = winners.length.sub(uint(1)); winnerCount = winnerCount.add(uint(1)); players[msg.sender].isWinner = true; } totalGamePrincipal = totalGamePrincipal.add(segmentPayment); require( daiToken.transferFrom(msg.sender, address(this), segmentPayment), "Transfer failed" ); // Allows the lending pool to convert DAI deposited on this contract to aDAI on lending pool uint256 contractBalance = daiToken.balanceOf(address(this)); require( daiToken.approve(address(lendingPool), contractBalance), "Fail to approve allowance to lending pool" ); lendingPool.deposit(address(daiToken), contractBalance, address(this), 155); } /// @notice Allows a player to join the game and controls function _joinGame() internal { require(getCurrentSegment() == 0, "Game has already started"); require( players[msg.sender].addr != msg.sender || players[msg.sender].canRejoin, "Cannot join the game more than once" ); activePlayersCount = activePlayersCount.add(1); require(activePlayersCount <= maxPlayersCount, "Reached max quantity of players allowed"); bool canRejoin = players[msg.sender].canRejoin; Player memory newPlayer = Player({ addr: msg.sender, mostRecentSegmentPaid: 0, amountPaid: 0, withdrawn: false, canRejoin: false, isWinner: false, winnerIndex: 0 }); players[msg.sender] = newPlayer; if (!canRejoin) { iterablePlayers.push(msg.sender); } emit JoinedGame(msg.sender, segmentPayment); _transferDaiToContract(); } }
/_openzeppelin/contracts/access/Ownable.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () internal { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } }
/_openzeppelin/contracts/math/SafeMath.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }
/_openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
/_openzeppelin/contracts/utils/Context.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
/_openzeppelin/contracts/utils/Pausable.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "./Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor () internal { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!paused(), "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(paused(), "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
/project_/contracts/aave/AToken.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.6.11; interface AToken { /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); }
/project_/contracts/aave/ILendingPool.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.6.11; interface ILendingPool { function deposit(address _reserve, uint256 _amount, address onBehalfOf, uint16 _referralCode) external; //see: https://github.com/aave/aave-protocol/blob/1ff8418eb5c73ce233ac44bfb7541d07828b273f/contracts/tokenization/AToken.sol#L218 function withdraw(address asset, uint amount, address to) external; } interface AaveProtocolDataProvider { function getReserveTokensAddresses(address asset) external view returns(address, address, address); }
/project_/contracts/aave/ILendingPoolAddressesProvider.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.6.11; /** @title ILendingPoolAddressesProvider interface @notice provides the interface to fetch the LendingPoolCore address */ abstract contract ILendingPoolAddressesProvider { function getLendingPool() public virtual view returns (address); function setLendingPoolImpl(address _pool) public virtual; function getAddress(bytes32 id) public virtual view returns (address); function getLendingPoolCore() public virtual view returns (address payable); function setLendingPoolCoreImpl(address _lendingPoolCore) public virtual; function getLendingPoolConfigurator() public virtual view returns (address); function setLendingPoolConfiguratorImpl(address _configurator) public virtual; function getLendingPoolDataProvider() public virtual view returns (address); function setLendingPoolDataProviderImpl(address _provider) public virtual; function getLendingPoolParametersProvider() public virtual view returns (address); function setLendingPoolParametersProviderImpl(address _parametersProvider) public virtual; function getTokenDistributor() public virtual view returns (address); function setTokenDistributor(address _tokenDistributor) public virtual; function getFeeProvider() public virtual view returns (address); function setFeeProviderImpl(address _feeProvider) public virtual; function getLendingPoolLiquidationManager() public virtual view returns (address); function setLendingPoolLiquidationManager(address _manager) public virtual; function getLendingPoolManager() public virtual view returns (address); function setLendingPoolManager(address _lendingPoolManager) public virtual; function getPriceOracle() public virtual view returns (address); function setPriceOracle(address _priceOracle) public virtual; function getLendingRateOracle() public virtual view returns (address); function setLendingRateOracle(address _lendingRateOracle) public virtual; }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_inboundCurrency","internalType":"contract IERC20"},{"type":"address","name":"_lendingPoolAddressProvider","internalType":"contract ILendingPoolAddressesProvider"},{"type":"uint256","name":"_segmentCount","internalType":"uint256"},{"type":"uint256","name":"_segmentLength","internalType":"uint256"},{"type":"uint256","name":"_segmentPayment","internalType":"uint256"},{"type":"uint8","name":"_earlyWithdrawalFee","internalType":"uint8"},{"type":"uint8","name":"_customFee","internalType":"uint8"},{"type":"address","name":"_dataProvider","internalType":"address"},{"type":"uint256","name":"_maxPlayersCount","internalType":"uint256"},{"type":"address","name":"_incentiveToken","internalType":"contract IERC20"}]},{"type":"event","name":"AdminWithdrawal","inputs":[{"type":"address","name":"admin","internalType":"address","indexed":true},{"type":"uint256","name":"totalGameInterest","internalType":"uint256","indexed":false},{"type":"uint256","name":"adminFeeAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"adminIncentiveAmount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Deposit","inputs":[{"type":"address","name":"player","internalType":"address","indexed":true},{"type":"uint256","name":"segment","internalType":"uint256","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"EarlyWithdrawal","inputs":[{"type":"address","name":"player","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalGamePrincipal","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"FundsRedeemedFromExternalPool","inputs":[{"type":"uint256","name":"totalAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalGamePrincipal","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalGameInterest","internalType":"uint256","indexed":false},{"type":"uint256","name":"rewards","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalIncentiveAmount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"JoinedGame","inputs":[{"type":"address","name":"player","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Paused","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Unpaused","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"WinnersAnnouncement","inputs":[{"type":"address[]","name":"winners","internalType":"address[]","indexed":false}],"anonymous":false},{"type":"event","name":"Withdrawal","inputs":[{"type":"address","name":"player","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"playerReward","internalType":"uint256","indexed":false},{"type":"uint256","name":"playerIncentive","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"activePlayersCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract AToken"}],"name":"adaiToken","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"adminFeeAmount","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"adminFeeWithdraw","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"adminWithdraw","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"allowRenouncingOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"customFee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20"}],"name":"daiToken","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"earlyWithdraw","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"earlyWithdrawalFee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"firstSegmentStart","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getCurrentSegment","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getNumberOfPlayers","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20"}],"name":"incentiveToken","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isGameCompleted","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"iterablePlayers","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"joinGame","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastSegment","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ILendingPool"}],"name":"lendingPool","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ILendingPoolAddressesProvider"}],"name":"lendingPoolAddressProvider","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"makeDeposit","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxPlayersCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"pause","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"paused","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"withdrawn","internalType":"bool"},{"type":"bool","name":"canRejoin","internalType":"bool"},{"type":"bool","name":"isWinner","internalType":"bool"},{"type":"address","name":"addr","internalType":"address"},{"type":"uint256","name":"mostRecentSegmentPaid","internalType":"uint256"},{"type":"uint256","name":"amountPaid","internalType":"uint256"},{"type":"uint256","name":"winnerIndex","internalType":"uint256"}],"name":"players","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"redeemFromExternalPool","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"redeemed","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"segmentLength","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"segmentPayment","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalGameInterest","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalGamePrincipal","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalIncentiveAmount","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unlockRenounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unpause","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"winnerCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"winners","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw","inputs":[]}]
Contract Creation Code
0x6101e06040526000805460ff60a81b19168155600281905560038190556007553480156200002c57600080fd5b50604051620038193803806200381983398181016040526101408110156200005357600080fd5b508051602082015160408301516060840151608085015160a086015160c087015160e088015161010089015161012090990151979896979596949593949293919290916000620000ab6001600160e01b036200056d16565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506000805460ff60a01b19169055601460ff85161115620001475760405162461bcd60e51b815260040180806020018281038252602c815260200180620036be602c913960400191505060405180910390fd5b600a8560ff1611156200018c5760405162461bcd60e51b8152600401808060200182810382526035815260200180620037b96035913960400191505060405180910390fd5b60008560ff1611620001d05760405162461bcd60e51b815260040180806020018281038252602d8152602001806200373c602d913960400191505060405180910390fd5b60008211620002115760405162461bcd60e51b815260040180806020018281038252602a815260200180620036ea602a913960400191505060405180910390fd5b6001600160a01b038a166200026d576040805162461bcd60e51b815260206004820181905260248201527f696e76616c6964205f696e626f756e6443757272656e63792061646472657373604482015290519081900360640190fd5b6001600160a01b038916620002b45760405162461bcd60e51b815260040180806020018281038252602b815260200180620037ee602b913960400191505060405180910390fd5b60008811620002f55760405162461bcd60e51b8152600401808060200182810382526027815260200180620037696027913960400191505060405180910390fd5b60008711620003365760405162461bcd60e51b8152600401808060200182810382526028815260200180620037146028913960400191505060405180910390fd5b60008611620003775760405162461bcd60e51b8152600401808060200182810382526029815260200180620037906029913960400191505060405180910390fd5b6001600160a01b038316620003d3576040805162461bcd60e51b815260206004820152601d60248201527f696e76616c6964205f6461746150726f76696465722061646472657373000000604482015290519081900360640190fd5b42610140526101208890526101608790526101008690527fff0000000000000000000000000000000000000000000000000000000000000060f886811b82166101a05285901b166101c0526001600160601b031960608b811b82166080528a901b1660c05260408051630261bf8b60e01b8152905184916001600160a01b038c1691630261bf8b91600480820192602092909190829003018186803b1580156200047c57600080fd5b505afa15801562000491573d6000803e3d6000fd5b505050506040513d6020811015620004a857600080fd5b5051600180546001600160a01b0319166001600160a01b03928316179055604080516334924edb60e21b81528d83166004820152905160009284169163d2493b6c916024808301926060929190829003018186803b1580156200050a57600080fd5b505afa1580156200051f573d6000803e3d6000fd5b505050506040513d60608110156200053657600080fd5b50516001600160601b0319606091821b811660a052610180959095529290921b90921660e052506200057198505050505050505050565b3390565b60805160601c60a05160601c60c05160601c60e05160601c61010051610120516101405161016051610180516101a05160f81c6101c05160f81c61301f6200069f600039806110c35280611e805280611eb252508061076d52806109ab52508061121b5280612abc5250806113ef5280611aa8525080610d375280611acd5250806105355280610abf5280610f4b52806113ba52806123c65250806105115280611043528061227d528061238452806124ad528061250f5280612c69525080610c86528061111152806117805280611d935280611de05250806110ed5250806113635280611bec52508061085652806108f35280610baa5280611394528061168a5280611c7f5280611d1c52806122a7528061253f528061262752806126e252806127c8525061301f6000f3fe608060405234801561001057600080fd5b50600436106102c85760003560e01c80638da5cb5b1161017b578063d4f77b1c116100d8578063f2fde38b1161008c578063f5c9786711610071578063f5c97867146104f7578063f8dd5ad3146104ff578063fd6673f514610507576102c8565b8063f2fde38b146104c9578063f4ceab1c146104ef576102c8565b8063e231bff0116100bd578063e231bff014610451578063e2eb41ff14610459578063f18d20be146104c1576102c8565b8063d4f77b1c14610441578063e0236a1814610449576102c8565b8063aad739f51161012f578063c39b583c11610114578063c39b583c14610429578063caa02e0814610431578063d013666e14610439576102c8565b8063aad739f514610404578063be22f54614610421576102c8565b8063a2fb117511610160578063a2fb1175146103d7578063a59a9973146103f4578063a98a5c94146103fc576102c8565b80638da5cb5b146103c757806395224b33146103cf576102c8565b80635edafd5a11610229578063715018a6116101dd5780637c80e6da116101c25780637c80e6da146103af5780637e5f8476146103b75780638456cb59146103bf576102c8565b8063715018a61461039f5780637a23032c146103a7576102c8565b8063633803001161020e578063633803001461036b578063638126f81461038f5780636a79328a14610397576102c8565b80635edafd5a1461035b5780635faeea3714610363576102c8565b80633ccfd60b116102805780633f4ba83a116102655780633f4ba83a1461032f57806340732c89146103375780635c975abb1461033f576102c8565b80633ccfd60b1461031f5780633e7433eb14610327576102c8565b806315d74bb3116102b157806315d74bb3146102ef57806316330d40146102f9578063250a2b0d14610317576102c8565b80630c8ac645146102cd57806311b2e2d9146102e7575b600080fd5b6102d561050f565b60408051918252519081900360200190f35b6102d5610533565b6102f7610557565b005b6103016109a9565b6040805160ff9092168252519081900360200190f35b6102d56109cd565b6102f76109d3565b6102d5610d35565b6102f7610d59565b6102f7610e30565b6103476110a0565b604080519115158252519081900360200190f35b6103016110c1565b6102d56110e5565b6103736110eb565b604080516001600160a01b039092168252519081900360200190f35b61037361110f565b6102d5611133565b6102f7611139565b6102d5611213565b6102d5611219565b61034761123d565b6102f761124d565b610373611316565b6102d5611325565b610373600480360360208110156103ed57600080fd5b503561132b565b610373611352565b610373611361565b6103736004803603602081101561041a57600080fd5b5035611385565b610373611392565b6103476113b6565b6102d56113e7565b6102d56113ed565b6102f7611411565b6102f7611466565b61034761186f565b61047f6004803603602081101561046f57600080fd5b50356001600160a01b031661187f565b6040805197151588529515156020880152931515868601526001600160a01b039092166060860152608085015260a084015260c0830152519081900360e00190f35b6103476118cc565b6102f7600480360360208110156104df57600080fd5b50356001600160a01b03166118dc565b6102f76119fd565b6102d5611aa1565b6102f7611afc565b6102d5611ff2565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b61055f6110a0565b156105a4576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6105ac6113b6565b156105fe576040805162461bcd60e51b815260206004820152601960248201527f47616d6520697320616c726561647920636f6d706c6574656400000000000000604482015290519081900360640190fd5b3360009081526008602052604090206002810154610663576040805162461bcd60e51b815260206004820152601560248201527f506c6179657220646f6573206e6f742065786973740000000000000000000000604482015290519081900360640190fd5b805460ff16156106ba576040805162461bcd60e51b815260206004820152601c60248201527f506c617965722068617320616c72656164792077697468647261776e00000000604482015290519081900360640190fd5b805460ff1916600190811782556003546106d99163ffffffff611ff816565b600355600754158015906106f45750805462010000900460ff165b1561075e5760075461070d90600163ffffffff611ff816565b600755805462ff0000191681556003810154600a805460009290811061072f57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60006107bf6107ae60646107a27f000000000000000000000000000000000000000000000000000000000000000060ff16866002015461205a90919063ffffffff16565b9063ffffffff6120ba16565b60028401549063ffffffff611ff816565b90506107da8260020154600554611ff890919063ffffffff16565b60055560006107e7611aa1565b9050806107fc57825461ff0019166101001783555b600554604080518481526020810192909252805133927f1670585e36568ede58d159518ce92cad99f75ad41c7d8281df3dd4eaa0c855d092908290030190a260015460408051631a4ca37b60e21b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260248201869052306044830152915191909216916369328dec91606480830192600092919082900301818387803b1580156108b657600080fd5b505af11580156108ca573d6000803e3d6000fd5b50506040805163a9059cbb60e01b81523360048201526024810186905290516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb925060448083019260209291908290030181600087803b15801561093d57600080fd5b505af1158015610951573d6000803e3d6000fd5b505050506040513d602081101561096757600080fd5b50516109a45760405162461bcd60e51b815260040180806020018281038252602f815260200180612d25602f913960400191505060405180910390fd5b505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60035481565b3360009081526008602052604090206002810154610a38576040805162461bcd60e51b815260206004820152601560248201527f506c6179657220646f6573206e6f742065786973740000000000000000000000604482015290519081900360640190fd5b805460ff1615610a8f576040805162461bcd60e51b815260206004820152601c60248201527f506c617965722068617320616c72656164792077697468647261776e00000000604482015290519081900360640190fd5b805460ff19166001178155600054600160b01b900460ff16610ab357610ab3611afc565b60028101546000610aeb7f0000000000000000000000000000000000000000000000000000000000000000600163ffffffff611ff816565b83600101541415610b4057610b1d610b106007546004546120ba90919063ffffffff16565b839063ffffffff61212116565b60025490925015610b4057600754600254610b3d9163ffffffff6120ba16565b90505b6040805183815260006020820152808201839052905133917f650fdf669e93aa6c8ff3defe2da9c12b64f1548e5e1e54e803f4c1beb6466c8e919081900360600190a26040805163a9059cbb60e01b81523360048201526024810184905290516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163a9059cbb9160448083019260209291908290030181600087803b158015610bf257600080fd5b505af1158015610c06573d6000803e3d6000fd5b505050506040513d6020811015610c1c57600080fd5b5051610c595760405162461bcd60e51b8152600401808060200182810382526029815260200180612e616029913960400191505060405180910390fd5b80156109a4576040805163a9059cbb60e01b81523360048201526024810183905290516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163a9059cbb9160448083019260209291908290030181600087803b158015610cce57600080fd5b505af1158015610ce2573d6000803e3d6000fd5b505050506040513d6020811015610cf857600080fd5b50516109a45760405162461bcd60e51b8152600401808060200182810382526033815260200180612f846033913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000081565b610d6161217b565b6001600160a01b0316610d72611316565b6001600160a01b031614610dcd576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b610dd56110a0565b610e26576040805162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015290519081900360640190fd5b610e2e61217f565b565b610e386110a0565b15610e7d576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b336000908152600860205260409020805460ff1615610ecd5760405162461bcd60e51b8152600401808060200182810382526021815260200180612f1d6021913960400191505060405180910390fd5b8054630100000090046001600160a01b03163314610f32576040805162461bcd60e51b815260206004820152601660248201527f53656e646572206973206e6f74206120706c6179657200000000000000000000604482015290519081900360640190fd5b6000610f3c611aa1565b9050600081118015610f6d57507f000000000000000000000000000000000000000000000000000000000000000081105b610fa85760405162461bcd60e51b8152600401808060200182810382526046815260200180612dcd6046913960600191505060405180910390fd5b8082600101541415610feb5760405162461bcd60e51b8152600401808060200182810382526023815260200180612f616023913960400191505060405180910390fd5b610ffc81600163ffffffff611ff816565b82600101541461103d5760405162461bcd60e51b8152600401808060200182810382526033815260200180612fb76033913960400191505060405180910390fd5b604080517f000000000000000000000000000000000000000000000000000000000000000081529051829133917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159181900360200190a361109c612246565b5050565b60005474010000000000000000000000000000000000000000900460ff1690565b7f000000000000000000000000000000000000000000000000000000000000000081565b60055481565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b60025481565b61114161217b565b6001600160a01b0316611152611316565b6001600160a01b0316146111ad576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b600054600160a81b900460ff1661120b576040805162461bcd60e51b815260206004820152600b60248201527f4e6f7420616c6c6f776564000000000000000000000000000000000000000000604482015290519081900360640190fd5b610e2e61284b565b60065481565b7f000000000000000000000000000000000000000000000000000000000000000081565b600054600160a81b900460ff1681565b61125561217b565b6001600160a01b0316611266611316565b6001600160a01b0316146112c1576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6112c96110a0565b1561130e576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b610e2e612916565b6000546001600160a01b031690565b60045481565b600a818154811061133857fe5b6000918252602090912001546001600160a01b0316905081565b6001546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b6009818154811061133857fe5b7f000000000000000000000000000000000000000000000000000000000000000081565b60007f00000000000000000000000000000000000000000000000000000000000000006113e1611aa1565b11905090565b60075481565b7f000000000000000000000000000000000000000000000000000000000000000081565b6114196110a0565b1561145e576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b610e2e6129cb565b61146e61217b565b6001600160a01b031661147f611316565b6001600160a01b0316146114da576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6114e26113b6565b611533576040805162461bcd60e51b815260206004820152601560248201527f47616d65206973206e6f7420636f6d706c657465640000000000000000000000604482015290519081900360640190fd5b600054600160b01b900460ff1661157b5760405162461bcd60e51b8152600401808060200182810382526025815260200180612e136025913960400191505060405180910390fd5b600054600160b81b900460ff16156115da576040805162461bcd60e51b815260206004820152601b60248201527f41646d696e2068617320616c72656164792077697468647261776e0000000000604482015290519081900360640190fd5b600080547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16600160b81b17815560075415801561161a57506000600254115b1561162457506002545b61162c611316565b6001600160a01b03167f80ebcacc706983394bb8fcc88ea7b9241338fb4617fffbea411b68b40ed5627e6004546006548460405180848152602001838152602001828152602001935050505060405180910390a260065415611778577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb6116bf611316565b6006546040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561171157600080fd5b505af1158015611725573d6000803e3d6000fd5b505050506040513d602081101561173b57600080fd5b50516117785760405162461bcd60e51b8152600401808060200182810382526025815260200180612da86025913960400191505060405180910390fd5b801561186c577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb6117b5611316565b836040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561180557600080fd5b505af1158015611819573d6000803e3d6000fd5b505050506040513d602081101561182f57600080fd5b505161186c5760405162461bcd60e51b815260040180806020018281038252602f815260200180612eab602f913960400191505060405180910390fd5b50565b600054600160b01b900460ff1681565b600860205260009081526040902080546001820154600283015460039093015460ff8084169461010085048216946201000081049092169363010000009092046001600160a01b03169287565b600054600160b81b900460ff1681565b6118e461217b565b6001600160a01b03166118f5611316565b6001600160a01b031614611950576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b0381166119955760405162461bcd60e51b8152600401808060200182810382526026815260200180612d826026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a36000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b611a0561217b565b6001600160a01b0316611a16611316565b6001600160a01b031614611a71576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16600160a81b179055565b6000611af77f00000000000000000000000000000000000000000000000000000000000000006107a2427f000000000000000000000000000000000000000000000000000000000000000063ffffffff611ff816565b905090565b611b046113b6565b611b55576040805162461bcd60e51b815260206004820152601560248201527f47616d65206973206e6f7420636f6d706c657465640000000000000000000000604482015290519081900360640190fd5b600054600160b01b900460ff1615611b9e5760405162461bcd60e51b815260040180806020018281038252602e815260200180612d54602e913960400191505060405180910390fd5b600080547fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff16600160b01b178155604080516370a0823160e01b815230600482015290516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916370a08231916024808301926020929190829003018186803b158015611c3257600080fd5b505afa158015611c46573d6000803e3d6000fd5b505050506040513d6020811015611c5c57600080fd5b50511115611cf95760015460408051631a4ca37b60e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526000196024830152306044830152915191909216916369328dec91606480830192600092919082900301818387803b158015611ce057600080fd5b505af1158015611cf4573d6000803e3d6000fd5b505050505b604080516370a0823160e01b815230600482015290516000916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916370a0823191602480820192602092909190829003018186803b158015611d6357600080fd5b505afa158015611d77573d6000803e3d6000fd5b505050506040513d6020811015611d8d57600080fd5b505190507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615611e5657604080516370a0823160e01b815230600482015290516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916370a08231916024808301926020929190829003018186803b158015611e2657600080fd5b505afa158015611e3a573d6000803e3d6000fd5b505050506040513d6020811015611e5057600080fd5b50516002555b600554600090821115611e7a57600554611e7790839063ffffffff611ff816565b90505b600060ff7f00000000000000000000000000000000000000000000000000000000000000001615611ef757611edd60646107a28460ff7f00000000000000000000000000000000000000000000000000000000000000001663ffffffff61205a16565b9050611eef828263ffffffff611ff816565b600455611f00565b50600481905560005b600754611f11576006829055611f17565b60068190555b60055460045460025460408051878152602081019490945283810192909252600060608401526080830152517f28d72925fdcea205b246c820015bd35812a740d1ec1a5cdc84f7784b50940fbb9181900360a00190a17fdbb9607e18553d40c255226e09883b48f92a108f6f895b0f37db6ae0d7fd56e6600a60405180806020018281038252838181548152602001915080548015611fdf57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611fc1575b50509250505060405180910390a1505050565b60095490565b60008282111561204f576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b508082035b92915050565b60008261206957506000612054565b8282028284828161207657fe5b04146120b35760405162461bcd60e51b8152600401808060200182810382526021815260200180612e8a6021913960400191505060405180910390fd5b9392505050565b6000808211612110576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161211957fe5b049392505050565b6000828201838110156120b3576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b3390565b6121876110a0565b6121d8576040805162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015290519081900360640190fd5b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa61222961217b565b604080516001600160a01b039092168252519081900360200190a1565b604080517fdd62ed3e00000000000000000000000000000000000000000000000000000000815233600482015230602482015290517f0000000000000000000000000000000000000000000000000000000000000000916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163dd62ed3e91604480820192602092909190829003018186803b1580156122ee57600080fd5b505afa158015612302573d6000803e3d6000fd5b505050506040513d602081101561231857600080fd5b505110156123575760405162461bcd60e51b8152600401808060200182810382526043815260200180612eda6043913960600191505060405180910390fd5b6000612361611aa1565b33600090815260086020526040902060018101829055600201549091506123ae907f000000000000000000000000000000000000000000000000000000000000000063ffffffff61212116565b336000908152600860205260409020600201556123f27f0000000000000000000000000000000000000000000000000000000000000000600163ffffffff611ff816565b8114156124a457600a80546001818101835560008390527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8909101805473ffffffffffffffffffffffffffffffffffffffff191633179055905461245b9163ffffffff611ff816565b3360009081526008602052604090206003015560075461248290600163ffffffff61212116565b600755336000908152600860205260409020805462ff00001916620100001790555b6005546124d7907f000000000000000000000000000000000000000000000000000000000000000063ffffffff61212116565b600555604080517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201527f0000000000000000000000000000000000000000000000000000000000000000604482015290516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916323b872dd9160648083019260209291908290030181600087803b15801561258757600080fd5b505af115801561259b573d6000803e3d6000fd5b505050506040513d60208110156125b157600080fd5b5051612604576040805162461bcd60e51b815260206004820152600f60248201527f5472616e73666572206661696c65640000000000000000000000000000000000604482015290519081900360640190fd5b604080516370a0823160e01b815230600482015290516000916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916370a0823191602480820192602092909190829003018186803b15801561266e57600080fd5b505afa158015612682573d6000803e3d6000fd5b505050506040513d602081101561269857600080fd5b5051600154604080517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0392831660048201526024810184905290519293507f00000000000000000000000000000000000000000000000000000000000000009091169163095ea7b3916044808201926020929091908290030181600087803b15801561272d57600080fd5b505af1158015612741573d6000803e3d6000fd5b505050506040513d602081101561275757600080fd5b50516127945760405162461bcd60e51b8152600401808060200182810382526029815260200180612e386029913960400191505060405180910390fd5b600154604080517fe8eda9df0000000000000000000000000000000000000000000000000000000081526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260248201859052306044830152609b60648301529151919092169163e8eda9df91608480830192600092919082900301818387803b15801561282f57600080fd5b505af1158015612843573d6000803e3d6000fd5b505050505050565b61285361217b565b6001600160a01b0316612864611316565b6001600160a01b0316146128bf576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a36000805473ffffffffffffffffffffffffffffffffffffffff19169055565b61291e6110a0565b15612963576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861222961217b565b6129d3611aa1565b15612a25576040805162461bcd60e51b815260206004820152601860248201527f47616d652068617320616c726561647920737461727465640000000000000000604482015290519081900360640190fd5b33600081815260086020526040902054630100000090046001600160a01b0316141580612a66575033600090815260086020526040902054610100900460ff165b612aa15760405162461bcd60e51b8152600401808060200182810382526023815260200180612f3e6023913960400191505060405180910390fd5b600354612ab590600163ffffffff61212116565b60038190557f00000000000000000000000000000000000000000000000000000000000000001015612b185760405162461bcd60e51b8152600401808060200182810382526027815260200180612cfe6027913960400191505060405180910390fd5b33600090815260086020526040902054610100900460ff16612b38612cc1565b506040805160e0810182526000808252602080830182815283850183815233606086018181526080870186815260a0880187815260c089018881529388526008909652979095208651815494519351965160ff199095169015151761ff001916610100931515939093029290921762ff000019166201000095151595909502949094177fffffffffffffffffff0000000000000000000000000000000000000000ffffff1663010000006001600160a01b0390931692909202919091178155935160018501555160028401555160039092019190915581612c6357600980546001810182556000919091527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af01805473ffffffffffffffffffffffffffffffffffffffff1916331790555b604080517f00000000000000000000000000000000000000000000000000000000000000008152905133917f485fd86c2a7d2d9ca3bf02e2ba776ea24271bc62274265b0bd5f478b3b7a1ca4919081900360200190a261109c612246565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091529056fe52656163686564206d6178207175616e74697479206f6620706c617965727320616c6c6f7765644661696c20746f207472616e7366657220455243323020746f6b656e73206f6e206561726c7920776974686472617752656465656d206f7065726174696f6e20616c72656164792068617070656e656420666f72207468652067616d654f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573734661696c20746f207472616e73666572204552323020746f6b656e7320746f2061646d696e4465706f73697420617661696c61626c65206f6e6c79206265747765656e207365676d656e74203120616e64207365676d656e74206e2d31202870656e756c74696d6174652946756e6473206e6f742072656465656d65642066726f6d2065787465726e616c20706f6f6c4661696c20746f20617070726f766520616c6c6f77616e636520746f206c656e64696e6720706f6f6c4661696c20746f207472616e7366657220455243323020746f6b656e73206f6e207769746864726177536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774661696c20746f207472616e73666572204552323020696e63656e7469766520746f6b656e7320746f2061646d696e596f75206e65656420746f206861766520616c6c6f77616e636520746f20646f207472616e7366657220444149206f6e2074686520736d61727420636f6e7472616374506c6179657220616c72656164792077697468647261772066726f6d2067616d6543616e6e6f74206a6f696e207468652067616d65206d6f7265207468616e206f6e6365506c6179657220616c726561647920706169642063757272656e74207365676d656e744661696c20746f207472616e7366657220455243323020696e63656e7469766520746f6b656e73206f6e207769746864726177506c61796572206469646e277420706179207468652070726576696f7573207365676d656e74202d2067616d65206f76657221a2646970667358221220140ca63d69ff4f5afd133e282c8107ed9205cb12821e8662c0c5828ef53bc4f864736f6c634300060b00335f637573746f6d466565206d757374206265206c657373207468616e206f7220657175616c20746f203230255f6d6178506c6179657273436f756e74206d7573742062652067726561746572207468616e207a65726f5f7365676d656e744c656e677468206d7573742062652067726561746572207468616e207a65726f5f6561726c795769746864726177616c466565206d7573742062652067726561746572207468616e207a65726f5f7365676d656e74436f756e74206d7573742062652067726561746572207468616e207a65726f5f7365676d656e745061796d656e74206d7573742062652067726561746572207468616e207a65726f5f6561726c795769746864726177616c466565206d757374206265206c657373207468616e206f7220657175616c20746f20313025696e76616c6964205f6c656e64696e67506f6f6c4164647265737350726f76696465722061646472657373000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a000000000000000000000000d1088091a174d33412a968fa34cb67131188b3320000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000024ea00000000000000000000000000000000000000000000000001158e460913d000000000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043d067ed784d9dd2ffeda73775e2cc4c560103a1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000471ece3750da237f93b8e339c536989b8978a438
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106102c85760003560e01c80638da5cb5b1161017b578063d4f77b1c116100d8578063f2fde38b1161008c578063f5c9786711610071578063f5c97867146104f7578063f8dd5ad3146104ff578063fd6673f514610507576102c8565b8063f2fde38b146104c9578063f4ceab1c146104ef576102c8565b8063e231bff0116100bd578063e231bff014610451578063e2eb41ff14610459578063f18d20be146104c1576102c8565b8063d4f77b1c14610441578063e0236a1814610449576102c8565b8063aad739f51161012f578063c39b583c11610114578063c39b583c14610429578063caa02e0814610431578063d013666e14610439576102c8565b8063aad739f514610404578063be22f54614610421576102c8565b8063a2fb117511610160578063a2fb1175146103d7578063a59a9973146103f4578063a98a5c94146103fc576102c8565b80638da5cb5b146103c757806395224b33146103cf576102c8565b80635edafd5a11610229578063715018a6116101dd5780637c80e6da116101c25780637c80e6da146103af5780637e5f8476146103b75780638456cb59146103bf576102c8565b8063715018a61461039f5780637a23032c146103a7576102c8565b8063633803001161020e578063633803001461036b578063638126f81461038f5780636a79328a14610397576102c8565b80635edafd5a1461035b5780635faeea3714610363576102c8565b80633ccfd60b116102805780633f4ba83a116102655780633f4ba83a1461032f57806340732c89146103375780635c975abb1461033f576102c8565b80633ccfd60b1461031f5780633e7433eb14610327576102c8565b806315d74bb3116102b157806315d74bb3146102ef57806316330d40146102f9578063250a2b0d14610317576102c8565b80630c8ac645146102cd57806311b2e2d9146102e7575b600080fd5b6102d561050f565b60408051918252519081900360200190f35b6102d5610533565b6102f7610557565b005b6103016109a9565b6040805160ff9092168252519081900360200190f35b6102d56109cd565b6102f76109d3565b6102d5610d35565b6102f7610d59565b6102f7610e30565b6103476110a0565b604080519115158252519081900360200190f35b6103016110c1565b6102d56110e5565b6103736110eb565b604080516001600160a01b039092168252519081900360200190f35b61037361110f565b6102d5611133565b6102f7611139565b6102d5611213565b6102d5611219565b61034761123d565b6102f761124d565b610373611316565b6102d5611325565b610373600480360360208110156103ed57600080fd5b503561132b565b610373611352565b610373611361565b6103736004803603602081101561041a57600080fd5b5035611385565b610373611392565b6103476113b6565b6102d56113e7565b6102d56113ed565b6102f7611411565b6102f7611466565b61034761186f565b61047f6004803603602081101561046f57600080fd5b50356001600160a01b031661187f565b6040805197151588529515156020880152931515868601526001600160a01b039092166060860152608085015260a084015260c0830152519081900360e00190f35b6103476118cc565b6102f7600480360360208110156104df57600080fd5b50356001600160a01b03166118dc565b6102f76119fd565b6102d5611aa1565b6102f7611afc565b6102d5611ff2565b7f000000000000000000000000000000000000000000000001158e460913d0000081565b7f000000000000000000000000000000000000000000000000000000000000000181565b61055f6110a0565b156105a4576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6105ac6113b6565b156105fe576040805162461bcd60e51b815260206004820152601960248201527f47616d6520697320616c726561647920636f6d706c6574656400000000000000604482015290519081900360640190fd5b3360009081526008602052604090206002810154610663576040805162461bcd60e51b815260206004820152601560248201527f506c6179657220646f6573206e6f742065786973740000000000000000000000604482015290519081900360640190fd5b805460ff16156106ba576040805162461bcd60e51b815260206004820152601c60248201527f506c617965722068617320616c72656164792077697468647261776e00000000604482015290519081900360640190fd5b805460ff1916600190811782556003546106d99163ffffffff611ff816565b600355600754158015906106f45750805462010000900460ff165b1561075e5760075461070d90600163ffffffff611ff816565b600755805462ff0000191681556003810154600a805460009290811061072f57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60006107bf6107ae60646107a27f000000000000000000000000000000000000000000000000000000000000000560ff16866002015461205a90919063ffffffff16565b9063ffffffff6120ba16565b60028401549063ffffffff611ff816565b90506107da8260020154600554611ff890919063ffffffff16565b60055560006107e7611aa1565b9050806107fc57825461ff0019166101001783555b600554604080518481526020810192909252805133927f1670585e36568ede58d159518ce92cad99f75ad41c7d8281df3dd4eaa0c855d092908290030190a260015460408051631a4ca37b60e21b81526001600160a01b037f000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a8116600483015260248201869052306044830152915191909216916369328dec91606480830192600092919082900301818387803b1580156108b657600080fd5b505af11580156108ca573d6000803e3d6000fd5b50506040805163a9059cbb60e01b81523360048201526024810186905290516001600160a01b037f000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a16935063a9059cbb925060448083019260209291908290030181600087803b15801561093d57600080fd5b505af1158015610951573d6000803e3d6000fd5b505050506040513d602081101561096757600080fd5b50516109a45760405162461bcd60e51b815260040180806020018281038252602f815260200180612d25602f913960400191505060405180910390fd5b505050565b7f000000000000000000000000000000000000000000000000000000000000000581565b60035481565b3360009081526008602052604090206002810154610a38576040805162461bcd60e51b815260206004820152601560248201527f506c6179657220646f6573206e6f742065786973740000000000000000000000604482015290519081900360640190fd5b805460ff1615610a8f576040805162461bcd60e51b815260206004820152601c60248201527f506c617965722068617320616c72656164792077697468647261776e00000000604482015290519081900360640190fd5b805460ff19166001178155600054600160b01b900460ff16610ab357610ab3611afc565b60028101546000610aeb7f0000000000000000000000000000000000000000000000000000000000000001600163ffffffff611ff816565b83600101541415610b4057610b1d610b106007546004546120ba90919063ffffffff16565b839063ffffffff61212116565b60025490925015610b4057600754600254610b3d9163ffffffff6120ba16565b90505b6040805183815260006020820152808201839052905133917f650fdf669e93aa6c8ff3defe2da9c12b64f1548e5e1e54e803f4c1beb6466c8e919081900360600190a26040805163a9059cbb60e01b81523360048201526024810184905290516001600160a01b037f000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a169163a9059cbb9160448083019260209291908290030181600087803b158015610bf257600080fd5b505af1158015610c06573d6000803e3d6000fd5b505050506040513d6020811015610c1c57600080fd5b5051610c595760405162461bcd60e51b8152600401808060200182810382526029815260200180612e616029913960400191505060405180910390fd5b80156109a4576040805163a9059cbb60e01b81523360048201526024810183905290516001600160a01b037f000000000000000000000000471ece3750da237f93b8e339c536989b8978a438169163a9059cbb9160448083019260209291908290030181600087803b158015610cce57600080fd5b505af1158015610ce2573d6000803e3d6000fd5b505050506040513d6020811015610cf857600080fd5b50516109a45760405162461bcd60e51b8152600401808060200182810382526033815260200180612f846033913960400191505060405180910390fd5b7f0000000000000000000000000000000000000000000000000000000062a330df81565b610d6161217b565b6001600160a01b0316610d72611316565b6001600160a01b031614610dcd576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b610dd56110a0565b610e26576040805162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015290519081900360640190fd5b610e2e61217f565b565b610e386110a0565b15610e7d576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b336000908152600860205260409020805460ff1615610ecd5760405162461bcd60e51b8152600401808060200182810382526021815260200180612f1d6021913960400191505060405180910390fd5b8054630100000090046001600160a01b03163314610f32576040805162461bcd60e51b815260206004820152601660248201527f53656e646572206973206e6f74206120706c6179657200000000000000000000604482015290519081900360640190fd5b6000610f3c611aa1565b9050600081118015610f6d57507f000000000000000000000000000000000000000000000000000000000000000181105b610fa85760405162461bcd60e51b8152600401808060200182810382526046815260200180612dcd6046913960600191505060405180910390fd5b8082600101541415610feb5760405162461bcd60e51b8152600401808060200182810382526023815260200180612f616023913960400191505060405180910390fd5b610ffc81600163ffffffff611ff816565b82600101541461103d5760405162461bcd60e51b8152600401808060200182810382526033815260200180612fb76033913960400191505060405180910390fd5b604080517f000000000000000000000000000000000000000000000001158e460913d0000081529051829133917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159181900360200190a361109c612246565b5050565b60005474010000000000000000000000000000000000000000900460ff1690565b7f000000000000000000000000000000000000000000000000000000000000000081565b60055481565b7f000000000000000000000000d1088091a174d33412a968fa34cb67131188b33281565b7f000000000000000000000000471ece3750da237f93b8e339c536989b8978a43881565b60025481565b61114161217b565b6001600160a01b0316611152611316565b6001600160a01b0316146111ad576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b600054600160a81b900460ff1661120b576040805162461bcd60e51b815260206004820152600b60248201527f4e6f7420616c6c6f776564000000000000000000000000000000000000000000604482015290519081900360640190fd5b610e2e61284b565b60065481565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81565b600054600160a81b900460ff1681565b61125561217b565b6001600160a01b0316611266611316565b6001600160a01b0316146112c1576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6112c96110a0565b1561130e576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b610e2e612916565b6000546001600160a01b031690565b60045481565b600a818154811061133857fe5b6000918252602090912001546001600160a01b0316905081565b6001546001600160a01b031681565b7f000000000000000000000000918146359264c492bd6934071c6bd31c854edbc381565b6009818154811061133857fe5b7f000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a81565b60007f00000000000000000000000000000000000000000000000000000000000000016113e1611aa1565b11905090565b60075481565b7f000000000000000000000000000000000000000000000000000000000024ea0081565b6114196110a0565b1561145e576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b610e2e6129cb565b61146e61217b565b6001600160a01b031661147f611316565b6001600160a01b0316146114da576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6114e26113b6565b611533576040805162461bcd60e51b815260206004820152601560248201527f47616d65206973206e6f7420636f6d706c657465640000000000000000000000604482015290519081900360640190fd5b600054600160b01b900460ff1661157b5760405162461bcd60e51b8152600401808060200182810382526025815260200180612e136025913960400191505060405180910390fd5b600054600160b81b900460ff16156115da576040805162461bcd60e51b815260206004820152601b60248201527f41646d696e2068617320616c72656164792077697468647261776e0000000000604482015290519081900360640190fd5b600080547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16600160b81b17815560075415801561161a57506000600254115b1561162457506002545b61162c611316565b6001600160a01b03167f80ebcacc706983394bb8fcc88ea7b9241338fb4617fffbea411b68b40ed5627e6004546006548460405180848152602001838152602001828152602001935050505060405180910390a260065415611778577f000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a6001600160a01b031663a9059cbb6116bf611316565b6006546040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561171157600080fd5b505af1158015611725573d6000803e3d6000fd5b505050506040513d602081101561173b57600080fd5b50516117785760405162461bcd60e51b8152600401808060200182810382526025815260200180612da86025913960400191505060405180910390fd5b801561186c577f000000000000000000000000471ece3750da237f93b8e339c536989b8978a4386001600160a01b031663a9059cbb6117b5611316565b836040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561180557600080fd5b505af1158015611819573d6000803e3d6000fd5b505050506040513d602081101561182f57600080fd5b505161186c5760405162461bcd60e51b815260040180806020018281038252602f815260200180612eab602f913960400191505060405180910390fd5b50565b600054600160b01b900460ff1681565b600860205260009081526040902080546001820154600283015460039093015460ff8084169461010085048216946201000081049092169363010000009092046001600160a01b03169287565b600054600160b81b900460ff1681565b6118e461217b565b6001600160a01b03166118f5611316565b6001600160a01b031614611950576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b0381166119955760405162461bcd60e51b8152600401808060200182810382526026815260200180612d826026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a36000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b611a0561217b565b6001600160a01b0316611a16611316565b6001600160a01b031614611a71576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16600160a81b179055565b6000611af77f000000000000000000000000000000000000000000000000000000000024ea006107a2427f0000000000000000000000000000000000000000000000000000000062a330df63ffffffff611ff816565b905090565b611b046113b6565b611b55576040805162461bcd60e51b815260206004820152601560248201527f47616d65206973206e6f7420636f6d706c657465640000000000000000000000604482015290519081900360640190fd5b600054600160b01b900460ff1615611b9e5760405162461bcd60e51b815260040180806020018281038252602e815260200180612d54602e913960400191505060405180910390fd5b600080547fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff16600160b01b178155604080516370a0823160e01b815230600482015290516001600160a01b037f000000000000000000000000918146359264c492bd6934071c6bd31c854edbc316916370a08231916024808301926020929190829003018186803b158015611c3257600080fd5b505afa158015611c46573d6000803e3d6000fd5b505050506040513d6020811015611c5c57600080fd5b50511115611cf95760015460408051631a4ca37b60e21b81526001600160a01b037f000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a811660048301526000196024830152306044830152915191909216916369328dec91606480830192600092919082900301818387803b158015611ce057600080fd5b505af1158015611cf4573d6000803e3d6000fd5b505050505b604080516370a0823160e01b815230600482015290516000916001600160a01b037f000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a16916370a0823191602480820192602092909190829003018186803b158015611d6357600080fd5b505afa158015611d77573d6000803e3d6000fd5b505050506040513d6020811015611d8d57600080fd5b505190507f000000000000000000000000471ece3750da237f93b8e339c536989b8978a4386001600160a01b031615611e5657604080516370a0823160e01b815230600482015290516001600160a01b037f000000000000000000000000471ece3750da237f93b8e339c536989b8978a43816916370a08231916024808301926020929190829003018186803b158015611e2657600080fd5b505afa158015611e3a573d6000803e3d6000fd5b505050506040513d6020811015611e5057600080fd5b50516002555b600554600090821115611e7a57600554611e7790839063ffffffff611ff816565b90505b600060ff7f00000000000000000000000000000000000000000000000000000000000000001615611ef757611edd60646107a28460ff7f00000000000000000000000000000000000000000000000000000000000000001663ffffffff61205a16565b9050611eef828263ffffffff611ff816565b600455611f00565b50600481905560005b600754611f11576006829055611f17565b60068190555b60055460045460025460408051878152602081019490945283810192909252600060608401526080830152517f28d72925fdcea205b246c820015bd35812a740d1ec1a5cdc84f7784b50940fbb9181900360a00190a17fdbb9607e18553d40c255226e09883b48f92a108f6f895b0f37db6ae0d7fd56e6600a60405180806020018281038252838181548152602001915080548015611fdf57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611fc1575b50509250505060405180910390a1505050565b60095490565b60008282111561204f576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b508082035b92915050565b60008261206957506000612054565b8282028284828161207657fe5b04146120b35760405162461bcd60e51b8152600401808060200182810382526021815260200180612e8a6021913960400191505060405180910390fd5b9392505050565b6000808211612110576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161211957fe5b049392505050565b6000828201838110156120b3576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b3390565b6121876110a0565b6121d8576040805162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015290519081900360640190fd5b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa61222961217b565b604080516001600160a01b039092168252519081900360200190a1565b604080517fdd62ed3e00000000000000000000000000000000000000000000000000000000815233600482015230602482015290517f000000000000000000000000000000000000000000000001158e460913d00000916001600160a01b037f000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a169163dd62ed3e91604480820192602092909190829003018186803b1580156122ee57600080fd5b505afa158015612302573d6000803e3d6000fd5b505050506040513d602081101561231857600080fd5b505110156123575760405162461bcd60e51b8152600401808060200182810382526043815260200180612eda6043913960600191505060405180910390fd5b6000612361611aa1565b33600090815260086020526040902060018101829055600201549091506123ae907f000000000000000000000000000000000000000000000001158e460913d0000063ffffffff61212116565b336000908152600860205260409020600201556123f27f0000000000000000000000000000000000000000000000000000000000000001600163ffffffff611ff816565b8114156124a457600a80546001818101835560008390527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8909101805473ffffffffffffffffffffffffffffffffffffffff191633179055905461245b9163ffffffff611ff816565b3360009081526008602052604090206003015560075461248290600163ffffffff61212116565b600755336000908152600860205260409020805462ff00001916620100001790555b6005546124d7907f000000000000000000000000000000000000000000000001158e460913d0000063ffffffff61212116565b600555604080517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201527f000000000000000000000000000000000000000000000001158e460913d00000604482015290516001600160a01b037f000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a16916323b872dd9160648083019260209291908290030181600087803b15801561258757600080fd5b505af115801561259b573d6000803e3d6000fd5b505050506040513d60208110156125b157600080fd5b5051612604576040805162461bcd60e51b815260206004820152600f60248201527f5472616e73666572206661696c65640000000000000000000000000000000000604482015290519081900360640190fd5b604080516370a0823160e01b815230600482015290516000916001600160a01b037f000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a16916370a0823191602480820192602092909190829003018186803b15801561266e57600080fd5b505afa158015612682573d6000803e3d6000fd5b505050506040513d602081101561269857600080fd5b5051600154604080517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0392831660048201526024810184905290519293507f000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a9091169163095ea7b3916044808201926020929091908290030181600087803b15801561272d57600080fd5b505af1158015612741573d6000803e3d6000fd5b505050506040513d602081101561275757600080fd5b50516127945760405162461bcd60e51b8152600401808060200182810382526029815260200180612e386029913960400191505060405180910390fd5b600154604080517fe8eda9df0000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000765de816845861e75a25fca122bb6898b8b1282a8116600483015260248201859052306044830152609b60648301529151919092169163e8eda9df91608480830192600092919082900301818387803b15801561282f57600080fd5b505af1158015612843573d6000803e3d6000fd5b505050505050565b61285361217b565b6001600160a01b0316612864611316565b6001600160a01b0316146128bf576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a36000805473ffffffffffffffffffffffffffffffffffffffff19169055565b61291e6110a0565b15612963576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861222961217b565b6129d3611aa1565b15612a25576040805162461bcd60e51b815260206004820152601860248201527f47616d652068617320616c726561647920737461727465640000000000000000604482015290519081900360640190fd5b33600081815260086020526040902054630100000090046001600160a01b0316141580612a66575033600090815260086020526040902054610100900460ff165b612aa15760405162461bcd60e51b8152600401808060200182810382526023815260200180612f3e6023913960400191505060405180910390fd5b600354612ab590600163ffffffff61212116565b60038190557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1015612b185760405162461bcd60e51b8152600401808060200182810382526027815260200180612cfe6027913960400191505060405180910390fd5b33600090815260086020526040902054610100900460ff16612b38612cc1565b506040805160e0810182526000808252602080830182815283850183815233606086018181526080870186815260a0880187815260c089018881529388526008909652979095208651815494519351965160ff199095169015151761ff001916610100931515939093029290921762ff000019166201000095151595909502949094177fffffffffffffffffff0000000000000000000000000000000000000000ffffff1663010000006001600160a01b0390931692909202919091178155935160018501555160028401555160039092019190915581612c6357600980546001810182556000919091527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af01805473ffffffffffffffffffffffffffffffffffffffff1916331790555b604080517f000000000000000000000000000000000000000000000001158e460913d000008152905133917f485fd86c2a7d2d9ca3bf02e2ba776ea24271bc62274265b0bd5f478b3b7a1ca4919081900360200190a261109c612246565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091529056fe52656163686564206d6178207175616e74697479206f6620706c617965727320616c6c6f7765644661696c20746f207472616e7366657220455243323020746f6b656e73206f6e206561726c7920776974686472617752656465656d206f7065726174696f6e20616c72656164792068617070656e656420666f72207468652067616d654f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573734661696c20746f207472616e73666572204552323020746f6b656e7320746f2061646d696e4465706f73697420617661696c61626c65206f6e6c79206265747765656e207365676d656e74203120616e64207365676d656e74206e2d31202870656e756c74696d6174652946756e6473206e6f742072656465656d65642066726f6d2065787465726e616c20706f6f6c4661696c20746f20617070726f766520616c6c6f77616e636520746f206c656e64696e6720706f6f6c4661696c20746f207472616e7366657220455243323020746f6b656e73206f6e207769746864726177536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774661696c20746f207472616e73666572204552323020696e63656e7469766520746f6b656e7320746f2061646d696e596f75206e65656420746f206861766520616c6c6f77616e636520746f20646f207472616e7366657220444149206f6e2074686520736d61727420636f6e7472616374506c6179657220616c72656164792077697468647261772066726f6d2067616d6543616e6e6f74206a6f696e207468652067616d65206d6f7265207468616e206f6e6365506c6179657220616c726561647920706169642063757272656e74207365676d656e744661696c20746f207472616e7366657220455243323020696e63656e7469766520746f6b656e73206f6e207769746864726177506c61796572206469646e277420706179207468652070726576696f7573207365676d656e74202d2067616d65206f76657221a2646970667358221220140ca63d69ff4f5afd133e282c8107ed9205cb12821e8662c0c5828ef53bc4f864736f6c634300060b0033