Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- GrantContract
- Optimization enabled
- true
- Compiler version
- v0.8.22+commit.4fc1097e
- Optimization runs
- 200
- EVM Version
- paris
- Verified at
- 2025-02-11T21:18:44.056163Z
Constructor Arguments
0x000000000000000000000000f33b4027f106cd1e2685516102785650a34d0c5f
Arg [0] (<b>address</b>) : <a href="{#{address_path(@conn, :show, @address)}}">0xf33b4027f106cd1e2685516102785650a34d0c5f</a>
Contract source code
// File: @openzeppelin/contracts/security/ReentrancyGuard.sol
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, aand then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}
// File: @openzeppelin/contracts/utils/Context.sol
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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 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) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
// File: @openzeppelin/contracts/access/Ownable.sol
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
/**
* @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.
*
* The initial owner is set to the address provided by the deployer. 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;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(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 {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// File: @openzeppelin/contracts/utils/math/SafeMath.sol
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol)
pragma solidity ^0.8.0;
// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.
/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
* now has built in overflow checking.
*/
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) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
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) {
unchecked {
// 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) {
unchecked {
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) {
unchecked {
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) {
return a + b;
}
/**
* @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) {
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) {
return a * b;
}
/**
* @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.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
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) {
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) {
unchecked {
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.
*
* 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) {
unchecked {
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) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}
// File: fundingcontract.sol
pragma solidity ^0.8.22;
contract GrantContract is ReentrancyGuard, Ownable {
using SafeMath for uint256;
struct Beneficiary {
uint256 totalAllotment;
uint256 unlockedAmount;
uint256 lastClaimBlock;
uint256 unlockInterval; // in blocks
string label;
bool isPaused; // Pause funding for this beneficiary
}
uint256 public blockTime = 5; // 5 seconds per block
mapping(address => Beneficiary) public beneficiaries;
address[] public beneficiaryList;
uint256 public contractBalance;
event FundsAdded(uint256 amount);
event FundsWithdrawn(uint256 amount);
event BeneficiaryAdded(address indexed beneficiary, uint256 amount, uint256 unlockInterval, string label);
event BeneficiaryRemoved(address indexed beneficiary);
event FundsClaimed(address indexed beneficiary, uint256 amount);
event BeneficiaryPaused(address indexed beneficiary);
event BeneficiaryUnpaused(address indexed beneficiary);
constructor(address initialOwner) Ownable(initialOwner) {}
// Add funds to the contract
function addFunds() external payable onlyOwner {
require(msg.value > 0, "No funds added");
contractBalance = contractBalance.add(msg.value);
emit FundsAdded(msg.value);
}
// Add or update a beneficiary's allotment
function allotFunds(
address _beneficiary,
uint256 _amount,
string memory _unlockInterval,
string memory _label
) external onlyOwner {
require(_beneficiary != address(0), "Invalid address");
require(_amount > 0, "Amount must be greater than zero");
uint256 unlockIntervalBlocks = calculateUnlockInterval(_unlockInterval);
Beneficiary storage beneficiary = beneficiaries[_beneficiary];
if (beneficiary.totalAllotment == 0) {
beneficiaryList.push(_beneficiary);
}
beneficiary.totalAllotment = _amount;
beneficiary.unlockedAmount = 0;
beneficiary.lastClaimBlock = block.number;
beneficiary.unlockInterval = unlockIntervalBlocks;
beneficiary.label = _label;
beneficiary.isPaused = false;
emit BeneficiaryAdded(_beneficiary, _amount, unlockIntervalBlocks, _label);
}
// Remove a beneficiary's allotment
function removeBeneficiary(address _beneficiary) external onlyOwner {
require(beneficiaries[_beneficiary].totalAllotment > 0, "No allotment found");
delete beneficiaries[_beneficiary];
emit BeneficiaryRemoved(_beneficiary);
}
// Pause funding for a specific beneficiary
function pauseBeneficiary(address _beneficiary) external onlyOwner {
require(beneficiaries[_beneficiary].totalAllotment > 0, "No allotment found");
beneficiaries[_beneficiary].isPaused = true;
emit BeneficiaryPaused(_beneficiary);
}
// Unpause funding for a specific beneficiary
function unpauseBeneficiary(address _beneficiary) external onlyOwner {
require(beneficiaries[_beneficiary].totalAllotment > 0, "No allotment found");
beneficiaries[_beneficiary].isPaused = false;
emit BeneficiaryUnpaused(_beneficiary);
}
// Claim funds
function claim() external nonReentrant {
Beneficiary storage beneficiary = beneficiaries[msg.sender];
require(beneficiary.totalAllotment > 0, "No allotment found");
require(!beneficiary.isPaused, "Funding for this beneficiary is paused");
uint256 blocksSinceLastClaim = block.number.sub(beneficiary.lastClaimBlock);
require(blocksSinceLastClaim >= beneficiary.unlockInterval, "Claim period not reached");
uint256 claimableIntervals = blocksSinceLastClaim.div(beneficiary.unlockInterval);
uint256 claimableAmount = beneficiary.totalAllotment
.div(365 * 24 * 60 * 60 / blockTime / beneficiary.unlockInterval)
.mul(claimableIntervals);
if (claimableAmount.add(beneficiary.unlockedAmount) > beneficiary.totalAllotment) {
claimableAmount = beneficiary.totalAllotment.sub(beneficiary.unlockedAmount);
}
require(claimableAmount > 0, "No funds to claim");
require(claimableAmount <= address(this).balance, "Insufficient contract balance");
beneficiary.unlockedAmount = beneficiary.unlockedAmount.add(claimableAmount);
beneficiary.lastClaimBlock = beneficiary.lastClaimBlock.add(claimableIntervals.mul(beneficiary.unlockInterval));
payable(msg.sender).transfer(claimableAmount);
emit FundsClaimed(msg.sender, claimableAmount);
}
// Withdraw excess funds from the contract
function withdrawFunds(uint256 _amount) external onlyOwner {
require(_amount <= address(this).balance, "Insufficient balance");
contractBalance = contractBalance.sub(_amount);
payable(owner()).transfer(_amount);
emit FundsWithdrawn(_amount);
}
// View all beneficiaries
function getAllBeneficiaries() external view returns (address[] memory) {
return beneficiaryList;
}
// View details of a specific beneficiary
function getBeneficiaryDetails(address _beneficiary) external view returns (Beneficiary memory) {
return beneficiaries[_beneficiary];
}
// Helper function to calculate unlock interval in blocks
function calculateUnlockInterval(string memory _unlockInterval) internal view returns (uint256) {
if (keccak256(bytes(_unlockInterval)) == keccak256(bytes("monthly"))) {
return (30 * 24 * 60 * 60) / blockTime;
} else if (keccak256(bytes(_unlockInterval)) == keccak256(bytes("quarterly"))) {
return (90 * 24 * 60 * 60) / blockTime;
} else if (keccak256(bytes(_unlockInterval)) == keccak256(bytes("half-yearly"))) {
return (180 * 24 * 60 * 60) / blockTime;
} else if (keccak256(bytes(_unlockInterval)) == keccak256(bytes("yearly"))) {
return (365 * 24 * 60 * 60) / blockTime;
} else {
revert("Invalid unlock interval");
}
}
}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"initialOwner","internalType":"address"}]},{"type":"error","name":"OwnableInvalidOwner","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"error","name":"OwnableUnauthorizedAccount","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"event","name":"BeneficiaryAdded","inputs":[{"type":"address","name":"beneficiary","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"unlockInterval","internalType":"uint256","indexed":false},{"type":"string","name":"label","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"BeneficiaryPaused","inputs":[{"type":"address","name":"beneficiary","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"BeneficiaryRemoved","inputs":[{"type":"address","name":"beneficiary","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"BeneficiaryUnpaused","inputs":[{"type":"address","name":"beneficiary","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"FundsAdded","inputs":[{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"FundsClaimed","inputs":[{"type":"address","name":"beneficiary","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"FundsWithdrawn","inputs":[{"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":"function","stateMutability":"payable","outputs":[],"name":"addFunds","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"allotFunds","inputs":[{"type":"address","name":"_beneficiary","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"},{"type":"string","name":"_unlockInterval","internalType":"string"},{"type":"string","name":"_label","internalType":"string"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"totalAllotment","internalType":"uint256"},{"type":"uint256","name":"unlockedAmount","internalType":"uint256"},{"type":"uint256","name":"lastClaimBlock","internalType":"uint256"},{"type":"uint256","name":"unlockInterval","internalType":"uint256"},{"type":"string","name":"label","internalType":"string"},{"type":"bool","name":"isPaused","internalType":"bool"}],"name":"beneficiaries","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"beneficiaryList","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"blockTime","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claim","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"contractBalance","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getAllBeneficiaries","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct GrantContract.Beneficiary","components":[{"type":"uint256","name":"totalAllotment","internalType":"uint256"},{"type":"uint256","name":"unlockedAmount","internalType":"uint256"},{"type":"uint256","name":"lastClaimBlock","internalType":"uint256"},{"type":"uint256","name":"unlockInterval","internalType":"uint256"},{"type":"string","name":"label","internalType":"string"},{"type":"bool","name":"isPaused","internalType":"bool"}]}],"name":"getBeneficiaryDetails","inputs":[{"type":"address","name":"_beneficiary","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"pauseBeneficiary","inputs":[{"type":"address","name":"_beneficiary","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeBeneficiary","inputs":[{"type":"address","name":"_beneficiary","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unpauseBeneficiary","inputs":[{"type":"address","name":"_beneficiary","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawFunds","inputs":[{"type":"uint256","name":"_amount","internalType":"uint256"}]}]
Contract Creation Code
0x6080604052600560025534801561001557600080fd5b50604051611690380380611690833981016040819052610034916100ca565b6001600055806001600160a01b03811661006857604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b61007181610078565b50506100fa565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000602082840312156100dc57600080fd5b81516001600160a01b03811681146100f357600080fd5b9392505050565b611587806101096000396000f3fe6080604052600436106100f35760003560e01c8063715018a61161008a5780639e761bbb116100595780639e761bbb1461029a578063a26759cb146102ba578063f2dcb315146102c2578063f2fde38b146102e257600080fd5b8063715018a61461021d5780638564c847146102325780638b7afe2e146102525780638da5cb5b1461026857600080fd5b806348b15166116100c657806348b15166146101975780634c3d4f1b146101bb5780634e71d92d146101e857806359633a1c146101fd57600080fd5b806301567739146100f857806314b55b5214610133578063155dd5ee146101555780632f14bae814610175575b600080fd5b34801561010457600080fd5b506101186101133660046110b9565b610302565b60405161012a9695949392919061111a565b60405180910390f35b34801561013f57600080fd5b5061015361014e3660046111fd565b6103c9565b005b34801561016157600080fd5b5061015361017036600461127b565b61056a565b34801561018157600080fd5b5061018a61063a565b60405161012a9190611294565b3480156101a357600080fd5b506101ad60025481565b60405190815260200161012a565b3480156101c757600080fd5b506101db6101d63660046110b9565b61069c565b60405161012a91906112e1565b3480156101f457600080fd5b506101536107d8565b34801561020957600080fd5b506101536102183660046110b9565b610aa1565b34801561022957600080fd5b50610153610b60565b34801561023e57600080fd5b5061015361024d3660046110b9565b610b72565b34801561025e57600080fd5b506101ad60055481565b34801561027457600080fd5b506001546001600160a01b03165b6040516001600160a01b03909116815260200161012a565b3480156102a657600080fd5b506102826102b536600461127b565b610bfe565b610153610c28565b3480156102ce57600080fd5b506101536102dd3660046110b9565b610cb6565b3480156102ee57600080fd5b506101536102fd3660046110b9565b610d3f565b600360205280600052604060002060009150905080600001549080600101549080600201549080600301549080600401805461033d9061133d565b80601f01602080910402602001604051908101604052809291908181526020018280546103699061133d565b80156103b65780601f1061038b576101008083540402835291602001916103b6565b820191906000526020600020905b81548152906001019060200180831161039957829003601f168201915b5050506005909301549192505060ff1686565b6103d1610d7d565b6001600160a01b03841661041e5760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b60448201526064015b60405180910390fd5b6000831161046e5760405162461bcd60e51b815260206004820181905260248201527f416d6f756e74206d7573742062652067726561746572207468616e207a65726f6044820152606401610415565b600061047983610daa565b6001600160a01b038616600090815260036020526040812080549293509190036104e957600480546001810182556000919091527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b0180546001600160a01b0319166001600160a01b0388161790555b84815560006001820155436002820155600381018290556004810161050e84826113c8565b5060058101805460ff191690556040516001600160a01b038716907f5367c35a8cbf1024f689c3420f598ba2b53a4d0a1ba202a4a9b1173ef01f83569061055a90889086908890611488565b60405180910390a2505050505050565b610572610d7d565b478111156105b95760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610415565b6005546105c69082610f72565b6005556001546040516001600160a01b039091169082156108fc029083906000818181858888f19350505050158015610603573d6000803e3d6000fd5b506040518181527f4a37b25aab49761ecf63117fe82b98d750917451133cf797507bc9fb5b96044a9060200160405180910390a150565b6060600480548060200260200160405190810160405280929190818152602001828054801561069257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610674575b5050505050905090565b6106d76040518060c0016040528060008152602001600081526020016000815260200160008152602001606081526020016000151581525090565b60036000836001600160a01b03166001600160a01b031681526020019081526020016000206040518060c00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201805461073f9061133d565b80601f016020809104026020016040519081016040528092919081815260200182805461076b9061133d565b80156107b85780601f1061078d576101008083540402835291602001916107b8565b820191906000526020600020905b81548152906001019060200180831161079b57829003601f168201915b50505091835250506005919091015460ff16151560209091015292915050565b6107e0610f85565b336000908152600360205260409020805461080d5760405162461bcd60e51b8152600401610415906114b0565b600581015460ff16156108715760405162461bcd60e51b815260206004820152602660248201527f46756e64696e6720666f7220746869732062656e6566696369617279206973206044820152651c185d5cd95960d21b6064820152608401610415565b600061088a826002015443610f7290919063ffffffff16565b905081600301548110156108e05760405162461bcd60e51b815260206004820152601860248201527f436c61696d20706572696f64206e6f74207265616368656400000000000000006044820152606401610415565b60006108f9836003015483610fde90919063ffffffff16565b905060006109338261092d86600301546002546301e1338061091b91906114f2565b61092591906114f2565b875490610fde565b90610fea565b8454600186015491925090610949908390610ff6565b1115610962576001840154845461095f91610f72565b90505b600081116109a65760405162461bcd60e51b81526020600482015260116024820152704e6f2066756e647320746f20636c61696d60781b6044820152606401610415565b478111156109f65760405162461bcd60e51b815260206004820152601d60248201527f496e73756666696369656e7420636f6e74726163742062616c616e63650000006044820152606401610415565b6001840154610a059082610ff6565b60018501556003840154610a2990610a1e908490610fea565b600286015490610ff6565b6002850155604051339082156108fc029083906000818181858888f19350505050158015610a5b573d6000803e3d6000fd5b5060405181815233907fa65a8b4f7f65a1063243d7f7e9e4da00ff767599acf21549ef2548a45d1695ae9060200160405180910390a250505050610a9f6001600055565b565b610aa9610d7d565b6001600160a01b038116600090815260036020526040902054610ade5760405162461bcd60e51b8152600401610415906114b0565b6001600160a01b03811660009081526003602081905260408220828155600181018390556002810183905590810182905590610b1d6004830182611054565b50600501805460ff191690556040516001600160a01b038216907f72977dad29432f655f11c2f0e72ef5124bb9ade7a512fb7a43a9f504df22342890600090a250565b610b68610d7d565b610a9f6000611002565b610b7a610d7d565b6001600160a01b038116600090815260036020526040902054610baf5760405162461bcd60e51b8152600401610415906114b0565b6001600160a01b038116600081815260036020526040808220600501805460ff19166001179055517f11dc51d41c66f7c36ffaa5c696a64074215ff817878631872421ea9505bbad0c9190a250565b60048181548110610c0e57600080fd5b6000918252602090912001546001600160a01b0316905081565b610c30610d7d565b60003411610c715760405162461bcd60e51b815260206004820152600e60248201526d139bc8199d5b991cc8185919195960921b6044820152606401610415565b600554610c7e9034610ff6565b6005556040513481527fd30fc8a1b5907be76206421a3040262f1f6aed0d418c05312ef5ff8de0c9ae4c9060200160405180910390a1565b610cbe610d7d565b6001600160a01b038116600090815260036020526040902054610cf35760405162461bcd60e51b8152600401610415906114b0565b6001600160a01b038116600081815260036020526040808220600501805460ff19169055517f9903599066f3132548c4b56deb3c9420499fbb5a418ca6b44863f708340666719190a250565b610d47610d7d565b6001600160a01b038116610d7157604051631e4fbdf760e01b815260006004820152602401610415565b610d7a81611002565b50565b6001546001600160a01b03163314610a9f5760405163118cdaa760e01b8152336004820152602401610415565b6040805180820190915260078152666d6f6e74686c7960c81b6020918201528151908201206000907fbc653c95ba6ab0e1ef2c238d03b66718c3dadf383ac23d2821c24ea540886de801610e0e57600254610e089062278d006114f2565b92915050565b604080518082019091526009815268717561727465726c7960b81b6020918201528251908301207fb99532807eda912da02940857de7093eee3ddee12d0360df0af333bb5a9bcf7d01610e6b57600254610e08906276a7006114f2565b60408051808201909152600b81526a68616c662d796561726c7960a81b6020918201528251908301207fb2ecc0bf796e2da563ff374d3c28c76c064e72b80624d134e39e10eed9625f1601610eca57600254610e089062ed4e006114f2565b604080518082019091526006815265796561726c7960d01b6020918201528251908301207f9a121b243c6becf8570e4498f5b5b66f2ca2f469fd618c1bc6a022a965722bf501610f2557600254610e08906301e133806114f2565b60405162461bcd60e51b815260206004820152601760248201527f496e76616c696420756e6c6f636b20696e74657276616c0000000000000000006044820152606401610415565b919050565b6000610f7e8284611514565b9392505050565b600260005403610fd75760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610415565b6002600055565b6000610f7e82846114f2565b6000610f7e8284611527565b6000610f7e828461153e565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b5080546110609061133d565b6000825580601f10611070575050565b601f016020900490600052602060002090810190610d7a91905b8082111561109e576000815560010161108a565b5090565b80356001600160a01b0381168114610f6d57600080fd5b6000602082840312156110cb57600080fd5b610f7e826110a2565b6000815180845260005b818110156110fa576020818501810151868301820152016110de565b506000602082860101526020601f19601f83011685010191505092915050565b86815285602082015284604082015283606082015260c06080820152600061114560c08301856110d4565b905082151560a0830152979650505050505050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261118157600080fd5b813567ffffffffffffffff8082111561119c5761119c61115a565b604051601f8301601f19908116603f011681019082821181831017156111c4576111c461115a565b816040528381528660208588010111156111dd57600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806000806080858703121561121357600080fd5b61121c856110a2565b935060208501359250604085013567ffffffffffffffff8082111561124057600080fd5b61124c88838901611170565b9350606087013591508082111561126257600080fd5b5061126f87828801611170565b91505092959194509250565b60006020828403121561128d57600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b818110156112d55783516001600160a01b0316835292840192918401916001016112b0565b50909695505050505050565b60208152815160208201526020820151604082015260408201516060820152606082015160808201526000608083015160c060a084015261132560e08401826110d4565b905060a0840151151560c08401528091505092915050565b600181811c9082168061135157607f821691505b60208210810361137157634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156113c3576000816000526020600020601f850160051c810160208610156113a05750805b601f850160051c820191505b818110156113bf578281556001016113ac565b5050505b505050565b815167ffffffffffffffff8111156113e2576113e261115a565b6113f6816113f0845461133d565b84611377565b602080601f83116001811461142b57600084156114135750858301515b600019600386901b1c1916600185901b1785556113bf565b600085815260208120601f198616915b8281101561145a5788860151825594840194600190910190840161143b565b50858210156114785787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b8381528260208201526060604082015260006114a760608301846110d4565b95945050505050565b602080825260129082015271139bc8185b1b1bdd1b595b9d08199bdd5b9960721b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60008261150f57634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115610e0857610e086114dc565b8082028115828204841417610e0857610e086114dc565b80820180821115610e0857610e086114dc56fea264697066735822122079cfc30acd68120481f40d23b202f70d342e0002b949eea2ad10b94586373b7764736f6c63430008160033000000000000000000000000f33b4027f106cd1e2685516102785650a34d0c5f
Deployed ByteCode
0x6080604052600436106100f35760003560e01c8063715018a61161008a5780639e761bbb116100595780639e761bbb1461029a578063a26759cb146102ba578063f2dcb315146102c2578063f2fde38b146102e257600080fd5b8063715018a61461021d5780638564c847146102325780638b7afe2e146102525780638da5cb5b1461026857600080fd5b806348b15166116100c657806348b15166146101975780634c3d4f1b146101bb5780634e71d92d146101e857806359633a1c146101fd57600080fd5b806301567739146100f857806314b55b5214610133578063155dd5ee146101555780632f14bae814610175575b600080fd5b34801561010457600080fd5b506101186101133660046110b9565b610302565b60405161012a9695949392919061111a565b60405180910390f35b34801561013f57600080fd5b5061015361014e3660046111fd565b6103c9565b005b34801561016157600080fd5b5061015361017036600461127b565b61056a565b34801561018157600080fd5b5061018a61063a565b60405161012a9190611294565b3480156101a357600080fd5b506101ad60025481565b60405190815260200161012a565b3480156101c757600080fd5b506101db6101d63660046110b9565b61069c565b60405161012a91906112e1565b3480156101f457600080fd5b506101536107d8565b34801561020957600080fd5b506101536102183660046110b9565b610aa1565b34801561022957600080fd5b50610153610b60565b34801561023e57600080fd5b5061015361024d3660046110b9565b610b72565b34801561025e57600080fd5b506101ad60055481565b34801561027457600080fd5b506001546001600160a01b03165b6040516001600160a01b03909116815260200161012a565b3480156102a657600080fd5b506102826102b536600461127b565b610bfe565b610153610c28565b3480156102ce57600080fd5b506101536102dd3660046110b9565b610cb6565b3480156102ee57600080fd5b506101536102fd3660046110b9565b610d3f565b600360205280600052604060002060009150905080600001549080600101549080600201549080600301549080600401805461033d9061133d565b80601f01602080910402602001604051908101604052809291908181526020018280546103699061133d565b80156103b65780601f1061038b576101008083540402835291602001916103b6565b820191906000526020600020905b81548152906001019060200180831161039957829003601f168201915b5050506005909301549192505060ff1686565b6103d1610d7d565b6001600160a01b03841661041e5760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b60448201526064015b60405180910390fd5b6000831161046e5760405162461bcd60e51b815260206004820181905260248201527f416d6f756e74206d7573742062652067726561746572207468616e207a65726f6044820152606401610415565b600061047983610daa565b6001600160a01b038616600090815260036020526040812080549293509190036104e957600480546001810182556000919091527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b0180546001600160a01b0319166001600160a01b0388161790555b84815560006001820155436002820155600381018290556004810161050e84826113c8565b5060058101805460ff191690556040516001600160a01b038716907f5367c35a8cbf1024f689c3420f598ba2b53a4d0a1ba202a4a9b1173ef01f83569061055a90889086908890611488565b60405180910390a2505050505050565b610572610d7d565b478111156105b95760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610415565b6005546105c69082610f72565b6005556001546040516001600160a01b039091169082156108fc029083906000818181858888f19350505050158015610603573d6000803e3d6000fd5b506040518181527f4a37b25aab49761ecf63117fe82b98d750917451133cf797507bc9fb5b96044a9060200160405180910390a150565b6060600480548060200260200160405190810160405280929190818152602001828054801561069257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610674575b5050505050905090565b6106d76040518060c0016040528060008152602001600081526020016000815260200160008152602001606081526020016000151581525090565b60036000836001600160a01b03166001600160a01b031681526020019081526020016000206040518060c00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201805461073f9061133d565b80601f016020809104026020016040519081016040528092919081815260200182805461076b9061133d565b80156107b85780601f1061078d576101008083540402835291602001916107b8565b820191906000526020600020905b81548152906001019060200180831161079b57829003601f168201915b50505091835250506005919091015460ff16151560209091015292915050565b6107e0610f85565b336000908152600360205260409020805461080d5760405162461bcd60e51b8152600401610415906114b0565b600581015460ff16156108715760405162461bcd60e51b815260206004820152602660248201527f46756e64696e6720666f7220746869732062656e6566696369617279206973206044820152651c185d5cd95960d21b6064820152608401610415565b600061088a826002015443610f7290919063ffffffff16565b905081600301548110156108e05760405162461bcd60e51b815260206004820152601860248201527f436c61696d20706572696f64206e6f74207265616368656400000000000000006044820152606401610415565b60006108f9836003015483610fde90919063ffffffff16565b905060006109338261092d86600301546002546301e1338061091b91906114f2565b61092591906114f2565b875490610fde565b90610fea565b8454600186015491925090610949908390610ff6565b1115610962576001840154845461095f91610f72565b90505b600081116109a65760405162461bcd60e51b81526020600482015260116024820152704e6f2066756e647320746f20636c61696d60781b6044820152606401610415565b478111156109f65760405162461bcd60e51b815260206004820152601d60248201527f496e73756666696369656e7420636f6e74726163742062616c616e63650000006044820152606401610415565b6001840154610a059082610ff6565b60018501556003840154610a2990610a1e908490610fea565b600286015490610ff6565b6002850155604051339082156108fc029083906000818181858888f19350505050158015610a5b573d6000803e3d6000fd5b5060405181815233907fa65a8b4f7f65a1063243d7f7e9e4da00ff767599acf21549ef2548a45d1695ae9060200160405180910390a250505050610a9f6001600055565b565b610aa9610d7d565b6001600160a01b038116600090815260036020526040902054610ade5760405162461bcd60e51b8152600401610415906114b0565b6001600160a01b03811660009081526003602081905260408220828155600181018390556002810183905590810182905590610b1d6004830182611054565b50600501805460ff191690556040516001600160a01b038216907f72977dad29432f655f11c2f0e72ef5124bb9ade7a512fb7a43a9f504df22342890600090a250565b610b68610d7d565b610a9f6000611002565b610b7a610d7d565b6001600160a01b038116600090815260036020526040902054610baf5760405162461bcd60e51b8152600401610415906114b0565b6001600160a01b038116600081815260036020526040808220600501805460ff19166001179055517f11dc51d41c66f7c36ffaa5c696a64074215ff817878631872421ea9505bbad0c9190a250565b60048181548110610c0e57600080fd5b6000918252602090912001546001600160a01b0316905081565b610c30610d7d565b60003411610c715760405162461bcd60e51b815260206004820152600e60248201526d139bc8199d5b991cc8185919195960921b6044820152606401610415565b600554610c7e9034610ff6565b6005556040513481527fd30fc8a1b5907be76206421a3040262f1f6aed0d418c05312ef5ff8de0c9ae4c9060200160405180910390a1565b610cbe610d7d565b6001600160a01b038116600090815260036020526040902054610cf35760405162461bcd60e51b8152600401610415906114b0565b6001600160a01b038116600081815260036020526040808220600501805460ff19169055517f9903599066f3132548c4b56deb3c9420499fbb5a418ca6b44863f708340666719190a250565b610d47610d7d565b6001600160a01b038116610d7157604051631e4fbdf760e01b815260006004820152602401610415565b610d7a81611002565b50565b6001546001600160a01b03163314610a9f5760405163118cdaa760e01b8152336004820152602401610415565b6040805180820190915260078152666d6f6e74686c7960c81b6020918201528151908201206000907fbc653c95ba6ab0e1ef2c238d03b66718c3dadf383ac23d2821c24ea540886de801610e0e57600254610e089062278d006114f2565b92915050565b604080518082019091526009815268717561727465726c7960b81b6020918201528251908301207fb99532807eda912da02940857de7093eee3ddee12d0360df0af333bb5a9bcf7d01610e6b57600254610e08906276a7006114f2565b60408051808201909152600b81526a68616c662d796561726c7960a81b6020918201528251908301207fb2ecc0bf796e2da563ff374d3c28c76c064e72b80624d134e39e10eed9625f1601610eca57600254610e089062ed4e006114f2565b604080518082019091526006815265796561726c7960d01b6020918201528251908301207f9a121b243c6becf8570e4498f5b5b66f2ca2f469fd618c1bc6a022a965722bf501610f2557600254610e08906301e133806114f2565b60405162461bcd60e51b815260206004820152601760248201527f496e76616c696420756e6c6f636b20696e74657276616c0000000000000000006044820152606401610415565b919050565b6000610f7e8284611514565b9392505050565b600260005403610fd75760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610415565b6002600055565b6000610f7e82846114f2565b6000610f7e8284611527565b6000610f7e828461153e565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b5080546110609061133d565b6000825580601f10611070575050565b601f016020900490600052602060002090810190610d7a91905b8082111561109e576000815560010161108a565b5090565b80356001600160a01b0381168114610f6d57600080fd5b6000602082840312156110cb57600080fd5b610f7e826110a2565b6000815180845260005b818110156110fa576020818501810151868301820152016110de565b506000602082860101526020601f19601f83011685010191505092915050565b86815285602082015284604082015283606082015260c06080820152600061114560c08301856110d4565b905082151560a0830152979650505050505050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261118157600080fd5b813567ffffffffffffffff8082111561119c5761119c61115a565b604051601f8301601f19908116603f011681019082821181831017156111c4576111c461115a565b816040528381528660208588010111156111dd57600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806000806080858703121561121357600080fd5b61121c856110a2565b935060208501359250604085013567ffffffffffffffff8082111561124057600080fd5b61124c88838901611170565b9350606087013591508082111561126257600080fd5b5061126f87828801611170565b91505092959194509250565b60006020828403121561128d57600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b818110156112d55783516001600160a01b0316835292840192918401916001016112b0565b50909695505050505050565b60208152815160208201526020820151604082015260408201516060820152606082015160808201526000608083015160c060a084015261132560e08401826110d4565b905060a0840151151560c08401528091505092915050565b600181811c9082168061135157607f821691505b60208210810361137157634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156113c3576000816000526020600020601f850160051c810160208610156113a05750805b601f850160051c820191505b818110156113bf578281556001016113ac565b5050505b505050565b815167ffffffffffffffff8111156113e2576113e261115a565b6113f6816113f0845461133d565b84611377565b602080601f83116001811461142b57600084156114135750858301515b600019600386901b1c1916600185901b1785556113bf565b600085815260208120601f198616915b8281101561145a5788860151825594840194600190910190840161143b565b50858210156114785787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b8381528260208201526060604082015260006114a760608301846110d4565b95945050505050565b602080825260129082015271139bc8185b1b1bdd1b595b9d08199bdd5b9960721b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60008261150f57634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115610e0857610e086114dc565b8082028115828204841417610e0857610e086114dc565b80820180821115610e0857610e086114dc56fea264697066735822122079cfc30acd68120481f40d23b202f70d342e0002b949eea2ad10b94586373b7764736f6c63430008160033