Overview
S Balance
S Value
$0.00More Info
Private Name Tags
ContractCreator
Loading...
Loading
Contract Name:
PacaFinanceWithBoostAndSchedule
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; pragma solidity ^0.8.20; interface iPriceOracle { // returns price in USD function getLatestPrice(address token) external view returns (uint256); } // File: paca.sol contract PacaFinanceWithBoostAndSchedule is Initializable, ReentrancyGuardUpgradeable { using SafeERC20 for IERC20; // Struct Definitions struct Pool { uint256 lockupPeriod; uint256 dailyRewardRate; uint256 totalStaked; uint256 totalRewards; address tokenAddress; } struct Stake { uint256 amount; uint256 lastClaimed; uint256 dailyRewardRate; uint256 unlockTime; bool complete; } struct StakeInput { address user; uint256 amount; uint256 unlockTime; uint256 dailyRewardRate; } struct Vesting { uint256 amount; uint256 bonus; uint256 lockedUntil; uint256 claimedAmount; uint256 claimedBonus; uint256 lastClaimed; uint256 createdAt; address token; bool complete; uint256 usdAmount; } struct UnlockStep { uint256 timeOffset; uint256 percentage; } struct BoostRange { uint256 minTokens; uint256 maxTokens; uint256 boostPercentage; } BoostRange[] public boosttiers; // Contract Variables Pool public pool; address public owner; mapping(address => bool) public owners; mapping(address => Stake[]) public stakes; mapping(address => Vesting[]) public vestings; mapping(address => UnlockStep[]) public unlockSchedules; mapping(address => address) public priceOracles; mapping(address => uint256) public dollarsVested; uint256 public lockupDuration; uint256 public minStakeLock; uint256 private constant BONUS_PERCENTAGE = 10; mapping(address => bool) public authorizedBots; // Events event Staked(address indexed user, uint256 amount); event RewardClaimed(address indexed user, uint256 reward); event VestingCreated(address indexed user, uint256 amount, uint256 bonus); event VestingClaimed(address indexed user, uint256 amount, uint256 bonus); event BonusClaimed(address indexed user, uint256 bonus); event PoolUpdated(uint256 lockupPeriod, uint256 dailyRewardRate); event UnlockScheduleSet(address indexed token); event FundsWithdrawn(address indexed owner, address indexed token, uint256 amount); event RewardsDeposited(uint256 amount); event CompoundRewards(address indexed user, uint256 amount); event MinStakeLockUpdated(uint256 amount); // Modifiers modifier onlyOwner() { require(owners[msg.sender], "Not authorized"); _; } modifier onlyBot() { require(authorizedBots[msg.sender], "Caller is not an authorized bot"); _; } function initialize() public initializer { __ReentrancyGuard_init(); // Initialize ReentrancyGuardUpgradeable owner = 0x41970Ce76b656030A79E7C1FA76FC4EB93980255; owners[0x41970Ce76b656030A79E7C1FA76FC4EB93980255] = true; lockupDuration = 250 days; minStakeLock = 16 ether; pool.tokenAddress = 0x29219dd400f2Bf60E5a23d13Be72B486D4038894; pool.lockupPeriod = 250 * 1 days; pool.dailyRewardRate = 33; // Push boost tiers in ascending order (amounts in wei, boosts as percentages) boosttiers.push(BoostRange(3500 * 1e18, 9999 * 1e18, 1)); // $3,500 to $9,999 = 0.01 boost boosttiers.push(BoostRange(10000 * 1e18, 19999 * 1e18, 2)); // $10,000 to $19,999 = 0.02 boost boosttiers.push(BoostRange(20000 * 1e18, 29999 * 1e18, 3)); // $20,000 to $29,999 = 0.03 boost boosttiers.push(BoostRange(30000 * 1e18, 39999 * 1e18, 4)); // $30,000 to $39,999 = 0.04 boost boosttiers.push(BoostRange(40000 * 1e18, 59999 * 1e18, 5)); // $40,000 to $59,999 = 0.05 boost boosttiers.push(BoostRange(60000 * 1e18, 79999 * 1e18, 6)); // $60,000 to $79,999 = 0.06 boost boosttiers.push(BoostRange(80000 * 1e18, 99999 * 1e18, 8)); // $80,000 to $99,999 = 0.08 boost boosttiers.push(BoostRange(100000 * 1e18, type(uint256).max, 10)); // $100,000+ = 0.1 boost // Example price oracle for a specific token // priceOracles[0x940181a94A35A4569E4529A3CDfB74e38FD98631] = 0x0Dde1b42F7B3891C9731280A74081501729A73c5; authorizedBots[0xbf12D3b827a230F7390EbCc9b83b289FdC98ba81] = true; authorizedBots[0x7c40f272570fdf9549d6f67493aC250a1DB52F27] = true; } // Ownership Management function addOwner(address _newOwner) external onlyOwner { require(!owners[_newOwner], "Already an owner"); owners[_newOwner] = true; } function removeOwner(address _owner) external onlyOwner { require(owners[_owner], "Not an owner"); require(_owner != msg.sender, "Cannot remove yourself"); owners[_owner] = false; } // Function to add a bot to the list (only callable by the contract owner) function addBot(address bot) external onlyOwner { require(bot != address(0), "Invalid address"); authorizedBots[bot] = true; } // Function to remove a bot from the list (only callable by the contract owner) function removeBot(address bot) external onlyOwner { require(bot != address(0), "Invalid address"); authorizedBots[bot] = false; } // Admin Functions function updatePool(uint256 _lockupPeriod, uint256 _dailyRewardRate) external onlyOwner { pool.lockupPeriod = _lockupPeriod * 1 days; pool.dailyRewardRate = _dailyRewardRate; emit PoolUpdated(_lockupPeriod, _dailyRewardRate); } function depositRewards(uint256 _amount) external onlyOwner { IERC20(pool.tokenAddress).safeTransferFrom(msg.sender, address(this), _amount); pool.totalRewards = pool.totalRewards + _amount; emit RewardsDeposited(_amount); } function updateStakeMin(uint256 _amount) external onlyOwner { minStakeLock = _amount; emit MinStakeLockUpdated(_amount); } // Add or edit a tier range function addOrEditTier(uint256 minTokens, uint256 maxTokens, uint256 boostPercentage) public onlyOwner { require(minTokens < maxTokens, "Invalid range: minTokens must be < maxTokens"); require(!rangesOverlap(minTokens, maxTokens), "Range overlaps with existing tiers"); // Check if editing an existing range for (uint256 i = 0; i < boosttiers.length; ++i) { if (boosttiers[i].minTokens == minTokens && boosttiers[i].maxTokens == maxTokens) { // Edit the existing range boosttiers[i].boostPercentage = boostPercentage; return; } } // Add new range boosttiers.push(BoostRange(minTokens, maxTokens, boostPercentage)); // Sort the ranges after adding sortRanges(); } // Check for range overlap function rangesOverlap(uint256 minTokens, uint256 maxTokens) internal view returns (bool) { for (uint256 i = 0; i < boosttiers.length; ++i) { if (minTokens <= boosttiers[i].maxTokens && maxTokens >= boosttiers[i].minTokens) { return true; } } return false; } // Sort ranges by minTokens function sortRanges() internal { for (uint256 i = 0; i < boosttiers.length; ++i) { for (uint256 j = i + 1; j < boosttiers.length; j++) { if (boosttiers[i].minTokens > boosttiers[j].minTokens) { // Swap ranges BoostRange memory temp = boosttiers[i]; boosttiers[i] = boosttiers[j]; boosttiers[j] = temp; } } } } // Remove a range by index function removeTier(uint256 index) external onlyOwner { require(index < boosttiers.length, "Index out of bounds"); for (uint256 i = index; i < boosttiers.length - 1; ++i) { boosttiers[i] = boosttiers[i + 1]; } boosttiers.pop(); } function withdrawFromStakingPool(uint256 _amount) external onlyOwner { IERC20(pool.tokenAddress).safeTransfer(msg.sender, _amount); emit FundsWithdrawn(msg.sender, pool.tokenAddress, _amount); } function withdrawFromVestingPool(address _token, uint256 _amount) external onlyOwner { IERC20(_token).safeTransfer(msg.sender, _amount); emit FundsWithdrawn(msg.sender, _token, _amount); } function setUnlockScheduleByPercentage( address _token, uint256 _lockTime, // Total lock time in seconds uint256 _percentagePerStep // Percentage unlocked per step (in basis points, e.g., 100 = 1%) ) external onlyOwner { require(_lockTime != 0, "Lock time must be greater than zero"); require(_percentagePerStep != 0, "Percentage per step must be greater than zero"); uint256 totalPercentage = 10000; // 100% in basis points require(totalPercentage % _percentagePerStep == 0, "Percentage must divide 100% evenly"); uint256 steps = totalPercentage / _percentagePerStep; // Number of steps uint256 stepTime = _lockTime / steps; // Time interval per step delete unlockSchedules[_token]; // Clear existing schedule for this token for (uint256 i = 1; i <= steps; ++i) { unlockSchedules[_token].push(UnlockStep({ timeOffset: stepTime * i, // Time offset for this step percentage: _percentagePerStep })); } emit UnlockScheduleSet(_token); } // Get the boost percentage for a given token amount function getBoost(uint256 depositedTokens) public view returns (uint256) { for (uint256 i = 0; i < boosttiers.length; ++i) { if (depositedTokens >= boosttiers[i].minTokens && depositedTokens <= boosttiers[i].maxTokens) { return boosttiers[i].boostPercentage; } } return 0; // Default boost if no range matches } function createStake(uint256 _amount) external { // Scale up for wei comparison, USDC is 1e6 require(_amount * 1e12 > minStakeLock, "Amount must be greater minStakeLock"); IERC20(pool.tokenAddress).safeTransferFrom(msg.sender, address(this), _amount); uint256 finalRewardRate = pool.dailyRewardRate; // Apply boost tiers logic if applicable finalRewardRate = finalRewardRate + getBoost(dollarsVested[msg.sender]); stakes[msg.sender].push(Stake({ amount: _amount, lastClaimed: block.timestamp, dailyRewardRate: finalRewardRate, unlockTime: block.timestamp + pool.lockupPeriod, complete: false })); pool.totalStaked = pool.totalStaked + _amount; emit Staked(msg.sender, _amount); } function createStakeForUser(address _user, uint256 _amount) external onlyOwner { require(_amount != 0, "Invalid amount"); stakes[_user].push(Stake({ amount: _amount, lastClaimed: block.timestamp, dailyRewardRate: pool.dailyRewardRate, unlockTime: block.timestamp + pool.lockupPeriod, complete: false })); pool.totalStaked = pool.totalStaked + _amount; emit Staked(_user, _amount); } function createStakes(StakeInput[] calldata stakesInput) external onlyBot payable { uint256 totalLength = stakesInput.length; uint256 currentTimestamp = block.timestamp; for (uint256 i; i < totalLength;) { StakeInput calldata stakeInput = stakesInput[i]; // Update pool total pool.totalStaked = pool.totalStaked + stakeInput.amount; // Create the stake for the user stakes[stakeInput.user].push(Stake({ amount: stakeInput.amount, lastClaimed: currentTimestamp, dailyRewardRate: stakeInput.dailyRewardRate, unlockTime: stakeInput.unlockTime, complete: false })); unchecked { ++i; } } } function getPoolRewards(address _user, uint _stakeIndex) public view returns (uint256) { Stake storage stake = stakes[_user][_stakeIndex]; uint256 elapsedTime = block.timestamp - stake.lastClaimed; uint256 rewards = (stake.amount * stake.dailyRewardRate * elapsedTime) / 1 days / 10000; return rewards; } function claimRewards() external nonReentrant { uint256 totalReward = 0; for (uint256 i = 0; i < stakes[msg.sender].length; ++i) { Stake storage stake = stakes[msg.sender][i]; uint rewards = getPoolRewards(msg.sender, i); totalReward = totalReward + rewards; stake.lastClaimed = block.timestamp; } require(totalReward != 0, "No rewards to claim"); require(pool.totalRewards >= totalReward, "Insufficient rewards in the pool"); pool.totalRewards = pool.totalRewards - totalReward; IERC20(pool.tokenAddress).safeTransfer(msg.sender, totalReward); emit RewardClaimed(msg.sender, totalReward); } function claimStake(uint256 _stakeIndex) external nonReentrant { // Ensure the stake index is valid require(_stakeIndex < stakes[msg.sender].length, "Invalid stake index"); // Load the stake Stake storage stake = stakes[msg.sender][_stakeIndex]; uint256 _amount = stake.amount; uint rewards = getPoolRewards(msg.sender, _stakeIndex); _amount = _amount + rewards; // Ensure there is a stake to claim require(_amount != 0, "No amount to claim"); // Optional: Ensure the stake is unlocked (if using lockup periods) require(block.timestamp >= stake.unlockTime, "Stake is still locked"); // Use actual pool balance for safety uint256 poolBalance = IERC20(pool.tokenAddress).balanceOf(address(this)); require(poolBalance >= _amount, "Insufficient rewards in the pool"); // Update state before external calls stake.amount = 0; stake.complete = true; pool.totalStaked -= _amount; // Transfer rewards to the user IERC20(pool.tokenAddress).safeTransfer(msg.sender, _amount); // Optional: Delete the stake for gas savings delete stakes[msg.sender][_stakeIndex]; // Emit a detailed event emit RewardClaimed(msg.sender, _amount); } function compoundAllRewards() external { uint256 totalReward = 0; for (uint256 i = 0; i < stakes[msg.sender].length; ++i) { Stake storage stake = stakes[msg.sender][i]; uint rewards = getPoolRewards(msg.sender, i); totalReward = totalReward + rewards; stake.lastClaimed = block.timestamp; } require(totalReward > minStakeLock, "Not enough to compound"); stakes[msg.sender].push(Stake({ amount: totalReward, lastClaimed: block.timestamp, dailyRewardRate: pool.dailyRewardRate + getBoost(dollarsVested[msg.sender]), unlockTime: block.timestamp + pool.lockupPeriod, complete: false })); pool.totalStaked = pool.totalStaked + totalReward; emit CompoundRewards(msg.sender, totalReward); } function createVesting(address _token, uint256 _amount) external { require(_amount != 0, "Amount must be greater than zero"); address oracle = priceOracles[_token]; require(oracle != address(0), "Price oracle not set for this token"); IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); uint256 bonus = (_amount * BONUS_PERCENTAGE) / 100; uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * _amount) / 1e18; require(usdPrice > minStakeLock, "Amount must be greater minStakeLock"); // Update user's dollarsVested dollarsVested[msg.sender] += usdPrice; vestings[msg.sender].push(Vesting({ amount: _amount, bonus: bonus, lockedUntil: block.timestamp + lockupDuration, claimedAmount: 0, claimedBonus: 0, lastClaimed: block.timestamp, createdAt: block.timestamp, token: _token, complete: false, usdAmount: usdPrice })); emit VestingCreated(msg.sender, _amount, bonus); } function getUnlockedVesting(address _user, uint256 _vestingIndex) public view returns (uint256) { Vesting storage vesting = vestings[_user][_vestingIndex]; uint256 timeElapsed = block.timestamp - vesting.createdAt; address token = vesting.token; uint256 unlockedAmount = 0; for (uint256 i = 0; i < unlockSchedules[token].length; ++i) { UnlockStep storage step = unlockSchedules[token][i]; uint256 timeTier = step.timeOffset; uint256 percentage = step.percentage; if (timeElapsed >= timeTier) { unlockedAmount = unlockedAmount + ((vesting.amount * percentage) / 10000); } } return unlockedAmount; } function getVestingSchedule(address _user, uint256 _vestingIndex) public view returns (uint256[] memory, uint256[] memory) { Vesting storage vesting = vestings[_user][_vestingIndex]; address token = vesting.token; uint256 scheduleLength = unlockSchedules[token].length; uint256[] memory unlockTimestamps = new uint256[](scheduleLength); uint256[] memory unlockPercentages = new uint256[](scheduleLength); for (uint256 i = 0; i < scheduleLength; ++i) { UnlockStep storage step = unlockSchedules[token][i]; // Calculate the absolute unlock timestamp unlockTimestamps[i] = vesting.createdAt + step.timeOffset; unlockPercentages[i] = step.percentage; // Percentage is stored as scaled by 10000 (e.g., 2500 = 25%) } return (unlockTimestamps, unlockPercentages); } function getUnlockedVestingBonus(address _user, uint256 _vestingIndex) public view returns (uint256) { Vesting storage vesting = vestings[_user][_vestingIndex]; uint256 timeElapsed = block.timestamp - vesting.createdAt; address token = vesting.token; uint256 unlockedAmount = 0; for (uint256 i = 0; i < unlockSchedules[token].length; ++i) { UnlockStep storage step = unlockSchedules[token][i]; uint256 timeTier = step.timeOffset; uint256 percentage = step.percentage; if (timeElapsed >= timeTier) { unlockedAmount = unlockedAmount + ((vesting.bonus * percentage) / 10000); } } return unlockedAmount; } function claimVesting(uint256 _vestingIndex) external nonReentrant { Vesting storage vesting = vestings[msg.sender][_vestingIndex]; require(vesting.complete == false, "Stake is Complete"); uint256 maxClaim = getUnlockedVesting(msg.sender, _vestingIndex); require(maxClaim >= vesting.claimedAmount, "Invalid claim amount"); uint256 amountToClaim = maxClaim - vesting.claimedAmount; require(amountToClaim != 0, "No vested amount to claim"); vesting.claimedAmount = vesting.claimedAmount + amountToClaim; if (vesting.claimedAmount >= vesting.amount) { vesting.complete = true; } // Update user's dollarsVested if (dollarsVested[msg.sender] > 0) { uint256 usdPrice = (iPriceOracle(priceOracles[vesting.token]).getLatestPrice(vesting.token) * amountToClaim) / 1e18; if (usdPrice >= dollarsVested[msg.sender]) { dollarsVested[msg.sender] = 0; } else { dollarsVested[msg.sender] -= usdPrice; } } IERC20(vesting.token).safeTransfer(msg.sender, amountToClaim); emit VestingClaimed(msg.sender, amountToClaim, 0); } function claimAllVestingByToken(address _token) external nonReentrant { uint256 totalReward = 0; uint256 vestingsProcessed = 0; for (uint256 i = 0; i < vestings[msg.sender].length; ++i) { Vesting storage vesting = vestings[msg.sender][i]; if (vesting.token == _token && !vesting.complete) { uint256 maxClaim = getUnlockedVesting(msg.sender, i); require(maxClaim >= vesting.claimedAmount, "Invalid claim amount"); uint256 amountToClaim = maxClaim - vesting.claimedAmount; if (amountToClaim > 0) { vesting.claimedAmount = vesting.claimedAmount + amountToClaim; totalReward = totalReward + amountToClaim; vesting.lastClaimed = block.timestamp; // Mark vesting as complete if fully claimed if (vesting.claimedAmount >= vesting.amount) { vesting.complete = true; } vestingsProcessed++; } } } require(totalReward != 0, "No rewards to claim"); // Update user's dollarsVested if (dollarsVested[msg.sender] > 0) { uint256 usdPrice = (iPriceOracle(priceOracles[_token]).getLatestPrice(_token) * totalReward) / 1e18; if (usdPrice >= dollarsVested[msg.sender]) { dollarsVested[msg.sender] = 0; } else { dollarsVested[msg.sender] -= usdPrice; } } // Ensure the contract has enough balance to fulfill the claim uint256 poolBalance = IERC20(_token).balanceOf(address(this)); require(poolBalance >= totalReward, "Insufficient rewards in the pool"); // Transfer the aggregated reward IERC20(_token).safeTransfer(msg.sender, totalReward); emit RewardClaimed(msg.sender, totalReward); } function claimBonus(uint256 _vestingIndex) external nonReentrant { Vesting storage vesting = vestings[msg.sender][_vestingIndex]; uint256 maxBonus = getUnlockedVestingBonus(msg.sender, _vestingIndex); require(maxBonus >= vesting.claimedBonus, "Invalid claim amount"); uint256 bonusToClaim = maxBonus - vesting.claimedBonus; require(bonusToClaim != 0, "No vested amount to claim"); vesting.claimedBonus = vesting.claimedBonus + bonusToClaim; IERC20(vesting.token).safeTransfer(msg.sender, bonusToClaim); emit BonusClaimed(msg.sender, bonusToClaim); } function setPriceOracle(address _token, address _oracle) external onlyOwner { priceOracles[_token] = _oracle; } function viewRewards(address _user) external view returns (uint256) { uint256 totalReward = 0; for (uint256 i = 0; i < stakes[_user].length; ++i) { uint rewards = getPoolRewards(_user, i); totalReward = totalReward + rewards; } return totalReward; } // View function to get all stakes for a specific address function getStakes(address user) external view returns (Stake[] memory) { return stakes[user]; } // View function to get all vestings for a specific address function getVestings(address user) external view returns (Vesting[] memory) { return vestings[user]; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at, * consider using {ReentrancyGuardTransient} instead. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard struct ReentrancyGuardStorage { uint256 _status; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) { assembly { $.slot := ReentrancyGuardStorageLocation } } /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); $._status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // On the first call to nonReentrant, _status will be NOT_ENTERED if ($._status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail $._status = ENTERED; } function _nonReentrantAfter() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) $._status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); return $._status == ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol) pragma solidity ^0.8.20; import {IERC20} from "./IERC20.sol"; import {IERC165} from "./IERC165.sol"; /** * @title IERC1363 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363]. * * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction. */ interface IERC1363 is IERC20, IERC165 { /* * Note: the ERC-165 identifier for this interface is 0xb0202a11. * 0xb0202a11 === * bytes4(keccak256('transferAndCall(address,uint256)')) ^ * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^ * bytes4(keccak256('approveAndCall(address,uint256)')) ^ * bytes4(keccak256('approveAndCall(address,uint256,bytes)')) */ /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @param data Additional data with no specified format, sent in call to `spender`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612]. * * Adds the {permit} method, which can be used to change an account's ERC-20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 standard as defined in the ERC. */ 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 value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` 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 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC1363} from "../../../interfaces/IERC1363.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC-20 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 { /** * @dev An operation with an ERC-20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. * * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. * * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. * * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being * set here. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { safeTransfer(token, to, value); } else if (!token.transferAndCall(to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferFromAndCallRelaxed( IERC1363 token, address from, address to, uint256 value, bytes memory data ) internal { if (to.code.length == 0) { safeTransferFrom(token, from, to, value); } else if (!token.transferFromAndCall(from, to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}. * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall} * once without retrying, and relies on the returned value to be true. * * Reverts if the returned value is other than `true`. */ function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { forceApprove(token, to, value); } else if (!token.approveAndCall(to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements. */ function _callOptionalReturn(IERC20 token, bytes memory data) private { uint256 returnSize; uint256 returnValue; assembly ("memory-safe") { let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) // bubble errors if iszero(success) { let ptr := mload(0x40) returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } returnSize := returndatasize() returnValue := mload(0) } if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { bool success; uint256 returnSize; uint256 returnValue; assembly ("memory-safe") { success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) returnSize := returndatasize() returnValue := mload(0) } return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Address.sol) pragma solidity ^0.8.20; import {Errors} from "./Errors.sol"; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert Errors.InsufficientBalance(address(this).balance, amount); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert Errors.FailedCall(); } } /** * @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 or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {Errors.FailedCall} error. * * 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. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @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`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert Errors.InsufficientBalance(address(this).balance, value); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case * of an unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {Errors.FailedCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}. */ function _revert(bytes memory returndata) 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 assembly ("memory-safe") { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert Errors.FailedCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol) pragma solidity ^0.8.20; /** * @dev Collection of common custom errors used in multiple contracts * * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library. * It is recommended to avoid relying on the error API for critical functionality. * * _Available since v5.1._ */ library Errors { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error InsufficientBalance(uint256 balance, uint256 needed); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedCall(); /** * @dev The deployment failed. */ error FailedDeployment(); /** * @dev A necessary precompile is missing. */ error MissingPrecompile(address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
{ "optimizer": { "enabled": true, "runs": 200 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"bonus","type":"uint256"}],"name":"BonusClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CompoundRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FundsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"MinStakeLockUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lockupPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"dailyRewardRate","type":"uint256"}],"name":"PoolUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"RewardClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardsDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"UnlockScheduleSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bonus","type":"uint256"}],"name":"VestingClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bonus","type":"uint256"}],"name":"VestingCreated","type":"event"},{"inputs":[{"internalType":"address","name":"bot","type":"address"}],"name":"addBot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minTokens","type":"uint256"},{"internalType":"uint256","name":"maxTokens","type":"uint256"},{"internalType":"uint256","name":"boostPercentage","type":"uint256"}],"name":"addOrEditTier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"addOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"authorizedBots","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"boosttiers","outputs":[{"internalType":"uint256","name":"minTokens","type":"uint256"},{"internalType":"uint256","name":"maxTokens","type":"uint256"},{"internalType":"uint256","name":"boostPercentage","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"claimAllVestingByToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vestingIndex","type":"uint256"}],"name":"claimBonus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakeIndex","type":"uint256"}],"name":"claimStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vestingIndex","type":"uint256"}],"name":"claimVesting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"compoundAllRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"createStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"createStakeForUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"unlockTime","type":"uint256"},{"internalType":"uint256","name":"dailyRewardRate","type":"uint256"}],"internalType":"struct PacaFinanceWithBoostAndSchedule.StakeInput[]","name":"stakesInput","type":"tuple[]"}],"name":"createStakes","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"createVesting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"depositRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"dollarsVested","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"depositedTokens","type":"uint256"}],"name":"getBoost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_stakeIndex","type":"uint256"}],"name":"getPoolRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getStakes","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"lastClaimed","type":"uint256"},{"internalType":"uint256","name":"dailyRewardRate","type":"uint256"},{"internalType":"uint256","name":"unlockTime","type":"uint256"},{"internalType":"bool","name":"complete","type":"bool"}],"internalType":"struct PacaFinanceWithBoostAndSchedule.Stake[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_vestingIndex","type":"uint256"}],"name":"getUnlockedVesting","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_vestingIndex","type":"uint256"}],"name":"getUnlockedVestingBonus","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_vestingIndex","type":"uint256"}],"name":"getVestingSchedule","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getVestings","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"bonus","type":"uint256"},{"internalType":"uint256","name":"lockedUntil","type":"uint256"},{"internalType":"uint256","name":"claimedAmount","type":"uint256"},{"internalType":"uint256","name":"claimedBonus","type":"uint256"},{"internalType":"uint256","name":"lastClaimed","type":"uint256"},{"internalType":"uint256","name":"createdAt","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"complete","type":"bool"},{"internalType":"uint256","name":"usdAmount","type":"uint256"}],"internalType":"struct PacaFinanceWithBoostAndSchedule.Vesting[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockupDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minStakeLock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"owners","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pool","outputs":[{"internalType":"uint256","name":"lockupPeriod","type":"uint256"},{"internalType":"uint256","name":"dailyRewardRate","type":"uint256"},{"internalType":"uint256","name":"totalStaked","type":"uint256"},{"internalType":"uint256","name":"totalRewards","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"priceOracles","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"bot","type":"address"}],"name":"removeBot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"removeOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"removeTier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_oracle","type":"address"}],"name":"setPriceOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_lockTime","type":"uint256"},{"internalType":"uint256","name":"_percentagePerStep","type":"uint256"}],"name":"setUnlockScheduleByPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakes","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"lastClaimed","type":"uint256"},{"internalType":"uint256","name":"dailyRewardRate","type":"uint256"},{"internalType":"uint256","name":"unlockTime","type":"uint256"},{"internalType":"bool","name":"complete","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"unlockSchedules","outputs":[{"internalType":"uint256","name":"timeOffset","type":"uint256"},{"internalType":"uint256","name":"percentage","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lockupPeriod","type":"uint256"},{"internalType":"uint256","name":"_dailyRewardRate","type":"uint256"}],"name":"updatePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"updateStakeMin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"vestings","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"bonus","type":"uint256"},{"internalType":"uint256","name":"lockedUntil","type":"uint256"},{"internalType":"uint256","name":"claimedAmount","type":"uint256"},{"internalType":"uint256","name":"claimedBonus","type":"uint256"},{"internalType":"uint256","name":"lastClaimed","type":"uint256"},{"internalType":"uint256","name":"createdAt","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"complete","type":"bool"},{"internalType":"uint256","name":"usdAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"viewRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawFromStakingPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawFromVestingPool","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50614017806100206000396000f3fe6080604052600436106102675760003560e01c8063710ea0ce11610144578063ac97b417116100b6578063d91930251161007a578063d91930251461088f578063d9613410146108af578063da40ef80146108cf578063e4d06f90146108ef578063f17ca4d11461090f578063ffecf5161461092257600080fd5b8063ac97b41714610771578063b92a349f14610791578063bd84477d146107b1578063bed9757e14610826578063cfb866da1461085457600080fd5b80638129fc1c116101085780638129fc1c146106bc578063853e0df2146106d15780638bdf67f2146106f15780638da5cb5b146107115780639562ee151461073157806396ed7f891461075157600080fd5b8063710ea0ce146106025780637497211b146106225780637a0c6dc0146106425780637ba6f4581461066f57806380ca0ecf1461069c57600080fd5b80633f35e722116101dd578063592d1dd1116101a1578063592d1dd1146105405780635fecd9261461056d57806367a74ddc1461058d5780636ae21510146105ad5780636c3b0c53146105c25780637065cb48146105e257600080fd5b80633f35e7221461046157806343c7c0111461048157806344c7d6ef146104a157806351f6cf2f146104c1578063584b62a1146104f657600080fd5b8063173825d91161022f578063173825d9146103ae5780631ada70a8146103d05780631bf6ddae146103e6578063372500ab1461040657806338a85ce21461041b5780633ba8396e1461043157600080fd5b8063013745181461026c578063022914a7146102bf5780630a84096a146102ff57806313c8e2de1461032d57806316f0115b1461034d575b600080fd5b34801561027857600080fd5b506102a2610287366004613ae6565b600b602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102cb57600080fd5b506102ef6102da366004613ae6565b60076020526000908152604090205460ff1681565b60405190151581526020016102b6565b34801561030b57600080fd5b5061031f61031a366004613b08565b610942565b6040519081526020016102b6565b34801561033957600080fd5b5061031f610348366004613b32565b610a5d565b34801561035957600080fd5b5060015460025460035460045460055461037d94939291906001600160a01b031685565b6040805195865260208601949094529284019190915260608301526001600160a01b0316608082015260a0016102b6565b3480156103ba57600080fd5b506103ce6103c9366004613ae6565b610b0e565b005b3480156103dc57600080fd5b5061031f600d5481565b3480156103f257600080fd5b506103ce610401366004613b32565b610c0f565b34801561041257600080fd5b506103ce610d7f565b34801561042757600080fd5b5061031f600e5481565b34801561043d57600080fd5b506102ef61044c366004613ae6565b600f6020526000908152604090205460ff1681565b34801561046d57600080fd5b506103ce61047c366004613b08565b610ee8565b34801561048d57600080fd5b506103ce61049c366004613ae6565b610f6f565b3480156104ad57600080fd5b506103ce6104bc366004613b32565b6112f4565b3480156104cd57600080fd5b506104e16104dc366004613b08565b6115ab565b604080519283526020830191909152016102b6565b34801561050257600080fd5b50610516610511366004613b08565b6115e7565b6040805195865260208601949094529284019190915260608301521515608082015260a0016102b6565b34801561054c57600080fd5b5061031f61055b366004613ae6565b600c6020526000908152604090205481565b34801561057957600080fd5b506103ce610588366004613ae6565b611638565b34801561059957600080fd5b506103ce6105a8366004613b4b565b6116d0565b3480156105b957600080fd5b506103ce61172d565b3480156105ce57600080fd5b506103ce6105dd366004613b08565b611906565b3480156105ee57600080fd5b506103ce6105fd366004613ae6565b611c34565b34801561060e57600080fd5b5061031f61061d366004613b08565b611ce3565b34801561062e57600080fd5b506103ce61063d366004613b32565b611d7a565b34801561064e57600080fd5b5061066261065d366004613ae6565b611eb8565b6040516102b69190613b7e565b34801561067b57600080fd5b5061068f61068a366004613ae6565b611f9f565b6040516102b69190613c2c565b3480156106a857600080fd5b5061031f6106b7366004613b08565b61203a565b3480156106c857600080fd5b506103ce612146565b3480156106dd57600080fd5b506103ce6106ec366004613b32565b61263c565b3480156106fd57600080fd5b506103ce61070c366004613b32565b6126c9565b34801561071d57600080fd5b506006546102a2906001600160a01b031681565b34801561073d57600080fd5b506103ce61074c366004613b32565b612758565b34801561075d57600080fd5b506103ce61076c366004613c8f565b6127bc565b34801561077d57600080fd5b506103ce61078c366004613b32565b61283d565b34801561079d57600080fd5b506103ce6107ac366004613cb1565b612aee565b3480156107bd57600080fd5b506107d16107cc366004613b08565b612d35565b604080519a8b5260208b0199909952978901969096526060880194909452608087019290925260a086015260c08501526001600160a01b031660e08401521515610100830152610120820152610140016102b6565b34801561083257600080fd5b50610846610841366004613b08565b612db3565b6040516102b6929190613d1f565b34801561086057600080fd5b5061087461086f366004613b32565b612f59565b604080519384526020840192909252908201526060016102b6565b34801561089b57600080fd5b506103ce6108aa366004613b32565b612f8c565b3480156108bb57600080fd5b506103ce6108ca366004613d4d565b6130b7565b3480156108db57600080fd5b5061031f6108ea366004613ae6565b613301565b3480156108fb57600080fd5b506103ce61090a366004613b08565b613359565b6103ce61091d366004613d79565b6134cf565b34801561092e57600080fd5b506103ce61093d366004613ae6565b61361a565b6001600160a01b038216600090815260096020526040812080548291908490811061096f5761096f613dee565b9060005260206000209060090201905060008160060154426109919190613e1a565b60078301549091506001600160a01b03166000805b6001600160a01b0383166000908152600a6020526040902054811015610a50576001600160a01b0383166000908152600a602052604081208054839081106109f0576109f0613dee565b600091825260209091206002909102018054600182015491925090818710610a3c57612710818960010154610a259190613e2d565b610a2f9190613e5a565b610a399086613e6e565b94505b50505080610a4990613e81565b90506109a6565b5093505050505b92915050565b6000805b600054811015610b055760008181548110610a7e57610a7e613dee565b9060005260206000209060030201600001548310158015610ac3575060008181548110610aad57610aad613dee565b9060005260206000209060030201600101548311155b15610af55760008181548110610adb57610adb613dee565b906000526020600020906003020160020154915050919050565b610afe81613e81565b9050610a61565b50600092915050565b3360009081526007602052604090205460ff16610b465760405162461bcd60e51b8152600401610b3d90613e9a565b60405180910390fd5b6001600160a01b03811660009081526007602052604090205460ff16610b9d5760405162461bcd60e51b815260206004820152600c60248201526b2737ba1030b71037bbb732b960a11b6044820152606401610b3d565b336001600160a01b03821603610bee5760405162461bcd60e51b815260206004820152601660248201527521b0b73737ba103932b6b7bb32903cb7bab939b2b63360511b6044820152606401610b3d565b6001600160a01b03166000908152600760205260409020805460ff19169055565b600e54610c218264e8d4a51000613e2d565b11610c3e5760405162461bcd60e51b8152600401610b3d90613ec2565b600554610c56906001600160a01b03163330846136b5565b600254336000908152600c6020526040902054610c7290610a5d565b610c7c9082613e6e565b905060086000336001600160a01b03166001600160a01b031681526020019081526020016000206040518060a0016040528084815260200142815260200183815260200160016000015442610cd19190613e6e565b81526000602091820181905283546001808201865594825290829020835160059092020190815590820151928101929092556040810151600283015560608101516003808401919091556080909101516004909201805460ff19169215159290921790915554610d42908390613e6e565b60035560405182815233907f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d906020015b60405180910390a25050565b610d87613722565b6000805b33600090815260086020526040902054811015610e0857336000908152600860205260408120805483908110610dc357610dc3613dee565b906000526020600020906005020190506000610ddf3384611ce3565b9050610deb8185613e6e565b42600190930192909255509150610e0181613e81565b9050610d8b565b5080600003610e4f5760405162461bcd60e51b81526020600482015260136024820152724e6f207265776172647320746f20636c61696d60681b6044820152606401610b3d565b600454811115610e715760405162461bcd60e51b8152600401610b3d90613f05565b600454610e7f908290613e1a565b600455600554610e99906001600160a01b0316338361375a565b60405181815233907f106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f72419060200160405180910390a250610ee66001600080516020613fc283398151915255565b565b3360009081526007602052604090205460ff16610f175760405162461bcd60e51b8152600401610b3d90613e9a565b610f2b6001600160a01b038316338361375a565b6040518181526001600160a01b0383169033907fa92ff919b850e4909ab2261d907ef955f11bc1716733a6cbece38d163a69af8a9060200160405180910390a35050565b610f77613722565b60008060005b336000908152600960205260409020548110156110b057336000908152600960205260408120805483908110610fb557610fb5613dee565b6000918252602090912060099091020160078101549091506001600160a01b038681169116148015610ff357506007810154600160a01b900460ff16155b1561109f576000611004338461203a565b9050816003015481101561102a5760405162461bcd60e51b8152600401610b3d90613f3a565b600082600301548261103c9190613e1a565b9050801561109c578083600301546110549190613e6e565b60038401556110638187613e6e565b426005850155835460038501549197501161108e5760078301805460ff60a01b1916600160a01b1790555b8461109881613e81565b9550505b50505b506110a981613e81565b9050610f7d565b50816000036110f75760405162461bcd60e51b81526020600482015260136024820152724e6f207265776172647320746f20636c61696d60681b6044820152606401610b3d565b336000908152600c602052604090205415611200576001600160a01b038381166000818152600b60205260408082205490516302c68be360e31b815260048101939093529092670de0b6b3a7640000928692909116906316345f1890602401602060405180830381865afa158015611173573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111979190613f68565b6111a19190613e2d565b6111ab9190613e5a565b336000908152600c602052604090205490915081106111d957336000908152600c60205260408120556111fe565b336000908152600c6020526040812080548392906111f8908490613e1a565b90915550505b505b6040516370a0823160e01b81523060048201526000906001600160a01b038516906370a0823190602401602060405180830381865afa158015611247573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126b9190613f68565b90508281101561128d5760405162461bcd60e51b8152600401610b3d90613f05565b6112a16001600160a01b038516338561375a565b60405183815233907f106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f7241906020015b60405180910390a25050506112f16001600080516020613fc283398151915255565b50565b6112fc613722565b3360009081526008602052604090205481106113505760405162461bcd60e51b8152602060048201526013602482015272092dcecc2d8d2c840e6e8c2d6ca40d2dcc8caf606b1b6044820152606401610b3d565b33600090815260086020526040812080548390811061137157611371613dee565b6000918252602082206005909102018054909250906113903385611ce3565b905061139c8183613e6e565b9150816000036113e35760405162461bcd60e51b81526020600482015260126024820152714e6f20616d6f756e7420746f20636c61696d60701b6044820152606401610b3d565b826003015442101561142f5760405162461bcd60e51b815260206004820152601560248201527414dd185ad9481a5cc81cdd1a5b1b081b1bd8dad959605a1b6044820152606401610b3d565b6005546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015611478573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149c9190613f68565b9050828110156114be5760405162461bcd60e51b8152600401610b3d90613f05565b600080855560048501805460ff19166001179055600380548592906114e4908490613e1a565b9091555050600554611500906001600160a01b0316338561375a565b33600090815260086020526040902080548690811061152157611521613dee565b60009182526020822060059091020181815560018101829055600281018290556003810191909155600401805460ff1916905560405133907f106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f7241906115889086815260200190565b60405180910390a2505050506112f16001600080516020613fc283398151915255565b600a60205281600052604060002081815481106115c757600080fd5b600091825260209091206002909102018054600190910154909250905082565b6008602052816000526040600020818154811061160357600080fd5b600091825260209091206005909102018054600182015460028301546003840154600490940154929550909350919060ff1685565b3360009081526007602052604090205460ff166116675760405162461bcd60e51b8152600401610b3d90613e9a565b6001600160a01b0381166116af5760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b6044820152606401610b3d565b6001600160a01b03166000908152600f60205260409020805460ff19169055565b3360009081526007602052604090205460ff166116ff5760405162461bcd60e51b8152600401610b3d90613e9a565b6001600160a01b039182166000908152600b6020526040902080546001600160a01b03191691909216179055565b6000805b336000908152600860205260409020548110156117ae5733600090815260086020526040812080548390811061176957611769613dee565b9060005260206000209060050201905060006117853384611ce3565b90506117918185613e6e565b426001909301929092555091506117a781613e81565b9050611731565b50600e5481116117f95760405162461bcd60e51b8152602060048201526016602482015275139bdd08195b9bdd59da081d1bc818dbdb5c1bdd5b9960521b6044820152606401610b3d565b336000818152600860209081526040808320815160a0810183528681524281850152948452600c909252918290205490929182019061183790610a5d565b6002546118449190613e6e565b81526020016001600001544261185a9190613e6e565b81526000602091820181905283546001808201865594825290829020835160059092020190815590820151928101929092556040810151600283015560608101516003808401919091556080909101516004909201805460ff191692151592909217909155546118cb908290613e6e565b60035560405181815233907f3afe5b60dee16617a8adbbd7d6c28f17a27efabb834872efa8e7ad5dafddf6f19060200160405180910390a250565b806000036119565760405162461bcd60e51b815260206004820181905260248201527f416d6f756e74206d7573742062652067726561746572207468616e207a65726f6044820152606401610b3d565b6001600160a01b038083166000908152600b602052604090205416806119ca5760405162461bcd60e51b815260206004820152602360248201527f5072696365206f7261636c65206e6f742073657420666f72207468697320746f60448201526235b2b760e91b6064820152608401610b3d565b6119df6001600160a01b0384163330856136b5565b600060646119ee600a85613e2d565b6119f89190613e5a565b6001600160a01b038581166000818152600b60205260408082205490516302c68be360e31b8152600481019390935293945092670de0b6b3a76400009287929116906316345f1890602401602060405180830381865afa158015611a60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a849190613f68565b611a8e9190613e2d565b611a989190613e5a565b9050600e548111611abb5760405162461bcd60e51b8152600401610b3d90613ec2565b336000908152600c602052604081208054839290611ada908490613e6e565b909155505033600090815260096020908152604091829020825161014081018452878152918201859052600d549092820190611b169042613e6e565b81526000602080830182905260408084018390524260608086018290526080808701929092526001600160a01b038d811660a08089019190915260c080890188905260e09889018c90528a5460018082018d559b8952978790208a51600990990201978855898701519a88019a909a558885015160028801559188015160038701559187015160048601558601516005850155958501516006840155928401516007830180546101008701511515600160a01b026001600160a81b031990911692909716919091179590951790945561012090920151600890920191909155805186815291820184905233917f9ade76f4385de306666dfb21a52b27d52db0fde8ad0f515fa261f532cac60d21910160405180910390a25050505050565b3360009081526007602052604090205460ff16611c635760405162461bcd60e51b8152600401610b3d90613e9a565b6001600160a01b03811660009081526007602052604090205460ff1615611cbf5760405162461bcd60e51b815260206004820152601060248201526f20b63932b0b23c9030b71037bbb732b960811b6044820152606401610b3d565b6001600160a01b03166000908152600760205260409020805460ff19166001179055565b6001600160a01b0382166000908152600860205260408120805482919084908110611d1057611d10613dee565b906000526020600020906005020190506000816001015442611d329190613e1a565b90506000612710620151808385600201548660000154611d529190613e2d565b611d5c9190613e2d565b611d669190613e5a565b611d709190613e5a565b9695505050505050565b3360009081526007602052604090205460ff16611da95760405162461bcd60e51b8152600401610b3d90613e9a565b6000548110611df05760405162461bcd60e51b8152602060048201526013602482015272496e646578206f7574206f6620626f756e647360681b6044820152606401610b3d565b805b600054611e0190600190613e1a565b811015611e7e576000611e15826001613e6e565b81548110611e2557611e25613dee565b906000526020600020906003020160008281548110611e4657611e46613dee565b60009182526020909120825460039092020190815560018083015490820155600291820154910155611e7781613e81565b9050611df2565b506000805480611e9057611e90613f81565b6000828152602081206003600019909301928302018181556001810182905560020155905550565b6001600160a01b0381166000908152600960209081526040808320805482518185028101850190935280835260609492939192909184015b82821015611f9457600084815260209081902060408051610140810182526009860290920180548352600180820154848601526002820154928401929092526003810154606084015260048101546080840152600581015460a0840152600681015460c084015260078101546001600160a01b03811660e0850152600160a01b900460ff161515610100840152600801546101208301529083529092019101611ef0565b505050509050919050565b6001600160a01b0381166000908152600860209081526040808320805482518185028101850190935280835260609492939192909184015b82821015611f945760008481526020908190206040805160a081018252600586029092018054835260018082015484860152600282015492840192909252600381015460608401526004015460ff16151560808301529083529092019101611fd7565b6001600160a01b038216600090815260096020526040812080548291908490811061206757612067613dee565b9060005260206000209060090201905060008160060154426120899190613e1a565b60078301549091506001600160a01b03166000805b6001600160a01b0383166000908152600a6020526040902054811015610a50576001600160a01b0383166000908152600a602052604081208054839081106120e8576120e8613dee565b6000918252602090912060029091020180546001820154919250908187106121325787546127109061211b908390613e2d565b6121259190613e5a565b61212f9086613e6e565b94505b5050508061213f90613e81565b905061209e565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff1660008115801561218c5750825b905060008267ffffffffffffffff1660011480156121a95750303b155b9050811580156121b7575080155b156121d55760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156121ff57845460ff60401b1916600160401b1785555b61220761379f565b600680546001600160a01b03199081167341970ce76b656030a79e7c1fa76fc4eb93980255178255600760209081527f1428bfef657344f5f7a0019d1554dccabe000be344bb83cdab918bd50f24b573805460ff1990811660019081179092556301499700600d81905567de0b6b3a76400000600e55600580549095167329219dd400f2bf60e5a23d13be72b486d4038894178555825560216002908155604080516060808201835268bdbc41e0348b300000825269021e0c0013070adc000082880190815282840187815260008054808a018255818052945160039586027f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5638181019290925593517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5648086019190915592517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e565948501558651808601885269021e19e0c9bab2400000815269043c25e0dcc1bd1c0000818d01908152818901998a528354808d01855584805291519188028084019290925551818501559751978401979097558551808501875269043c33c1937564800000815269065a3fc1a67c6f5c0000818c019081528188018781528354808d0185558480529251928802808b019390935590518285015551908401558551808501875269065a4da25d3016c00000815269087859a27037219c0000818c0190815260048289019081528354808d0185558480529251928802808b0193909355905182850155519084015585518085018752690878678326eac90000008152690cb48d6403ac861c0000818c019081528188019c8d528254808c0184558380529151918702808a019290925551818401559a519a83019a909a5584518084018652690cb49b44ba602d80000081526910f0c1259721ea9c0000818b019081528187019c8d528b54808b018d558c805291519186028089019290925551818301559a519a82019a909a55835180830185526910f0cf064dd592000000815269152cf4e72a974f1c0000818a0190815260088287019081528b54808b018d558c80529251928602808901939093559051828d015551908201558351918201845269152d02c7e14af68000008252600019828901908152600a94830194855289548089018b558a80529251929093029485019190915590519783019790975551950194909455600f9091527f77c9ddf83be31065a9eb7ed19d93a8a4db24cad8351f41cc546083ac9e9d8c7f8054841682179055737c40f272570fdf9549d6f67493ac250a1db52f279091527f1b209462f90614903451721396f08356b5037572bebcd67a02efc98f03bec9d18054909216179055831561263557845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050565b3360009081526007602052604090205460ff1661266b5760405162461bcd60e51b8152600401610b3d90613e9a565b600554612682906001600160a01b0316338361375a565b6005546040518281526001600160a01b039091169033907fa92ff919b850e4909ab2261d907ef955f11bc1716733a6cbece38d163a69af8a9060200160405180910390a350565b3360009081526007602052604090205460ff166126f85760405162461bcd60e51b8152600401610b3d90613e9a565b600554612710906001600160a01b03163330846136b5565b60045461271e908290613e6e565b6004556040518181527f4e9221f2cca6ca0397acc6004ea0b716798254f5abcf53924fab34f0373e5d4e906020015b60405180910390a150565b3360009081526007602052604090205460ff166127875760405162461bcd60e51b8152600401610b3d90613e9a565b600e8190556040518181527fe5dadb089824c750e4e7a2e98bfbe130f1a09834769e81339639fbe18606859b9060200161274d565b3360009081526007602052604090205460ff166127eb5760405162461bcd60e51b8152600401610b3d90613e9a565b6127f88262015180613e2d565b600155600281905560408051838152602081018390527f7fa9647ec1cc14e3822b46d05a2b9d4e019bde8875c0088c46b6503d71bf1722910160405180910390a15050565b612845613722565b33600090815260096020526040812080548390811061286657612866613dee565b600091825260209091206009909102016007810154909150600160a01b900460ff16156128c95760405162461bcd60e51b81526020600482015260116024820152705374616b6520697320436f6d706c65746560781b6044820152606401610b3d565b60006128d5338461203a565b905081600301548110156128fb5760405162461bcd60e51b8152600401610b3d90613f3a565b600082600301548261290d9190613e1a565b90508060000361295b5760405162461bcd60e51b81526020600482015260196024820152784e6f2076657374656420616d6f756e7420746f20636c61696d60381b6044820152606401610b3d565b80836003015461296b9190613e6e565b6003840181905583541161298f5760078301805460ff60a01b1916600160a01b1790555b336000908152600c602052604090205415612a9d5760078301546001600160a01b039081166000818152600b60205260408082205490516302c68be360e31b815260048101939093529092670de0b6b3a7640000928592909116906316345f1890602401602060405180830381865afa158015612a10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a349190613f68565b612a3e9190613e2d565b612a489190613e5a565b336000908152600c60205260409020549091508110612a7657336000908152600c6020526040812055612a9b565b336000908152600c602052604081208054839290612a95908490613e1a565b90915550505b505b6007830154612ab6906001600160a01b0316338361375a565b604080518281526000602082015233917f4a94c2c356e29a6583071e731bdacf2ca56565ba5efebcff6936eb7923b5172191016112cf565b3360009081526007602052604090205460ff16612b1d5760405162461bcd60e51b8152600401610b3d90613e9a565b81600003612b795760405162461bcd60e51b815260206004820152602360248201527f4c6f636b2074696d65206d7573742062652067726561746572207468616e207a60448201526265726f60e81b6064820152608401610b3d565b80600003612bdf5760405162461bcd60e51b815260206004820152602d60248201527f50657263656e74616765207065722073746570206d757374206265206772656160448201526c746572207468616e207a65726f60981b6064820152608401610b3d565b612710612bec8282613f97565b15612c445760405162461bcd60e51b815260206004820152602260248201527f50657263656e74616765206d757374206469766964652031303025206576656e6044820152616c7960f01b6064820152608401610b3d565b6000612c508383613e5a565b90506000612c5e8286613e5a565b6001600160a01b0387166000908152600a60205260408120919250612c839190613a8f565b60015b828111612cf8576001600160a01b0387166000908152600a60205260409081902081518083019092529080612cbb8486613e2d565b815260209081018890528254600181810185556000948552938290208351600290920201908155910151910155612cf181613e81565b9050612c86565b506040516001600160a01b038716907fde4b6ccc38b84f88129403b65a309f9b1c41d4c316bc2118d7614e449b9d4c4590600090a2505050505050565b60096020528160005260406000208181548110612d5157600080fd5b6000918252602090912060099091020180546001820154600283015460038401546004850154600586015460068701546007880154600890980154969950949750929591949093916001600160a01b03811691600160a01b90910460ff16908a565b6001600160a01b038216600090815260096020526040812080546060928392909185908110612de457612de4613dee565b600091825260208083206007600990930201918201546001600160a01b0316808452600a9091526040832054919350918167ffffffffffffffff811115612e2d57612e2d613fab565b604051908082528060200260200182016040528015612e56578160200160208202803683370190505b50905060008267ffffffffffffffff811115612e7457612e74613fab565b604051908082528060200260200182016040528015612e9d578160200160208202803683370190505b50905060005b83811015612f4a576001600160a01b0385166000908152600a60205260408120805483908110612ed557612ed5613dee565b9060005260206000209060020201905080600001548760060154612ef99190613e6e565b848381518110612f0b57612f0b613dee565b6020026020010181815250508060010154838381518110612f2e57612f2e613dee565b602090810291909101015250612f4381613e81565b9050612ea3565b50909890975095505050505050565b60008181548110612f6957600080fd5b600091825260209091206003909102018054600182015460029092015490925083565b612f94613722565b336000908152600960205260408120805483908110612fb557612fb5613dee565b906000526020600020906009020190506000612fd13384610942565b90508160040154811015612ff75760405162461bcd60e51b8152600401610b3d90613f3a565b60008260040154826130099190613e1a565b9050806000036130575760405162461bcd60e51b81526020600482015260196024820152784e6f2076657374656420616d6f756e7420746f20636c61696d60381b6044820152606401610b3d565b8083600401546130679190613e6e565b60048401556007830154613085906001600160a01b0316338361375a565b60405181815233907f4e69fdc49495bcab2b4375781457ba16653a90eb4ffb6588351bdc39071433e2906020016112cf565b3360009081526007602052604090205460ff166130e65760405162461bcd60e51b8152600401610b3d90613e9a565b81831061314a5760405162461bcd60e51b815260206004820152602c60248201527f496e76616c69642072616e67653a206d696e546f6b656e73206d75737420626560448201526b203c206d6178546f6b656e7360a01b6064820152608401610b3d565b61315483836137af565b156131ac5760405162461bcd60e51b815260206004820152602260248201527f52616e6765206f7665726c6170732077697468206578697374696e6720746965604482015261727360f01b6064820152608401610b3d565b60005b6000548110156132535783600082815481106131cd576131cd613dee565b90600052602060002090600302016000015414801561320f575082600082815481106131fb576131fb613dee565b906000526020600020906003020160010154145b1561324357816000828154811061322857613228613dee565b90600052602060002090600302016002018190555050505050565b61324c81613e81565b90506131af565b5060408051606081018252848152602081018481529181018381526000805460018101825590805291517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56360039093029283015591517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56482015590517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e565909101556132fc61383e565b505050565b600080805b6001600160a01b0384166000908152600860205260409020548110156133525760006133328583611ce3565b905061333e8184613e6e565b9250508061334b90613e81565b9050613306565b5092915050565b3360009081526007602052604090205460ff166133885760405162461bcd60e51b8152600401610b3d90613e9a565b806000036133c95760405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a5908185b5bdd5b9d60921b6044820152606401610b3d565b60086000836001600160a01b03166001600160a01b031681526020019081526020016000206040518060a0016040528083815260200142815260200160018001548152602001600160000154426134209190613e6e565b81526000602091820181905283546001808201865594825290829020835160059092020190815590820151928101929092556040810151600283015560608101516003808401919091556080909101516004909201805460ff19169215159290921790915554613491908290613e6e565b6003556040518181526001600160a01b038316907f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d90602001610d73565b336000908152600f602052604090205460ff1661352e5760405162461bcd60e51b815260206004820152601f60248201527f43616c6c6572206973206e6f7420616e20617574686f72697a656420626f74006044820152606401610b3d565b804260005b82811015612635573685858381811061354e5761354e613dee565b9050608002019050806020013560016002015461356b9190613e6e565b6003556008600061357f6020840184613ae6565b6001600160a01b0316815260208082019290925260409081016000908120825160a081018452858501358152808501888152606080880135838701908152979095013594820194855260808201848152835460018082018655948652969094209151600590960290910194855551848201559351600284015590516003830155516004909101805460ff191691151591909117905501613533565b3360009081526007602052604090205460ff166136495760405162461bcd60e51b8152600401610b3d90613e9a565b6001600160a01b0381166136915760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b6044820152606401610b3d565b6001600160a01b03166000908152600f60205260409020805460ff19166001179055565b6040516001600160a01b03848116602483015283811660448301526064820183905261371c9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506139cd565b50505050565b600080516020613fc283398151915280546001190161375457604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b6040516001600160a01b038381166024830152604482018390526132fc91859182169063a9059cbb906064016136ea565b6001600080516020613fc283398151915255565b6137a7613a3e565b610ee6613a87565b6000805b60005481101561383457600081815481106137d0576137d0613dee565b90600052602060002090600302016001015484111580156138155750600081815481106137ff576137ff613dee565b9060005260206000209060030201600001548310155b15613824576001915050610a57565b61382d81613e81565b90506137b3565b5060009392505050565b60005b6000548110156112f1576000613858826001613e6e565b90505b6000548110156139bc576000818154811061387857613878613dee565b9060005260206000209060030201600001546000838154811061389d5761389d613dee565b90600052602060002090600302016000015411156139aa5760008083815481106138c9576138c9613dee565b9060005260206000209060030201604051806060016040529081600082015481526020016001820154815260200160028201548152505090506000828154811061391557613915613dee565b90600052602060002090600302016000848154811061393657613936613dee565b9060005260206000209060030201600082015481600001556001820154816001015560028201548160020155905050806000838154811061397957613979613dee565b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020155905050505b806139b481613e81565b91505061385b565b506139c681613e81565b9050613841565b600080602060008451602086016000885af1806139f0576040513d6000823e3d81fd5b50506000513d91508115613a08578060011415613a15565b6001600160a01b0384163b155b1561371c57604051635274afe760e01b81526001600160a01b0385166004820152602401610b3d565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff16610ee657604051631afcd79f60e31b815260040160405180910390fd5b61378b613a3e565b50805460008255600202906000526020600020908101906112f191905b80821115613ac65760008082556001820155600201613aac565b5090565b80356001600160a01b0381168114613ae157600080fd5b919050565b600060208284031215613af857600080fd5b613b0182613aca565b9392505050565b60008060408385031215613b1b57600080fd5b613b2483613aca565b946020939093013593505050565b600060208284031215613b4457600080fd5b5035919050565b60008060408385031215613b5e57600080fd5b613b6783613aca565b9150613b7560208401613aca565b90509250929050565b602080825282518282018190526000919060409081850190868401855b82811015613c1f5781518051855286810151878601528581015186860152606080820151908601526080808201519086015260a0808201519086015260c0808201519086015260e0808201516001600160a01b0316908601526101008082015115159086015261012090810151908501526101409093019290850190600101613b9b565b5091979650505050505050565b602080825282518282018190526000919060409081850190868401855b82811015613c1f57815180518552868101518786015285810151868601526060808201519086015260809081015115159085015260a09093019290850190600101613c49565b60008060408385031215613ca257600080fd5b50508035926020909101359150565b600080600060608486031215613cc657600080fd5b613ccf84613aca565b95602085013595506040909401359392505050565b600081518084526020808501945080840160005b83811015613d1457815187529582019590820190600101613cf8565b509495945050505050565b604081526000613d326040830185613ce4565b8281036020840152613d448185613ce4565b95945050505050565b600080600060608486031215613d6257600080fd5b505081359360208301359350604090920135919050565b60008060208385031215613d8c57600080fd5b823567ffffffffffffffff80821115613da457600080fd5b818501915085601f830112613db857600080fd5b813581811115613dc757600080fd5b8660208260071b8501011115613ddc57600080fd5b60209290920196919550909350505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115610a5757610a57613e04565b8082028115828204841417610a5757610a57613e04565b634e487b7160e01b600052601260045260246000fd5b600082613e6957613e69613e44565b500490565b80820180821115610a5757610a57613e04565b600060018201613e9357613e93613e04565b5060010190565b6020808252600e908201526d139bdd08185d5d1a1bdc9a5e995960921b604082015260600190565b60208082526023908201527f416d6f756e74206d7573742062652067726561746572206d696e5374616b654c6040820152626f636b60e81b606082015260800190565b6020808252818101527f496e73756666696369656e74207265776172647320696e2074686520706f6f6c604082015260600190565b602080825260149082015273125b9d985b1a590818db185a5b48185b5bdd5b9d60621b604082015260600190565b600060208284031215613f7a57600080fd5b5051919050565b634e487b7160e01b600052603160045260246000fd5b600082613fa657613fa6613e44565b500690565b634e487b7160e01b600052604160045260246000fdfe9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a264697066735822122039af34d0748ff9359e4c0802def9ed8a49114a877d02cdd4fdf8a6114bc7265064736f6c63430008140033
Deployed Bytecode
0x6080604052600436106102675760003560e01c8063710ea0ce11610144578063ac97b417116100b6578063d91930251161007a578063d91930251461088f578063d9613410146108af578063da40ef80146108cf578063e4d06f90146108ef578063f17ca4d11461090f578063ffecf5161461092257600080fd5b8063ac97b41714610771578063b92a349f14610791578063bd84477d146107b1578063bed9757e14610826578063cfb866da1461085457600080fd5b80638129fc1c116101085780638129fc1c146106bc578063853e0df2146106d15780638bdf67f2146106f15780638da5cb5b146107115780639562ee151461073157806396ed7f891461075157600080fd5b8063710ea0ce146106025780637497211b146106225780637a0c6dc0146106425780637ba6f4581461066f57806380ca0ecf1461069c57600080fd5b80633f35e722116101dd578063592d1dd1116101a1578063592d1dd1146105405780635fecd9261461056d57806367a74ddc1461058d5780636ae21510146105ad5780636c3b0c53146105c25780637065cb48146105e257600080fd5b80633f35e7221461046157806343c7c0111461048157806344c7d6ef146104a157806351f6cf2f146104c1578063584b62a1146104f657600080fd5b8063173825d91161022f578063173825d9146103ae5780631ada70a8146103d05780631bf6ddae146103e6578063372500ab1461040657806338a85ce21461041b5780633ba8396e1461043157600080fd5b8063013745181461026c578063022914a7146102bf5780630a84096a146102ff57806313c8e2de1461032d57806316f0115b1461034d575b600080fd5b34801561027857600080fd5b506102a2610287366004613ae6565b600b602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102cb57600080fd5b506102ef6102da366004613ae6565b60076020526000908152604090205460ff1681565b60405190151581526020016102b6565b34801561030b57600080fd5b5061031f61031a366004613b08565b610942565b6040519081526020016102b6565b34801561033957600080fd5b5061031f610348366004613b32565b610a5d565b34801561035957600080fd5b5060015460025460035460045460055461037d94939291906001600160a01b031685565b6040805195865260208601949094529284019190915260608301526001600160a01b0316608082015260a0016102b6565b3480156103ba57600080fd5b506103ce6103c9366004613ae6565b610b0e565b005b3480156103dc57600080fd5b5061031f600d5481565b3480156103f257600080fd5b506103ce610401366004613b32565b610c0f565b34801561041257600080fd5b506103ce610d7f565b34801561042757600080fd5b5061031f600e5481565b34801561043d57600080fd5b506102ef61044c366004613ae6565b600f6020526000908152604090205460ff1681565b34801561046d57600080fd5b506103ce61047c366004613b08565b610ee8565b34801561048d57600080fd5b506103ce61049c366004613ae6565b610f6f565b3480156104ad57600080fd5b506103ce6104bc366004613b32565b6112f4565b3480156104cd57600080fd5b506104e16104dc366004613b08565b6115ab565b604080519283526020830191909152016102b6565b34801561050257600080fd5b50610516610511366004613b08565b6115e7565b6040805195865260208601949094529284019190915260608301521515608082015260a0016102b6565b34801561054c57600080fd5b5061031f61055b366004613ae6565b600c6020526000908152604090205481565b34801561057957600080fd5b506103ce610588366004613ae6565b611638565b34801561059957600080fd5b506103ce6105a8366004613b4b565b6116d0565b3480156105b957600080fd5b506103ce61172d565b3480156105ce57600080fd5b506103ce6105dd366004613b08565b611906565b3480156105ee57600080fd5b506103ce6105fd366004613ae6565b611c34565b34801561060e57600080fd5b5061031f61061d366004613b08565b611ce3565b34801561062e57600080fd5b506103ce61063d366004613b32565b611d7a565b34801561064e57600080fd5b5061066261065d366004613ae6565b611eb8565b6040516102b69190613b7e565b34801561067b57600080fd5b5061068f61068a366004613ae6565b611f9f565b6040516102b69190613c2c565b3480156106a857600080fd5b5061031f6106b7366004613b08565b61203a565b3480156106c857600080fd5b506103ce612146565b3480156106dd57600080fd5b506103ce6106ec366004613b32565b61263c565b3480156106fd57600080fd5b506103ce61070c366004613b32565b6126c9565b34801561071d57600080fd5b506006546102a2906001600160a01b031681565b34801561073d57600080fd5b506103ce61074c366004613b32565b612758565b34801561075d57600080fd5b506103ce61076c366004613c8f565b6127bc565b34801561077d57600080fd5b506103ce61078c366004613b32565b61283d565b34801561079d57600080fd5b506103ce6107ac366004613cb1565b612aee565b3480156107bd57600080fd5b506107d16107cc366004613b08565b612d35565b604080519a8b5260208b0199909952978901969096526060880194909452608087019290925260a086015260c08501526001600160a01b031660e08401521515610100830152610120820152610140016102b6565b34801561083257600080fd5b50610846610841366004613b08565b612db3565b6040516102b6929190613d1f565b34801561086057600080fd5b5061087461086f366004613b32565b612f59565b604080519384526020840192909252908201526060016102b6565b34801561089b57600080fd5b506103ce6108aa366004613b32565b612f8c565b3480156108bb57600080fd5b506103ce6108ca366004613d4d565b6130b7565b3480156108db57600080fd5b5061031f6108ea366004613ae6565b613301565b3480156108fb57600080fd5b506103ce61090a366004613b08565b613359565b6103ce61091d366004613d79565b6134cf565b34801561092e57600080fd5b506103ce61093d366004613ae6565b61361a565b6001600160a01b038216600090815260096020526040812080548291908490811061096f5761096f613dee565b9060005260206000209060090201905060008160060154426109919190613e1a565b60078301549091506001600160a01b03166000805b6001600160a01b0383166000908152600a6020526040902054811015610a50576001600160a01b0383166000908152600a602052604081208054839081106109f0576109f0613dee565b600091825260209091206002909102018054600182015491925090818710610a3c57612710818960010154610a259190613e2d565b610a2f9190613e5a565b610a399086613e6e565b94505b50505080610a4990613e81565b90506109a6565b5093505050505b92915050565b6000805b600054811015610b055760008181548110610a7e57610a7e613dee565b9060005260206000209060030201600001548310158015610ac3575060008181548110610aad57610aad613dee565b9060005260206000209060030201600101548311155b15610af55760008181548110610adb57610adb613dee565b906000526020600020906003020160020154915050919050565b610afe81613e81565b9050610a61565b50600092915050565b3360009081526007602052604090205460ff16610b465760405162461bcd60e51b8152600401610b3d90613e9a565b60405180910390fd5b6001600160a01b03811660009081526007602052604090205460ff16610b9d5760405162461bcd60e51b815260206004820152600c60248201526b2737ba1030b71037bbb732b960a11b6044820152606401610b3d565b336001600160a01b03821603610bee5760405162461bcd60e51b815260206004820152601660248201527521b0b73737ba103932b6b7bb32903cb7bab939b2b63360511b6044820152606401610b3d565b6001600160a01b03166000908152600760205260409020805460ff19169055565b600e54610c218264e8d4a51000613e2d565b11610c3e5760405162461bcd60e51b8152600401610b3d90613ec2565b600554610c56906001600160a01b03163330846136b5565b600254336000908152600c6020526040902054610c7290610a5d565b610c7c9082613e6e565b905060086000336001600160a01b03166001600160a01b031681526020019081526020016000206040518060a0016040528084815260200142815260200183815260200160016000015442610cd19190613e6e565b81526000602091820181905283546001808201865594825290829020835160059092020190815590820151928101929092556040810151600283015560608101516003808401919091556080909101516004909201805460ff19169215159290921790915554610d42908390613e6e565b60035560405182815233907f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d906020015b60405180910390a25050565b610d87613722565b6000805b33600090815260086020526040902054811015610e0857336000908152600860205260408120805483908110610dc357610dc3613dee565b906000526020600020906005020190506000610ddf3384611ce3565b9050610deb8185613e6e565b42600190930192909255509150610e0181613e81565b9050610d8b565b5080600003610e4f5760405162461bcd60e51b81526020600482015260136024820152724e6f207265776172647320746f20636c61696d60681b6044820152606401610b3d565b600454811115610e715760405162461bcd60e51b8152600401610b3d90613f05565b600454610e7f908290613e1a565b600455600554610e99906001600160a01b0316338361375a565b60405181815233907f106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f72419060200160405180910390a250610ee66001600080516020613fc283398151915255565b565b3360009081526007602052604090205460ff16610f175760405162461bcd60e51b8152600401610b3d90613e9a565b610f2b6001600160a01b038316338361375a565b6040518181526001600160a01b0383169033907fa92ff919b850e4909ab2261d907ef955f11bc1716733a6cbece38d163a69af8a9060200160405180910390a35050565b610f77613722565b60008060005b336000908152600960205260409020548110156110b057336000908152600960205260408120805483908110610fb557610fb5613dee565b6000918252602090912060099091020160078101549091506001600160a01b038681169116148015610ff357506007810154600160a01b900460ff16155b1561109f576000611004338461203a565b9050816003015481101561102a5760405162461bcd60e51b8152600401610b3d90613f3a565b600082600301548261103c9190613e1a565b9050801561109c578083600301546110549190613e6e565b60038401556110638187613e6e565b426005850155835460038501549197501161108e5760078301805460ff60a01b1916600160a01b1790555b8461109881613e81565b9550505b50505b506110a981613e81565b9050610f7d565b50816000036110f75760405162461bcd60e51b81526020600482015260136024820152724e6f207265776172647320746f20636c61696d60681b6044820152606401610b3d565b336000908152600c602052604090205415611200576001600160a01b038381166000818152600b60205260408082205490516302c68be360e31b815260048101939093529092670de0b6b3a7640000928692909116906316345f1890602401602060405180830381865afa158015611173573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111979190613f68565b6111a19190613e2d565b6111ab9190613e5a565b336000908152600c602052604090205490915081106111d957336000908152600c60205260408120556111fe565b336000908152600c6020526040812080548392906111f8908490613e1a565b90915550505b505b6040516370a0823160e01b81523060048201526000906001600160a01b038516906370a0823190602401602060405180830381865afa158015611247573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126b9190613f68565b90508281101561128d5760405162461bcd60e51b8152600401610b3d90613f05565b6112a16001600160a01b038516338561375a565b60405183815233907f106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f7241906020015b60405180910390a25050506112f16001600080516020613fc283398151915255565b50565b6112fc613722565b3360009081526008602052604090205481106113505760405162461bcd60e51b8152602060048201526013602482015272092dcecc2d8d2c840e6e8c2d6ca40d2dcc8caf606b1b6044820152606401610b3d565b33600090815260086020526040812080548390811061137157611371613dee565b6000918252602082206005909102018054909250906113903385611ce3565b905061139c8183613e6e565b9150816000036113e35760405162461bcd60e51b81526020600482015260126024820152714e6f20616d6f756e7420746f20636c61696d60701b6044820152606401610b3d565b826003015442101561142f5760405162461bcd60e51b815260206004820152601560248201527414dd185ad9481a5cc81cdd1a5b1b081b1bd8dad959605a1b6044820152606401610b3d565b6005546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015611478573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149c9190613f68565b9050828110156114be5760405162461bcd60e51b8152600401610b3d90613f05565b600080855560048501805460ff19166001179055600380548592906114e4908490613e1a565b9091555050600554611500906001600160a01b0316338561375a565b33600090815260086020526040902080548690811061152157611521613dee565b60009182526020822060059091020181815560018101829055600281018290556003810191909155600401805460ff1916905560405133907f106f923f993c2149d49b4255ff723acafa1f2d94393f561d3eda32ae348f7241906115889086815260200190565b60405180910390a2505050506112f16001600080516020613fc283398151915255565b600a60205281600052604060002081815481106115c757600080fd5b600091825260209091206002909102018054600190910154909250905082565b6008602052816000526040600020818154811061160357600080fd5b600091825260209091206005909102018054600182015460028301546003840154600490940154929550909350919060ff1685565b3360009081526007602052604090205460ff166116675760405162461bcd60e51b8152600401610b3d90613e9a565b6001600160a01b0381166116af5760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b6044820152606401610b3d565b6001600160a01b03166000908152600f60205260409020805460ff19169055565b3360009081526007602052604090205460ff166116ff5760405162461bcd60e51b8152600401610b3d90613e9a565b6001600160a01b039182166000908152600b6020526040902080546001600160a01b03191691909216179055565b6000805b336000908152600860205260409020548110156117ae5733600090815260086020526040812080548390811061176957611769613dee565b9060005260206000209060050201905060006117853384611ce3565b90506117918185613e6e565b426001909301929092555091506117a781613e81565b9050611731565b50600e5481116117f95760405162461bcd60e51b8152602060048201526016602482015275139bdd08195b9bdd59da081d1bc818dbdb5c1bdd5b9960521b6044820152606401610b3d565b336000818152600860209081526040808320815160a0810183528681524281850152948452600c909252918290205490929182019061183790610a5d565b6002546118449190613e6e565b81526020016001600001544261185a9190613e6e565b81526000602091820181905283546001808201865594825290829020835160059092020190815590820151928101929092556040810151600283015560608101516003808401919091556080909101516004909201805460ff191692151592909217909155546118cb908290613e6e565b60035560405181815233907f3afe5b60dee16617a8adbbd7d6c28f17a27efabb834872efa8e7ad5dafddf6f19060200160405180910390a250565b806000036119565760405162461bcd60e51b815260206004820181905260248201527f416d6f756e74206d7573742062652067726561746572207468616e207a65726f6044820152606401610b3d565b6001600160a01b038083166000908152600b602052604090205416806119ca5760405162461bcd60e51b815260206004820152602360248201527f5072696365206f7261636c65206e6f742073657420666f72207468697320746f60448201526235b2b760e91b6064820152608401610b3d565b6119df6001600160a01b0384163330856136b5565b600060646119ee600a85613e2d565b6119f89190613e5a565b6001600160a01b038581166000818152600b60205260408082205490516302c68be360e31b8152600481019390935293945092670de0b6b3a76400009287929116906316345f1890602401602060405180830381865afa158015611a60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a849190613f68565b611a8e9190613e2d565b611a989190613e5a565b9050600e548111611abb5760405162461bcd60e51b8152600401610b3d90613ec2565b336000908152600c602052604081208054839290611ada908490613e6e565b909155505033600090815260096020908152604091829020825161014081018452878152918201859052600d549092820190611b169042613e6e565b81526000602080830182905260408084018390524260608086018290526080808701929092526001600160a01b038d811660a08089019190915260c080890188905260e09889018c90528a5460018082018d559b8952978790208a51600990990201978855898701519a88019a909a558885015160028801559188015160038701559187015160048601558601516005850155958501516006840155928401516007830180546101008701511515600160a01b026001600160a81b031990911692909716919091179590951790945561012090920151600890920191909155805186815291820184905233917f9ade76f4385de306666dfb21a52b27d52db0fde8ad0f515fa261f532cac60d21910160405180910390a25050505050565b3360009081526007602052604090205460ff16611c635760405162461bcd60e51b8152600401610b3d90613e9a565b6001600160a01b03811660009081526007602052604090205460ff1615611cbf5760405162461bcd60e51b815260206004820152601060248201526f20b63932b0b23c9030b71037bbb732b960811b6044820152606401610b3d565b6001600160a01b03166000908152600760205260409020805460ff19166001179055565b6001600160a01b0382166000908152600860205260408120805482919084908110611d1057611d10613dee565b906000526020600020906005020190506000816001015442611d329190613e1a565b90506000612710620151808385600201548660000154611d529190613e2d565b611d5c9190613e2d565b611d669190613e5a565b611d709190613e5a565b9695505050505050565b3360009081526007602052604090205460ff16611da95760405162461bcd60e51b8152600401610b3d90613e9a565b6000548110611df05760405162461bcd60e51b8152602060048201526013602482015272496e646578206f7574206f6620626f756e647360681b6044820152606401610b3d565b805b600054611e0190600190613e1a565b811015611e7e576000611e15826001613e6e565b81548110611e2557611e25613dee565b906000526020600020906003020160008281548110611e4657611e46613dee565b60009182526020909120825460039092020190815560018083015490820155600291820154910155611e7781613e81565b9050611df2565b506000805480611e9057611e90613f81565b6000828152602081206003600019909301928302018181556001810182905560020155905550565b6001600160a01b0381166000908152600960209081526040808320805482518185028101850190935280835260609492939192909184015b82821015611f9457600084815260209081902060408051610140810182526009860290920180548352600180820154848601526002820154928401929092526003810154606084015260048101546080840152600581015460a0840152600681015460c084015260078101546001600160a01b03811660e0850152600160a01b900460ff161515610100840152600801546101208301529083529092019101611ef0565b505050509050919050565b6001600160a01b0381166000908152600860209081526040808320805482518185028101850190935280835260609492939192909184015b82821015611f945760008481526020908190206040805160a081018252600586029092018054835260018082015484860152600282015492840192909252600381015460608401526004015460ff16151560808301529083529092019101611fd7565b6001600160a01b038216600090815260096020526040812080548291908490811061206757612067613dee565b9060005260206000209060090201905060008160060154426120899190613e1a565b60078301549091506001600160a01b03166000805b6001600160a01b0383166000908152600a6020526040902054811015610a50576001600160a01b0383166000908152600a602052604081208054839081106120e8576120e8613dee565b6000918252602090912060029091020180546001820154919250908187106121325787546127109061211b908390613e2d565b6121259190613e5a565b61212f9086613e6e565b94505b5050508061213f90613e81565b905061209e565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff1660008115801561218c5750825b905060008267ffffffffffffffff1660011480156121a95750303b155b9050811580156121b7575080155b156121d55760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156121ff57845460ff60401b1916600160401b1785555b61220761379f565b600680546001600160a01b03199081167341970ce76b656030a79e7c1fa76fc4eb93980255178255600760209081527f1428bfef657344f5f7a0019d1554dccabe000be344bb83cdab918bd50f24b573805460ff1990811660019081179092556301499700600d81905567de0b6b3a76400000600e55600580549095167329219dd400f2bf60e5a23d13be72b486d4038894178555825560216002908155604080516060808201835268bdbc41e0348b300000825269021e0c0013070adc000082880190815282840187815260008054808a018255818052945160039586027f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5638181019290925593517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5648086019190915592517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e565948501558651808601885269021e19e0c9bab2400000815269043c25e0dcc1bd1c0000818d01908152818901998a528354808d01855584805291519188028084019290925551818501559751978401979097558551808501875269043c33c1937564800000815269065a3fc1a67c6f5c0000818c019081528188018781528354808d0185558480529251928802808b019390935590518285015551908401558551808501875269065a4da25d3016c00000815269087859a27037219c0000818c0190815260048289019081528354808d0185558480529251928802808b0193909355905182850155519084015585518085018752690878678326eac90000008152690cb48d6403ac861c0000818c019081528188019c8d528254808c0184558380529151918702808a019290925551818401559a519a83019a909a5584518084018652690cb49b44ba602d80000081526910f0c1259721ea9c0000818b019081528187019c8d528b54808b018d558c805291519186028089019290925551818301559a519a82019a909a55835180830185526910f0cf064dd592000000815269152cf4e72a974f1c0000818a0190815260088287019081528b54808b018d558c80529251928602808901939093559051828d015551908201558351918201845269152d02c7e14af68000008252600019828901908152600a94830194855289548089018b558a80529251929093029485019190915590519783019790975551950194909455600f9091527f77c9ddf83be31065a9eb7ed19d93a8a4db24cad8351f41cc546083ac9e9d8c7f8054841682179055737c40f272570fdf9549d6f67493ac250a1db52f279091527f1b209462f90614903451721396f08356b5037572bebcd67a02efc98f03bec9d18054909216179055831561263557845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050565b3360009081526007602052604090205460ff1661266b5760405162461bcd60e51b8152600401610b3d90613e9a565b600554612682906001600160a01b0316338361375a565b6005546040518281526001600160a01b039091169033907fa92ff919b850e4909ab2261d907ef955f11bc1716733a6cbece38d163a69af8a9060200160405180910390a350565b3360009081526007602052604090205460ff166126f85760405162461bcd60e51b8152600401610b3d90613e9a565b600554612710906001600160a01b03163330846136b5565b60045461271e908290613e6e565b6004556040518181527f4e9221f2cca6ca0397acc6004ea0b716798254f5abcf53924fab34f0373e5d4e906020015b60405180910390a150565b3360009081526007602052604090205460ff166127875760405162461bcd60e51b8152600401610b3d90613e9a565b600e8190556040518181527fe5dadb089824c750e4e7a2e98bfbe130f1a09834769e81339639fbe18606859b9060200161274d565b3360009081526007602052604090205460ff166127eb5760405162461bcd60e51b8152600401610b3d90613e9a565b6127f88262015180613e2d565b600155600281905560408051838152602081018390527f7fa9647ec1cc14e3822b46d05a2b9d4e019bde8875c0088c46b6503d71bf1722910160405180910390a15050565b612845613722565b33600090815260096020526040812080548390811061286657612866613dee565b600091825260209091206009909102016007810154909150600160a01b900460ff16156128c95760405162461bcd60e51b81526020600482015260116024820152705374616b6520697320436f6d706c65746560781b6044820152606401610b3d565b60006128d5338461203a565b905081600301548110156128fb5760405162461bcd60e51b8152600401610b3d90613f3a565b600082600301548261290d9190613e1a565b90508060000361295b5760405162461bcd60e51b81526020600482015260196024820152784e6f2076657374656420616d6f756e7420746f20636c61696d60381b6044820152606401610b3d565b80836003015461296b9190613e6e565b6003840181905583541161298f5760078301805460ff60a01b1916600160a01b1790555b336000908152600c602052604090205415612a9d5760078301546001600160a01b039081166000818152600b60205260408082205490516302c68be360e31b815260048101939093529092670de0b6b3a7640000928592909116906316345f1890602401602060405180830381865afa158015612a10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a349190613f68565b612a3e9190613e2d565b612a489190613e5a565b336000908152600c60205260409020549091508110612a7657336000908152600c6020526040812055612a9b565b336000908152600c602052604081208054839290612a95908490613e1a565b90915550505b505b6007830154612ab6906001600160a01b0316338361375a565b604080518281526000602082015233917f4a94c2c356e29a6583071e731bdacf2ca56565ba5efebcff6936eb7923b5172191016112cf565b3360009081526007602052604090205460ff16612b1d5760405162461bcd60e51b8152600401610b3d90613e9a565b81600003612b795760405162461bcd60e51b815260206004820152602360248201527f4c6f636b2074696d65206d7573742062652067726561746572207468616e207a60448201526265726f60e81b6064820152608401610b3d565b80600003612bdf5760405162461bcd60e51b815260206004820152602d60248201527f50657263656e74616765207065722073746570206d757374206265206772656160448201526c746572207468616e207a65726f60981b6064820152608401610b3d565b612710612bec8282613f97565b15612c445760405162461bcd60e51b815260206004820152602260248201527f50657263656e74616765206d757374206469766964652031303025206576656e6044820152616c7960f01b6064820152608401610b3d565b6000612c508383613e5a565b90506000612c5e8286613e5a565b6001600160a01b0387166000908152600a60205260408120919250612c839190613a8f565b60015b828111612cf8576001600160a01b0387166000908152600a60205260409081902081518083019092529080612cbb8486613e2d565b815260209081018890528254600181810185556000948552938290208351600290920201908155910151910155612cf181613e81565b9050612c86565b506040516001600160a01b038716907fde4b6ccc38b84f88129403b65a309f9b1c41d4c316bc2118d7614e449b9d4c4590600090a2505050505050565b60096020528160005260406000208181548110612d5157600080fd5b6000918252602090912060099091020180546001820154600283015460038401546004850154600586015460068701546007880154600890980154969950949750929591949093916001600160a01b03811691600160a01b90910460ff16908a565b6001600160a01b038216600090815260096020526040812080546060928392909185908110612de457612de4613dee565b600091825260208083206007600990930201918201546001600160a01b0316808452600a9091526040832054919350918167ffffffffffffffff811115612e2d57612e2d613fab565b604051908082528060200260200182016040528015612e56578160200160208202803683370190505b50905060008267ffffffffffffffff811115612e7457612e74613fab565b604051908082528060200260200182016040528015612e9d578160200160208202803683370190505b50905060005b83811015612f4a576001600160a01b0385166000908152600a60205260408120805483908110612ed557612ed5613dee565b9060005260206000209060020201905080600001548760060154612ef99190613e6e565b848381518110612f0b57612f0b613dee565b6020026020010181815250508060010154838381518110612f2e57612f2e613dee565b602090810291909101015250612f4381613e81565b9050612ea3565b50909890975095505050505050565b60008181548110612f6957600080fd5b600091825260209091206003909102018054600182015460029092015490925083565b612f94613722565b336000908152600960205260408120805483908110612fb557612fb5613dee565b906000526020600020906009020190506000612fd13384610942565b90508160040154811015612ff75760405162461bcd60e51b8152600401610b3d90613f3a565b60008260040154826130099190613e1a565b9050806000036130575760405162461bcd60e51b81526020600482015260196024820152784e6f2076657374656420616d6f756e7420746f20636c61696d60381b6044820152606401610b3d565b8083600401546130679190613e6e565b60048401556007830154613085906001600160a01b0316338361375a565b60405181815233907f4e69fdc49495bcab2b4375781457ba16653a90eb4ffb6588351bdc39071433e2906020016112cf565b3360009081526007602052604090205460ff166130e65760405162461bcd60e51b8152600401610b3d90613e9a565b81831061314a5760405162461bcd60e51b815260206004820152602c60248201527f496e76616c69642072616e67653a206d696e546f6b656e73206d75737420626560448201526b203c206d6178546f6b656e7360a01b6064820152608401610b3d565b61315483836137af565b156131ac5760405162461bcd60e51b815260206004820152602260248201527f52616e6765206f7665726c6170732077697468206578697374696e6720746965604482015261727360f01b6064820152608401610b3d565b60005b6000548110156132535783600082815481106131cd576131cd613dee565b90600052602060002090600302016000015414801561320f575082600082815481106131fb576131fb613dee565b906000526020600020906003020160010154145b1561324357816000828154811061322857613228613dee565b90600052602060002090600302016002018190555050505050565b61324c81613e81565b90506131af565b5060408051606081018252848152602081018481529181018381526000805460018101825590805291517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56360039093029283015591517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56482015590517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e565909101556132fc61383e565b505050565b600080805b6001600160a01b0384166000908152600860205260409020548110156133525760006133328583611ce3565b905061333e8184613e6e565b9250508061334b90613e81565b9050613306565b5092915050565b3360009081526007602052604090205460ff166133885760405162461bcd60e51b8152600401610b3d90613e9a565b806000036133c95760405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a5908185b5bdd5b9d60921b6044820152606401610b3d565b60086000836001600160a01b03166001600160a01b031681526020019081526020016000206040518060a0016040528083815260200142815260200160018001548152602001600160000154426134209190613e6e565b81526000602091820181905283546001808201865594825290829020835160059092020190815590820151928101929092556040810151600283015560608101516003808401919091556080909101516004909201805460ff19169215159290921790915554613491908290613e6e565b6003556040518181526001600160a01b038316907f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d90602001610d73565b336000908152600f602052604090205460ff1661352e5760405162461bcd60e51b815260206004820152601f60248201527f43616c6c6572206973206e6f7420616e20617574686f72697a656420626f74006044820152606401610b3d565b804260005b82811015612635573685858381811061354e5761354e613dee565b9050608002019050806020013560016002015461356b9190613e6e565b6003556008600061357f6020840184613ae6565b6001600160a01b0316815260208082019290925260409081016000908120825160a081018452858501358152808501888152606080880135838701908152979095013594820194855260808201848152835460018082018655948652969094209151600590960290910194855551848201559351600284015590516003830155516004909101805460ff191691151591909117905501613533565b3360009081526007602052604090205460ff166136495760405162461bcd60e51b8152600401610b3d90613e9a565b6001600160a01b0381166136915760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b6044820152606401610b3d565b6001600160a01b03166000908152600f60205260409020805460ff19166001179055565b6040516001600160a01b03848116602483015283811660448301526064820183905261371c9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506139cd565b50505050565b600080516020613fc283398151915280546001190161375457604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b6040516001600160a01b038381166024830152604482018390526132fc91859182169063a9059cbb906064016136ea565b6001600080516020613fc283398151915255565b6137a7613a3e565b610ee6613a87565b6000805b60005481101561383457600081815481106137d0576137d0613dee565b90600052602060002090600302016001015484111580156138155750600081815481106137ff576137ff613dee565b9060005260206000209060030201600001548310155b15613824576001915050610a57565b61382d81613e81565b90506137b3565b5060009392505050565b60005b6000548110156112f1576000613858826001613e6e565b90505b6000548110156139bc576000818154811061387857613878613dee565b9060005260206000209060030201600001546000838154811061389d5761389d613dee565b90600052602060002090600302016000015411156139aa5760008083815481106138c9576138c9613dee565b9060005260206000209060030201604051806060016040529081600082015481526020016001820154815260200160028201548152505090506000828154811061391557613915613dee565b90600052602060002090600302016000848154811061393657613936613dee565b9060005260206000209060030201600082015481600001556001820154816001015560028201548160020155905050806000838154811061397957613979613dee565b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020155905050505b806139b481613e81565b91505061385b565b506139c681613e81565b9050613841565b600080602060008451602086016000885af1806139f0576040513d6000823e3d81fd5b50506000513d91508115613a08578060011415613a15565b6001600160a01b0384163b155b1561371c57604051635274afe760e01b81526001600160a01b0385166004820152602401610b3d565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff16610ee657604051631afcd79f60e31b815260040160405180910390fd5b61378b613a3e565b50805460008255600202906000526020600020908101906112f191905b80821115613ac65760008082556001820155600201613aac565b5090565b80356001600160a01b0381168114613ae157600080fd5b919050565b600060208284031215613af857600080fd5b613b0182613aca565b9392505050565b60008060408385031215613b1b57600080fd5b613b2483613aca565b946020939093013593505050565b600060208284031215613b4457600080fd5b5035919050565b60008060408385031215613b5e57600080fd5b613b6783613aca565b9150613b7560208401613aca565b90509250929050565b602080825282518282018190526000919060409081850190868401855b82811015613c1f5781518051855286810151878601528581015186860152606080820151908601526080808201519086015260a0808201519086015260c0808201519086015260e0808201516001600160a01b0316908601526101008082015115159086015261012090810151908501526101409093019290850190600101613b9b565b5091979650505050505050565b602080825282518282018190526000919060409081850190868401855b82811015613c1f57815180518552868101518786015285810151868601526060808201519086015260809081015115159085015260a09093019290850190600101613c49565b60008060408385031215613ca257600080fd5b50508035926020909101359150565b600080600060608486031215613cc657600080fd5b613ccf84613aca565b95602085013595506040909401359392505050565b600081518084526020808501945080840160005b83811015613d1457815187529582019590820190600101613cf8565b509495945050505050565b604081526000613d326040830185613ce4565b8281036020840152613d448185613ce4565b95945050505050565b600080600060608486031215613d6257600080fd5b505081359360208301359350604090920135919050565b60008060208385031215613d8c57600080fd5b823567ffffffffffffffff80821115613da457600080fd5b818501915085601f830112613db857600080fd5b813581811115613dc757600080fd5b8660208260071b8501011115613ddc57600080fd5b60209290920196919550909350505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115610a5757610a57613e04565b8082028115828204841417610a5757610a57613e04565b634e487b7160e01b600052601260045260246000fd5b600082613e6957613e69613e44565b500490565b80820180821115610a5757610a57613e04565b600060018201613e9357613e93613e04565b5060010190565b6020808252600e908201526d139bdd08185d5d1a1bdc9a5e995960921b604082015260600190565b60208082526023908201527f416d6f756e74206d7573742062652067726561746572206d696e5374616b654c6040820152626f636b60e81b606082015260800190565b6020808252818101527f496e73756666696369656e74207265776172647320696e2074686520706f6f6c604082015260600190565b602080825260149082015273125b9d985b1a590818db185a5b48185b5bdd5b9d60621b604082015260600190565b600060208284031215613f7a57600080fd5b5051919050565b634e487b7160e01b600052603160045260246000fd5b600082613fa657613fa6613e44565b500690565b634e487b7160e01b600052604160045260246000fdfe9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a264697066735822122039af34d0748ff9359e4c0802def9ed8a49114a877d02cdd4fdf8a6114bc7265064736f6c63430008140033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.