More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 1,527 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Harvest Rewards | 4086913 | 48 mins ago | IN | 0 BERA | 0.00004902 | ||||
Harvest Rewards | 4086616 | 58 mins ago | IN | 0 BERA | 0.00001727 | ||||
Harvest Rewards | 4085537 | 1 hr ago | IN | 0 BERA | 0 | ||||
Harvest Rewards | 4084167 | 2 hrs ago | IN | 0 BERA | 0.00004802 | ||||
Harvest Rewards | 4084058 | 2 hrs ago | IN | 0 BERA | 0.00251756 | ||||
Harvest Rewards | 4083864 | 2 hrs ago | IN | 0 BERA | 0.0000147 | ||||
Harvest Rewards | 4083394 | 2 hrs ago | IN | 0 BERA | 0 | ||||
Harvest Rewards | 4082255 | 3 hrs ago | IN | 0 BERA | 0.00004802 | ||||
Harvest Rewards | 4082174 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Harvest Rewards | 4082160 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Harvest Rewards | 4082151 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Harvest Rewards | 4082140 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Harvest Rewards | 4082130 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Harvest Rewards | 4082116 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Harvest Rewards | 4082105 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Harvest Rewards | 4082095 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Harvest Rewards | 4082081 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Harvest Rewards | 4082071 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Harvest Rewards | 4082058 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Harvest Rewards | 4082046 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Harvest Rewards | 4082035 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Harvest Rewards | 4082020 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Harvest Rewards | 4082011 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Harvest Rewards | 4081999 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Harvest Rewards | 4081991 | 3 hrs ago | IN | 0 BERA | 0 |
Loading...
Loading
Contract Name:
OogaRewards
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
No with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity >= 0.8.20; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "./interfaces/IOogaRewards.sol"; import "./interfaces/IBOogaTokenUsage.sol"; /* * This contract is used to distribute rewards to users that allocated bOOGA here * * rewards can be distributed in the form of one or more tokens * They are mainly managed to be received from the FeeManager contract, but other sources can be added (dev wallet for instance) * * The freshly received rewards are stored in a pending slot * * The content of this pending slot will be progressively transferred over time into a distribution slot * This distribution slot is the source of the rewards distribution to bOOGA allocators during the current cycle * * This transfer from the pending slot to the distribution slot is based on cycleRewardPercent and CYCLE_PERIOD_SECONDS * */ contract OogaRewards is Ownable, ReentrancyGuard, IBOogaTokenUsage, IOogaRewards { using SafeERC20 for IERC20; using EnumerableSet for EnumerableSet.AddressSet; struct UserInfo { uint256 pendingRewards; uint256 rewardDebt; } struct RewardsInfo { uint256 currentDistributionAmount; // total amount to distribute during the current cycle uint256 currentCycleDistributedAmount; // amount already distributed for the current cycle (times 1e2) uint256 pendingAmount; // total amount in the pending slot, not distributed yet uint256 distributedAmount; // total amount that has been distributed since initialization uint256 accRewardsPerShare; // accumulated rewards per share (times 1e18) uint256 lastUpdateTime; // last time the rewards distribution occurred uint256 cycleRewardsPercent; // fixed part of the pending rewards to assign to currentDistributionAmount on every cycle bool distributionDisabled; // deactivate a token distribution (for temporary rewards) } // actively distributed tokens EnumerableSet.AddressSet private _distributedTokens; uint256 public constant MAX_DISTRIBUTED_TOKENS = 5; // rewards info for every rewards token mapping(address => RewardsInfo) public rewardsInfo; mapping(address => mapping(address => UserInfo)) public users; address public immutable bOogaToken; // bOogaToken contract mapping(address => uint256) public usersAllocation; // User's bOOGA allocation uint256 public totalAllocation; // Contract's total bOOGA allocation uint256 public constant MIN_CYCLE_REWARDS_PERCENT = 1; // 0.01% uint256 public constant DEFAULT_CYCLE_REWARDS_PERCENT = 10000; // 100% uint256 public constant MAX_CYCLE_REWARDS_PERCENT = 10000; // 100% // rewards will be added to the currentDistributionAmount on each new cycle uint256 public constant cycleDurationSeconds = 3 days; uint256 public currentCycleStartTime; constructor(address bOogaToken_, uint256 startTime_) { require(bOogaToken_ != address(0), "zero address"); bOogaToken = bOogaToken_; currentCycleStartTime = startTime_; } /** * EVENTS */ event UserUpdated(address indexed user, uint256 previousBalance, uint256 newBalance); event RewardsCollected(address indexed user, address indexed token, uint256 amount); event CycleRewardsPercentUpdated(address indexed token, uint256 previousValue, uint256 newValue); event RewardsAddedToPending(address indexed token, uint256 amount); event DistributedTokenDisabled(address indexed token); event DistributedTokenRemoved(address indexed token); event DistributedTokenEnabled(address indexed token); /** * MODIFIERS */ /** * @dev Checks if an index exists */ modifier validateDistributedTokensIndex(uint256 index) { require(index < _distributedTokens.length(), "validateDistributedTokensIndex: index exists?"); _; } /** * @dev Checks if token exists */ modifier validateDistributedToken(address token) { require(_distributedTokens.contains(token), "validateDistributedTokens: token does not exists"); _; } /** * @dev Checks if caller is the bOogaToken contract */ modifier bOOGATokenOnly() { require(msg.sender == bOogaToken, "bOOGATokenOnly: caller should be bOogaToken"); _; } /** * @dev Returns the number of rewards tokens */ function distributedTokensLength() external view override returns (uint256) { return _distributedTokens.length(); } /** * @dev Returns rewards token address from given index */ function distributedToken(uint256 index) external view override validateDistributedTokensIndex(index) returns (address) { return address(_distributedTokens.at(index)); } /** * @dev Returns true if given token is a rewards token */ function isDistributedToken(address token) external view override returns (bool) { return _distributedTokens.contains(token); } /** * @dev Returns time at which the next cycle will start */ function nextCycleStartTime() public view returns (uint256) { return currentCycleStartTime + cycleDurationSeconds; } /** * @dev Returns user's rewards pending amount for a given token */ function pendingRewardsAmount(address token, address userAddress) external view returns (uint256) { if (totalAllocation == 0) { return users[token][userAddress].pendingRewards; } RewardsInfo storage rewardsInfo_ = rewardsInfo[token]; uint256 accRewardsPerShare = rewardsInfo_.accRewardsPerShare; uint256 lastUpdateTime = rewardsInfo_.lastUpdateTime; uint256 rewardAmountPerSecond = _rewardsAmountPerSecond(token); uint256 _nextCycleStartTime = nextCycleStartTime(); // check if the current cycle has changed since last update if (block.timestamp > _nextCycleStartTime) { // get remaining rewards from last cycle accRewardsPerShare = accRewardsPerShare + (_nextCycleStartTime - lastUpdateTime) * rewardAmountPerSecond * 1e16 / totalAllocation; lastUpdateTime = _nextCycleStartTime; rewardAmountPerSecond = rewardsInfo_.pendingAmount * rewardsInfo_.cycleRewardsPercent / 100 / cycleDurationSeconds; } // get pending rewards from current cycle if (!rewardsInfo_.distributionDisabled) { accRewardsPerShare = accRewardsPerShare + ((block.timestamp - lastUpdateTime) * rewardAmountPerSecond * 1e16 / totalAllocation); } return usersAllocation[userAddress] * accRewardsPerShare / 1e18 - users[token][userAddress].rewardDebt + users[token][userAddress].pendingRewards; } /** * PUBLIC FUNCTIONS */ /** * @dev Updates the current cycle start time if previous cycle has ended */ function updateCurrentCycleStartTime() public { uint256 nextCycleStartTime_ = nextCycleStartTime(); if (block.timestamp >= nextCycleStartTime_) { currentCycleStartTime = nextCycleStartTime_; } } /** * @dev Updates rewards info for a given token */ function updateRewardsInfo(address token) external validateDistributedToken(token) { _updateRewardsInfo(token); } /** * EXTERNAL PUBLIC FUNCTIONS */ /** * @dev Updates all rewardsInfo */ function massUpdateRewardsInfo() external { uint256 length = _distributedTokens.length(); for (uint256 index = 0; index < length; ++index) { _updateRewardsInfo(_distributedTokens.at(index)); } } /** * @dev Harvests caller's pending rewards of a given token */ function harvestRewards(address token) external nonReentrant { if (!_distributedTokens.contains(token)) { require(rewardsInfo[token].distributedAmount > 0, "harvestRewards: invalid token"); } _harvestRewards(token); } /** * @dev Harvests all caller's pending rewards */ function harvestAllRewards() external nonReentrant { uint256 length = _distributedTokens.length(); for (uint256 index = 0; index < length; ++index) { _harvestRewards(_distributedTokens.at(index)); } } /** * @dev Transfers the given amount of token from caller to pendingAmount * * Must only be called by a trustable address */ function addRewardsToPending(address token, uint256 amount) external override nonReentrant { uint256 prevTokenBalance = IERC20(token).balanceOf(address(this)); RewardsInfo storage rewardsInfo_ = rewardsInfo[token]; IERC20(token).safeTransferFrom(msg.sender, address(this), amount); // handle tokens with transfer tax uint256 receivedAmount = IERC20(token).balanceOf(address(this)) - prevTokenBalance; rewardsInfo_.pendingAmount = rewardsInfo_.pendingAmount + receivedAmount; emit RewardsAddedToPending(token, receivedAmount); } /** * @dev Emergency withdraw token's balance on the contract */ function emergencyWithdraw(IERC20 token) public nonReentrant onlyOwner { _emergencyWithdraw(token); } /** * @dev Emergency withdraw all reward tokens' balances on the contract */ function emergencyWithdrawAll() external nonReentrant onlyOwner { for (uint256 index = 0; index < _distributedTokens.length(); ++index) { _emergencyWithdraw(IERC20(_distributedTokens.at(index))); } } /** * OWNABLE FUNCTIONS */ /** * Allocates "userAddress" user's "amount" of bOOGA to this rewards contract * * Can only be called by bOOGAToken contract, which is trusted to verify amounts * "data" is only here for compatibility reasons (IBOogaTokenUsage) */ function allocate(address userAddress, uint256 amount, bytes calldata /*data*/ ) external override nonReentrant bOOGATokenOnly { uint256 newUserAllocation = usersAllocation[userAddress] + amount; uint256 newTotalAllocation = totalAllocation + amount; _updateUser(userAddress, newUserAllocation, newTotalAllocation); } /** * Deallocates "userAddress" user's "amount" of bOOGA allocation from this rewards contract * * Can only be called by bOOGAToken contract, which is trusted to verify amounts * "data" is only here for compatibility reasons (IBOogaTokenUsage) */ function deallocate(address userAddress, uint256 amount, bytes calldata /*data*/ ) external override nonReentrant bOOGATokenOnly { uint256 newUserAllocation = usersAllocation[userAddress] - amount; uint256 newTotalAllocation = totalAllocation - amount; _updateUser(userAddress, newUserAllocation, newTotalAllocation); } /** * @dev Enables a given token to be distributed as rewards * * Effective from the next cycle */ function enableDistributedToken(address token) external onlyOwner { RewardsInfo storage rewardsInfo_ = rewardsInfo[token]; require( rewardsInfo_.lastUpdateTime == 0 || rewardsInfo_.distributionDisabled, "enableDistributedToken: Already enabled rewards token" ); require( _distributedTokens.contains(token) || _distributedTokens.length() < MAX_DISTRIBUTED_TOKENS, "enableDistributedToken: too many distributedTokens" ); // initialize lastUpdateTime if never set before if (rewardsInfo_.lastUpdateTime == 0) { rewardsInfo_.lastUpdateTime = block.timestamp; } // initialize cycleRewardsPercent to the minimum if never set before if (rewardsInfo_.cycleRewardsPercent == 0) { rewardsInfo_.cycleRewardsPercent = DEFAULT_CYCLE_REWARDS_PERCENT; } rewardsInfo_.distributionDisabled = false; _distributedTokens.add(token); emit DistributedTokenEnabled(token); } /** * @dev Disables distribution of a given token as rewards * * Effective from the next cycle */ function disableDistributedToken(address token) external onlyOwner { RewardsInfo storage rewardsInfo_ = rewardsInfo[token]; require( rewardsInfo_.lastUpdateTime > 0 && !rewardsInfo_.distributionDisabled, "disableDistributedToken: Already disabled rewards token" ); rewardsInfo_.distributionDisabled = true; emit DistributedTokenDisabled(token); } /** * @dev Updates the percentage of pending rewards that will be distributed during the next cycle * * Must be a value between MIN_CYCLE_REWARDS_PERCENT and MAX_CYCLE_REWARDS_PERCENT */ function updateCycleRewardsPercent(address token, uint256 percent) external onlyOwner { require(percent <= MAX_CYCLE_REWARDS_PERCENT, "updateCycleRewardsPercent: percent mustn't exceed maximum"); require(percent >= MIN_CYCLE_REWARDS_PERCENT, "updateCycleRewardsPercent: percent mustn't exceed minimum"); RewardsInfo storage rewardsInfo_ = rewardsInfo[token]; uint256 previousPercent = rewardsInfo_.cycleRewardsPercent; rewardsInfo_.cycleRewardsPercent = percent; emit CycleRewardsPercentUpdated(token, previousPercent, rewardsInfo_.cycleRewardsPercent); } /** * @dev remove an address from _distributedTokens * * Can only be valid for a disabled rewards token and if the distribution has ended */ function removeTokenFromDistributedTokens(address tokenToRemove) external onlyOwner { RewardsInfo storage _rewardsInfo = rewardsInfo[tokenToRemove]; require( _rewardsInfo.distributionDisabled && _rewardsInfo.currentDistributionAmount == 0, "removeTokenFromDistributedTokens: cannot be removed" ); _distributedTokens.remove(tokenToRemove); emit DistributedTokenRemoved(tokenToRemove); } /** * @dev Emergency withdraw token's balance on the contract */ function _emergencyWithdraw(IERC20 token) internal { uint256 balance = token.balanceOf(address(this)); require(balance > 0, "emergencyWithdraw: token balance is null"); _safeTokenTransfer(token, msg.sender, balance); } /** * INTERNAL FUNCTIONS */ /** * @dev Returns the amount of rewards token distributed every second (times 1e2) */ function _rewardsAmountPerSecond(address token) internal view returns (uint256) { if (!_distributedTokens.contains(token)) return 0; return rewardsInfo[token].currentDistributionAmount * 1e2 / cycleDurationSeconds; } /** * @dev Updates every user's rewards allocation for each distributed token */ function _updateRewardsInfo(address token) internal { uint256 currentBlockTimestamp = block.timestamp; RewardsInfo storage rewardsInfo_ = rewardsInfo[token]; updateCurrentCycleStartTime(); uint256 lastUpdateTime = rewardsInfo_.lastUpdateTime; uint256 accRewardsPerShare = rewardsInfo_.accRewardsPerShare; if (currentBlockTimestamp <= lastUpdateTime) { return; } // if no bOOGA is allocated or initial distribution has not started yet if (totalAllocation == 0 || currentBlockTimestamp < currentCycleStartTime) { rewardsInfo_.lastUpdateTime = currentBlockTimestamp; return; } uint256 currentDistributionAmount = rewardsInfo_.currentDistributionAmount; // gas saving uint256 currentCycleDistributedAmount = rewardsInfo_.currentCycleDistributedAmount; // gas saving // check if the current cycle has changed since last update if (lastUpdateTime < currentCycleStartTime) { // update accRewardPerShare for the end of the previous cycle accRewardsPerShare = accRewardsPerShare + (currentDistributionAmount * 1e2 - currentCycleDistributedAmount) * 1e16 / totalAllocation; // check if distribution is enabled if (!rewardsInfo_.distributionDisabled) { // transfer the token's cycleRewardsPercent part from the pending slot to the distribution slot rewardsInfo_.distributedAmount = rewardsInfo_.distributedAmount + currentDistributionAmount; uint256 pendingAmount = rewardsInfo_.pendingAmount; currentDistributionAmount = pendingAmount * rewardsInfo_.cycleRewardsPercent / 10000; if (pendingAmount > 0 && currentDistributionAmount == 0) { rewardsInfo_.currentDistributionAmount = pendingAmount; rewardsInfo_.pendingAmount = 0; } else { rewardsInfo_.currentDistributionAmount = currentDistributionAmount; rewardsInfo_.pendingAmount = pendingAmount - currentDistributionAmount; } } else { // stop the token's distribution on next cycle rewardsInfo_.distributedAmount = rewardsInfo_.distributedAmount + currentDistributionAmount; currentDistributionAmount = 0; rewardsInfo_.currentDistributionAmount = 0; } currentCycleDistributedAmount = 0; lastUpdateTime = currentCycleStartTime; } uint256 toDistribute = (currentBlockTimestamp - lastUpdateTime) * _rewardsAmountPerSecond(token); // ensure that we can't distribute more than currentDistributionAmount (for instance w/ a > 24h service interruption) if (currentCycleDistributedAmount + toDistribute > currentDistributionAmount * 1e2) { toDistribute = currentDistributionAmount * 1e2 - currentCycleDistributedAmount; } rewardsInfo_.currentCycleDistributedAmount = currentCycleDistributedAmount + toDistribute; rewardsInfo_.accRewardsPerShare = accRewardsPerShare + toDistribute * 1e16 / totalAllocation; rewardsInfo_.lastUpdateTime = currentBlockTimestamp; } /** * Updates "userAddress" user's and total allocations for each distributed token */ function _updateUser(address userAddress, uint256 newUserAllocation, uint256 newTotalAllocation) internal { uint256 previousUserAllocation = usersAllocation[userAddress]; // for each distributedToken uint256 length = _distributedTokens.length(); for (uint256 index = 0; index < length; ++index) { address token = _distributedTokens.at(index); _updateRewardsInfo(token); UserInfo storage user = users[token][userAddress]; uint256 accRewardsPerShare = rewardsInfo[token].accRewardsPerShare; uint256 pending = previousUserAllocation * accRewardsPerShare / 1e18 - user.rewardDebt; user.pendingRewards = user.pendingRewards + pending; user.rewardDebt = newUserAllocation * accRewardsPerShare / 1e18; } usersAllocation[userAddress] = newUserAllocation; totalAllocation = newTotalAllocation; emit UserUpdated(userAddress, previousUserAllocation, newUserAllocation); } /** * @dev Harvests msg.sender's pending rewards of a given token */ function _harvestRewards(address token) internal { _updateRewardsInfo(token); UserInfo storage user = users[token][msg.sender]; uint256 accRewardsPerShare = rewardsInfo[token].accRewardsPerShare; uint256 userBOOGAAllocation = usersAllocation[msg.sender]; uint256 newRewardDebt = userBOOGAAllocation * accRewardsPerShare / 1e18; uint256 pending = user.pendingRewards + newRewardDebt - user.rewardDebt; user.pendingRewards = 0; user.rewardDebt = newRewardDebt; _safeTokenTransfer(IERC20(token), msg.sender, pending); emit RewardsCollected(msg.sender, token, pending); } /** * @dev Safe token transfer function, in case rounding error causes pool to not have enough tokens */ function _safeTokenTransfer(IERC20 token, address to, uint256 amount) internal { if (amount > 0) { uint256 tokenBal = token.balanceOf(address(this)); if (amount > tokenBal) { token.safeTransfer(to, tokenBal); } else { token.safeTransfer(to, amount); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^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() { _transferOwnership(_msgSender()); } /** * @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 { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @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 { require(newOwner != address(0), "Ownable: new owner is the zero address"); _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); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // 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`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _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; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT pragma solidity >= 0.8.20; interface IOogaRewards { function distributedTokensLength() external view returns (uint256); function distributedToken(uint256 index) external view returns (address); function isDistributedToken(address token) external view returns (bool); function addRewardsToPending(address token, uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity >= 0.8.20; interface IBOogaTokenUsage { function allocate(address userAddress, uint256 amount, bytes calldata data) external; function deallocate(address userAddress, uint256 amount, bytes calldata data) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol) pragma solidity ^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 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; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @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); /** * @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 `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
{ "remappings": [ "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "openzeppelin/=lib/openzeppelin-contracts/contracts/", "solmate/=lib/solmate/src/" ], "optimizer": { "enabled": false, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "shanghai", "viaIR": true, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"bOogaToken_","type":"address"},{"internalType":"uint256","name":"startTime_","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"CycleRewardsPercentUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"DistributedTokenDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"DistributedTokenEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"DistributedTokenRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardsAddedToPending","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardsCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBalance","type":"uint256"}],"name":"UserUpdated","type":"event"},{"inputs":[],"name":"DEFAULT_CYCLE_REWARDS_PERCENT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_CYCLE_REWARDS_PERCENT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_DISTRIBUTED_TOKENS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_CYCLE_REWARDS_PERCENT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"addRewardsToPending","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"allocate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bOogaToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentCycleStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cycleDurationSeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"deallocate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"disableDistributedToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"distributedToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"distributedTokensLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyWithdrawAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"enableDistributedToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"harvestAllRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"harvestRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"isDistributedToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"massUpdateRewardsInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nextCycleStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"userAddress","type":"address"}],"name":"pendingRewardsAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenToRemove","type":"address"}],"name":"removeTokenFromDistributedTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardsInfo","outputs":[{"internalType":"uint256","name":"currentDistributionAmount","type":"uint256"},{"internalType":"uint256","name":"currentCycleDistributedAmount","type":"uint256"},{"internalType":"uint256","name":"pendingAmount","type":"uint256"},{"internalType":"uint256","name":"distributedAmount","type":"uint256"},{"internalType":"uint256","name":"accRewardsPerShare","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTime","type":"uint256"},{"internalType":"uint256","name":"cycleRewardsPercent","type":"uint256"},{"internalType":"bool","name":"distributionDisabled","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAllocation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateCurrentCycleStartTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"percent","type":"uint256"}],"name":"updateCycleRewardsPercent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"updateRewardsInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"users","outputs":[{"internalType":"uint256","name":"pendingRewards","type":"uint256"},{"internalType":"uint256","name":"rewardDebt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"usersAllocation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60a0604052346200004f576200001f6200001862000164565b90620002bf565b6200002962000055565b613ea4620004cc823960805181818161025001528181611c030152611cbd0152613ea490f35b6200005b565b60405190565b5f80fd5b601f801991011690565b634e487b7160e01b5f52604160045260245ffd5b9062000089906200005f565b810190811060018060401b03821117620000a257604052565b62000069565b90620000bf620000b762000055565b92836200007d565b565b5f80fd5b60018060a01b031690565b620000db90620000c5565b90565b620000e981620000d0565b03620000f157565b5f80fd5b905051906200010482620000de565b565b90565b620001148162000106565b036200011c57565b5f80fd5b905051906200012f8262000109565b565b91906040838203126200015e5780620001516200015b925f8601620000f5565b9360200162000120565b90565b620000c1565b6200018762004370803803806200017b81620000a8565b92833981019062000131565b9091565b90565b90565b620001aa620001a4620001b0926200018b565b6200018e565b620000c5565b90565b620001be9062000191565b90565b60209181520190565b5f7f7a65726f20616464726573730000000000000000000000000000000000000000910152565b62000200600c602092620001c1565b6200020b81620001ca565b0190565b620002269060208101905f818303910152620001f1565b90565b156200023157565b6200023b62000055565b62461bcd60e51b81528062000253600482016200020f565b0390fd5b5f1b90565b906200026a5f199162000257565b9181191691161790565b6200028d62000287620002939262000106565b6200018e565b62000106565b90565b90565b90620002b3620002ad620002bb9262000274565b62000296565b82546200025c565b9055565b906200030791620002cf62000309565b620002fc81620002f4620002ed620002e75f620001b3565b620000d0565b91620000d0565b141562000229565b608052600862000299565b565b6200031362000315565b565b6200031f62000355565b565b90565b6200033d62000337620003439262000321565b6200018e565b62000106565b90565b62000352600162000324565b90565b6200035f62000377565b620003756200036d62000346565b600162000299565b565b6200038b62000385620004bc565b6200044d565b565b5f1c90565b60018060a01b031690565b620003ac620003b2916200038d565b62000392565b90565b620003c190546200039d565b90565b90620003d760018060a01b039162000257565b9181191691161790565b620003fa620003f46200040092620000c5565b6200018e565b620000c5565b90565b6200040e90620003e1565b90565b6200041c9062000403565b90565b90565b906200043c62000436620004449262000411565b6200041f565b8254620003c4565b9055565b5f0190565b620004585f620003b5565b62000464825f62000422565b906200049c620004957f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09362000411565b9162000411565b91620004a762000055565b80620004b38162000448565b0390a3565b5f90565b620004c6620004b8565b50339056fe60806040526004361015610013575b610f08565b61001d5f3561022b565b80623ad45014610226578063034d7fcb146102215780631c75e3691461021c578063515ce51714610217578063549230c9146102125780635726d26e1461020d5780635d9b436a146102085780635e80536a146102035780636138a606146101fe5780636ff1c9bc146101f9578063715018a6146101f457806379203dc4146101ef578063799fb965146101ea5780638ca8fef9146101e55780638da5cb5b146101e05780638e464baa146101db57806393c563af146101d6578063bd394a8d146101d1578063c4d3e083146101cc578063ca250022146101c7578063cc2dae83146101c2578063d2af0b94146101bd578063d637ff83146101b8578063dd191719146101b3578063ddd48f47146101ae578063de9d477e146101a9578063e0c1b6bb146101a4578063e4c26d961461019f578063e895cca31461019a578063eb013a2014610195578063f2bfbcc414610190578063f2fde38b1461018b5763fc56a8130361000e57610ec9565b610d6d565b610d38565b610ccb565b610c98565b610c65565b610c30565b610be4565b610baf565b610b43565b610b0e565b610ad9565b610a6e565b610a3b565b610a06565b6109a2565b61096f565b61093a565b6108cd565b610899565b610837565b6107f3565b610772565b61073f565b6106bf565b610688565b61053b565b6104ea565b6104b3565b610480565b610449565b61034c565b6102ab565b60e01c90565b60405190565b5f80fd5b5f80fd5b5f91031261024957565b61023b565b7f000000000000000000000000000000000000000000000000000000000000000090565b60018060a01b031690565b61028690610272565b90565b6102929061027d565b9052565b91906102a9905f60208501940190610289565b565b346102db576102bb36600461023f565b6102d76102c661024e565b6102ce610231565b91829182610296565b0390f35b610237565b5f80fd5b6102ed8161027d565b036102f457565b5f80fd5b90503590610305826102e4565b565b906020828203126103205761031d915f016102f8565b90565b61023b565b151590565b61033390610325565b9052565b919061034a905f6020850194019061032a565b565b3461037c57610378610367610362366004610307565b611050565b61036f610231565b91829182610337565b0390f35b610237565b90565b61038d81610381565b0361039457565b5f80fd5b905035906103a582610384565b565b5f80fd5b5f80fd5b5f80fd5b909182601f830112156103ed5781359167ffffffffffffffff83116103e85760200192600183028401116103e357565b6103af565b6103ab565b6103a7565b9160608383031261043f57610409825f85016102f8565b926104178360208301610398565b92604082013567ffffffffffffffff811161043a5761043692016103b3565b9091565b6102e0565b61023b565b5f0190565b3461047b5761046561045c3660046103f2565b92919091611c7e565b61046d610231565b8061047781610444565b0390f35b610237565b346104ae57610498610493366004610307565b611712565b6104a0610231565b806104aa81610444565b0390f35b610237565b346104e5576104cf6104c63660046103f2565b92919091611d38565b6104d7610231565b806104e181610444565b0390f35b610237565b34610518576104fa36600461023f565b610502611478565b61050a610231565b8061051481610444565b0390f35b610237565b9060208282031261053657610533915f01610398565b90565b61023b565b3461056b5761056761055661055136600461051d565b611038565b61055e610231565b91829182610296565b0390f35b610237565b9190604083820312610598578061058c610595925f86016102f8565b936020016102f8565b90565b61023b565b90565b6105b46105af6105b992610272565b61059d565b610272565b90565b6105c5906105a0565b90565b6105d1906105bc565b90565b906105de906105c8565b5f5260205260405f2090565b906105f4906105c8565b5f5260205260405f2090565b5f1c90565b90565b61061461061991610600565b610605565b90565b6106269054610608565b90565b9061063861063d9260056105d4565b6105ea565b90610655600161064e5f850161061c565b930161061c565b90565b61066190610381565b9052565b91602061068692949361067f60408201965f830190610658565b0190610658565b565b346106ba576106a161069b366004610570565b90610629565b906106b66106ad610231565b92839283610665565b0390f35b610237565b346106ed576106d76106d2366004610307565b611587565b6106df610231565b806106e981610444565b0390f35b610237565b6106fb9061027d565b90565b610707816106f2565b0361070e57565b5f80fd5b9050359061071f826106fe565b565b9060208282031261073a57610737915f01610712565b90565b61023b565b3461076d57610757610752366004610721565b611a80565b61075f610231565b8061076981610444565b0390f35b610237565b346107a05761078236600461023f565b61078a613014565b610792610231565b8061079c81610444565b0390f35b610237565b1c90565b6107b99060086107be93026107a5565b610605565b90565b906107cc91546107a9565b90565b6107db60075f906107c1565b90565b91906107f1905f60208501940190610658565b565b346108235761080336600461023f565b61081f61080e6107cf565b610816610231565b918291826107de565b0390f35b610237565b61083460085f906107c1565b90565b346108675761084736600461023f565b610863610852610828565b61085a610231565b918291826107de565b0390f35b610237565b91906040838203126108945780610888610891925f86016102f8565b93602001610398565b90565b61023b565b346108c8576108b26108ac36600461086c565b90612427565b6108ba610231565b806108c481610444565b0390f35b610237565b346108fd576108dd36600461023f565b6108f96108e8612f05565b6108f0610231565b91829182610296565b0390f35b610237565b90565b61091961091461091e92610902565b61059d565b610381565b90565b61092c612710610905565b90565b610937610921565b90565b3461096a5761094a36600461023f565b61096661095561092f565b61095d610231565b918291826107de565b0390f35b610237565b3461099d57610987610982366004610307565b61207a565b61098f610231565b8061099981610444565b0390f35b610237565b346109d2576109b236600461023f565b6109ce6109bd610f13565b6109c5610231565b918291826107de565b0390f35b610237565b906109e1906105c8565b5f5260205260405f2090565b610a03906109fe6006915f926109d7565b6107c1565b90565b34610a3657610a32610a21610a1c366004610307565b6109ed565b610a29610231565b918291826107de565b0390f35b610237565b34610a6957610a4b36600461023f565b610a536115ae565b610a5b610231565b80610a6581610444565b0390f35b610237565b34610a9d57610a87610a8136600461086c565b90611a3b565b610a8f610231565b80610a9981610444565b0390f35b610237565b90565b610ab9610ab4610abe92610aa2565b61059d565b610381565b90565b610acb6005610aa5565b90565b610ad6610ac1565b90565b34610b0957610ae936600461023f565b610b05610af4610ace565b610afc610231565b918291826107de565b0390f35b610237565b34610b3e57610b1e36600461023f565b610b3a610b296110a8565b610b31610231565b918291826107de565b0390f35b610237565b34610b7157610b5336600461023f565b610b5b611b20565b610b63610231565b80610b6d81610444565b0390f35b610237565b90565b610b8d610b88610b9292610b76565b61059d565b610381565b90565b610ba16203f480610b79565b90565b610bac610b95565b90565b34610bdf57610bbf36600461023f565b610bdb610bca610ba4565b610bd2610231565b918291826107de565b0390f35b610237565b34610c1257610bfc610bf7366004610307565b61259a565b610c04610231565b80610c0e81610444565b0390f35b610237565b610c22612710610905565b90565b610c2d610c17565b90565b34610c6057610c4036600461023f565b610c5c610c4b610c25565b610c53610231565b918291826107de565b0390f35b610237565b34610c9357610c7536600461023f565b610c7d61179a565b610c85610231565b80610c8f81610444565b0390f35b610237565b34610cc657610cb0610cab366004610307565b6121f2565b610cb8610231565b80610cc281610444565b0390f35b610237565b34610cfc57610cf8610ce7610ce1366004610570565b906111de565b610cef610231565b918291826107de565b0390f35b610237565b90565b610d18610d13610d1d92610d01565b61059d565b610381565b90565b610d2a6001610d04565b90565b610d35610d20565b90565b34610d6857610d4836600461023f565b610d64610d53610d2d565b610d5b610231565b918291826107de565b0390f35b610237565b34610d9b57610d85610d80366004610307565b613109565b610d8d610231565b80610d9781610444565b0390f35b610237565b90610daa906105c8565b5f5260205260405f2090565b60ff1690565b610dc8610dcd91610600565b610db6565b90565b610dda9054610dbc565b90565b610de8906004610da0565b90610df45f830161061c565b91610e016001820161061c565b91610e0e6002830161061c565b91610e1b6003820161061c565b91610e286004830161061c565b91610e356005820161061c565b91610e4e6007610e476006850161061c565b9301610dd0565b90565b959391989796949290986101008701995f8801610e6d91610658565b60208701610e7a91610658565b60408601610e8791610658565b60608501610e9491610658565b60808401610ea191610658565b60a08301610eae91610658565b60c08201610ebb91610658565b60e001610ec79161032a565b565b34610f0357610eff610ee4610edf366004610307565b610ddd565b94610ef6989698949194939293610231565b98899889610e51565b0390f35b610237565b5f80fd5b5f90565b90565b610f1b610f0c565b50610f2e610f296002610f10565b613daf565b90565b5f90565b60209181520190565b60207f696e646578206578697374733f00000000000000000000000000000000000000917f76616c69646174654469737472696275746564546f6b656e73496e6465783a205f8201520152565b610f98602d604092610f35565b610fa181610f3e565b0190565b610fba9060208101905f818303910152610f8b565b90565b15610fc457565b610fcc610231565b62461bcd60e51b815280610fe260048201610fa5565b0390fd5b9061101d916110188261101261100c6110076110026002610f10565b613daf565b610381565b91610381565b10610fbd565b611020565b90565b9061103591506110306002610f10565b613e15565b90565b61104990611044610f31565b610fe6565b90565b5f90565b61106c9061105c61104c565b506110676002610f10565b613d75565b90565b634e487b7160e01b5f52601160045260245ffd5b61109261109891939293610381565b92610381565b82018092116110a357565b61106f565b6110b0610f0c565b506110cc6110be600861061c565b6110c6610b95565b90611083565b90565b90565b6110e66110e16110eb926110cf565b61059d565b610381565b90565b90565b61110061110691939293610381565b92610381565b820391821161111157565b61106f565b61112561112b91939293610381565b92610381565b91611137838202610381565b92818404149015171561114657565b61106f565b90565b61116261115d6111679261114b565b61059d565b610381565b90565b634e487b7160e01b5f52601260045260245ffd5b61118a61119091610381565b91610381565b90811561119b570490565b61116a565b90565b6111b76111b26111bc926111a0565b61059d565b610381565b90565b90565b6111d66111d16111db926111bf565b61059d565b610381565b90565b6111e6610f0c565b506111f1600761061c565b6112036111fd5f6110d2565b91610381565b146113fd576112ff5f6112f9611305946112f46112ec6112c56112ae61123361122e60048b90610da0565b6110ee565b61123f6004820161061c565b9061124c6005820161061c565b906112568c6126ff565b9061125f6110a8565b4261127261126c83610381565b91610381565b11611358575b50611288600761128e9201610dd0565b15610325565b611308575b50506112a96112a4600688906109d7565b61061c565b611116565b6112bf670de0b6b3a76400006111c2565b9061117e565b6112e660016112e06112d960058c906105d4565b87906105ea565b0161061c565b906110f1565b9560056105d4565b6105ea565b0161061c565b90611083565b90565b61133b61132561134b926113206113519695426110f1565b611116565b611335662386f26fc1000061114e565b90611116565b611345600761061c565b9061117e565b90611083565b5f80611293565b9361138f6113796113a59461137461139f9497959795896110f1565b611116565b611389662386f26fc1000061114e565b90611116565b611399600761061c565b9061117e565b90611083565b919061128e61128860076113f46113e66113d66113c46002880161061c565b6113d06006890161061c565b90611116565b6113e060646111a3565b9061117e565b6113ee610b95565b9061117e565b93925050611278565b61141561141b926114105f9360056105d4565b6105ea565b0161061c565b90565b5f1b90565b9061142f5f199161141e565b9181191691161790565b61144d61144861145292610381565b61059d565b610381565b90565b90565b9061146d61146861147492611439565b611455565b8254611423565b9055565b6114806110a8565b4261149361148d83610381565b91610381565b101561149d575b50565b6114a8906008611458565b5f61149a565b60207f20646f6573206e6f742065786973747300000000000000000000000000000000917f76616c69646174654469737472696275746564546f6b656e733a20746f6b656e5f8201520152565b6115086030604092610f35565b611511816114ae565b0190565b61152a9060208101905f8183039101526114fb565b90565b1561153457565b61153c610231565b62461bcd60e51b81528061155260048201611515565b0390fd5b61157a906115756115708261156b6002610f10565b613d75565b61152d565b61157c565b565b61158590612772565b565b61159090611556565b565b61159b90610381565b5f1981146115a95760010190565b61106f565b6115c06115bb6002610f10565b613daf565b6115c95f6110d2565b5b806115dd6115d784610381565b91610381565b101561160d57611608906116036115fe6115f76002610f10565b8390613e15565b612772565b611592565b6115ca565b5050565b6116229061161d61325f565b6116ae565b61162a6132ad565b565b5f7f68617276657374526577617264733a20696e76616c696420746f6b656e000000910152565b611660601d602092610f35565b6116698161162c565b0190565b6116829060208101905f818303910152611653565b90565b1561168c57565b611694610231565b62461bcd60e51b8152806116aa6004820161166d565b0390fd5b6116d9906116cf6116c96116c26002610f10565b8390613d75565b15610325565b6116db575b612ccd565b565b61170d6116f560036116ef60048590610da0565b0161061c565b6117076117015f6110d2565b91610381565b11611685565b6116d4565b61171b90611611565b565b61172561325f565b61172d611737565b6117356132ad565b565b6117496117446002610f10565b613daf565b6117525f6110d2565b5b8061176661176084610381565b91610381565b1015611796576117919061178c6117876117806002610f10565b8390613e15565b612ccd565b611592565b611753565b5050565b6117a261171d565b565b906117b6916117b161325f565b61187a565b6117be6132ad565b565b6117c9906105a0565b90565b6117d5906117c0565b90565b6117e1906105bc565b90565b6117ed906105bc565b90565b601f801991011690565b634e487b7160e01b5f52604160045260245ffd5b90611818906117f0565b810190811067ffffffffffffffff82111761183257604052565b6117fa565b60e01b90565b9050519061184a82610384565b565b9060208282031261186557611862915f0161183d565b90565b61023b565b611872610231565b3d5f823e3d90fd5b6118c2602061189061188b846117cc565b6117d8565b6370a08231906118b76118a2306117e4565b926118ab610231565b95869485938493611837565b835260048301610296565b03915afa908115611a36575f91611a08575b506119086118ec6118e760048590610da0565b6110ee565b936118f6846117cc565b9033611901306117e4565b9192613392565b611950602061191e611919856117cc565b6117d8565b6370a0823190611945611930306117e4565b92611939610231565b95869485938493611837565b835260048301610296565b03915afa8015611a035761198f92611970925f926119d3575b50906110f1565b92600261198861198182840161061c565b8690611083565b9101611458565b6119ce6119bc7f6be8535fae97a5677bece5c298a5838092d0e8c92b11a3e81e10449194219bbf926105c8565b926119c5610231565b918291826107de565b0390a2565b6119f591925060203d81116119fc575b6119ed818361180e565b81019061184c565b905f611969565b503d6119e3565b61186a565b611a29915060203d8111611a2f575b611a21818361180e565b81019061184c565b5f6118d4565b503d611a17565b61186a565b90611a45916117a4565b565b611a5890611a5361325f565b611a62565b611a606132ad565b565b611a7390611a6e612f9b565b611a75565b565b611a7e9061264d565b565b611a8990611a47565b565b611a9361325f565b611a9b611aa5565b611aa36132ad565b565b611aad612f9b565b611ab5611ab7565b565b611ac05f6110d2565b5b80611ae5611adf611ada611ad56002610f10565b613daf565b610381565b91610381565b1015611b1d57611b1890611b13611b0e611b09611b026002610f10565b8490613e15565b6117cc565b61264d565b611592565b611ac1565b50565b611b28611a8b565b565b90611b3e939291611b3961325f565b611bf0565b611b466132ad565b565b60207f20624f6f6761546f6b656e000000000000000000000000000000000000000000917f624f4f4741546f6b656e4f6e6c793a2063616c6c65722073686f756c642062655f8201520152565b611ba2602b604092610f35565b611bab81611b48565b0190565b611bc49060208101905f818303910152611b95565b90565b15611bce57565b611bd6610231565b62461bcd60e51b815280611bec60048201611baf565b0390fd5b90611c38939291611c3333611c2d611c277f000000000000000000000000000000000000000000000000000000000000000061027d565b9161027d565b14611bc7565b611c3a565b565b909150611c7c9250611c73611c63611c5c611c57600685906109d7565b61061c565b8490611083565b92611c6e600761061c565b611083565b90919091612b1b565b565b90611c8a939291611b2a565b565b90611ca0939291611c9b61325f565b611caa565b611ca86132ad565b565b90611cf2939291611ced33611ce7611ce17f000000000000000000000000000000000000000000000000000000000000000061027d565b9161027d565b14611bc7565b611cf4565b565b909150611d369250611d2d611d1d611d16611d11600685906109d7565b61061c565b84906110f1565b92611d28600761061c565b6110f1565b90919091612b1b565b565b90611d44939291611c8c565b565b611d5790611d52612f9b565b611eee565b565b60207f656e61626c6564207265776172647320746f6b656e0000000000000000000000917f656e61626c654469737472696275746564546f6b656e3a20416c7265616479205f8201520152565b611db36035604092610f35565b611dbc81611d59565b0190565b611dd59060208101905f818303910152611da6565b90565b15611ddf57565b611de7610231565b62461bcd60e51b815280611dfd60048201611dc0565b0390fd5b60207f206469737472696275746564546f6b656e730000000000000000000000000000917f656e61626c654469737472696275746564546f6b656e3a20746f6f206d616e795f8201520152565b611e5b6032604092610f35565b611e6481611e01565b0190565b611e7d9060208101905f818303910152611e4e565b90565b15611e8757565b611e8f610231565b62461bcd60e51b815280611ea560048201611e68565b0390fd5b90611eb560ff9161141e565b9181191691161790565b611ec890610325565b90565b90565b90611ee3611ede611eea92611ebf565b611ecb565b8254611ea9565b9055565b611faa611f05611f0060048490610da0565b6110ee565b611f116005820161061c565b611f23611f1d5f6110d2565b91610381565b148015612063575b611f3490611dd8565b611f48611f416002610f10565b8490613d75565b801561202c575b611f5890611e80565b611f646005820161061c565b611f76611f705f6110d2565b91610381565b1461201a575b611f886006820161061c565b611f9a611f945f6110d2565b91610381565b14612001575b60075f9101611ece565b611fbe611fb76002610f10565b829061397a565b50611fe97fefa645a0ab6703d2f2e7f177f50d16c90ce1c71e317bb91cbbdab430e0a39682916105c8565b90611ff2610231565b80611ffc81610444565b0390a2565b61201561200c610c17565b60068301611458565b611fa0565b6120274260058301611458565b611f7c565b50611f5861204261203d6002610f10565b613daf565b61205b612055612050610ac1565b610381565b91610381565b109050611f4f565b50611f3461207360078301610dd0565b9050611f2b565b61208390611d46565b565b61209690612091612f9b565b612140565b565b60207f2064697361626c6564207265776172647320746f6b656e000000000000000000917f64697361626c654469737472696275746564546f6b656e3a20416c72656164795f8201520152565b6120f26037604092610f35565b6120fb81612098565b0190565b6121149060208101905f8183039101526120e5565b90565b1561211e57565b612126610231565b62461bcd60e51b81528061213c600482016120ff565b0390fd5b61219061215761215260048490610da0565b6110ee565b6121636005820161061c565b61217561216f5f6110d2565b91610381565b11806121d2575b61218590612117565b600760019101611ece565b6121ba7f961f10509197d967c55f8720c2b6a80d48433ef36db1b12cf3bf6bcf66da4346916105c8565b906121c3610231565b806121cd81610444565b0390a2565b506121856121eb6121e560078401610dd0565b15610325565b905061217c565b6121fb90612085565b565b9061220f9161220a612f9b565b612361565b565b60207f6e74206d7573746e277420657863656564206d6178696d756d00000000000000917f7570646174654379636c655265776172647350657263656e743a2070657263655f8201520152565b61226b6039604092610f35565b61227481612211565b0190565b61228d9060208101905f81830391015261225e565b90565b1561229757565b61229f610231565b62461bcd60e51b8152806122b560048201612278565b0390fd5b60207f6e74206d7573746e277420657863656564206d696e696d756d00000000000000917f7570646174654379636c655265776172647350657263656e743a2070657263655f8201520152565b6123136039604092610f35565b61231c816122b9565b0190565b6123359060208101905f818303910152612306565b90565b1561233f57565b612347610231565b62461bcd60e51b81528061235d60048201612320565b0390fd5b906123868161237f612379612374610921565b610381565b91610381565b1115612290565b6123aa816123a361239d612398610d20565b610381565b91610381565b1015612338565b6123e360066123c36123be60048690610da0565b6110ee565b936123db6123d283870161061c565b94838701611458565b92930161061c565b61240d7f0d8168d755f5c8a7e102241b41e7561ab7536fba6348dc00388334d62d26878e926105c8565b92612422612419610231565b92839283610665565b0390a2565b90612431916121fd565b565b6124449061243f612f9b565b6124ee565b565b60207f3a2063616e6e6f742062652072656d6f76656400000000000000000000000000917f72656d6f7665546f6b656e46726f6d4469737472696275746564546f6b656e735f8201520152565b6124a06033604092610f35565b6124a981612446565b0190565b6124c29060208101905f818303910152612493565b90565b156124cc57565b6124d4610231565b62461bcd60e51b8152806124ea600482016124ad565b0390fd5b61251e61250561250060048490610da0565b6110ee565b61251160078201610dd0565b9081612575575b506124c5565b61253261252b6002610f10565b8290613b4a565b5061255d7f17cd3cc84c669de8c5c4218fd1d9814e647b547d1e7f59287ea6989aa4e032c2916105c8565b90612566610231565b8061257081610444565b0390a2565b61258191505f0161061c565b61259361258d5f6110d2565b91610381565b145f612518565b6125a390612433565b565b60207f206973206e756c6c000000000000000000000000000000000000000000000000917f656d657267656e637957697468647261773a20746f6b656e2062616c616e63655f8201520152565b6125ff6028604092610f35565b612608816125a5565b0190565b6126219060208101905f8183039101526125f2565b90565b1561262b57565b612633610231565b62461bcd60e51b8152806126496004820161260c565b0390fd5b61268e90602061265c826117d8565b6370a082319061268361266e306117e4565b92612677610231565b96879485938493611837565b835260048301610296565b03915afa80156126fa576126ca925f916126cc575b50906126c1826126bb6126b55f6110d2565b91610381565b11612624565b90339091612df0565b565b6126ed915060203d81116126f3575b6126e5818361180e565b81019061184c565b5f6126a3565b503d6126db565b61186a565b612707610f0c565b5061272561271f6127186002610f10565b8390613d75565b15610325565b612765576127546127445f61273e612762946004610da0565b0161061c565b61274e60646111a3565b90611116565b61275c610b95565b9061117e565b90565b5061276f5f6110d2565b90565b429061278861278360048390610da0565b6110ee565b90612791611478565b61279d6005830161061c565b6127a96004840161061c565b90846127bd6127b783610381565b91610381565b1115612b11576127cd600761061c565b6127df6127d95f6110d2565b91610381565b148015612aee575b612adc576128d56005936128e596936128de936128055f890161061c565b9261281260018a0161061c565b918061282f612829612824600861061c565b610381565b91610381565b10612920575b9061284c612846612852938a6110f1565b916126ff565b90611116565b9261285e828590611083565b61288361287d6128788461287260646111a3565b90611116565b610381565b91610381565b116128e7575b506128cf916128a861289f6128bf938690611083565b60018b01611458565b926128b9662386f26fc1000061114e565b90611116565b6128c9600761061c565b9061117e565b90611083565b60048501611458565b9101611458565b565b6128bf919350916128a861289f61291561290e6128cf9661290860646111a3565b90611116565b87906110f1565b959350505091612889565b5092919061297161296161294b61297794936129468761294060646111a3565b90611116565b6110f1565b61295b662386f26fc1000061114e565b90611116565b61296b600761061c565b9061117e565b90611083565b9061298d61298760078a01610dd0565b15610325565b5f14612a98576129ab6129b4916129a660038b0161061c565b611083565b60038901611458565b6129c06002880161061c565b916129eb6129da846129d460068c0161061c565b90611116565b6129e5612710610905565b9061117e565b92806129ff6129f95f6110d2565b91610381565b1180612a7e575b5f14612a5657612a18905f8a01611458565b612a2d612a245f6110d2565b60028a01611458565b5b5b612852612a3b5f6110d2565b9161284c612846612a4c600861061c565b9293505050612835565b612a70612a7991612a69865f8d01611458565b85906110f1565b60028a01611458565b612a2e565b5083612a92612a8c5f6110d2565b91610381565b14612a06565b612ab0612ab991612aab60038b0161061c565b611083565b60038901611458565b612ac25f6110d2565b91612ad7612acf5f6110d2565b5f8a01611458565b612a2f565b5050506005612aec929101611458565b565b5084612b0b612b05612b00600861061c565b610381565b91610381565b106127e7565b5050505050565b90565b919290612b32612b2d600685906109d7565b61061c565b91612b45612b406002610f10565b613daf565b94612b4f5f6110d2565b5b80612b63612b5d89610381565b91610381565b1015612c61576002612b7490610f10565b81612b7e91613e15565b80612b8890612772565b600581612b94916105d4565b87612b9e916105ea565b612ba790612b18565b90600490612bb491610da0565b600401612bc09061061c565b8681612bcb91611116565b670de0b6b3a7640000612bdd906111c2565b612be69161117e565b82600101612bf39061061c565b612bfc916110f1565b825f01612c089061061c565b90612c1291611083565b825f0190612c1f91611458565b8590612c2a91611116565b670de0b6b3a7640000612c3c906111c2565b612c459161117e565b9060010190612c5391611458565b612c5c90611592565b612b50565b50612c87919550939193612c8085612c7b600686906109d7565b611458565b6007611458565b9091612cb37f97ce9d7086176d6da45e4e7999788176e2629a7591ffe505b0c1b13fe8052cc6926105c8565b92612cc8612cbf610231565b92839283610665565b0390a2565b612cd681612772565b612cf4612cef612ce8600584906105d4565b33906105ea565b612b18565b612d8b612d43612d2c612d136004612d0d818890610da0565b0161061c565b612d27612d22600633906109d7565b61061c565b611116565b612d3d670de0b6b3a76400006111c2565b9061117e565b916001612d6f612d5e612d575f850161061c565b8690611083565b612d6983850161061c565b906110f1565b93612d84612d7c5f6110d2565b5f8501611458565b9101611458565b612d9f612d97836117cc565b338391612df0565b33919091612deb612dd9612dd37f5cbc2d25e94cfcae49c20ef253b5bdba9c8fba9e437f0423f0ac464d4897d645936105c8565b936105c8565b93612de2610231565b918291826107de565b0390a3565b9180612e04612dfe5f6110d2565b91610381565b11612e0f575b505050565b612e4f6020612e1d856117d8565b6370a0823190612e44612e2f306117e4565b92612e38610231565b95869485938493611837565b835260048301610296565b03915afa908115612ed4575f91612ea6575b509080612e76612e7084610381565b91610381565b115f14612e935750612e8a92919091613315565b5b5f8080612e0a565b9050612ea192919091613315565b612e8b565b612ec7915060203d8111612ecd575b612ebf818361180e565b81019061184c565b5f612e61565b503d612eb5565b61186a565b60018060a01b031690565b612ef0612ef591610600565b612ed9565b90565b612f029054612ee4565b90565b612f0d610f31565b50612f175f612ef8565b90565b5f7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572910152565b612f4d60208092610f35565b612f5681612f1a565b0190565b612f6f9060208101905f818303910152612f41565b90565b15612f7957565b612f81610231565b62461bcd60e51b815280612f9760048201612f5a565b0390fd5b612fc5612fa6612f05565b612fbf612fb9612fb4613923565b61027d565b9161027d565b14612f72565b565b612fcf612f9b565b612fd7613001565b565b612fed612fe8612ff2926110cf565b61059d565b610272565b90565b612ffe90612fd9565b90565b61301261300d5f612ff5565b613152565b565b61301c612fc7565b565b61302f9061302a612f9b565b6130d9565b565b60207f6464726573730000000000000000000000000000000000000000000000000000917f4f776e61626c653a206e6577206f776e657220697320746865207a65726f20615f8201520152565b61308b6026604092610f35565b61309481613031565b0190565b6130ad9060208101905f81830391015261307e565b90565b156130b757565b6130bf610231565b62461bcd60e51b8152806130d560048201613098565b0390fd5b61310790613102816130fb6130f56130f05f612ff5565b61027d565b9161027d565b14156130b0565b613152565b565b6131129061301e565b565b9061312560018060a01b039161141e565b9181191691161790565b90565b9061314761314261314e926105c8565b61312f565b8254613114565b9055565b61315b5f612ef8565b613165825f613132565b906131996131937f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0936105c8565b916105c8565b916131a2610231565b806131ac81610444565b0390a3565b90565b6131c86131c36131cd926131b1565b61059d565b610381565b90565b6131da60026131b4565b90565b5f7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00910152565b613211601f602092610f35565b61321a816131dd565b0190565b6132339060208101905f818303910152613204565b90565b1561323d57565b613245610231565b62461bcd60e51b81528061325b6004820161321e565b0390fd5b61328c61326c600161061c565b61328561327f61327a6131d0565b610381565b91610381565b1415613236565b61329e6132976131d0565b6001611458565b565b6132aa6001610d04565b90565b6132bf6132b86132a0565b6001611458565b565b63ffffffff1690565b63ffffffff60e01b1690565b6132ea6132e56132ef926132c1565b611837565b6132ca565b90565b91602061331392949361330c60408201965f830190610289565b0190610658565b565b9161335960049261334a61335e959361333163a9059cbb6132d6565b9261333a610231565b96879460208601908152016132f2565b6020820181038252038361180e565b613568565b565b604090613389613390949695939661337f60608401985f850190610289565b6020830190610289565b0190610658565b565b6133df93916133cb6004946133da93946133af6323b872dd6132d6565b939190916133bb610231565b9788956020870190815201613360565b6020820181038252038361180e565b613568565b565b906133f46133ed610231565b928361180e565b565b67ffffffffffffffff8111613414576134106020916117f0565b0190565b6117fa565b9061342b613426836133f6565b6133e1565b918252565b5f7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564910152565b6134616020613419565b9061346e60208301613430565b565b613478613457565b90565b5190565b61348881610325565b0361348f57565b5f80fd5b905051906134a08261347f565b565b906020828203126134bb576134b8915f01613493565b90565b61023b565b60207f6f74207375636365656400000000000000000000000000000000000000000000917f5361666545524332303a204552433230206f7065726174696f6e20646964206e5f8201520152565b61351a602a604092610f35565b613523816134c0565b0190565b61353c9060208101905f81830391015261350d565b90565b1561354657565b61354e610231565b62461bcd60e51b81528061356460048201613527565b0390fd5b6135b191613578613587926117d8565b90613581613470565b916135d9565b6135908161347b565b6135a261359c5f6110d2565b91610381565b149081156135b3575b5061353f565b565b6135ce915060206135c38261347b565b8183010191016134a2565b5f6135ab565b606090565b906135f892916135e76135d4565b50906135f25f6110d2565b91613712565b90565b613604906105bc565b90565b60207f722063616c6c0000000000000000000000000000000000000000000000000000917f416464726573733a20696e73756666696369656e742062616c616e636520666f5f8201520152565b6136616026604092610f35565b61366a81613607565b0190565b6136839060208101905f818303910152613654565b90565b1561368d57565b613695610231565b62461bcd60e51b8152806136ab6004820161366e565b0390fd5b67ffffffffffffffff81116136cd576136c96020916117f0565b0190565b6117fa565b906136e46136df836136af565b6133e1565b918252565b3d5f14613704576136f93d6136d2565b903d5f602084013e5b565b61370c6135d4565b90613702565b915f809161376895936137236135d4565b5061374a613730306135fb565b3161374361373d85610381565b91610381565b1015613686565b8591602082019151925af19161375e6136e9565b90929091926137ed565b90565b5f7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000910152565b61379f601d602092610f35565b6137a88161376b565b0190565b6137c19060208101905f818303910152613792565b90565b156137cb57565b6137d3610231565b62461bcd60e51b8152806137e9600482016137ac565b0390fd5b9192906137f86135d4565b505f1461383c57506138098261347b565b61381b6138155f6110d2565b91610381565b14613825575b5090565b61383161383691613842565b6137c4565b5f613821565b826138d2565b61384a61104c565b503b61385e6138585f6110d2565b91610381565b1190565b5190565b5f5b838110613878575050905f910152565b806020918301518185015201613868565b6138a86138b16020936138b69361389f81613862565b93848093610f35565b95869101613866565b6117f0565b0190565b6138cf9160208201915f818403910152613889565b90565b906138dc8261347b565b6138ee6138e85f6110d2565b91610381565b115f146138fe5750805190602001fd5b61391f9061390a610231565b91829162461bcd60e51b8352600483016138ba565b0390fd5b61392b610f31565b503390565b613939906105a0565b90565b61395061394b61395592610272565b61059d565b610381565b90565b90565b61396f61396a61397492610381565b61141e565b613958565b90565b90565b906139ac6139a66139a161399c5f6139b19661399461104c565b500194613930565b61393c565b61395b565b91613977565b613ab2565b90565b90565b5f5260205f2090565b634e487b7160e01b5f52603260045260245ffd5b5490565b6139e1816139d4565b8210156139fb576139f36001916139b7565b910201905f90565b6139c0565b1b90565b91906008613a1f910291613a195f1984613a00565b92613a00565b9181191691161790565b613a3290613958565b90565b613a3e90610600565b90565b9190613a57613a52613a5f93613a29565b613a35565b908354613a04565b9055565b9081549168010000000000000000831015613a935782613a8b916001613a91950181556139d8565b90613a41565b565b6117fa565b5490565b90613aa690613a29565b5f5260205260405f2090565b613aba61104c565b50613acf613ac9828490613b15565b15610325565b5f14613b0f57613b05613b0a92613af1613aea5f85016139b4565b8290613a63565b6001613afe5f8501613a98565b9301613a9c565b611458565b600190565b50505f90565b613b33916001613b2e92613b2761104c565b5001613a9c565b61061c565b613b45613b3f5f6110d2565b91610381565b141590565b90613b7c613b76613b71613b6c5f613b8196613b6461104c565b500194613930565b61393c565b61395b565b91613977565b613c6f565b90565b5f5260205f2090565b613b9681613a98565b821015613bb057613ba8600191613b84565b910201905f90565b6139c0565b90565b613bc8906008613bcd93026107a5565b613bb5565b90565b90613bdb9154613bb8565b90565b634e487b7160e01b5f52603160045260245ffd5b5f90565b613c0891613c02613bf2565b91613a41565b565b613c13816139d4565b8015613c34576001900390613c31613c2b83836139d8565b90613bf6565b55565b613bde565b9190613c4f613c4a613c5793611439565b611455565b908354613a04565b9055565b613c6d91613c67610f0c565b91613c39565b565b613c7761104c565b50613c8e613c89600183018490613a9c565b61061c565b9081613ca2613c9c5f6110d2565b91610381565b14155f14613d6e57613d20926001613d1b9284613cc95f96613cc385610d04565b906110f1565b613ce6613cd7888501613a98565b613ce086610d04565b906110f1565b80613cf9613cf384610381565b91610381565b03613d25575b505050613d15613d108683016139b4565b613c0a565b01613a9c565b613c5b565b600190565b613d6692613d58613d44613d3e613d61948c8901613b8d565b90613bd0565b93613d5285918c8901613b8d565b90613a41565b91858501613a9c565b611458565b5f8080613cff565b5050505f90565b90613da7613da1613d9c613d975f613dac96613d8f61104c565b500194613930565b61393c565b61395b565b91613977565b613b15565b90565b613dc65f613dcb92613dbf610f0c565b5001613977565b613dce565b90565b5f613de291613ddb610f0c565b5001613a98565b90565b613df1613df691610600565b611439565b90565b613e0d613e08613e1292610381565b61059d565b610272565b90565b613e40613e3b613e4a93613e365f613e4595613e2f610f31565b5001613977565b613e4d565b613de5565b613df9565b6105bc565b90565b613e6b915f613e6592613e5e613bf2565b5001613b8d565b90613bd0565b9056fea26469706673582212209fb4628d78766b1c797c74d808dc5067220acff030ec97156aa72a35b8e249d264736f6c63430008150033000000000000000000000000fa663e26b34ec3a45f5e1d3484cfbf3cf10f42af0000000000000000000000000000000000000000000000000000000067fbc2e6
Deployed Bytecode
0x60806040526004361015610013575b610f08565b61001d5f3561022b565b80623ad45014610226578063034d7fcb146102215780631c75e3691461021c578063515ce51714610217578063549230c9146102125780635726d26e1461020d5780635d9b436a146102085780635e80536a146102035780636138a606146101fe5780636ff1c9bc146101f9578063715018a6146101f457806379203dc4146101ef578063799fb965146101ea5780638ca8fef9146101e55780638da5cb5b146101e05780638e464baa146101db57806393c563af146101d6578063bd394a8d146101d1578063c4d3e083146101cc578063ca250022146101c7578063cc2dae83146101c2578063d2af0b94146101bd578063d637ff83146101b8578063dd191719146101b3578063ddd48f47146101ae578063de9d477e146101a9578063e0c1b6bb146101a4578063e4c26d961461019f578063e895cca31461019a578063eb013a2014610195578063f2bfbcc414610190578063f2fde38b1461018b5763fc56a8130361000e57610ec9565b610d6d565b610d38565b610ccb565b610c98565b610c65565b610c30565b610be4565b610baf565b610b43565b610b0e565b610ad9565b610a6e565b610a3b565b610a06565b6109a2565b61096f565b61093a565b6108cd565b610899565b610837565b6107f3565b610772565b61073f565b6106bf565b610688565b61053b565b6104ea565b6104b3565b610480565b610449565b61034c565b6102ab565b60e01c90565b60405190565b5f80fd5b5f80fd5b5f91031261024957565b61023b565b7f000000000000000000000000fa663e26b34ec3a45f5e1d3484cfbf3cf10f42af90565b60018060a01b031690565b61028690610272565b90565b6102929061027d565b9052565b91906102a9905f60208501940190610289565b565b346102db576102bb36600461023f565b6102d76102c661024e565b6102ce610231565b91829182610296565b0390f35b610237565b5f80fd5b6102ed8161027d565b036102f457565b5f80fd5b90503590610305826102e4565b565b906020828203126103205761031d915f016102f8565b90565b61023b565b151590565b61033390610325565b9052565b919061034a905f6020850194019061032a565b565b3461037c57610378610367610362366004610307565b611050565b61036f610231565b91829182610337565b0390f35b610237565b90565b61038d81610381565b0361039457565b5f80fd5b905035906103a582610384565b565b5f80fd5b5f80fd5b5f80fd5b909182601f830112156103ed5781359167ffffffffffffffff83116103e85760200192600183028401116103e357565b6103af565b6103ab565b6103a7565b9160608383031261043f57610409825f85016102f8565b926104178360208301610398565b92604082013567ffffffffffffffff811161043a5761043692016103b3565b9091565b6102e0565b61023b565b5f0190565b3461047b5761046561045c3660046103f2565b92919091611c7e565b61046d610231565b8061047781610444565b0390f35b610237565b346104ae57610498610493366004610307565b611712565b6104a0610231565b806104aa81610444565b0390f35b610237565b346104e5576104cf6104c63660046103f2565b92919091611d38565b6104d7610231565b806104e181610444565b0390f35b610237565b34610518576104fa36600461023f565b610502611478565b61050a610231565b8061051481610444565b0390f35b610237565b9060208282031261053657610533915f01610398565b90565b61023b565b3461056b5761056761055661055136600461051d565b611038565b61055e610231565b91829182610296565b0390f35b610237565b9190604083820312610598578061058c610595925f86016102f8565b936020016102f8565b90565b61023b565b90565b6105b46105af6105b992610272565b61059d565b610272565b90565b6105c5906105a0565b90565b6105d1906105bc565b90565b906105de906105c8565b5f5260205260405f2090565b906105f4906105c8565b5f5260205260405f2090565b5f1c90565b90565b61061461061991610600565b610605565b90565b6106269054610608565b90565b9061063861063d9260056105d4565b6105ea565b90610655600161064e5f850161061c565b930161061c565b90565b61066190610381565b9052565b91602061068692949361067f60408201965f830190610658565b0190610658565b565b346106ba576106a161069b366004610570565b90610629565b906106b66106ad610231565b92839283610665565b0390f35b610237565b346106ed576106d76106d2366004610307565b611587565b6106df610231565b806106e981610444565b0390f35b610237565b6106fb9061027d565b90565b610707816106f2565b0361070e57565b5f80fd5b9050359061071f826106fe565b565b9060208282031261073a57610737915f01610712565b90565b61023b565b3461076d57610757610752366004610721565b611a80565b61075f610231565b8061076981610444565b0390f35b610237565b346107a05761078236600461023f565b61078a613014565b610792610231565b8061079c81610444565b0390f35b610237565b1c90565b6107b99060086107be93026107a5565b610605565b90565b906107cc91546107a9565b90565b6107db60075f906107c1565b90565b91906107f1905f60208501940190610658565b565b346108235761080336600461023f565b61081f61080e6107cf565b610816610231565b918291826107de565b0390f35b610237565b61083460085f906107c1565b90565b346108675761084736600461023f565b610863610852610828565b61085a610231565b918291826107de565b0390f35b610237565b91906040838203126108945780610888610891925f86016102f8565b93602001610398565b90565b61023b565b346108c8576108b26108ac36600461086c565b90612427565b6108ba610231565b806108c481610444565b0390f35b610237565b346108fd576108dd36600461023f565b6108f96108e8612f05565b6108f0610231565b91829182610296565b0390f35b610237565b90565b61091961091461091e92610902565b61059d565b610381565b90565b61092c612710610905565b90565b610937610921565b90565b3461096a5761094a36600461023f565b61096661095561092f565b61095d610231565b918291826107de565b0390f35b610237565b3461099d57610987610982366004610307565b61207a565b61098f610231565b8061099981610444565b0390f35b610237565b346109d2576109b236600461023f565b6109ce6109bd610f13565b6109c5610231565b918291826107de565b0390f35b610237565b906109e1906105c8565b5f5260205260405f2090565b610a03906109fe6006915f926109d7565b6107c1565b90565b34610a3657610a32610a21610a1c366004610307565b6109ed565b610a29610231565b918291826107de565b0390f35b610237565b34610a6957610a4b36600461023f565b610a536115ae565b610a5b610231565b80610a6581610444565b0390f35b610237565b34610a9d57610a87610a8136600461086c565b90611a3b565b610a8f610231565b80610a9981610444565b0390f35b610237565b90565b610ab9610ab4610abe92610aa2565b61059d565b610381565b90565b610acb6005610aa5565b90565b610ad6610ac1565b90565b34610b0957610ae936600461023f565b610b05610af4610ace565b610afc610231565b918291826107de565b0390f35b610237565b34610b3e57610b1e36600461023f565b610b3a610b296110a8565b610b31610231565b918291826107de565b0390f35b610237565b34610b7157610b5336600461023f565b610b5b611b20565b610b63610231565b80610b6d81610444565b0390f35b610237565b90565b610b8d610b88610b9292610b76565b61059d565b610381565b90565b610ba16203f480610b79565b90565b610bac610b95565b90565b34610bdf57610bbf36600461023f565b610bdb610bca610ba4565b610bd2610231565b918291826107de565b0390f35b610237565b34610c1257610bfc610bf7366004610307565b61259a565b610c04610231565b80610c0e81610444565b0390f35b610237565b610c22612710610905565b90565b610c2d610c17565b90565b34610c6057610c4036600461023f565b610c5c610c4b610c25565b610c53610231565b918291826107de565b0390f35b610237565b34610c9357610c7536600461023f565b610c7d61179a565b610c85610231565b80610c8f81610444565b0390f35b610237565b34610cc657610cb0610cab366004610307565b6121f2565b610cb8610231565b80610cc281610444565b0390f35b610237565b34610cfc57610cf8610ce7610ce1366004610570565b906111de565b610cef610231565b918291826107de565b0390f35b610237565b90565b610d18610d13610d1d92610d01565b61059d565b610381565b90565b610d2a6001610d04565b90565b610d35610d20565b90565b34610d6857610d4836600461023f565b610d64610d53610d2d565b610d5b610231565b918291826107de565b0390f35b610237565b34610d9b57610d85610d80366004610307565b613109565b610d8d610231565b80610d9781610444565b0390f35b610237565b90610daa906105c8565b5f5260205260405f2090565b60ff1690565b610dc8610dcd91610600565b610db6565b90565b610dda9054610dbc565b90565b610de8906004610da0565b90610df45f830161061c565b91610e016001820161061c565b91610e0e6002830161061c565b91610e1b6003820161061c565b91610e286004830161061c565b91610e356005820161061c565b91610e4e6007610e476006850161061c565b9301610dd0565b90565b959391989796949290986101008701995f8801610e6d91610658565b60208701610e7a91610658565b60408601610e8791610658565b60608501610e9491610658565b60808401610ea191610658565b60a08301610eae91610658565b60c08201610ebb91610658565b60e001610ec79161032a565b565b34610f0357610eff610ee4610edf366004610307565b610ddd565b94610ef6989698949194939293610231565b98899889610e51565b0390f35b610237565b5f80fd5b5f90565b90565b610f1b610f0c565b50610f2e610f296002610f10565b613daf565b90565b5f90565b60209181520190565b60207f696e646578206578697374733f00000000000000000000000000000000000000917f76616c69646174654469737472696275746564546f6b656e73496e6465783a205f8201520152565b610f98602d604092610f35565b610fa181610f3e565b0190565b610fba9060208101905f818303910152610f8b565b90565b15610fc457565b610fcc610231565b62461bcd60e51b815280610fe260048201610fa5565b0390fd5b9061101d916110188261101261100c6110076110026002610f10565b613daf565b610381565b91610381565b10610fbd565b611020565b90565b9061103591506110306002610f10565b613e15565b90565b61104990611044610f31565b610fe6565b90565b5f90565b61106c9061105c61104c565b506110676002610f10565b613d75565b90565b634e487b7160e01b5f52601160045260245ffd5b61109261109891939293610381565b92610381565b82018092116110a357565b61106f565b6110b0610f0c565b506110cc6110be600861061c565b6110c6610b95565b90611083565b90565b90565b6110e66110e16110eb926110cf565b61059d565b610381565b90565b90565b61110061110691939293610381565b92610381565b820391821161111157565b61106f565b61112561112b91939293610381565b92610381565b91611137838202610381565b92818404149015171561114657565b61106f565b90565b61116261115d6111679261114b565b61059d565b610381565b90565b634e487b7160e01b5f52601260045260245ffd5b61118a61119091610381565b91610381565b90811561119b570490565b61116a565b90565b6111b76111b26111bc926111a0565b61059d565b610381565b90565b90565b6111d66111d16111db926111bf565b61059d565b610381565b90565b6111e6610f0c565b506111f1600761061c565b6112036111fd5f6110d2565b91610381565b146113fd576112ff5f6112f9611305946112f46112ec6112c56112ae61123361122e60048b90610da0565b6110ee565b61123f6004820161061c565b9061124c6005820161061c565b906112568c6126ff565b9061125f6110a8565b4261127261126c83610381565b91610381565b11611358575b50611288600761128e9201610dd0565b15610325565b611308575b50506112a96112a4600688906109d7565b61061c565b611116565b6112bf670de0b6b3a76400006111c2565b9061117e565b6112e660016112e06112d960058c906105d4565b87906105ea565b0161061c565b906110f1565b9560056105d4565b6105ea565b0161061c565b90611083565b90565b61133b61132561134b926113206113519695426110f1565b611116565b611335662386f26fc1000061114e565b90611116565b611345600761061c565b9061117e565b90611083565b5f80611293565b9361138f6113796113a59461137461139f9497959795896110f1565b611116565b611389662386f26fc1000061114e565b90611116565b611399600761061c565b9061117e565b90611083565b919061128e61128860076113f46113e66113d66113c46002880161061c565b6113d06006890161061c565b90611116565b6113e060646111a3565b9061117e565b6113ee610b95565b9061117e565b93925050611278565b61141561141b926114105f9360056105d4565b6105ea565b0161061c565b90565b5f1b90565b9061142f5f199161141e565b9181191691161790565b61144d61144861145292610381565b61059d565b610381565b90565b90565b9061146d61146861147492611439565b611455565b8254611423565b9055565b6114806110a8565b4261149361148d83610381565b91610381565b101561149d575b50565b6114a8906008611458565b5f61149a565b60207f20646f6573206e6f742065786973747300000000000000000000000000000000917f76616c69646174654469737472696275746564546f6b656e733a20746f6b656e5f8201520152565b6115086030604092610f35565b611511816114ae565b0190565b61152a9060208101905f8183039101526114fb565b90565b1561153457565b61153c610231565b62461bcd60e51b81528061155260048201611515565b0390fd5b61157a906115756115708261156b6002610f10565b613d75565b61152d565b61157c565b565b61158590612772565b565b61159090611556565b565b61159b90610381565b5f1981146115a95760010190565b61106f565b6115c06115bb6002610f10565b613daf565b6115c95f6110d2565b5b806115dd6115d784610381565b91610381565b101561160d57611608906116036115fe6115f76002610f10565b8390613e15565b612772565b611592565b6115ca565b5050565b6116229061161d61325f565b6116ae565b61162a6132ad565b565b5f7f68617276657374526577617264733a20696e76616c696420746f6b656e000000910152565b611660601d602092610f35565b6116698161162c565b0190565b6116829060208101905f818303910152611653565b90565b1561168c57565b611694610231565b62461bcd60e51b8152806116aa6004820161166d565b0390fd5b6116d9906116cf6116c96116c26002610f10565b8390613d75565b15610325565b6116db575b612ccd565b565b61170d6116f560036116ef60048590610da0565b0161061c565b6117076117015f6110d2565b91610381565b11611685565b6116d4565b61171b90611611565b565b61172561325f565b61172d611737565b6117356132ad565b565b6117496117446002610f10565b613daf565b6117525f6110d2565b5b8061176661176084610381565b91610381565b1015611796576117919061178c6117876117806002610f10565b8390613e15565b612ccd565b611592565b611753565b5050565b6117a261171d565b565b906117b6916117b161325f565b61187a565b6117be6132ad565b565b6117c9906105a0565b90565b6117d5906117c0565b90565b6117e1906105bc565b90565b6117ed906105bc565b90565b601f801991011690565b634e487b7160e01b5f52604160045260245ffd5b90611818906117f0565b810190811067ffffffffffffffff82111761183257604052565b6117fa565b60e01b90565b9050519061184a82610384565b565b9060208282031261186557611862915f0161183d565b90565b61023b565b611872610231565b3d5f823e3d90fd5b6118c2602061189061188b846117cc565b6117d8565b6370a08231906118b76118a2306117e4565b926118ab610231565b95869485938493611837565b835260048301610296565b03915afa908115611a36575f91611a08575b506119086118ec6118e760048590610da0565b6110ee565b936118f6846117cc565b9033611901306117e4565b9192613392565b611950602061191e611919856117cc565b6117d8565b6370a0823190611945611930306117e4565b92611939610231565b95869485938493611837565b835260048301610296565b03915afa8015611a035761198f92611970925f926119d3575b50906110f1565b92600261198861198182840161061c565b8690611083565b9101611458565b6119ce6119bc7f6be8535fae97a5677bece5c298a5838092d0e8c92b11a3e81e10449194219bbf926105c8565b926119c5610231565b918291826107de565b0390a2565b6119f591925060203d81116119fc575b6119ed818361180e565b81019061184c565b905f611969565b503d6119e3565b61186a565b611a29915060203d8111611a2f575b611a21818361180e565b81019061184c565b5f6118d4565b503d611a17565b61186a565b90611a45916117a4565b565b611a5890611a5361325f565b611a62565b611a606132ad565b565b611a7390611a6e612f9b565b611a75565b565b611a7e9061264d565b565b611a8990611a47565b565b611a9361325f565b611a9b611aa5565b611aa36132ad565b565b611aad612f9b565b611ab5611ab7565b565b611ac05f6110d2565b5b80611ae5611adf611ada611ad56002610f10565b613daf565b610381565b91610381565b1015611b1d57611b1890611b13611b0e611b09611b026002610f10565b8490613e15565b6117cc565b61264d565b611592565b611ac1565b50565b611b28611a8b565b565b90611b3e939291611b3961325f565b611bf0565b611b466132ad565b565b60207f20624f6f6761546f6b656e000000000000000000000000000000000000000000917f624f4f4741546f6b656e4f6e6c793a2063616c6c65722073686f756c642062655f8201520152565b611ba2602b604092610f35565b611bab81611b48565b0190565b611bc49060208101905f818303910152611b95565b90565b15611bce57565b611bd6610231565b62461bcd60e51b815280611bec60048201611baf565b0390fd5b90611c38939291611c3333611c2d611c277f000000000000000000000000fa663e26b34ec3a45f5e1d3484cfbf3cf10f42af61027d565b9161027d565b14611bc7565b611c3a565b565b909150611c7c9250611c73611c63611c5c611c57600685906109d7565b61061c565b8490611083565b92611c6e600761061c565b611083565b90919091612b1b565b565b90611c8a939291611b2a565b565b90611ca0939291611c9b61325f565b611caa565b611ca86132ad565b565b90611cf2939291611ced33611ce7611ce17f000000000000000000000000fa663e26b34ec3a45f5e1d3484cfbf3cf10f42af61027d565b9161027d565b14611bc7565b611cf4565b565b909150611d369250611d2d611d1d611d16611d11600685906109d7565b61061c565b84906110f1565b92611d28600761061c565b6110f1565b90919091612b1b565b565b90611d44939291611c8c565b565b611d5790611d52612f9b565b611eee565b565b60207f656e61626c6564207265776172647320746f6b656e0000000000000000000000917f656e61626c654469737472696275746564546f6b656e3a20416c7265616479205f8201520152565b611db36035604092610f35565b611dbc81611d59565b0190565b611dd59060208101905f818303910152611da6565b90565b15611ddf57565b611de7610231565b62461bcd60e51b815280611dfd60048201611dc0565b0390fd5b60207f206469737472696275746564546f6b656e730000000000000000000000000000917f656e61626c654469737472696275746564546f6b656e3a20746f6f206d616e795f8201520152565b611e5b6032604092610f35565b611e6481611e01565b0190565b611e7d9060208101905f818303910152611e4e565b90565b15611e8757565b611e8f610231565b62461bcd60e51b815280611ea560048201611e68565b0390fd5b90611eb560ff9161141e565b9181191691161790565b611ec890610325565b90565b90565b90611ee3611ede611eea92611ebf565b611ecb565b8254611ea9565b9055565b611faa611f05611f0060048490610da0565b6110ee565b611f116005820161061c565b611f23611f1d5f6110d2565b91610381565b148015612063575b611f3490611dd8565b611f48611f416002610f10565b8490613d75565b801561202c575b611f5890611e80565b611f646005820161061c565b611f76611f705f6110d2565b91610381565b1461201a575b611f886006820161061c565b611f9a611f945f6110d2565b91610381565b14612001575b60075f9101611ece565b611fbe611fb76002610f10565b829061397a565b50611fe97fefa645a0ab6703d2f2e7f177f50d16c90ce1c71e317bb91cbbdab430e0a39682916105c8565b90611ff2610231565b80611ffc81610444565b0390a2565b61201561200c610c17565b60068301611458565b611fa0565b6120274260058301611458565b611f7c565b50611f5861204261203d6002610f10565b613daf565b61205b612055612050610ac1565b610381565b91610381565b109050611f4f565b50611f3461207360078301610dd0565b9050611f2b565b61208390611d46565b565b61209690612091612f9b565b612140565b565b60207f2064697361626c6564207265776172647320746f6b656e000000000000000000917f64697361626c654469737472696275746564546f6b656e3a20416c72656164795f8201520152565b6120f26037604092610f35565b6120fb81612098565b0190565b6121149060208101905f8183039101526120e5565b90565b1561211e57565b612126610231565b62461bcd60e51b81528061213c600482016120ff565b0390fd5b61219061215761215260048490610da0565b6110ee565b6121636005820161061c565b61217561216f5f6110d2565b91610381565b11806121d2575b61218590612117565b600760019101611ece565b6121ba7f961f10509197d967c55f8720c2b6a80d48433ef36db1b12cf3bf6bcf66da4346916105c8565b906121c3610231565b806121cd81610444565b0390a2565b506121856121eb6121e560078401610dd0565b15610325565b905061217c565b6121fb90612085565b565b9061220f9161220a612f9b565b612361565b565b60207f6e74206d7573746e277420657863656564206d6178696d756d00000000000000917f7570646174654379636c655265776172647350657263656e743a2070657263655f8201520152565b61226b6039604092610f35565b61227481612211565b0190565b61228d9060208101905f81830391015261225e565b90565b1561229757565b61229f610231565b62461bcd60e51b8152806122b560048201612278565b0390fd5b60207f6e74206d7573746e277420657863656564206d696e696d756d00000000000000917f7570646174654379636c655265776172647350657263656e743a2070657263655f8201520152565b6123136039604092610f35565b61231c816122b9565b0190565b6123359060208101905f818303910152612306565b90565b1561233f57565b612347610231565b62461bcd60e51b81528061235d60048201612320565b0390fd5b906123868161237f612379612374610921565b610381565b91610381565b1115612290565b6123aa816123a361239d612398610d20565b610381565b91610381565b1015612338565b6123e360066123c36123be60048690610da0565b6110ee565b936123db6123d283870161061c565b94838701611458565b92930161061c565b61240d7f0d8168d755f5c8a7e102241b41e7561ab7536fba6348dc00388334d62d26878e926105c8565b92612422612419610231565b92839283610665565b0390a2565b90612431916121fd565b565b6124449061243f612f9b565b6124ee565b565b60207f3a2063616e6e6f742062652072656d6f76656400000000000000000000000000917f72656d6f7665546f6b656e46726f6d4469737472696275746564546f6b656e735f8201520152565b6124a06033604092610f35565b6124a981612446565b0190565b6124c29060208101905f818303910152612493565b90565b156124cc57565b6124d4610231565b62461bcd60e51b8152806124ea600482016124ad565b0390fd5b61251e61250561250060048490610da0565b6110ee565b61251160078201610dd0565b9081612575575b506124c5565b61253261252b6002610f10565b8290613b4a565b5061255d7f17cd3cc84c669de8c5c4218fd1d9814e647b547d1e7f59287ea6989aa4e032c2916105c8565b90612566610231565b8061257081610444565b0390a2565b61258191505f0161061c565b61259361258d5f6110d2565b91610381565b145f612518565b6125a390612433565b565b60207f206973206e756c6c000000000000000000000000000000000000000000000000917f656d657267656e637957697468647261773a20746f6b656e2062616c616e63655f8201520152565b6125ff6028604092610f35565b612608816125a5565b0190565b6126219060208101905f8183039101526125f2565b90565b1561262b57565b612633610231565b62461bcd60e51b8152806126496004820161260c565b0390fd5b61268e90602061265c826117d8565b6370a082319061268361266e306117e4565b92612677610231565b96879485938493611837565b835260048301610296565b03915afa80156126fa576126ca925f916126cc575b50906126c1826126bb6126b55f6110d2565b91610381565b11612624565b90339091612df0565b565b6126ed915060203d81116126f3575b6126e5818361180e565b81019061184c565b5f6126a3565b503d6126db565b61186a565b612707610f0c565b5061272561271f6127186002610f10565b8390613d75565b15610325565b612765576127546127445f61273e612762946004610da0565b0161061c565b61274e60646111a3565b90611116565b61275c610b95565b9061117e565b90565b5061276f5f6110d2565b90565b429061278861278360048390610da0565b6110ee565b90612791611478565b61279d6005830161061c565b6127a96004840161061c565b90846127bd6127b783610381565b91610381565b1115612b11576127cd600761061c565b6127df6127d95f6110d2565b91610381565b148015612aee575b612adc576128d56005936128e596936128de936128055f890161061c565b9261281260018a0161061c565b918061282f612829612824600861061c565b610381565b91610381565b10612920575b9061284c612846612852938a6110f1565b916126ff565b90611116565b9261285e828590611083565b61288361287d6128788461287260646111a3565b90611116565b610381565b91610381565b116128e7575b506128cf916128a861289f6128bf938690611083565b60018b01611458565b926128b9662386f26fc1000061114e565b90611116565b6128c9600761061c565b9061117e565b90611083565b60048501611458565b9101611458565b565b6128bf919350916128a861289f61291561290e6128cf9661290860646111a3565b90611116565b87906110f1565b959350505091612889565b5092919061297161296161294b61297794936129468761294060646111a3565b90611116565b6110f1565b61295b662386f26fc1000061114e565b90611116565b61296b600761061c565b9061117e565b90611083565b9061298d61298760078a01610dd0565b15610325565b5f14612a98576129ab6129b4916129a660038b0161061c565b611083565b60038901611458565b6129c06002880161061c565b916129eb6129da846129d460068c0161061c565b90611116565b6129e5612710610905565b9061117e565b92806129ff6129f95f6110d2565b91610381565b1180612a7e575b5f14612a5657612a18905f8a01611458565b612a2d612a245f6110d2565b60028a01611458565b5b5b612852612a3b5f6110d2565b9161284c612846612a4c600861061c565b9293505050612835565b612a70612a7991612a69865f8d01611458565b85906110f1565b60028a01611458565b612a2e565b5083612a92612a8c5f6110d2565b91610381565b14612a06565b612ab0612ab991612aab60038b0161061c565b611083565b60038901611458565b612ac25f6110d2565b91612ad7612acf5f6110d2565b5f8a01611458565b612a2f565b5050506005612aec929101611458565b565b5084612b0b612b05612b00600861061c565b610381565b91610381565b106127e7565b5050505050565b90565b919290612b32612b2d600685906109d7565b61061c565b91612b45612b406002610f10565b613daf565b94612b4f5f6110d2565b5b80612b63612b5d89610381565b91610381565b1015612c61576002612b7490610f10565b81612b7e91613e15565b80612b8890612772565b600581612b94916105d4565b87612b9e916105ea565b612ba790612b18565b90600490612bb491610da0565b600401612bc09061061c565b8681612bcb91611116565b670de0b6b3a7640000612bdd906111c2565b612be69161117e565b82600101612bf39061061c565b612bfc916110f1565b825f01612c089061061c565b90612c1291611083565b825f0190612c1f91611458565b8590612c2a91611116565b670de0b6b3a7640000612c3c906111c2565b612c459161117e565b9060010190612c5391611458565b612c5c90611592565b612b50565b50612c87919550939193612c8085612c7b600686906109d7565b611458565b6007611458565b9091612cb37f97ce9d7086176d6da45e4e7999788176e2629a7591ffe505b0c1b13fe8052cc6926105c8565b92612cc8612cbf610231565b92839283610665565b0390a2565b612cd681612772565b612cf4612cef612ce8600584906105d4565b33906105ea565b612b18565b612d8b612d43612d2c612d136004612d0d818890610da0565b0161061c565b612d27612d22600633906109d7565b61061c565b611116565b612d3d670de0b6b3a76400006111c2565b9061117e565b916001612d6f612d5e612d575f850161061c565b8690611083565b612d6983850161061c565b906110f1565b93612d84612d7c5f6110d2565b5f8501611458565b9101611458565b612d9f612d97836117cc565b338391612df0565b33919091612deb612dd9612dd37f5cbc2d25e94cfcae49c20ef253b5bdba9c8fba9e437f0423f0ac464d4897d645936105c8565b936105c8565b93612de2610231565b918291826107de565b0390a3565b9180612e04612dfe5f6110d2565b91610381565b11612e0f575b505050565b612e4f6020612e1d856117d8565b6370a0823190612e44612e2f306117e4565b92612e38610231565b95869485938493611837565b835260048301610296565b03915afa908115612ed4575f91612ea6575b509080612e76612e7084610381565b91610381565b115f14612e935750612e8a92919091613315565b5b5f8080612e0a565b9050612ea192919091613315565b612e8b565b612ec7915060203d8111612ecd575b612ebf818361180e565b81019061184c565b5f612e61565b503d612eb5565b61186a565b60018060a01b031690565b612ef0612ef591610600565b612ed9565b90565b612f029054612ee4565b90565b612f0d610f31565b50612f175f612ef8565b90565b5f7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572910152565b612f4d60208092610f35565b612f5681612f1a565b0190565b612f6f9060208101905f818303910152612f41565b90565b15612f7957565b612f81610231565b62461bcd60e51b815280612f9760048201612f5a565b0390fd5b612fc5612fa6612f05565b612fbf612fb9612fb4613923565b61027d565b9161027d565b14612f72565b565b612fcf612f9b565b612fd7613001565b565b612fed612fe8612ff2926110cf565b61059d565b610272565b90565b612ffe90612fd9565b90565b61301261300d5f612ff5565b613152565b565b61301c612fc7565b565b61302f9061302a612f9b565b6130d9565b565b60207f6464726573730000000000000000000000000000000000000000000000000000917f4f776e61626c653a206e6577206f776e657220697320746865207a65726f20615f8201520152565b61308b6026604092610f35565b61309481613031565b0190565b6130ad9060208101905f81830391015261307e565b90565b156130b757565b6130bf610231565b62461bcd60e51b8152806130d560048201613098565b0390fd5b61310790613102816130fb6130f56130f05f612ff5565b61027d565b9161027d565b14156130b0565b613152565b565b6131129061301e565b565b9061312560018060a01b039161141e565b9181191691161790565b90565b9061314761314261314e926105c8565b61312f565b8254613114565b9055565b61315b5f612ef8565b613165825f613132565b906131996131937f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0936105c8565b916105c8565b916131a2610231565b806131ac81610444565b0390a3565b90565b6131c86131c36131cd926131b1565b61059d565b610381565b90565b6131da60026131b4565b90565b5f7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00910152565b613211601f602092610f35565b61321a816131dd565b0190565b6132339060208101905f818303910152613204565b90565b1561323d57565b613245610231565b62461bcd60e51b81528061325b6004820161321e565b0390fd5b61328c61326c600161061c565b61328561327f61327a6131d0565b610381565b91610381565b1415613236565b61329e6132976131d0565b6001611458565b565b6132aa6001610d04565b90565b6132bf6132b86132a0565b6001611458565b565b63ffffffff1690565b63ffffffff60e01b1690565b6132ea6132e56132ef926132c1565b611837565b6132ca565b90565b91602061331392949361330c60408201965f830190610289565b0190610658565b565b9161335960049261334a61335e959361333163a9059cbb6132d6565b9261333a610231565b96879460208601908152016132f2565b6020820181038252038361180e565b613568565b565b604090613389613390949695939661337f60608401985f850190610289565b6020830190610289565b0190610658565b565b6133df93916133cb6004946133da93946133af6323b872dd6132d6565b939190916133bb610231565b9788956020870190815201613360565b6020820181038252038361180e565b613568565b565b906133f46133ed610231565b928361180e565b565b67ffffffffffffffff8111613414576134106020916117f0565b0190565b6117fa565b9061342b613426836133f6565b6133e1565b918252565b5f7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564910152565b6134616020613419565b9061346e60208301613430565b565b613478613457565b90565b5190565b61348881610325565b0361348f57565b5f80fd5b905051906134a08261347f565b565b906020828203126134bb576134b8915f01613493565b90565b61023b565b60207f6f74207375636365656400000000000000000000000000000000000000000000917f5361666545524332303a204552433230206f7065726174696f6e20646964206e5f8201520152565b61351a602a604092610f35565b613523816134c0565b0190565b61353c9060208101905f81830391015261350d565b90565b1561354657565b61354e610231565b62461bcd60e51b81528061356460048201613527565b0390fd5b6135b191613578613587926117d8565b90613581613470565b916135d9565b6135908161347b565b6135a261359c5f6110d2565b91610381565b149081156135b3575b5061353f565b565b6135ce915060206135c38261347b565b8183010191016134a2565b5f6135ab565b606090565b906135f892916135e76135d4565b50906135f25f6110d2565b91613712565b90565b613604906105bc565b90565b60207f722063616c6c0000000000000000000000000000000000000000000000000000917f416464726573733a20696e73756666696369656e742062616c616e636520666f5f8201520152565b6136616026604092610f35565b61366a81613607565b0190565b6136839060208101905f818303910152613654565b90565b1561368d57565b613695610231565b62461bcd60e51b8152806136ab6004820161366e565b0390fd5b67ffffffffffffffff81116136cd576136c96020916117f0565b0190565b6117fa565b906136e46136df836136af565b6133e1565b918252565b3d5f14613704576136f93d6136d2565b903d5f602084013e5b565b61370c6135d4565b90613702565b915f809161376895936137236135d4565b5061374a613730306135fb565b3161374361373d85610381565b91610381565b1015613686565b8591602082019151925af19161375e6136e9565b90929091926137ed565b90565b5f7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000910152565b61379f601d602092610f35565b6137a88161376b565b0190565b6137c19060208101905f818303910152613792565b90565b156137cb57565b6137d3610231565b62461bcd60e51b8152806137e9600482016137ac565b0390fd5b9192906137f86135d4565b505f1461383c57506138098261347b565b61381b6138155f6110d2565b91610381565b14613825575b5090565b61383161383691613842565b6137c4565b5f613821565b826138d2565b61384a61104c565b503b61385e6138585f6110d2565b91610381565b1190565b5190565b5f5b838110613878575050905f910152565b806020918301518185015201613868565b6138a86138b16020936138b69361389f81613862565b93848093610f35565b95869101613866565b6117f0565b0190565b6138cf9160208201915f818403910152613889565b90565b906138dc8261347b565b6138ee6138e85f6110d2565b91610381565b115f146138fe5750805190602001fd5b61391f9061390a610231565b91829162461bcd60e51b8352600483016138ba565b0390fd5b61392b610f31565b503390565b613939906105a0565b90565b61395061394b61395592610272565b61059d565b610381565b90565b90565b61396f61396a61397492610381565b61141e565b613958565b90565b90565b906139ac6139a66139a161399c5f6139b19661399461104c565b500194613930565b61393c565b61395b565b91613977565b613ab2565b90565b90565b5f5260205f2090565b634e487b7160e01b5f52603260045260245ffd5b5490565b6139e1816139d4565b8210156139fb576139f36001916139b7565b910201905f90565b6139c0565b1b90565b91906008613a1f910291613a195f1984613a00565b92613a00565b9181191691161790565b613a3290613958565b90565b613a3e90610600565b90565b9190613a57613a52613a5f93613a29565b613a35565b908354613a04565b9055565b9081549168010000000000000000831015613a935782613a8b916001613a91950181556139d8565b90613a41565b565b6117fa565b5490565b90613aa690613a29565b5f5260205260405f2090565b613aba61104c565b50613acf613ac9828490613b15565b15610325565b5f14613b0f57613b05613b0a92613af1613aea5f85016139b4565b8290613a63565b6001613afe5f8501613a98565b9301613a9c565b611458565b600190565b50505f90565b613b33916001613b2e92613b2761104c565b5001613a9c565b61061c565b613b45613b3f5f6110d2565b91610381565b141590565b90613b7c613b76613b71613b6c5f613b8196613b6461104c565b500194613930565b61393c565b61395b565b91613977565b613c6f565b90565b5f5260205f2090565b613b9681613a98565b821015613bb057613ba8600191613b84565b910201905f90565b6139c0565b90565b613bc8906008613bcd93026107a5565b613bb5565b90565b90613bdb9154613bb8565b90565b634e487b7160e01b5f52603160045260245ffd5b5f90565b613c0891613c02613bf2565b91613a41565b565b613c13816139d4565b8015613c34576001900390613c31613c2b83836139d8565b90613bf6565b55565b613bde565b9190613c4f613c4a613c5793611439565b611455565b908354613a04565b9055565b613c6d91613c67610f0c565b91613c39565b565b613c7761104c565b50613c8e613c89600183018490613a9c565b61061c565b9081613ca2613c9c5f6110d2565b91610381565b14155f14613d6e57613d20926001613d1b9284613cc95f96613cc385610d04565b906110f1565b613ce6613cd7888501613a98565b613ce086610d04565b906110f1565b80613cf9613cf384610381565b91610381565b03613d25575b505050613d15613d108683016139b4565b613c0a565b01613a9c565b613c5b565b600190565b613d6692613d58613d44613d3e613d61948c8901613b8d565b90613bd0565b93613d5285918c8901613b8d565b90613a41565b91858501613a9c565b611458565b5f8080613cff565b5050505f90565b90613da7613da1613d9c613d975f613dac96613d8f61104c565b500194613930565b61393c565b61395b565b91613977565b613b15565b90565b613dc65f613dcb92613dbf610f0c565b5001613977565b613dce565b90565b5f613de291613ddb610f0c565b5001613a98565b90565b613df1613df691610600565b611439565b90565b613e0d613e08613e1292610381565b61059d565b610272565b90565b613e40613e3b613e4a93613e365f613e4595613e2f610f31565b5001613977565b613e4d565b613de5565b613df9565b6105bc565b90565b613e6b915f613e6592613e5e613bf2565b5001613b8d565b90613bd0565b9056fea26469706673582212209fb4628d78766b1c797c74d808dc5067220acff030ec97156aa72a35b8e249d264736f6c63430008150033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000fa663e26b34ec3a45f5e1d3484cfbf3cf10f42af0000000000000000000000000000000000000000000000000000000067fbc2e6
-----Decoded View---------------
Arg [0] : bOogaToken_ (address): 0xFa663E26B34EC3A45f5e1d3484CFBF3cF10f42af
Arg [1] : startTime_ (uint256): 1744552678
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000fa663e26b34ec3a45f5e1d3484cfbf3cf10f42af
Arg [1] : 0000000000000000000000000000000000000000000000000000000067fbc2e6
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.