Latest 25 from a total of 2,151 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Withdraw Vested ... | 26873653 | 35 days ago | IN | 0 ETH | 0.00000001 | ||||
| Withdraw | 24899537 | 70 days ago | IN | 0 ETH | 0.00000054 | ||||
| Withdraw | 21578634 | 127 days ago | IN | 0 ETH | 0.00000004 | ||||
| Withdraw | 20732591 | 140 days ago | IN | 0 ETH | 0.00000091 | ||||
| Withdraw Vested ... | 20346465 | 147 days ago | IN | 0 ETH | 0.00000164 | ||||
| Withdraw Vested ... | 18694997 | 169 days ago | IN | 0 ETH | 0.00000169 | ||||
| Withdraw | 18002271 | 177 days ago | IN | 0 ETH | 0.00000216 | ||||
| Withdraw | 18002235 | 177 days ago | IN | 0 ETH | 0.00000216 | ||||
| Withdraw Vested ... | 17390415 | 188 days ago | IN | 0 ETH | 0.00000217 | ||||
| Withdraw Vested ... | 17390395 | 188 days ago | IN | 0 ETH | 0.00000367 | ||||
| Withdraw | 16952995 | 204 days ago | IN | 0 ETH | 0.00000106 | ||||
| Withdraw | 16952983 | 204 days ago | IN | 0 ETH | 0.00000053 | ||||
| Withdraw Vested ... | 16858322 | 208 days ago | IN | 0 ETH | 0.00000082 | ||||
| Withdraw Vested ... | 15375773 | 257 days ago | IN | 0 ETH | 0.00000245 | ||||
| Withdraw Vested ... | 15357448 | 258 days ago | IN | 0 ETH | 0.00000206 | ||||
| Withdraw Vested ... | 15153242 | 267 days ago | IN | 0 ETH | 0.00000362 | ||||
| Withdraw Vested ... | 15149678 | 267 days ago | IN | 0 ETH | 0.00000256 | ||||
| Withdraw Vested ... | 15132580 | 268 days ago | IN | 0 ETH | 0.00000355 | ||||
| Withdraw Vested ... | 14701915 | 286 days ago | IN | 0 ETH | 0.00000301 | ||||
| Exit Early | 14701908 | 286 days ago | IN | 0 ETH | 0.00000465 | ||||
| Withdraw | 14701896 | 286 days ago | IN | 0 ETH | 0.00000368 | ||||
| Withdraw Vested ... | 14590456 | 290 days ago | IN | 0 ETH | 0.00000572 | ||||
| Withdraw Vested ... | 14316556 | 300 days ago | IN | 0 ETH | 0.00000842 | ||||
| Withdraw Vested ... | 14316547 | 300 days ago | IN | 0 ETH | 0.00000956 | ||||
| Exit Early | 14316545 | 300 days ago | IN | 0 ETH | 0.00000945 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
StablecoinFarm
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import { Pausable } from '../Pausable.sol';
import { BalanceManagement } from '../BalanceManagement.sol';
import { IRevenueShare } from '../interfaces/IRevenueShare.sol';
contract StablecoinFarm is Pausable, BalanceManagement {
using SafeERC20 for IERC20;
struct VestedBalance {
uint256 amount;
uint256 unlockTime;
}
// Info of each user.
struct UserInfo {
uint256 amount; // How many tokens the user has provided.
uint256 rewardDebt; // Reward debt. See the explanation below.
uint256 remainingRewardTokenAmount; // Tokens that weren't distributed for a user per pool.
// Any point in time, the amount of reward tokens entitled to a user but pending to be distributed is:
// pending reward = (user.amount * pool.accumulatedRewardTokenPerShare) - user.rewardDebt
//
// Whenever a user deposits or withdraws Staked tokens to a pool. Here's what happens:
// 1. The pool's `accumulatedRewardTokenPerShare` (and `lastRewardTime`) gets updated.
// 2. A user receives the pending reward sent to his/her address.
// 3. The user's `amount` gets updated.
// 4. The user's `rewardDebt` gets updated.
}
// Info of each pool.
struct PoolInfo {
address stakingToken; // Contract address of staked token
uint256 stakingTokenTotalAmount; //Total amount of deposited tokens
uint256 accumulatedRewardTokenPerShare; // Accumulated reward token per share, times 1e12. See below.
uint32 lastRewardTime; // Last timestamp number that reward token distribution occurs.
uint16 allocationPoint; // How many allocation points are assigned to this pool.
}
address public immutable rewardToken; // The reward token.
address public treasury; // The penalty address of the treasury.
address public LPRevenueShare; // The penalty address of the fee LPRevenueShare contract.
uint256 public rewardTokenPerSecond; // Reward tokens vested per second.
PoolInfo[] public poolInfo; // Info of each pool.
mapping(address => bool) public isStakingTokenSet;
mapping(uint256 => mapping(address => UserInfo)) public userInfo; // Info of each user that stakes tokens.
mapping(uint256 => mapping(address => VestedBalance[])) public userVested; // vested tokens
uint256 public totalAllocationPoint = 0; // the sum of all allocation points in all pools.
uint32 public immutable startTime; // the timestamp when reward token farming starts.
uint32 public endTime; // time on which the reward calculation should end.
uint256 public immutable vestingDuration;
uint256 public exitEarlyUserShare = 500; // 50%
uint256 public exitEarlyTreasuryShare = 200; // 20%
uint256 public exitEarlyLPShare = 300; // 30%
// Factor to perform multiplication and division operations.
uint256 private constant SHARE_PRECISION = 1e18;
event Staked(address indexed user, uint256 indexed pid, uint256 amount);
event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);
event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount);
event WithdrawVesting(address indexed user, uint256 amount);
event Vested(address indexed user, uint256 indexed pid, uint256 amount);
event Locked(address indexed user, uint256 indexed pid, uint256 amount);
event ExitEarly(address indexed user, uint256 amount);
constructor(
address _rewardToken,
uint256 _rewardTokenPerSecond,
uint32 _startTime,
uint32 _endTimeAddSeconds,
uint256 _vestingDuration
) {
rewardToken = _rewardToken;
rewardTokenPerSecond = _rewardTokenPerSecond;
startTime = _startTime;
endTime = startTime + _endTimeAddSeconds;
vestingDuration = _vestingDuration;
}
/**
* @dev Sets a new treasury
* @param _newTreasury is a new treasury address
*/
function setTreasury(address _newTreasury) external onlyOwner {
require(_newTreasury != address(0), 'Zero address error');
treasury = _newTreasury;
}
/**
* @dev Sets a new LP revenue share
* @param _newRevenueShare is a new LP revenue share address
*/
function setLPRevenueShare(address _newRevenueShare) external onlyOwner {
require(_newRevenueShare != address(0), 'Zero address error');
LPRevenueShare = _newRevenueShare;
}
/**
* @dev Sets portions for exit early. If it needs to set 33.3%, just provide a 333 value.
* Pay attention, the sum of all values must be 1000, which means 100%
* @param _userPercent is a user percent
* @param _treasuryPercent is a treasury percent
* @param _lpPercent is an LP share percent
*/
function setPercentsShare(
uint256 _userPercent,
uint256 _treasuryPercent,
uint256 _lpPercent
) external onlyOwner {
require(
_userPercent + _treasuryPercent + _lpPercent == 1000,
'Total percentage should be 100% in total'
);
exitEarlyUserShare = _userPercent;
exitEarlyTreasuryShare = _treasuryPercent;
exitEarlyLPShare = _lpPercent;
}
/**
* @dev Deposit staking tokens for reward token allocation.
* @param _pid is a pool id
* @param _amount is a number of deposit tokens
*/
function stake(uint256 _pid, uint256 _amount) external whenNotPaused {
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][msg.sender];
_updatePool(_pid);
IERC20(pool.stakingToken).safeTransferFrom(msg.sender, address(this), _amount);
user.remainingRewardTokenAmount = pendingRewardToken(_pid, msg.sender);
user.amount += _amount;
pool.stakingTokenTotalAmount += _amount;
user.rewardDebt = (user.amount * pool.accumulatedRewardTokenPerShare) / SHARE_PRECISION;
emit Staked(msg.sender, _pid, _amount);
}
/**
* @dev Withdraw only staked iUSDC/iUSDT tokens
* @param _pid is a pool id
* @param _amount is an amount of withdrawn tokens
*/
function withdraw(uint256 _pid, uint256 _amount) external whenNotPaused {
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][msg.sender];
if (user.amount < _amount) {
revert('Can not withdraw this amount');
}
_updatePool(_pid);
user.remainingRewardTokenAmount = pendingRewardToken(_pid, msg.sender);
user.amount -= _amount;
pool.stakingTokenTotalAmount -= _amount;
user.rewardDebt = (user.amount * pool.accumulatedRewardTokenPerShare) / SHARE_PRECISION;
IERC20(pool.stakingToken).safeTransfer(msg.sender, _amount);
emit Withdraw(msg.sender, _pid, _amount);
}
/**
* @dev Withdraw without caring about rewards. EMERGENCY ONLY.
* @param _pid is a pool id
*/
function emergencyWithdraw(uint256 _pid) external {
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][msg.sender];
uint256 userAmount = user.amount;
pool.stakingTokenTotalAmount -= userAmount;
user.amount = 0;
user.rewardDebt = 0;
user.remainingRewardTokenAmount = 0;
IERC20(pool.stakingToken).safeTransfer(msg.sender, userAmount);
emit EmergencyWithdraw(msg.sender, _pid, userAmount);
}
/**
* @dev Add seconds to endTime parameter
* @param _addSeconds is an additional seconds value
*/
function changeEndTime(uint32 _addSeconds) external onlyManager {
endTime += _addSeconds;
}
/**
* @dev Changes reward token amount per second. Use this function to moderate the `lockup amount`.
* Essentially this function changes the amount of the reward which is entitled to the user
* for his token staking by the time the `endTime` is passed.
* Good practice to update pools without messing up the contract.
* @param _rewardTokenPerSecond is a new value for reward token per second
* @param _withUpdate if set in true all pools will be updated,
* otherwise only new rewardTokenPerSecond will be set
*/
function setRewardTokenPerSecond(
uint256 _rewardTokenPerSecond,
bool _withUpdate
) external onlyManager {
if (_withUpdate) {
_massUpdatePools();
}
rewardTokenPerSecond = _rewardTokenPerSecond;
}
/**
* @dev Add a new staking token to the pool. Can only be called by managers.
* @param _allocPoint is an allocation point
* @param _stakingToken is a staked token address that will be used for the new pool
* @param _withUpdate if set in true all pools will be updated,
* otherwise only the new pool will be added
*/
function add(uint16 _allocPoint, address _stakingToken, bool _withUpdate) external onlyManager {
require(!isStakingTokenSet[_stakingToken], 'Staking token was already set');
require(poolInfo.length < 5, 'No more then 5 pools can be added');
if (_withUpdate) {
_massUpdatePools();
}
uint256 lastRewardTime = block.timestamp > startTime ? block.timestamp : startTime;
totalAllocationPoint += _allocPoint;
poolInfo.push(
PoolInfo({
stakingToken: _stakingToken,
stakingTokenTotalAmount: 0,
allocationPoint: _allocPoint,
lastRewardTime: uint32(lastRewardTime),
accumulatedRewardTokenPerShare: 0
})
);
isStakingTokenSet[_stakingToken] = true;
}
/**
* @dev Update the given pool's reward token allocation point. Can only be called by managers.
* @param _pid is a pool id that exists in the list
* @param _allocPoint is an allocation point
* @param _withUpdate if set in true all pools will be updated,
* otherwise only allocation data will be updated
*/
function set(uint256 _pid, uint16 _allocPoint, bool _withUpdate) external onlyManager {
if (_withUpdate) {
_massUpdatePools();
}
totalAllocationPoint = totalAllocationPoint - poolInfo[_pid].allocationPoint + _allocPoint;
poolInfo[_pid].allocationPoint = _allocPoint;
}
/**
* @dev Update reward variables for all pools.
*/
function massUpdatePools() external whenNotPaused {
_massUpdatePools();
}
/**
* @dev Update reward variables of the given pool to be up-to-date.
*/
function updatePool(uint256 _pid) external whenNotPaused {
_updatePool(_pid);
}
/**
* @dev How many pools are in the contract
*/
function poolLength() external view returns (uint256) {
return poolInfo.length;
}
/**
* @dev Vest all pending rewards. Vest tokens means that they will be locked for the
* vestingDuration time
* @param _pid is a pool id
*/
function vest(uint256 _pid) external whenNotPaused {
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][msg.sender];
_updatePool(_pid);
uint256 pending = pendingRewardToken(_pid, msg.sender);
require(pending > 0, 'Amount of tokens can not be zero value');
uint256 unlockTime = block.timestamp + vestingDuration;
VestedBalance[] storage vestings = userVested[_pid][msg.sender];
require(vestings.length <= 100, 'User can not execute vest function more than 100 times');
vestings.push(VestedBalance({ amount: pending, unlockTime: unlockTime }));
user.remainingRewardTokenAmount = 0;
user.rewardDebt = (user.amount * pool.accumulatedRewardTokenPerShare) / SHARE_PRECISION;
emit Vested(msg.sender, _pid, pending);
}
/**
* @dev user can get his rewards for staked iUSDC/iUSDT if locked time has already occurred
* @param _pid is a pool id
*/
function withdrawVestedRewards(uint256 _pid) external {
// withdraw only `vestedTotal` amount
_updatePool(_pid);
(uint256 vested, , ) = checkVestingBalances(_pid, msg.sender);
uint256 amount;
if (vested > 0) {
uint256 length = userVested[_pid][msg.sender].length;
for (uint256 i = 0; i < length; i++) {
uint256 vestAmount = userVested[_pid][msg.sender][i].amount;
if (userVested[_pid][msg.sender][i].unlockTime > block.timestamp) {
break;
}
amount = amount + vestAmount;
delete userVested[_pid][msg.sender][i];
}
}
if (amount > 0) {
safeRewardTransfer(msg.sender, amount);
} else {
revert('Tokens are not available for now');
}
emit WithdrawVesting(msg.sender, amount);
}
/**
* @dev The user receives only `exitEarlyUserShare` - 50% tokens by default
* `exitEarlyTreasuryShare` - 20% tokens by default transfers to the treasury account
* `exitEarlyLPShare` - 30% tokens by default transfers to the LP revenue share contract
* @param _pid is a pool id
*/
function exitEarly(uint256 _pid) external {
_updatePool(_pid);
// can withdraw 50% immediately
(, uint256 vesting, ) = checkVestingBalances(_pid, msg.sender);
require(vesting > 0, 'Total vesting tokens can not be zero');
uint256 amountUser = (vesting * exitEarlyUserShare) / 1000;
uint256 amountTreasury = (vesting * exitEarlyTreasuryShare) / 1000;
uint256 amountLP = (vesting * exitEarlyLPShare) / 1000;
safeRewardTransfer(msg.sender, amountUser);
// transfer penalties
IERC20(rewardToken).safeTransfer(treasury, amountTreasury);
IERC20(rewardToken).safeTransfer(LPRevenueShare, amountLP);
_cleanVestingBalances(_pid, msg.sender);
emit ExitEarly(msg.sender, amountUser);
}
/**
* @dev Unsupported operation
* @param _pid is a pool id
*/
function lockVesting(uint256 _pid) external {
revert('Unsupported operation');
}
/**
* @dev Unsupported operation
* @param _pid is a pool id
*/
function lockPending(uint256 _pid) external {
revert('Unsupported operation');
}
/**
* @dev Return reward multiplier over the given _from to _to time.
* @param _from is a from datetime in seconds
* @param _to is a to datetime in seconds
* @return multiplier
*/
function getMultiplier(uint256 _from, uint256 _to) public view returns (uint256) {
_from = _from > startTime ? _from : startTime;
if (_from > endTime || _to < startTime) {
return 0;
} else if (_to > endTime) {
return endTime - _from;
} else return _to - _from;
}
/**
* @dev Check if provided token is staked token in the pool
* @param _tokenAddress is a checked token
* @return result true if provided token is staked token in the pool, otherwise false
*/
function isReservedToken(address _tokenAddress) public view override returns (bool) {
uint256 length = poolInfo.length;
for (uint256 pid; pid < length; ++pid) {
if (_tokenAddress == poolInfo[pid].stakingToken) {
return true;
}
}
return false;
}
/**
* @dev View function to see pending reward tokens on the frontend.
* @param _pid is a pool id
* @param _user is a user address to check rewards
* @return pending reward token amount
*/
function pendingRewardToken(uint256 _pid, address _user) public view returns (uint256 pending) {
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][_user];
uint256 acc = pool.accumulatedRewardTokenPerShare;
if (block.timestamp > pool.lastRewardTime && pool.stakingTokenTotalAmount != 0) {
uint256 multiplier = getMultiplier(pool.lastRewardTime, block.timestamp);
uint256 tokenReward = (multiplier * rewardTokenPerSecond * pool.allocationPoint) /
totalAllocationPoint;
acc += (tokenReward * SHARE_PRECISION) / pool.stakingTokenTotalAmount;
}
pending =
(user.amount * acc) /
SHARE_PRECISION -
user.rewardDebt +
user.remainingRewardTokenAmount;
}
/**
* @dev Information on a user's total/vestedTotal/vestingTotal balances
* @param _pid is a pool id
* @param _user is a user address to check rewards
* @return vestedTotal is the number of vested tokens (that are available to withdraw)
* @return vestingTotal is the number of vesting tokens (that are not available to withdraw yet)
* @return vestData is the list with the number of tokens and their unlock time
*/
function checkVestingBalances(
uint256 _pid,
address _user
)
public
view
returns (
uint256 vestedTotal, // available to withdraw
uint256 vestingTotal,
VestedBalance[] memory vestData
)
{
VestedBalance[] storage vests = userVested[_pid][_user];
uint256 index;
for (uint256 i = 0; i < vests.length; i++) {
if (vests[i].unlockTime > block.timestamp) {
if (index == 0) {
vestData = new VestedBalance[](vests.length - i);
}
vestData[index] = vests[i];
index++;
vestingTotal += vests[i].amount;
} else {
vestedTotal = vestedTotal + vests[i].amount;
}
}
}
function _cleanVestingBalances(uint256 _pid, address _user) internal {
VestedBalance[] storage vests = userVested[_pid][_user];
for (uint256 i = 0; i < vests.length; i++) {
if (vests[i].unlockTime > block.timestamp) {
delete vests[i];
}
}
}
/**
* @dev Safe reward token transfer function.
* Revert error if not enough tokens on the smart contract
* Just in case the pool does not have enough reward tokens.
* @param _to is an address to transfer rewards
* @param _amount is a number of reward tokens that will be transferred to the user
*/
function safeRewardTransfer(address _to, uint256 _amount) private {
uint256 rewardTokenBalance = IERC20(rewardToken).balanceOf(address(this));
if (_amount > rewardTokenBalance) {
revert('Not enough tokens on the smart contract');
} else {
IERC20(rewardToken).safeTransfer(_to, _amount);
}
}
/**
* @dev Update reward variables for all pools
*/
function _massUpdatePools() private {
uint256 length = poolInfo.length;
for (uint256 pid; pid < length; ++pid) {
_updatePool(pid);
}
}
/**
* @dev Update reward variables of the given pool to be up-to-date.
* @param _pid is a pool id
*/
function _updatePool(uint256 _pid) private {
PoolInfo storage pool = poolInfo[_pid];
if (block.timestamp <= pool.lastRewardTime) {
return;
}
if (pool.stakingTokenTotalAmount == 0) {
pool.lastRewardTime = uint32(block.timestamp);
return;
}
uint256 multiplier = getMultiplier(pool.lastRewardTime, block.timestamp);
uint256 rewardTokenAmount = (multiplier * rewardTokenPerSecond * pool.allocationPoint) /
totalAllocationPoint;
pool.accumulatedRewardTokenPerShare +=
(rewardTokenAmount * SHARE_PRECISION) /
pool.stakingTokenTotalAmount;
pool.lastRewardTime = uint32(block.timestamp);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.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 anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_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.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-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.
*/
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].
*/
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.6.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.8.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-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;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
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));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
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");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
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");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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
* ====
*
* [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://diligence.consensys.net/posts/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.5.11/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);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (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;
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { ITokenBalance } from './interfaces/ITokenBalance.sol';
import { ManagerRole } from './roles/ManagerRole.sol';
import './helpers/TransferHelper.sol' as TransferHelper;
import './Constants.sol' as Constants;
/**
* @title BalanceManagement
* @notice Base contract for the withdrawal of tokens, except for reserved ones
*/
abstract contract BalanceManagement is ManagerRole {
/**
* @notice Emitted when the specified token is reserved
*/
error ReservedTokenError();
/**
* @notice Performs the withdrawal of tokens, except for reserved ones
* @dev Use the "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" address for the native token
* @param _tokenAddress The address of the token
* @param _tokenAmount The amount of the token
*/
function cleanup(address _tokenAddress, uint256 _tokenAmount) external onlyManager {
if (isReservedToken(_tokenAddress)) {
revert ReservedTokenError();
}
if (_tokenAddress == Constants.NATIVE_TOKEN_ADDRESS) {
TransferHelper.safeTransferNative(msg.sender, _tokenAmount);
} else {
TransferHelper.safeTransfer(_tokenAddress, msg.sender, _tokenAmount);
}
}
/**
* @notice Getter of the token balance of the current contract
* @dev Use the "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" address for the native token
* @param _tokenAddress The address of the token
* @return The token balance of the current contract
*/
function tokenBalance(address _tokenAddress) public view returns (uint256) {
if (_tokenAddress == Constants.NATIVE_TOKEN_ADDRESS) {
return address(this).balance;
} else {
return ITokenBalance(_tokenAddress).balanceOf(address(this));
}
}
/**
* @notice Getter of the reserved token flag
* @dev Override to add reserved token addresses
* @param _tokenAddress The address of the token
* @return The reserved token flag
*/
function isReservedToken(address _tokenAddress) public view virtual returns (bool) {
// The function returns false by default.
// The explicit return statement is omitted to avoid the unused parameter warning.
// See https://github.com/ethereum/solidity/issues/5295
}
}// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.19; /** * @dev The default token decimals value */ uint256 constant DECIMALS_DEFAULT = 18; /** * @dev The maximum uint256 value for swap amount limit settings */ uint256 constant INFINITY = type(uint256).max; /** * @dev The default limit of account list size */ uint256 constant LIST_SIZE_LIMIT_DEFAULT = 100; /** * @dev The limit of swap router list size */ uint256 constant LIST_SIZE_LIMIT_ROUTERS = 200; /** * @dev The factor for percentage settings. Example: 100 is 0.1% */ uint256 constant MILLIPERCENT_FACTOR = 100_000; /** * @dev The de facto standard address to denote the native token */ address constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @notice Optional value structure
* @dev Is used in mappings to allow zero values
* @param isSet Value presence flag
* @param value Numeric value
*/
struct OptionalValue {
bool isSet;
uint256 value;
}
/**
* @notice Key-to-value structure
* @dev Is used as an array parameter item to perform multiple key-value settings
* @param key Numeric key
* @param value Numeric value
*/
struct KeyToValue {
uint256 key;
uint256 value;
}
/**
* @notice Key-to-value structure for address values
* @dev Is used as an array parameter item to perform multiple key-value settings with address values
* @param key Numeric key
* @param value Address value
*/
struct KeyToAddressValue {
uint256 key;
address value;
}
/**
* @notice Address-to-flag structure
* @dev Is used as an array parameter item to perform multiple settings
* @param account Account address
* @param flag Flag value
*/
struct AccountToFlag {
address account;
bool flag;
}
/**
* @notice Emitted when a list exceeds the size limit
*/
error ListSizeLimitError();
/**
* @notice Sets or updates a value in a combined map (a mapping with a key list and key index mapping)
* @param _map The mapping reference
* @param _keyList The key list reference
* @param _keyIndexMap The key list index mapping reference
* @param _key The numeric key
* @param _value The address value
* @param _sizeLimit The map and list size limit
* @return isNewKey True if the key was just added, otherwise false
*/
function combinedMapSet(
mapping(uint256 => address) storage _map,
uint256[] storage _keyList,
mapping(uint256 => OptionalValue) storage _keyIndexMap,
uint256 _key,
address _value,
uint256 _sizeLimit
) returns (bool isNewKey) {
isNewKey = !_keyIndexMap[_key].isSet;
if (isNewKey) {
uniqueListAdd(_keyList, _keyIndexMap, _key, _sizeLimit);
}
_map[_key] = _value;
}
/**
* @notice Removes a value from a combined map (a mapping with a key list and key index mapping)
* @param _map The mapping reference
* @param _keyList The key list reference
* @param _keyIndexMap The key list index mapping reference
* @param _key The numeric key
* @return isChanged True if the combined map was changed, otherwise false
*/
function combinedMapRemove(
mapping(uint256 => address) storage _map,
uint256[] storage _keyList,
mapping(uint256 => OptionalValue) storage _keyIndexMap,
uint256 _key
) returns (bool isChanged) {
isChanged = _keyIndexMap[_key].isSet;
if (isChanged) {
delete _map[_key];
uniqueListRemove(_keyList, _keyIndexMap, _key);
}
}
/**
* @notice Adds a value to a unique value list (a list with value index mapping)
* @param _list The list reference
* @param _indexMap The value index mapping reference
* @param _value The numeric value
* @param _sizeLimit The list size limit
* @return isChanged True if the list was changed, otherwise false
*/
function uniqueListAdd(
uint256[] storage _list,
mapping(uint256 => OptionalValue) storage _indexMap,
uint256 _value,
uint256 _sizeLimit
) returns (bool isChanged) {
isChanged = !_indexMap[_value].isSet;
if (isChanged) {
if (_list.length >= _sizeLimit) {
revert ListSizeLimitError();
}
_indexMap[_value] = OptionalValue(true, _list.length);
_list.push(_value);
}
}
/**
* @notice Removes a value from a unique value list (a list with value index mapping)
* @param _list The list reference
* @param _indexMap The value index mapping reference
* @param _value The numeric value
* @return isChanged True if the list was changed, otherwise false
*/
function uniqueListRemove(
uint256[] storage _list,
mapping(uint256 => OptionalValue) storage _indexMap,
uint256 _value
) returns (bool isChanged) {
OptionalValue storage indexItem = _indexMap[_value];
isChanged = indexItem.isSet;
if (isChanged) {
uint256 itemIndex = indexItem.value;
uint256 lastIndex = _list.length - 1;
if (itemIndex != lastIndex) {
uint256 lastValue = _list[lastIndex];
_list[itemIndex] = lastValue;
_indexMap[lastValue].value = itemIndex;
}
_list.pop();
delete _indexMap[_value];
}
}
/**
* @notice Adds a value to a unique address value list (a list with value index mapping)
* @param _list The list reference
* @param _indexMap The value index mapping reference
* @param _value The address value
* @param _sizeLimit The list size limit
* @return isChanged True if the list was changed, otherwise false
*/
function uniqueAddressListAdd(
address[] storage _list,
mapping(address => OptionalValue) storage _indexMap,
address _value,
uint256 _sizeLimit
) returns (bool isChanged) {
isChanged = !_indexMap[_value].isSet;
if (isChanged) {
if (_list.length >= _sizeLimit) {
revert ListSizeLimitError();
}
_indexMap[_value] = OptionalValue(true, _list.length);
_list.push(_value);
}
}
/**
* @notice Removes a value from a unique address value list (a list with value index mapping)
* @param _list The list reference
* @param _indexMap The value index mapping reference
* @param _value The address value
* @return isChanged True if the list was changed, otherwise false
*/
function uniqueAddressListRemove(
address[] storage _list,
mapping(address => OptionalValue) storage _indexMap,
address _value
) returns (bool isChanged) {
OptionalValue storage indexItem = _indexMap[_value];
isChanged = indexItem.isSet;
if (isChanged) {
uint256 itemIndex = indexItem.value;
uint256 lastIndex = _list.length - 1;
if (itemIndex != lastIndex) {
address lastValue = _list[lastIndex];
_list[itemIndex] = lastValue;
_indexMap[lastValue].value = itemIndex;
}
_list.pop();
delete _indexMap[_value];
}
}
/**
* @notice Adds or removes a value to/from a unique address value list (a list with value index mapping)
* @dev The list size limit is checked on items adding only
* @param _list The list reference
* @param _indexMap The value index mapping reference
* @param _value The address value
* @param _flag The value inclusion flag
* @param _sizeLimit The list size limit
* @return isChanged True if the list was changed, otherwise false
*/
function uniqueAddressListUpdate(
address[] storage _list,
mapping(address => OptionalValue) storage _indexMap,
address _value,
bool _flag,
uint256 _sizeLimit
) returns (bool isChanged) {
return
_flag
? uniqueAddressListAdd(_list, _indexMap, _value, _sizeLimit)
: uniqueAddressListRemove(_list, _indexMap, _value);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @notice Emitted when an approval action fails
*/
error SafeApproveError();
/**
* @notice Emitted when a transfer action fails
*/
error SafeTransferError();
/**
* @notice Emitted when a transferFrom action fails
*/
error SafeTransferFromError();
/**
* @notice Emitted when a transfer of the native token fails
*/
error SafeTransferNativeError();
/**
* @notice Safely approve the token to the account
* @param _token The token address
* @param _to The token approval recipient address
* @param _value The token approval amount
*/
function safeApprove(address _token, address _to, uint256 _value) {
// 0x095ea7b3 is the selector for "approve(address,uint256)"
(bool success, bytes memory data) = _token.call(
abi.encodeWithSelector(0x095ea7b3, _to, _value)
);
bool condition = success && (data.length == 0 || abi.decode(data, (bool)));
if (!condition) {
revert SafeApproveError();
}
}
/**
* @notice Safely transfer the token to the account
* @param _token The token address
* @param _to The token transfer recipient address
* @param _value The token transfer amount
*/
function safeTransfer(address _token, address _to, uint256 _value) {
// 0xa9059cbb is the selector for "transfer(address,uint256)"
(bool success, bytes memory data) = _token.call(
abi.encodeWithSelector(0xa9059cbb, _to, _value)
);
bool condition = success && (data.length == 0 || abi.decode(data, (bool)));
if (!condition) {
revert SafeTransferError();
}
}
/**
* @notice Safely transfer the token between the accounts
* @param _token The token address
* @param _from The token transfer source address
* @param _to The token transfer recipient address
* @param _value The token transfer amount
*/
function safeTransferFrom(address _token, address _from, address _to, uint256 _value) {
// 0x23b872dd is the selector for "transferFrom(address,address,uint256)"
(bool success, bytes memory data) = _token.call(
abi.encodeWithSelector(0x23b872dd, _from, _to, _value)
);
bool condition = success && (data.length == 0 || abi.decode(data, (bool)));
if (!condition) {
revert SafeTransferFromError();
}
}
/**
* @notice Safely transfer the native token to the account
* @param _to The native token transfer recipient address
* @param _value The native token transfer amount
*/
function safeTransferNative(address _to, uint256 _value) {
(bool success, ) = _to.call{ value: _value }(new bytes(0));
if (!success) {
revert SafeTransferNativeError();
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
/**
* @title IRevenueShare
* @notice Revenue share interface
*/
interface IRevenueShare {
/**
* @notice Withdraws tokens
*/
function withdraw() external;
/**
* @notice Locks tokens
* @param _amount The number of tokens to lock
*/
function lock(uint256 _amount) external;
/**
* @notice Locks tokens on behalf of the user
* @param _amount The number of tokens to lock
* @param _user The address of the user
*/
function lock(uint256 _amount, address _user) external;
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @title ITokenBalance
* @notice Token balance interface
*/
interface ITokenBalance {
/**
* @notice Getter of the token balance by the account
* @param _account The account address
* @return Token balance
*/
function balanceOf(address _account) external view returns (uint256);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { Pausable as PausableBase } from '@openzeppelin/contracts/security/Pausable.sol';
import { ManagerRole } from './roles/ManagerRole.sol';
/**
* @title Pausable
* @notice Base contract that implements the emergency pause mechanism
*/
abstract contract Pausable is PausableBase, ManagerRole {
/**
* @notice Enter pause state
*/
function pause() external onlyManager whenNotPaused {
_pause();
}
/**
* @notice Exit pause state
*/
function unpause() external onlyManager whenPaused {
_unpause();
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { Ownable } from '@openzeppelin/contracts/access/Ownable.sol';
import { RoleBearers } from './RoleBearers.sol';
/**
* @title ManagerRole
* @notice Base contract that implements the Manager role.
* The manager role is a high-permission role for core team members only.
* Managers can set vaults and routers addresses, fees, cross-chain protocols,
* and other parameters for Interchain (cross-chain) swaps and single-network swaps.
* Please note, the manager role is unique for every contract,
* hence different addresses may be assigned as managers for different contracts.
*/
abstract contract ManagerRole is Ownable, RoleBearers {
bytes32 private constant ROLE_KEY = keccak256('Manager');
/**
* @notice Emitted when the Manager role status for the account is updated
* @param account The account address
* @param value The Manager role status flag
*/
event SetManager(address indexed account, bool indexed value);
/**
* @notice Emitted when the Manager role status for the account is renounced
* @param account The account address
*/
event RenounceManagerRole(address indexed account);
/**
* @notice Emitted when the caller is not a Manager role bearer
*/
error OnlyManagerError();
/**
* @dev Modifier to check if the caller is a Manager role bearer
*/
modifier onlyManager() {
if (!isManager(msg.sender)) {
revert OnlyManagerError();
}
_;
}
/**
* @notice Updates the Manager role status for the account
* @param _account The account address
* @param _value The Manager role status flag
*/
function setManager(address _account, bool _value) public onlyOwner {
_setRoleBearer(ROLE_KEY, _account, _value);
emit SetManager(_account, _value);
}
/**
* @notice Renounces the Manager role
*/
function renounceManagerRole() external onlyManager {
_setRoleBearer(ROLE_KEY, msg.sender, false);
emit RenounceManagerRole(msg.sender);
}
/**
* @notice Getter of the Manager role bearer count
* @return The Manager role bearer count
*/
function managerCount() external view returns (uint256) {
return _roleBearerCount(ROLE_KEY);
}
/**
* @notice Getter of the complete list of the Manager role bearers
* @return The complete list of the Manager role bearers
*/
function fullManagerList() external view returns (address[] memory) {
return _fullRoleBearerList(ROLE_KEY);
}
/**
* @notice Getter of the Manager role bearer status
* @param _account The account address
*/
function isManager(address _account) public view returns (bool) {
return _isRoleBearer(ROLE_KEY, _account);
}
function _initRoles(
address _owner,
address[] memory _managers,
bool _addOwnerToManagers
) internal {
address ownerAddress = _owner == address(0) ? msg.sender : _owner;
for (uint256 index; index < _managers.length; index++) {
setManager(_managers[index], true);
}
if (_addOwnerToManagers && !isManager(ownerAddress)) {
setManager(ownerAddress, true);
}
if (ownerAddress != msg.sender) {
transferOwnership(ownerAddress);
}
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import '../Constants.sol' as Constants;
import '../DataStructures.sol' as DataStructures;
/**
* @title RoleBearers
* @notice Base contract that implements role-based access control
* @dev A custom implementation providing full role bearer lists
*/
abstract contract RoleBearers {
mapping(bytes32 /*roleKey*/ => address[] /*roleBearers*/) private roleBearerTable;
mapping(bytes32 /*roleKey*/ => mapping(address /*account*/ => DataStructures.OptionalValue /*status*/))
private roleBearerIndexTable;
function _setRoleBearer(bytes32 _roleKey, address _account, bool _value) internal {
DataStructures.uniqueAddressListUpdate(
roleBearerTable[_roleKey],
roleBearerIndexTable[_roleKey],
_account,
_value,
Constants.LIST_SIZE_LIMIT_DEFAULT
);
}
function _isRoleBearer(bytes32 _roleKey, address _account) internal view returns (bool) {
return roleBearerIndexTable[_roleKey][_account].isSet;
}
function _roleBearerCount(bytes32 _roleKey) internal view returns (uint256) {
return roleBearerTable[_roleKey].length;
}
function _fullRoleBearerList(bytes32 _roleKey) internal view returns (address[] memory) {
return roleBearerTable[_roleKey];
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"uint256","name":"_rewardTokenPerSecond","type":"uint256"},{"internalType":"uint32","name":"_startTime","type":"uint32"},{"internalType":"uint32","name":"_endTimeAddSeconds","type":"uint32"},{"internalType":"uint256","name":"_vestingDuration","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ListSizeLimitError","type":"error"},{"inputs":[],"name":"OnlyManagerError","type":"error"},{"inputs":[],"name":"ReservedTokenError","type":"error"},{"inputs":[],"name":"SafeTransferError","type":"error"},{"inputs":[],"name":"SafeTransferNativeError","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EmergencyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ExitEarly","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Locked","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":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"RenounceManagerRole","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"bool","name":"value","type":"bool"}],"name":"SetManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Vested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawVesting","type":"event"},{"inputs":[],"name":"LPRevenueShare","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_allocPoint","type":"uint16"},{"internalType":"address","name":"_stakingToken","type":"address"},{"internalType":"bool","name":"_withUpdate","type":"bool"}],"name":"add","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_addSeconds","type":"uint32"}],"name":"changeEndTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"checkVestingBalances","outputs":[{"internalType":"uint256","name":"vestedTotal","type":"uint256"},{"internalType":"uint256","name":"vestingTotal","type":"uint256"},{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"unlockTime","type":"uint256"}],"internalType":"struct StablecoinFarm.VestedBalance[]","name":"vestData","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"cleanup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endTime","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"exitEarly","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exitEarlyLPShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exitEarlyTreasuryShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exitEarlyUserShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fullManagerList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_from","type":"uint256"},{"internalType":"uint256","name":"_to","type":"uint256"}],"name":"getMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"isReservedToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isStakingTokenSet","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"lockPending","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"lockVesting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"managerCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"massUpdatePools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"pendingRewardToken","outputs":[{"internalType":"uint256","name":"pending","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolInfo","outputs":[{"internalType":"address","name":"stakingToken","type":"address"},{"internalType":"uint256","name":"stakingTokenTotalAmount","type":"uint256"},{"internalType":"uint256","name":"accumulatedRewardTokenPerShare","type":"uint256"},{"internalType":"uint32","name":"lastRewardTime","type":"uint32"},{"internalType":"uint16","name":"allocationPoint","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceManagerRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardTokenPerSecond","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint16","name":"_allocPoint","type":"uint16"},{"internalType":"bool","name":"_withUpdate","type":"bool"}],"name":"set","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newRevenueShare","type":"address"}],"name":"setLPRevenueShare","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"bool","name":"_value","type":"bool"}],"name":"setManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_userPercent","type":"uint256"},{"internalType":"uint256","name":"_treasuryPercent","type":"uint256"},{"internalType":"uint256","name":"_lpPercent","type":"uint256"}],"name":"setPercentsShare","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rewardTokenPerSecond","type":"uint256"},{"internalType":"bool","name":"_withUpdate","type":"bool"}],"name":"setRewardTokenPerSecond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newTreasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startTime","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"tokenBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAllocationPoint","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":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"updatePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"userInfo","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"rewardDebt","type":"uint256"},{"internalType":"uint256","name":"remainingRewardTokenAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userVested","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"unlockTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"vest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vestingDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"withdrawVestedRewards","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60e06040526000600a556101f4600c5560c8600d5561012c600e553480156200002757600080fd5b5060405162003126380380620031268339810160408190526200004a9162000125565b6000805460ff191690556200005f33620000b2565b6001600160a01b038516608052600584905563ffffffff831660a08190526200008a90839062000191565b600b805463ffffffff191663ffffffff9290921691909117905560c05250620001c492505050565b600080546001600160a01b03838116610100818102610100600160a81b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b805163ffffffff811681146200012057600080fd5b919050565b600080600080600060a086880312156200013e57600080fd5b85516001600160a01b03811681146200015657600080fd5b602087015190955093506200016e604087016200010b565b92506200017e606087016200010b565b9150608086015190509295509295909350565b63ffffffff818116838216019080821115620001bd57634e487b7160e01b600052601160045260246000fd5b5092915050565b60805160a05160c051612eec6200023a60003960008181610335015261125e0152600081816105060152818161154901528181611576015281816115b80152818161179a01526117c701526000818161073601528181610c5301528181610c8d015281816120ea01526121cc0152612eec6000f3fe608060405234801561001057600080fd5b50600436106102d65760003560e01c80638da5cb5b11610182578063cf42947b116100e9578063e859c0b5116100a2578063f2fde38b1161007c578063f2fde38b1461070b578063f3ae24151461071e578063f7c618c114610731578063fc2aff3a1461075857600080fd5b8063e859c0b5146106dc578063eedc966a146106e5578063f0f44260146106f857600080fd5b8063cf42947b14610658578063d1c1b4a81461066b578063d1c339d01461067e578063d3e33ddd14610691578063d8e6e417146106a4578063e3725b15146106c757600080fd5b80639dd2a9361161013b5780639dd2a93614610543578063a1a6690f14610603578063a5e90eee1461060c578063a64b1d5f1461061f578063c2c518e114610628578063ca45412d1461063057600080fd5b80638da5cb5b146105565780638dbb1e3a1461056c57806393f1a40b1461057f578063957cb949146105d457806395ea0db1146105dd57806398ec8da6146105f057600080fd5b8063440d724811610241578063630b5ba1116101fa57806378e97925116101d457806378e97925146105015780637b0472f0146105285780638456cb591461053b57806387642b7a1461054357600080fd5b8063630b5ba1146104de5780636a760b80146104e6578063715018a6146104f957600080fd5b8063440d72481461044c578063441a3e701461046f57806351eb05a6146104825780635312ea8e146104955780635c975abb146104a857806361d027b3146104b357600080fd5b806331326d161161029357806331326d16146103ce5780633197cbb6146103d75780633b57e4af146103fc5780633c6a4e611461040f5780633e4a56fb146104225780633f4ba83a1461044457600080fd5b8063081e3eda146102db578063103b7397146102f25780631514617e146103305780631526fe27146103575780631653fd33146103a657806330eb1278146103b9575b600080fd5b6006545b6040519081526020015b60405180910390f35b600080516020612e9783398151915260005260016020527f3c2285c553468ca8f30447b24bb463c127f1b840e23a0cafa23caa79d906669a546102df565b6102df7f000000000000000000000000000000000000000000000000000000000000000081565b61036a610365366004612a13565b610770565b604080516001600160a01b03909616865260208601949094529284019190915263ffffffff16606083015261ffff16608082015260a0016102e9565b6102df6103b4366004612a43565b6107c8565b6103cc6103c7366004612a6f565b61090c565b005b6102df600d5481565b600b546103e79063ffffffff1681565b60405163ffffffff90911681526020016102e9565b6103cc61040a366004612a13565b610997565b6103cc61041d366004612a13565b610b66565b610435610430366004612a43565b610cfc565b6040516102e993929190612a99565b6103cc610ebe565b61045f61045a366004612af9565b610ef6565b60405190151581526020016102e9565b6103cc61047d366004612b1b565b610f61565b6103cc610490366004612a13565b6110c0565b6103cc6104a3366004612a13565b6110d4565b60005460ff1661045f565b6003546104c6906001600160a01b031681565b6040516001600160a01b0390911681526020016102e9565b6103cc61118c565b6103cc6104f4366004612a13565b61119c565b6103cc6113b8565b6103e77f000000000000000000000000000000000000000000000000000000000000000081565b6103cc610536366004612b1b565b6113ca565b6103cc6114cf565b6103cc610551366004612a13565b611505565b60005461010090046001600160a01b03166104c6565b6102df61057a366004612b1b565b611545565b6105b961058d366004612a43565b600860209081526000928352604080842090915290825290208054600182015460029092015490919083565b604080519384526020840192909252908201526060016102e9565b6102df600c5481565b6103cc6105eb366004612af9565b611628565b6103cc6105fe366004612b5d565b61169d565b6102df600a5481565b6103cc61061a366004612ba4565b611954565b6102df60055481565b6103cc6119b1565b61064361063e366004612bdb565b611a1e565b604080519283526020830191909152016102e9565b6103cc610666366004612c10565b611a68565b6103cc610679366004612c36565b611aca565b6004546104c6906001600160a01b031681565b6103cc61069f366004612c5b565b611b97565b61045f6106b2366004612af9565b60076020526000908152604090205460ff1681565b6106cf611c23565b6040516102e99190612c87565b6102df600e5481565b6102df6106f3366004612af9565b611c3c565b6103cc610706366004612af9565b611cd7565b6103cc610719366004612af9565b611d4c565b61045f61072c366004612af9565b611dc2565b6104c67f000000000000000000000000000000000000000000000000000000000000000081565b6103cc610766366004612cd4565b611e02565b905090565b6006818154811061078057600080fd5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b039092169350919063ffffffff811690640100000000900461ffff1685565b600080600684815481106107de576107de612cf9565b600091825260208083208784526008825260408085206001600160a01b03891686529092529220600260049092029092019081015460038201549193509063ffffffff16421180156108335750600183015415155b156108c35760038301546000906108509063ffffffff1642611545565b90506000600a548560030160049054906101000a900461ffff1661ffff166005548461087c9190612d25565b6108869190612d25565b6108909190612d3c565b60018601549091506108aa670de0b6b3a764000083612d25565b6108b49190612d3c565b6108be9084612d5e565b925050505b600282015460018301548354670de0b6b3a7640000906108e4908590612d25565b6108ee9190612d3c565b6108f89190612d71565b6109029190612d5e565b9695505050505050565b61091533611dc2565b61093257604051637c3ea23f60e01b815260040160405180910390fd5b61093b82610ef6565b1561095957604051634477699960e11b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0383160161098c576109883382611e3c565b5050565b610988823383611ecf565b6109a081611fc1565b60006109ac8233610cfc565b50509050600080821115610aca576000838152600960209081526040808320338452909152812054905b81811015610ac75760008581526009602090815260408083203384529091528120805483908110610a0957610a09612cf9565b6000918252602080832060029092029091015488835260098252604080842033855290925291208054919250429184908110610a4757610a47612cf9565b9060005260206000209060020201600101541115610a655750610ac7565b610a6f8185612d5e565b6000878152600960209081526040808320338452909152902080549195509083908110610a9e57610a9e612cf9565b600091825260208220600290910201818155600101555080610abf81612d84565b9150506109d6565b50505b8015610adf57610ada33826120d2565b610b2c565b60405162461bcd60e51b815260206004820181905260248201527f546f6b656e7320617265206e6f7420617661696c61626c6520666f72206e6f7760448201526064015b60405180910390fd5b60405181815233907f7391907e2ab707a2bed13f0fa64fdaa84d5fb991113e1dad366f47b55ec6e6119060200160405180910390a2505050565b610b6f81611fc1565b6000610b7b8233610cfc565b5091505060008111610bdb5760405162461bcd60e51b8152602060048201526024808201527f546f74616c2076657374696e6720746f6b656e732063616e206e6f74206265206044820152637a65726f60e01b6064820152608401610b23565b60006103e8600c5483610bee9190612d25565b610bf89190612d3c565b905060006103e8600d5484610c0d9190612d25565b610c179190612d3c565b905060006103e8600e5485610c2c9190612d25565b610c369190612d3c565b9050610c4233846120d2565b600354610c7c906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169116846121ef565b600454610cb6906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169116836121ef565b610cc08533612252565b60405183815233907f1be3144880c716b1152eab5fbba4f339f9590430ecfd4f1c7cd4a10e3c2797a59060200160405180910390a25050505050565b60008281526009602090815260408083206001600160a01b03851684529091528120819060609082805b8254811015610eb45742838281548110610d4257610d42612cf9565b9060005260206000209060020201600101541115610e705781600003610dd0578254610d6f908290612d71565b67ffffffffffffffff811115610d8757610d87612d9d565b604051908082528060200260200182016040528015610dcc57816020015b6040805180820190915260008082526020820152815260200190600190039081610da55790505b5093505b828181548110610de257610de2612cf9565b906000526020600020906002020160405180604001604052908160008201548152602001600182015481525050848381518110610e2157610e21612cf9565b60200260200101819052508180610e3790612d84565b925050828181548110610e4c57610e4c612cf9565b90600052602060002090600202016000015485610e699190612d5e565b9450610ea2565b828181548110610e8257610e82612cf9565b90600052602060002090600202016000015486610e9f9190612d5e565b95505b80610eac81612d84565b915050610d26565b5050509250925092565b610ec733611dc2565b610ee457604051637c3ea23f60e01b815260040160405180910390fd5b610eec6122eb565b610ef4612334565b565b600654600090815b81811015610f575760068181548110610f1957610f19612cf9565b60009182526020909120600490910201546001600160a01b0390811690851603610f47575060019392505050565b610f5081612d84565b9050610efe565b5060009392505050565b610f69612386565b600060068381548110610f7e57610f7e612cf9565b600091825260208083208684526008825260408085203386529092529220805460049092029092019250831115610ff75760405162461bcd60e51b815260206004820152601c60248201527f43616e206e6f74207769746864726177207468697320616d6f756e74000000006044820152606401610b23565b61100084611fc1565b61100a84336107c8565b6002820155805483908290600090611023908490612d71565b925050819055508282600101600082825461103e9190612d71565b909155505060028201548154670de0b6b3a76400009161105d91612d25565b6110679190612d3c565b60018201558154611082906001600160a01b031633856121ef565b604051838152849033907ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568906020015b60405180910390a350505050565b6110c8612386565b6110d181611fc1565b50565b6000600682815481106110e9576110e9612cf9565b600091825260208083208584526008825260408085203386529092529083208054600493909302909101600181018054919550919383929161112c908490612d71565b909155505060008083556001830181905560028301558254611158906001600160a01b031633836121ef565b604051818152849033907fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae0595906020016110b2565b611194612386565b610ef46123cc565b6111a4612386565b6000600682815481106111b9576111b9612cf9565b600091825260208083208584526008825260408085203386529092529220600490910290910191506111ea83611fc1565b60006111f684336107c8565b9050600081116112575760405162461bcd60e51b815260206004820152602660248201527f416d6f756e74206f6620746f6b656e732063616e206e6f74206265207a65726f6044820152652076616c756560d01b6064820152608401610b23565b60006112837f000000000000000000000000000000000000000000000000000000000000000042612d5e565b60008681526009602090815260408083203384529091529020805491925090606410156113115760405162461bcd60e51b815260206004820152603660248201527f557365722063616e206e6f74206578656375746520766573742066756e6374696044820152756f6e206d6f7265207468616e203130302074696d657360501b6064820152608401610b23565b60408051808201909152838152602080820184815283546001818101865560008681529384209451600292830290950194855591519390910192909255858201558501548454670de0b6b3a76400009161136a91612d25565b6113749190612d3c565b6001850155604051838152869033907ffbeff59d2bfda0d79ea8a29f8c57c66d48c7a13eabbdb90908d9115ec41c9dc69060200160405180910390a3505050505050565b6113c06123f3565b610ef46000612453565b6113d2612386565b6000600683815481106113e7576113e7612cf9565b6000918252602080832086845260088252604080852033865290925292206004909102909101915061141884611fc1565b815461142f906001600160a01b03163330866124ac565b61143984336107c8565b6002820155805483908290600090611452908490612d5e565b925050819055508282600101600082825461146d9190612d5e565b909155505060028201548154670de0b6b3a76400009161148c91612d25565b6114969190612d3c565b6001820155604051838152849033907f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90906020016110b2565b6114d833611dc2565b6114f557604051637c3ea23f60e01b815260040160405180910390fd5b6114fd612386565b610ef46124e4565b60405162461bcd60e51b81526020600482015260156024820152742ab739bab83837b93a32b21037b832b930ba34b7b760591b6044820152606401610b23565b60007f000000000000000000000000000000000000000000000000000000000000000063ffffffff1683116115a0577f000000000000000000000000000000000000000000000000000000000000000063ffffffff166115a2565b825b600b5490935063ffffffff168311806115e057507f000000000000000000000000000000000000000000000000000000000000000063ffffffff1682105b156115ed57506000611622565b600b5463ffffffff1682111561161857600b5461161190849063ffffffff16612d71565b9050611622565b6116118383612d71565b92915050565b6116306123f3565b6001600160a01b03811661167b5760405162461bcd60e51b81526020600482015260126024820152712d32b9379030b2323932b9b99032b93937b960711b6044820152606401610b23565b600480546001600160a01b0319166001600160a01b0392909216919091179055565b6116a633611dc2565b6116c357604051637c3ea23f60e01b815260040160405180910390fd5b6001600160a01b03821660009081526007602052604090205460ff161561172c5760405162461bcd60e51b815260206004820152601d60248201527f5374616b696e6720746f6b656e2077617320616c7265616479207365740000006044820152606401610b23565b6006546005116117885760405162461bcd60e51b815260206004820152602160248201527f4e6f206d6f7265207468656e203520706f6f6c732063616e20626520616464656044820152601960fa1b6064820152608401610b23565b8015611796576117966123cc565b60007f000000000000000000000000000000000000000000000000000000000000000063ffffffff1642116117f1577f000000000000000000000000000000000000000000000000000000000000000063ffffffff166117f3565b425b90508361ffff16600a600082825461180b9190612d5e565b90915550506040805160a0810182526001600160a01b039485168082526000602080840182815284860183815263ffffffff9788166060870190815261ffff9b8c1660808801908152600680546001808201835591885298517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f6004909a02998a0180546001600160a01b03191691909e1617909c5592517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d4088015590517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d41870155517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d42909501805491519590971665ffffffffffff19909116176401000000009490991693909302979097179093559185526007909152909220805460ff1916909117905550565b61195c6123f3565b611975600080516020612e978339815191528383612521565b604051811515906001600160a01b038416907fbe9474bb3e78da7e315cdffa5cfa30b767fcc95bbf44a6197da60228eea1028690600090a35050565b6119ba33611dc2565b6119d757604051637c3ea23f60e01b815260040160405180910390fd5b6119f1600080516020612e97833981519152336000612521565b60405133907f6cc2c67081f55c2fffb7c008fa995fbbf890f48c7c16fba93d8220f00dc84cc590600090a2565b60096020528260005260406000206020528160005260406000208181548110611a4657600080fd5b6000918252602090912060029091020180546001909101549093509150839050565b611a7133611dc2565b611a8e57604051637c3ea23f60e01b815260040160405180910390fd5b600b8054829190600090611aa990849063ffffffff16612db3565b92506101000a81548163ffffffff021916908363ffffffff16021790555050565b611ad333611dc2565b611af057604051637c3ea23f60e01b815260040160405180910390fd5b8015611afe57611afe6123cc565b8161ffff1660068481548110611b1657611b16612cf9565b6000918252602090912060049091020160030154600a54611b4391640100000000900461ffff1690612d71565b611b4d9190612d5e565b600a819055508160068481548110611b6757611b67612cf9565b906000526020600020906004020160030160046101000a81548161ffff021916908361ffff160217905550505050565b611b9f6123f3565b80611baa8385612d5e565b611bb49190612d5e565b6103e814611c155760405162461bcd60e51b815260206004820152602860248201527f546f74616c2070657263656e746167652073686f756c642062652031303025206044820152671a5b881d1bdd185b60c21b6064820152608401610b23565b600c92909255600d55600e55565b606061076b600080516020612e97833981519152612548565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601611c6a575047919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015611cae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116229190612dd7565b919050565b611cdf6123f3565b6001600160a01b038116611d2a5760405162461bcd60e51b81526020600482015260126024820152712d32b9379030b2323932b9b99032b93937b960711b6044820152606401610b23565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b611d546123f3565b6001600160a01b038116611db95760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b23565b6110d181612453565b6001600160a01b03811660009081527f260b29b219d450563ddb0e5ca806bdadb1e125f7e8c506de0443797dd7122728602052604081205460ff16611622565b611e0b33611dc2565b611e2857604051637c3ea23f60e01b815260040160405180910390fd5b8015611e3657611e366123cc565b50600555565b604080516000808252602082019092526001600160a01b038416908390604051611e669190612e14565b60006040518083038185875af1925050503d8060008114611ea3576040519150601f19603f3d011682016040523d82523d6000602084013e611ea8565b606091505b5050905080611eca57604051632e05b05360e21b815260040160405180910390fd5b505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151600092839290871691611f2b9190612e14565b6000604051808303816000865af19150503d8060008114611f68576040519150601f19603f3d011682016040523d82523d6000602084013e611f6d565b606091505b50915091506000828015611f99575081511580611f99575081806020019051810190611f999190612e30565b905080611fb957604051632fdb1b7f60e11b815260040160405180910390fd5b505050505050565b600060068281548110611fd657611fd6612cf9565b60009182526020909120600490910201600381015490915063ffffffff164211611ffe575050565b806001015460000361202357600301805463ffffffff19164263ffffffff1617905550565b600381015460009061203b9063ffffffff1642611545565b90506000600a548360030160049054906101000a900461ffff1661ffff16600554846120679190612d25565b6120719190612d25565b61207b9190612d3c565b6001840154909150612095670de0b6b3a764000083612d25565b61209f9190612d3c565b8360020160008282546120b29190612d5e565b90915550505050600301805463ffffffff19164263ffffffff1617905550565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015612139573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215d9190612dd7565b9050808211156121bf5760405162461bcd60e51b815260206004820152602760248201527f4e6f7420656e6f75676820746f6b656e73206f6e2074686520736d61727420636044820152661bdb9d1c9858dd60ca1b6064820152608401610b23565b611eca6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001684845b6040516001600160a01b038316602482015260448101829052611eca90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526125b4565b60008281526009602090815260408083206001600160a01b03851684529091528120905b81548110156122e5574282828154811061229257612292612cf9565b90600052602060002090600202016001015411156122d3578181815481106122bc576122bc612cf9565b600091825260208220600290910201818155600101555b806122dd81612d84565b915050612276565b50505050565b60005460ff16610ef45760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610b23565b61233c6122eb565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60005460ff1615610ef45760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610b23565b60065460005b81811015610988576123e381611fc1565b6123ec81612d84565b90506123d2565b6000546001600160a01b03610100909104163314610ef45760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b23565b600080546001600160a01b03838116610100818102610100600160a81b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b6040516001600160a01b03808516602483015283166044820152606481018290526122e59085906323b872dd60e01b9060840161221b565b6124ec612386565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586123693390565b600083815260016020908152604080832060029092529091206122e5919084846064612686565b6000818152600160209081526040918290208054835181840281018401909452808452606093928301828280156125a857602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161258a575b50505050509050919050565b6000612609826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166126a99092919063ffffffff16565b805190915015611eca57808060200190518101906126279190612e30565b611eca5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610b23565b60008261269d576126988686866126c0565b610902565b610902868686856127e8565b60606126b8848460008561289a565b949350505050565b6001600160a01b0381166000908152602083905260409020805460ff169081156127e057600180820154865490916000916126fb9190612d71565b905080821461278857600087828154811061271857612718612cf9565b9060005260206000200160009054906101000a90046001600160a01b031690508088848154811061274b5761274b612cf9565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815290879052604090206001018290555b8680548061279857612798612e4d565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038716825287905260408120805460ff191681556001015550505b509392505050565b6001600160a01b03821660009081526020849052604090205460ff161580156126b8578454821161282c5760405163b1655e3360e01b815260040160405180910390fd5b6040805180820182526001808252875460208084019182526001600160a01b03881660008181528a83529586209451855460ff1916901515178555915193830193909355885491820189558884529190922090910180546001600160a01b0319169091179055949350505050565b6060824710156128fb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610b23565b600080866001600160a01b031685876040516129179190612e14565b60006040518083038185875af1925050503d8060008114612954576040519150601f19603f3d011682016040523d82523d6000602084013e612959565b606091505b509150915061296a87838387612975565b979650505050505050565b606083156129e45782516000036129dd576001600160a01b0385163b6129dd5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b23565b50816126b8565b6126b883838151156129f95781518083602001fd5b8060405162461bcd60e51b8152600401610b239190612e63565b600060208284031215612a2557600080fd5b5035919050565b80356001600160a01b0381168114611cd257600080fd5b60008060408385031215612a5657600080fd5b82359150612a6660208401612a2c565b90509250929050565b60008060408385031215612a8257600080fd5b612a8b83612a2c565b946020939093013593505050565b600060608201858352602085818501526040606081860152828651808552608087019150838801945060005b81811015612aea57855180518452850151858401529484019491830191600101612ac5565b50909998505050505050505050565b600060208284031215612b0b57600080fd5b612b1482612a2c565b9392505050565b60008060408385031215612b2e57600080fd5b50508035926020909101359150565b803561ffff81168114611cd257600080fd5b80151581146110d157600080fd5b600080600060608486031215612b7257600080fd5b612b7b84612b3d565b9250612b8960208501612a2c565b91506040840135612b9981612b4f565b809150509250925092565b60008060408385031215612bb757600080fd5b612bc083612a2c565b91506020830135612bd081612b4f565b809150509250929050565b600080600060608486031215612bf057600080fd5b83359250612c0060208501612a2c565b9150604084013590509250925092565b600060208284031215612c2257600080fd5b813563ffffffff81168114612b1457600080fd5b600080600060608486031215612c4b57600080fd5b83359250612b8960208501612b3d565b600080600060608486031215612c7057600080fd5b505081359360208301359350604090920135919050565b6020808252825182820181905260009190848201906040850190845b81811015612cc85783516001600160a01b031683529284019291840191600101612ca3565b50909695505050505050565b60008060408385031215612ce757600080fd5b823591506020830135612bd081612b4f565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761162257611622612d0f565b600082612d5957634e487b7160e01b600052601260045260246000fd5b500490565b8082018082111561162257611622612d0f565b8181038181111561162257611622612d0f565b600060018201612d9657612d96612d0f565b5060010190565b634e487b7160e01b600052604160045260246000fd5b63ffffffff818116838216019080821115612dd057612dd0612d0f565b5092915050565b600060208284031215612de957600080fd5b5051919050565b60005b83811015612e0b578181015183820152602001612df3565b50506000910152565b60008251612e26818460208701612df0565b9190910192915050565b600060208284031215612e4257600080fd5b8151612b1481612b4f565b634e487b7160e01b600052603160045260246000fd5b6020815260008251806020840152612e82816040850160208701612df0565b601f01601f1916919091016040019291505056fe6d439300980e333f0256d64be2c9f67e86f4493ce25f82498d6db7f4be3d9e6fa26469706673582212204cf58adf6df40960a65714c5e68781524573c8984ff61c1e873f5fd4eb1cda6164736f6c634300081300330000000000000000000000002b1d36f5b61addaf7da7ebbd11b35fd8cfb0de31000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000661f4fdb0000000000000000000000000000000000000000000000000000000001da9c00000000000000000000000000000000000000000000000000000000000076a700
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102d65760003560e01c80638da5cb5b11610182578063cf42947b116100e9578063e859c0b5116100a2578063f2fde38b1161007c578063f2fde38b1461070b578063f3ae24151461071e578063f7c618c114610731578063fc2aff3a1461075857600080fd5b8063e859c0b5146106dc578063eedc966a146106e5578063f0f44260146106f857600080fd5b8063cf42947b14610658578063d1c1b4a81461066b578063d1c339d01461067e578063d3e33ddd14610691578063d8e6e417146106a4578063e3725b15146106c757600080fd5b80639dd2a9361161013b5780639dd2a93614610543578063a1a6690f14610603578063a5e90eee1461060c578063a64b1d5f1461061f578063c2c518e114610628578063ca45412d1461063057600080fd5b80638da5cb5b146105565780638dbb1e3a1461056c57806393f1a40b1461057f578063957cb949146105d457806395ea0db1146105dd57806398ec8da6146105f057600080fd5b8063440d724811610241578063630b5ba1116101fa57806378e97925116101d457806378e97925146105015780637b0472f0146105285780638456cb591461053b57806387642b7a1461054357600080fd5b8063630b5ba1146104de5780636a760b80146104e6578063715018a6146104f957600080fd5b8063440d72481461044c578063441a3e701461046f57806351eb05a6146104825780635312ea8e146104955780635c975abb146104a857806361d027b3146104b357600080fd5b806331326d161161029357806331326d16146103ce5780633197cbb6146103d75780633b57e4af146103fc5780633c6a4e611461040f5780633e4a56fb146104225780633f4ba83a1461044457600080fd5b8063081e3eda146102db578063103b7397146102f25780631514617e146103305780631526fe27146103575780631653fd33146103a657806330eb1278146103b9575b600080fd5b6006545b6040519081526020015b60405180910390f35b600080516020612e9783398151915260005260016020527f3c2285c553468ca8f30447b24bb463c127f1b840e23a0cafa23caa79d906669a546102df565b6102df7f000000000000000000000000000000000000000000000000000000000076a70081565b61036a610365366004612a13565b610770565b604080516001600160a01b03909616865260208601949094529284019190915263ffffffff16606083015261ffff16608082015260a0016102e9565b6102df6103b4366004612a43565b6107c8565b6103cc6103c7366004612a6f565b61090c565b005b6102df600d5481565b600b546103e79063ffffffff1681565b60405163ffffffff90911681526020016102e9565b6103cc61040a366004612a13565b610997565b6103cc61041d366004612a13565b610b66565b610435610430366004612a43565b610cfc565b6040516102e993929190612a99565b6103cc610ebe565b61045f61045a366004612af9565b610ef6565b60405190151581526020016102e9565b6103cc61047d366004612b1b565b610f61565b6103cc610490366004612a13565b6110c0565b6103cc6104a3366004612a13565b6110d4565b60005460ff1661045f565b6003546104c6906001600160a01b031681565b6040516001600160a01b0390911681526020016102e9565b6103cc61118c565b6103cc6104f4366004612a13565b61119c565b6103cc6113b8565b6103e77f00000000000000000000000000000000000000000000000000000000661f4fdb81565b6103cc610536366004612b1b565b6113ca565b6103cc6114cf565b6103cc610551366004612a13565b611505565b60005461010090046001600160a01b03166104c6565b6102df61057a366004612b1b565b611545565b6105b961058d366004612a43565b600860209081526000928352604080842090915290825290208054600182015460029092015490919083565b604080519384526020840192909252908201526060016102e9565b6102df600c5481565b6103cc6105eb366004612af9565b611628565b6103cc6105fe366004612b5d565b61169d565b6102df600a5481565b6103cc61061a366004612ba4565b611954565b6102df60055481565b6103cc6119b1565b61064361063e366004612bdb565b611a1e565b604080519283526020830191909152016102e9565b6103cc610666366004612c10565b611a68565b6103cc610679366004612c36565b611aca565b6004546104c6906001600160a01b031681565b6103cc61069f366004612c5b565b611b97565b61045f6106b2366004612af9565b60076020526000908152604090205460ff1681565b6106cf611c23565b6040516102e99190612c87565b6102df600e5481565b6102df6106f3366004612af9565b611c3c565b6103cc610706366004612af9565b611cd7565b6103cc610719366004612af9565b611d4c565b61045f61072c366004612af9565b611dc2565b6104c67f0000000000000000000000002b1d36f5b61addaf7da7ebbd11b35fd8cfb0de3181565b6103cc610766366004612cd4565b611e02565b905090565b6006818154811061078057600080fd5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b039092169350919063ffffffff811690640100000000900461ffff1685565b600080600684815481106107de576107de612cf9565b600091825260208083208784526008825260408085206001600160a01b03891686529092529220600260049092029092019081015460038201549193509063ffffffff16421180156108335750600183015415155b156108c35760038301546000906108509063ffffffff1642611545565b90506000600a548560030160049054906101000a900461ffff1661ffff166005548461087c9190612d25565b6108869190612d25565b6108909190612d3c565b60018601549091506108aa670de0b6b3a764000083612d25565b6108b49190612d3c565b6108be9084612d5e565b925050505b600282015460018301548354670de0b6b3a7640000906108e4908590612d25565b6108ee9190612d3c565b6108f89190612d71565b6109029190612d5e565b9695505050505050565b61091533611dc2565b61093257604051637c3ea23f60e01b815260040160405180910390fd5b61093b82610ef6565b1561095957604051634477699960e11b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0383160161098c576109883382611e3c565b5050565b610988823383611ecf565b6109a081611fc1565b60006109ac8233610cfc565b50509050600080821115610aca576000838152600960209081526040808320338452909152812054905b81811015610ac75760008581526009602090815260408083203384529091528120805483908110610a0957610a09612cf9565b6000918252602080832060029092029091015488835260098252604080842033855290925291208054919250429184908110610a4757610a47612cf9565b9060005260206000209060020201600101541115610a655750610ac7565b610a6f8185612d5e565b6000878152600960209081526040808320338452909152902080549195509083908110610a9e57610a9e612cf9565b600091825260208220600290910201818155600101555080610abf81612d84565b9150506109d6565b50505b8015610adf57610ada33826120d2565b610b2c565b60405162461bcd60e51b815260206004820181905260248201527f546f6b656e7320617265206e6f7420617661696c61626c6520666f72206e6f7760448201526064015b60405180910390fd5b60405181815233907f7391907e2ab707a2bed13f0fa64fdaa84d5fb991113e1dad366f47b55ec6e6119060200160405180910390a2505050565b610b6f81611fc1565b6000610b7b8233610cfc565b5091505060008111610bdb5760405162461bcd60e51b8152602060048201526024808201527f546f74616c2076657374696e6720746f6b656e732063616e206e6f74206265206044820152637a65726f60e01b6064820152608401610b23565b60006103e8600c5483610bee9190612d25565b610bf89190612d3c565b905060006103e8600d5484610c0d9190612d25565b610c179190612d3c565b905060006103e8600e5485610c2c9190612d25565b610c369190612d3c565b9050610c4233846120d2565b600354610c7c906001600160a01b037f0000000000000000000000002b1d36f5b61addaf7da7ebbd11b35fd8cfb0de3181169116846121ef565b600454610cb6906001600160a01b037f0000000000000000000000002b1d36f5b61addaf7da7ebbd11b35fd8cfb0de3181169116836121ef565b610cc08533612252565b60405183815233907f1be3144880c716b1152eab5fbba4f339f9590430ecfd4f1c7cd4a10e3c2797a59060200160405180910390a25050505050565b60008281526009602090815260408083206001600160a01b03851684529091528120819060609082805b8254811015610eb45742838281548110610d4257610d42612cf9565b9060005260206000209060020201600101541115610e705781600003610dd0578254610d6f908290612d71565b67ffffffffffffffff811115610d8757610d87612d9d565b604051908082528060200260200182016040528015610dcc57816020015b6040805180820190915260008082526020820152815260200190600190039081610da55790505b5093505b828181548110610de257610de2612cf9565b906000526020600020906002020160405180604001604052908160008201548152602001600182015481525050848381518110610e2157610e21612cf9565b60200260200101819052508180610e3790612d84565b925050828181548110610e4c57610e4c612cf9565b90600052602060002090600202016000015485610e699190612d5e565b9450610ea2565b828181548110610e8257610e82612cf9565b90600052602060002090600202016000015486610e9f9190612d5e565b95505b80610eac81612d84565b915050610d26565b5050509250925092565b610ec733611dc2565b610ee457604051637c3ea23f60e01b815260040160405180910390fd5b610eec6122eb565b610ef4612334565b565b600654600090815b81811015610f575760068181548110610f1957610f19612cf9565b60009182526020909120600490910201546001600160a01b0390811690851603610f47575060019392505050565b610f5081612d84565b9050610efe565b5060009392505050565b610f69612386565b600060068381548110610f7e57610f7e612cf9565b600091825260208083208684526008825260408085203386529092529220805460049092029092019250831115610ff75760405162461bcd60e51b815260206004820152601c60248201527f43616e206e6f74207769746864726177207468697320616d6f756e74000000006044820152606401610b23565b61100084611fc1565b61100a84336107c8565b6002820155805483908290600090611023908490612d71565b925050819055508282600101600082825461103e9190612d71565b909155505060028201548154670de0b6b3a76400009161105d91612d25565b6110679190612d3c565b60018201558154611082906001600160a01b031633856121ef565b604051838152849033907ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568906020015b60405180910390a350505050565b6110c8612386565b6110d181611fc1565b50565b6000600682815481106110e9576110e9612cf9565b600091825260208083208584526008825260408085203386529092529083208054600493909302909101600181018054919550919383929161112c908490612d71565b909155505060008083556001830181905560028301558254611158906001600160a01b031633836121ef565b604051818152849033907fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae0595906020016110b2565b611194612386565b610ef46123cc565b6111a4612386565b6000600682815481106111b9576111b9612cf9565b600091825260208083208584526008825260408085203386529092529220600490910290910191506111ea83611fc1565b60006111f684336107c8565b9050600081116112575760405162461bcd60e51b815260206004820152602660248201527f416d6f756e74206f6620746f6b656e732063616e206e6f74206265207a65726f6044820152652076616c756560d01b6064820152608401610b23565b60006112837f000000000000000000000000000000000000000000000000000000000076a70042612d5e565b60008681526009602090815260408083203384529091529020805491925090606410156113115760405162461bcd60e51b815260206004820152603660248201527f557365722063616e206e6f74206578656375746520766573742066756e6374696044820152756f6e206d6f7265207468616e203130302074696d657360501b6064820152608401610b23565b60408051808201909152838152602080820184815283546001818101865560008681529384209451600292830290950194855591519390910192909255858201558501548454670de0b6b3a76400009161136a91612d25565b6113749190612d3c565b6001850155604051838152869033907ffbeff59d2bfda0d79ea8a29f8c57c66d48c7a13eabbdb90908d9115ec41c9dc69060200160405180910390a3505050505050565b6113c06123f3565b610ef46000612453565b6113d2612386565b6000600683815481106113e7576113e7612cf9565b6000918252602080832086845260088252604080852033865290925292206004909102909101915061141884611fc1565b815461142f906001600160a01b03163330866124ac565b61143984336107c8565b6002820155805483908290600090611452908490612d5e565b925050819055508282600101600082825461146d9190612d5e565b909155505060028201548154670de0b6b3a76400009161148c91612d25565b6114969190612d3c565b6001820155604051838152849033907f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90906020016110b2565b6114d833611dc2565b6114f557604051637c3ea23f60e01b815260040160405180910390fd5b6114fd612386565b610ef46124e4565b60405162461bcd60e51b81526020600482015260156024820152742ab739bab83837b93a32b21037b832b930ba34b7b760591b6044820152606401610b23565b60007f00000000000000000000000000000000000000000000000000000000661f4fdb63ffffffff1683116115a0577f00000000000000000000000000000000000000000000000000000000661f4fdb63ffffffff166115a2565b825b600b5490935063ffffffff168311806115e057507f00000000000000000000000000000000000000000000000000000000661f4fdb63ffffffff1682105b156115ed57506000611622565b600b5463ffffffff1682111561161857600b5461161190849063ffffffff16612d71565b9050611622565b6116118383612d71565b92915050565b6116306123f3565b6001600160a01b03811661167b5760405162461bcd60e51b81526020600482015260126024820152712d32b9379030b2323932b9b99032b93937b960711b6044820152606401610b23565b600480546001600160a01b0319166001600160a01b0392909216919091179055565b6116a633611dc2565b6116c357604051637c3ea23f60e01b815260040160405180910390fd5b6001600160a01b03821660009081526007602052604090205460ff161561172c5760405162461bcd60e51b815260206004820152601d60248201527f5374616b696e6720746f6b656e2077617320616c7265616479207365740000006044820152606401610b23565b6006546005116117885760405162461bcd60e51b815260206004820152602160248201527f4e6f206d6f7265207468656e203520706f6f6c732063616e20626520616464656044820152601960fa1b6064820152608401610b23565b8015611796576117966123cc565b60007f00000000000000000000000000000000000000000000000000000000661f4fdb63ffffffff1642116117f1577f00000000000000000000000000000000000000000000000000000000661f4fdb63ffffffff166117f3565b425b90508361ffff16600a600082825461180b9190612d5e565b90915550506040805160a0810182526001600160a01b039485168082526000602080840182815284860183815263ffffffff9788166060870190815261ffff9b8c1660808801908152600680546001808201835591885298517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f6004909a02998a0180546001600160a01b03191691909e1617909c5592517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d4088015590517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d41870155517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d42909501805491519590971665ffffffffffff19909116176401000000009490991693909302979097179093559185526007909152909220805460ff1916909117905550565b61195c6123f3565b611975600080516020612e978339815191528383612521565b604051811515906001600160a01b038416907fbe9474bb3e78da7e315cdffa5cfa30b767fcc95bbf44a6197da60228eea1028690600090a35050565b6119ba33611dc2565b6119d757604051637c3ea23f60e01b815260040160405180910390fd5b6119f1600080516020612e97833981519152336000612521565b60405133907f6cc2c67081f55c2fffb7c008fa995fbbf890f48c7c16fba93d8220f00dc84cc590600090a2565b60096020528260005260406000206020528160005260406000208181548110611a4657600080fd5b6000918252602090912060029091020180546001909101549093509150839050565b611a7133611dc2565b611a8e57604051637c3ea23f60e01b815260040160405180910390fd5b600b8054829190600090611aa990849063ffffffff16612db3565b92506101000a81548163ffffffff021916908363ffffffff16021790555050565b611ad333611dc2565b611af057604051637c3ea23f60e01b815260040160405180910390fd5b8015611afe57611afe6123cc565b8161ffff1660068481548110611b1657611b16612cf9565b6000918252602090912060049091020160030154600a54611b4391640100000000900461ffff1690612d71565b611b4d9190612d5e565b600a819055508160068481548110611b6757611b67612cf9565b906000526020600020906004020160030160046101000a81548161ffff021916908361ffff160217905550505050565b611b9f6123f3565b80611baa8385612d5e565b611bb49190612d5e565b6103e814611c155760405162461bcd60e51b815260206004820152602860248201527f546f74616c2070657263656e746167652073686f756c642062652031303025206044820152671a5b881d1bdd185b60c21b6064820152608401610b23565b600c92909255600d55600e55565b606061076b600080516020612e97833981519152612548565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601611c6a575047919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015611cae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116229190612dd7565b919050565b611cdf6123f3565b6001600160a01b038116611d2a5760405162461bcd60e51b81526020600482015260126024820152712d32b9379030b2323932b9b99032b93937b960711b6044820152606401610b23565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b611d546123f3565b6001600160a01b038116611db95760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b23565b6110d181612453565b6001600160a01b03811660009081527f260b29b219d450563ddb0e5ca806bdadb1e125f7e8c506de0443797dd7122728602052604081205460ff16611622565b611e0b33611dc2565b611e2857604051637c3ea23f60e01b815260040160405180910390fd5b8015611e3657611e366123cc565b50600555565b604080516000808252602082019092526001600160a01b038416908390604051611e669190612e14565b60006040518083038185875af1925050503d8060008114611ea3576040519150601f19603f3d011682016040523d82523d6000602084013e611ea8565b606091505b5050905080611eca57604051632e05b05360e21b815260040160405180910390fd5b505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151600092839290871691611f2b9190612e14565b6000604051808303816000865af19150503d8060008114611f68576040519150601f19603f3d011682016040523d82523d6000602084013e611f6d565b606091505b50915091506000828015611f99575081511580611f99575081806020019051810190611f999190612e30565b905080611fb957604051632fdb1b7f60e11b815260040160405180910390fd5b505050505050565b600060068281548110611fd657611fd6612cf9565b60009182526020909120600490910201600381015490915063ffffffff164211611ffe575050565b806001015460000361202357600301805463ffffffff19164263ffffffff1617905550565b600381015460009061203b9063ffffffff1642611545565b90506000600a548360030160049054906101000a900461ffff1661ffff16600554846120679190612d25565b6120719190612d25565b61207b9190612d3c565b6001840154909150612095670de0b6b3a764000083612d25565b61209f9190612d3c565b8360020160008282546120b29190612d5e565b90915550505050600301805463ffffffff19164263ffffffff1617905550565b6040516370a0823160e01b81523060048201526000907f0000000000000000000000002b1d36f5b61addaf7da7ebbd11b35fd8cfb0de316001600160a01b0316906370a0823190602401602060405180830381865afa158015612139573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215d9190612dd7565b9050808211156121bf5760405162461bcd60e51b815260206004820152602760248201527f4e6f7420656e6f75676820746f6b656e73206f6e2074686520736d61727420636044820152661bdb9d1c9858dd60ca1b6064820152608401610b23565b611eca6001600160a01b037f0000000000000000000000002b1d36f5b61addaf7da7ebbd11b35fd8cfb0de311684845b6040516001600160a01b038316602482015260448101829052611eca90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526125b4565b60008281526009602090815260408083206001600160a01b03851684529091528120905b81548110156122e5574282828154811061229257612292612cf9565b90600052602060002090600202016001015411156122d3578181815481106122bc576122bc612cf9565b600091825260208220600290910201818155600101555b806122dd81612d84565b915050612276565b50505050565b60005460ff16610ef45760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610b23565b61233c6122eb565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60005460ff1615610ef45760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610b23565b60065460005b81811015610988576123e381611fc1565b6123ec81612d84565b90506123d2565b6000546001600160a01b03610100909104163314610ef45760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b23565b600080546001600160a01b03838116610100818102610100600160a81b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b6040516001600160a01b03808516602483015283166044820152606481018290526122e59085906323b872dd60e01b9060840161221b565b6124ec612386565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586123693390565b600083815260016020908152604080832060029092529091206122e5919084846064612686565b6000818152600160209081526040918290208054835181840281018401909452808452606093928301828280156125a857602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161258a575b50505050509050919050565b6000612609826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166126a99092919063ffffffff16565b805190915015611eca57808060200190518101906126279190612e30565b611eca5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610b23565b60008261269d576126988686866126c0565b610902565b610902868686856127e8565b60606126b8848460008561289a565b949350505050565b6001600160a01b0381166000908152602083905260409020805460ff169081156127e057600180820154865490916000916126fb9190612d71565b905080821461278857600087828154811061271857612718612cf9565b9060005260206000200160009054906101000a90046001600160a01b031690508088848154811061274b5761274b612cf9565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815290879052604090206001018290555b8680548061279857612798612e4d565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038716825287905260408120805460ff191681556001015550505b509392505050565b6001600160a01b03821660009081526020849052604090205460ff161580156126b8578454821161282c5760405163b1655e3360e01b815260040160405180910390fd5b6040805180820182526001808252875460208084019182526001600160a01b03881660008181528a83529586209451855460ff1916901515178555915193830193909355885491820189558884529190922090910180546001600160a01b0319169091179055949350505050565b6060824710156128fb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610b23565b600080866001600160a01b031685876040516129179190612e14565b60006040518083038185875af1925050503d8060008114612954576040519150601f19603f3d011682016040523d82523d6000602084013e612959565b606091505b509150915061296a87838387612975565b979650505050505050565b606083156129e45782516000036129dd576001600160a01b0385163b6129dd5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b23565b50816126b8565b6126b883838151156129f95781518083602001fd5b8060405162461bcd60e51b8152600401610b239190612e63565b600060208284031215612a2557600080fd5b5035919050565b80356001600160a01b0381168114611cd257600080fd5b60008060408385031215612a5657600080fd5b82359150612a6660208401612a2c565b90509250929050565b60008060408385031215612a8257600080fd5b612a8b83612a2c565b946020939093013593505050565b600060608201858352602085818501526040606081860152828651808552608087019150838801945060005b81811015612aea57855180518452850151858401529484019491830191600101612ac5565b50909998505050505050505050565b600060208284031215612b0b57600080fd5b612b1482612a2c565b9392505050565b60008060408385031215612b2e57600080fd5b50508035926020909101359150565b803561ffff81168114611cd257600080fd5b80151581146110d157600080fd5b600080600060608486031215612b7257600080fd5b612b7b84612b3d565b9250612b8960208501612a2c565b91506040840135612b9981612b4f565b809150509250925092565b60008060408385031215612bb757600080fd5b612bc083612a2c565b91506020830135612bd081612b4f565b809150509250929050565b600080600060608486031215612bf057600080fd5b83359250612c0060208501612a2c565b9150604084013590509250925092565b600060208284031215612c2257600080fd5b813563ffffffff81168114612b1457600080fd5b600080600060608486031215612c4b57600080fd5b83359250612b8960208501612b3d565b600080600060608486031215612c7057600080fd5b505081359360208301359350604090920135919050565b6020808252825182820181905260009190848201906040850190845b81811015612cc85783516001600160a01b031683529284019291840191600101612ca3565b50909695505050505050565b60008060408385031215612ce757600080fd5b823591506020830135612bd081612b4f565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761162257611622612d0f565b600082612d5957634e487b7160e01b600052601260045260246000fd5b500490565b8082018082111561162257611622612d0f565b8181038181111561162257611622612d0f565b600060018201612d9657612d96612d0f565b5060010190565b634e487b7160e01b600052604160045260246000fd5b63ffffffff818116838216019080821115612dd057612dd0612d0f565b5092915050565b600060208284031215612de957600080fd5b5051919050565b60005b83811015612e0b578181015183820152602001612df3565b50506000910152565b60008251612e26818460208701612df0565b9190910192915050565b600060208284031215612e4257600080fd5b8151612b1481612b4f565b634e487b7160e01b600052603160045260246000fd5b6020815260008251806020840152612e82816040850160208701612df0565b601f01601f1916919091016040019291505056fe6d439300980e333f0256d64be2c9f67e86f4493ce25f82498d6db7f4be3d9e6fa26469706673582212204cf58adf6df40960a65714c5e68781524573c8984ff61c1e873f5fd4eb1cda6164736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000002b1d36f5b61addaf7da7ebbd11b35fd8cfb0de31000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000661f4fdb0000000000000000000000000000000000000000000000000000000001da9c00000000000000000000000000000000000000000000000000000000000076a700
-----Decoded View---------------
Arg [0] : _rewardToken (address): 0x2b1D36f5B61AdDAf7DA7ebbd11B35FD8cfb0DE31
Arg [1] : _rewardTokenPerSecond (uint256): 1
Arg [2] : _startTime (uint32): 1713328091
Arg [3] : _endTimeAddSeconds (uint32): 31104000
Arg [4] : _vestingDuration (uint256): 7776000
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000002b1d36f5b61addaf7da7ebbd11b35fd8cfb0de31
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [2] : 00000000000000000000000000000000000000000000000000000000661f4fdb
Arg [3] : 0000000000000000000000000000000000000000000000000000000001da9c00
Arg [4] : 000000000000000000000000000000000000000000000000000000000076a700
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$1,228.85
Net Worth in ETH
Token Allocations
ITP
100.00%
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| ETH | 100.00% | $0.00 | 162,025.9116 | $0.00 |
Loading...
Loading
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.