More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 1,736 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Withdraw Locked | 18461741 | 457 days ago | IN | 0 ETH | 0.00672858 | ||||
Get Reward | 18173710 | 498 days ago | IN | 0 ETH | 0.00363387 | ||||
Withdraw Locked | 18173708 | 498 days ago | IN | 0 ETH | 0.00642052 | ||||
Withdraw Locked | 18140038 | 502 days ago | IN | 0 ETH | 0.00551039 | ||||
Withdraw Locked | 17406413 | 605 days ago | IN | 0 ETH | 0.00875115 | ||||
Withdraw Locked | 17338677 | 615 days ago | IN | 0 ETH | 0.0124044 | ||||
Withdraw Locked | 17312887 | 619 days ago | IN | 0 ETH | 0.01471722 | ||||
Withdraw Locked | 17240842 | 629 days ago | IN | 0 ETH | 0.05123958 | ||||
Withdraw Locked | 17154399 | 641 days ago | IN | 0 ETH | 0.01895789 | ||||
Withdraw Locked | 17146956 | 642 days ago | IN | 0 ETH | 0.02076281 | ||||
Withdraw Locked | 17142763 | 643 days ago | IN | 0 ETH | 0.02178722 | ||||
Withdraw Locked | 17141661 | 643 days ago | IN | 0 ETH | 0.01929826 | ||||
Withdraw Locked | 17114166 | 647 days ago | IN | 0 ETH | 0.02147671 | ||||
Withdraw Locked | 17095046 | 649 days ago | IN | 0 ETH | 0.01781637 | ||||
Withdraw Locked | 17094349 | 649 days ago | IN | 0 ETH | 0.02270809 | ||||
Withdraw Locked | 17093825 | 649 days ago | IN | 0 ETH | 0.01862632 | ||||
Recover ERC20 | 17053235 | 655 days ago | IN | 0 ETH | 0.00362793 | ||||
Withdraw Locked | 17052688 | 655 days ago | IN | 0 ETH | 0.01212382 | ||||
Withdraw Locked | 17050515 | 656 days ago | IN | 0 ETH | 0.01704501 | ||||
Withdraw Locked | 17048706 | 656 days ago | IN | 0 ETH | 0.01095892 | ||||
Get Reward | 17048704 | 656 days ago | IN | 0 ETH | 0.01032801 | ||||
Withdraw Locked | 17046335 | 656 days ago | IN | 0 ETH | 0.02129921 | ||||
Withdraw Locked | 17042977 | 657 days ago | IN | 0 ETH | 0.03024926 | ||||
Withdraw Locked | 17042974 | 657 days ago | IN | 0 ETH | 0.0300983 | ||||
Withdraw Locked | 17042968 | 657 days ago | IN | 0 ETH | 0.02842708 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
EuclideanFarm
Compiler Version
v0.8.13+commit.abaa5c0e
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.13; // ┬ ┬┌┐┌┌─┐┬ ┬╔═╗╔╦╗╦ ╦ // │ ││││└─┐├─┤║╣ ║ ╠═╣ // └─┘┘└┘└─┘┴ ┴╚═╝ ╩ ╩ ╩ // ======================= // EuclideanFarm.sol /// @title Modified StakingRewards from Frax/Synthetix with a "coordination multiplier" /// @author @EIP-A1tair /// @notice Allows users to stake unshETH and earn USH, with a multiplier /// based on how well the pool confirms to a target ratio of tokens /// @dev Uses Euclidean distance to calculate the "coordination ratio" import "communal/Math.sol"; import "communal/SafeMath.sol"; import "communal/SafeERC20.sol"; import 'communal/TransferHelper.sol'; import "communal/ReentrancyGuard.sol"; // Inheritance import "communal/Owned.sol"; import "forge-std/console.sol"; import { UD60x18, ud, fromUD60x18, unwrap, mulDiv18, add, sub, mul, div, mulDiv, inv, powu, exp } from "@prb/math/UD60x18.sol"; // just do everything in signed, the casting ugliness isn't worth the aids // import { UD60x18, ud, fromUD60x18, mul, div, sqrt, inv, powu } from "@prb/math/UD60x18.sol"; interface ILSDRegistry { function vaultAddress() external view returns (address); //ratios should be in the form of [0.25e18, 0.25e18, 0.25e18, 0.25e18] for 4 LSDs function targetRatio() external view returns (uint256[] calldata); function lsdAddresses() external view returns (address[] calldata); function shanghaiTime() external view returns (uint256); function nonce() external view returns (uint256); } interface ILSDVault { function balanceInUnderlying() external view returns (uint256); function stakedETHperunshETH() external view returns (uint256); } interface IDarknet { function checkPrice(address lsd) external view returns(uint256); } contract EuclideanFarm is Owned, ReentrancyGuard { using SafeMath for uint256; using SafeERC20 for IERC20; /* ========== STATE VARIABLES ========== */ // Instances IERC20 public stakingToken; // Constant for various precisions uint256 private constant MULTIPLIER_PRECISION = 1e18; // Time tracking uint256 public periodFinish; uint256 public lastUpdateTime; // Lock time and multiplier settings uint256 public lock_max_multiplier = uint256(3e18); // E18. 1x = e18 uint256 public lock_time_for_max_multiplier; //set this to rewardsDuration - 6 hours at initialization uint256 public lock_time_min; //set this at initialization // Coordination multipliers uint256 public max_cord_multiplier = uint256(3e18); uint256 public min_cord_multiplier = uint256(1e18); uint256 public nonce = 0; uint256 public max_nonce = 2; //no more than 2 changes to targetRatio // uint256 public lastRatioUpdate; // uint256 public min_cooldown = 21 days; // uint256 public min_ratio_distance = 0.5e18; //there is only one lockTime - needs to be equal to shanghaiTime address public LSDRegistryAddress; address public LSDVaultAddress; uint256 public shanghaiTime; // Reward addresses, rates, and managers mapping(address => address) public rewardManagers; // token addr -> manager addr address[] public rewardTokens; uint256[] public rewardRates; string[] public rewardSymbols; mapping(address => uint256) public rewardTokenAddrToIdx; // token addr -> token index // Reward period uint256 public rewardsDuration; // from now until Shanghai // Reward tracking uint256[] private rewardsPerTokenStored; mapping(address => mapping(uint256 => uint256)) private userRewardsPerTokenPaid; // staker addr -> token id -> paid amount mapping(address => mapping(uint256 => uint256)) private rewards; // staker addr -> token id -> reward amount mapping(address => uint256) private lastRewardClaimTime; // staker addr -> timestamp // Balance tracking uint256 private _total_liquidity_locked; uint256 private _total_combined_weight; mapping(address => uint256) private _locked_liquidity; mapping(address => uint256) private _combined_weights; // Stake tracking mapping(address => LockedStake[]) private lockedStakes; // Greylisting of bad addresses mapping(address => bool) public greylist; //how long until this one is offensive too? // Administrative booleans bool public stakesUnlocked; // Release locked stakes in case of emergency bool public withdrawalsPaused; // For emergencies bool public rewardsCollectionPaused; // For emergencies bool public stakingPaused; // For emergencies //Price feed for LSDs for coordination multiplier calculations address public darknetAddress; /* ========== STRUCTS ========== */ struct LockedStake { bytes32 kek_id; uint256 start_timestamp; uint256 liquidity; uint256 ending_timestamp; uint256 lock_multiplier; // 6 decimals of precision. 1x = 1000000 } /* ========== MODIFIERS ========== */ modifier onlyByOwner() { require(msg.sender == owner, "Not the owner"); _; } modifier onlyTknMgrs(address reward_token_address) { require(msg.sender == owner || isTokenManagerFor(msg.sender, reward_token_address), "Not owner or tkn mgr"); _; } modifier notStakingPaused() { require(stakingPaused == false, "Staking paused"); _; } modifier updateRewardAndBalance(address account, bool sync_too) { _updateRewardAndBalance(account, sync_too); _; } /* ========== CONSTRUCTOR ========== */ //this also needs to point to an LSDRegistry constructor ( address _owner, address _stakingToken, address _LSDRegistry, uint256 _shanghaiTime, address _darknetAddress, string[] memory _rewardSymbols, address[] memory _rewardTokens, address[] memory _rewardManagers, uint256[] memory _rewardRates ) Owned(_owner){ //check that LSDRegistry is not 0x0 require(_LSDRegistry != address(0), "LSDRegistry is 0x0"); LSDRegistryAddress = _LSDRegistry; LSDVaultAddress = ILSDRegistry(LSDRegistryAddress).vaultAddress(); //check that LSDRegistry's shanghaiTime matches the given shanghaiTime require(_shanghaiTime == ILSDRegistry(LSDRegistryAddress).shanghaiTime(), "shanghaiTime mismatch"); shanghaiTime = _shanghaiTime; stakingToken = IERC20(_stakingToken); darknetAddress = _darknetAddress; rewardTokens = _rewardTokens; rewardRates = _rewardRates; rewardSymbols = _rewardSymbols; rewardsDuration = shanghaiTime - block.timestamp; lock_time_for_max_multiplier = rewardsDuration - 24 hours; for (uint256 i = 0; i < _rewardTokens.length; i++){ // For fast token address -> token ID lookups later rewardTokenAddrToIdx[_rewardTokens[i]] = i; // Initialize the stored rewards rewardsPerTokenStored.push(0); // Initialize the reward managers rewardManagers[_rewardTokens[i]] = _rewardManagers[i]; } // Other booleans stakesUnlocked = false; // Initialization lastUpdateTime = block.timestamp; periodFinish = block.timestamp.add(rewardsDuration); } /* ========== VIEWS ========== */ // Total locked liquidity tokens function totalLiquidityLocked() external view returns (uint256) { return _total_liquidity_locked; } // Locked liquidity for a given account function lockedLiquidityOf(address account) external view returns (uint256) { return _locked_liquidity[account]; } // Total 'balance' used for calculating the percent of the pool the account owns // Takes into account the locked stake time multiplier function totalCombinedWeight() external view returns (uint256) { return _total_combined_weight; } // Combined weight for a specific account function combinedWeightOf(address account) external view returns (uint256) { return _combined_weights[account]; } // Calculated the combined weight for an account function calcCurCombinedWeight(address account) public view returns ( uint256 old_combined_weight, uint256 new_combined_weight ) { // Get the old combined weight old_combined_weight = _combined_weights[account]; // Loop through the locked stakes, first by getting the liquidity * lock_multiplier portion new_combined_weight = 0; for (uint256 i = 0; i < lockedStakes[account].length; i++) { LockedStake memory thisStake = lockedStakes[account][i]; uint256 lock_multiplier = thisStake.lock_multiplier; //add coordination multiplier here uint256 cord_multiplier = coordinationMultiplier(); require(cord_multiplier != 0, "Multiplier error"); //set min_cord_multiplier < 1e18 if we want to shrink yield below base rate if (cord_multiplier <= min_cord_multiplier){ cord_multiplier = min_cord_multiplier; } // If the lock is expired if (thisStake.ending_timestamp <= block.timestamp) { // If the lock expired in the time since the last claim, the weight needs to be proportionately averaged this time if (lastRewardClaimTime[account] < thisStake.ending_timestamp){ uint256 time_before_expiry = (thisStake.ending_timestamp).sub(lastRewardClaimTime[account]); uint256 time_after_expiry = (block.timestamp).sub(thisStake.ending_timestamp); // Get the weighted-average lock_multiplier uint256 numerator = ((lock_multiplier).mul(time_before_expiry)).add(((MULTIPLIER_PRECISION).mul(time_after_expiry))); lock_multiplier = numerator.div(time_before_expiry.add(time_after_expiry)); } // Otherwise, it needs to just be 1x else { lock_multiplier = MULTIPLIER_PRECISION; } } uint256 liquidity = thisStake.liquidity; uint256 combined_boosted_amount = liquidity.mul(lock_multiplier).div(MULTIPLIER_PRECISION); uint256 coordination_boosted_amount = combined_boosted_amount.mul(cord_multiplier).div(MULTIPLIER_PRECISION); new_combined_weight = new_combined_weight.add(coordination_boosted_amount); } } // All the locked stakes for a given account function lockedStakesOf(address account) external view returns (LockedStake[] memory) { return lockedStakes[account]; } // All the locked stakes for a given account function getRewardSymbols() external view returns (string[] memory) { return rewardSymbols; } // All the reward tokens function getAllRewardTokens() external view returns (address[] memory) { return rewardTokens; } // All the reward rates function getAllRewardRates() external view returns (uint256[] memory) { return rewardRates; } // Multiplier amount, given the length of the lock function lockMultiplier(uint256 secs) public view returns (uint256) { uint256 lock_multiplier = uint256(MULTIPLIER_PRECISION).add( secs .mul(lock_max_multiplier.sub(MULTIPLIER_PRECISION)) .div(lock_time_for_max_multiplier) ); if (lock_multiplier > lock_max_multiplier) lock_multiplier = lock_max_multiplier; return lock_multiplier; } function sqrt(uint y) internal pure returns (uint z) { if (y > 3) { z = y; uint x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } // else z = 0 (default value) } function euclideanDistance(uint256[] memory _a, uint256[] memory _b) internal pure returns (uint256) { require(_a.length == _b.length, "Array length mismatch"); int256 a; int256 b; uint256 sumSqDiff; uint256 diff; for (uint256 i = 0; i < _a.length; i++) { a = int256(_a[i]/1e15); b = int256(_b[i]/1e15); diff = uint256(a > b ? a - b : b - a); uint256 squareDiff = diff**2; sumSqDiff += squareDiff; } return sqrt(sumSqDiff)*1e15; } function coordinationMultiplier() public view returns(uint256) { //get ratios //fetch the current targetRatio locally //ratios should be in the form of [0.25e18, 0.25e18, 0.25e18, 0.25e18] for 4 LSDs uint256[] memory targetRatio = ILSDRegistry(LSDRegistryAddress).targetRatio(); address[] memory lsdAddresses = ILSDRegistry(LSDRegistryAddress).lsdAddresses(); //make sure the lengths match require(targetRatio.length == lsdAddresses.length, "targetRatio and lsdAddresses length mismatch"); uint256 tabs = lsdAddresses.length; console.log(tabs); uint256[] memory currentRatio = new uint256[](tabs); console.log(currentRatio.length); console.log(LSDVaultAddress); uint256 totalETHbalance = ILSDVault(LSDVaultAddress).balanceInUnderlying(); console.log(totalETHbalance); //get the current balances of all LSDs in vault in terms of underlying ETH to compute ratio for (uint256 i = 0; i < tabs; i++) { uint256 balance = IERC20(lsdAddresses[i]).balanceOf(LSDVaultAddress); //convert to actual underlying amounts uint256 rate = IDarknet(darknetAddress).checkPrice(lsdAddresses[i]); uint256 ratio = mulDiv(balance, rate, totalETHbalance); currentRatio[i] = ratio; } //from here onwards these operations cost ~50k gas uint256 _x = euclideanDistance(targetRatio, currentRatio); uint256 L = mulDiv18(_x, 2.5e18); UD60x18 l_scaled = div(ud(L), ud(1.0e18)); UD60x18 e_L = exp(l_scaled); UD60x18 hell = ud(3.0e18).sub(inv(e_L)).sub(ud(L)); UD60x18 hella = div(powu(hell, 3),ud(4.0e18)); return unwrap(hella.add(ud(1.0e18))); } // Last time the reward was applicable function lastTimeRewardApplicable() internal view returns (uint256) { return Math.min(block.timestamp, periodFinish); } // Amount of reward tokens per LP token function rewardsPerToken() public view returns (uint256[] memory newRewardsPerTokenStored) { if (_total_liquidity_locked == 0 || _total_combined_weight == 0) { return rewardsPerTokenStored; } else { newRewardsPerTokenStored = new uint256[](rewardTokens.length); for (uint256 i = 0; i < rewardsPerTokenStored.length; i++){ newRewardsPerTokenStored[i] = rewardsPerTokenStored[i].add( lastTimeRewardApplicable().sub(lastUpdateTime).mul(rewardRates[i]).mul(1e18).div(_total_combined_weight) ); } return newRewardsPerTokenStored; } } // Amount of reward tokens an account has earned / accrued // Note: In the edge-case of one of the account's stake expiring since the last claim, this will // return a slightly inflated number function earned(address account) public view returns (uint256[] memory new_earned) { uint256[] memory reward_arr = rewardsPerToken(); new_earned = new uint256[](rewardTokens.length); if (_combined_weights[account] == 0){ for (uint256 i = 0; i < rewardTokens.length; i++){ new_earned[i] = 0; } } else { for (uint256 i = 0; i < rewardTokens.length; i++){ new_earned[i] = (_combined_weights[account]) .mul(reward_arr[i].sub(userRewardsPerTokenPaid[account][i])) .div(1e18) .add(rewards[account][i]); } } } // Total reward tokens emitted in the given period function getRewardForDuration() external view returns (uint256[] memory rewards_per_duration_arr) { rewards_per_duration_arr = new uint256[](rewardRates.length); for (uint256 i = 0; i < rewardRates.length; i++){ rewards_per_duration_arr[i] = rewardRates[i].mul(rewardsDuration); } } // See if the caller_addr is a manager for the reward token function isTokenManagerFor(address caller_addr, address reward_token_addr) public view returns (bool){ if (caller_addr == owner) return true; // Contract owner else if (rewardManagers[reward_token_addr] == caller_addr) return true; // Reward manager return false; } /* ========== MUTATIVE FUNCTIONS ========== */ function synchronize() external { uint256 proposedNonce = ILSDRegistry(LSDRegistryAddress).nonce(); require(nonce != proposedNonce, "Already synchronized"); _synchronize(); } function _synchronize() internal { //set current coordination-boosted rate to the new min uint256 current_boosted_rate = coordinationMultiplier()*rewardRates[0]/1e18; //only for USH rewards, change later if needed rewardRates[0] = current_boosted_rate; //update to the new target ratio } function _updateRewardAndBalance(address account, bool sync_too) internal { // Need to retro-adjust some things if the period hasn't been renewed, then start a new one if (sync_too){ sync(); } if (account != address(0)) { // To keep the math correct, the user's combined weight must be recomputed ( uint256 old_combined_weight, uint256 new_combined_weight ) = calcCurCombinedWeight(account); // Calculate the earnings first _syncEarned(account); // Update the user's and the global combined weights if (new_combined_weight >= old_combined_weight) { uint256 weight_diff = new_combined_weight.sub(old_combined_weight); _total_combined_weight = _total_combined_weight.add(weight_diff); _combined_weights[account] = old_combined_weight.add(weight_diff); } else { uint256 weight_diff = old_combined_weight.sub(new_combined_weight); _total_combined_weight = _total_combined_weight.sub(weight_diff); _combined_weights[account] = old_combined_weight.sub(weight_diff); } } } function _syncEarned(address account) internal { if (account != address(0)) { // Calculate the earnings uint256[] memory earned_arr = earned(account); // Update the rewards array for (uint256 i = 0; i < earned_arr.length; i++){ rewards[account][i] = earned_arr[i]; } // Update the rewards paid array for (uint256 i = 0; i < earned_arr.length; i++){ userRewardsPerTokenPaid[account][i] = rewardsPerTokenStored[i]; } } } // Two different stake functions are needed because of delegateCall and msg.sender issues function stakeLocked(uint256 liquidity) nonReentrant public { _stakeLocked(msg.sender, msg.sender, liquidity, block.timestamp); } // If this were not internal, and source_address had an infinite approve, this could be exploitable // (pull funds from source_address and stake for an arbitrary staker_address) function _stakeLocked( address staker_address, address source_address, uint256 liquidity, uint256 start_timestamp ) internal updateRewardAndBalance(staker_address, true) { require(!stakingPaused, "Staking paused"); require(liquidity > 0, "Must stake more than zero"); require(greylist[staker_address] == false, "Address has been greylisted"); // require(secs >= lock_time_min, "Minimum stake time not met"); // require(secs <= lock_time_for_max_multiplier,"Trying to lock for too long"); uint256 secs = shanghaiTime - block.timestamp; uint256 lock_multiplier = lockMultiplier(secs); bytes32 kek_id = keccak256(abi.encodePacked(staker_address, start_timestamp, liquidity, _locked_liquidity[staker_address])); lockedStakes[staker_address].push(LockedStake( kek_id, start_timestamp, liquidity, shanghaiTime,//replaced start_timestamp.add(secs) w/ shanghaiTime lock_multiplier )); // Pull the tokens from the source_address TransferHelper.safeTransferFrom(address(stakingToken), source_address, address(this), liquidity); // Update liquidities _total_liquidity_locked = _total_liquidity_locked.add(liquidity); _locked_liquidity[staker_address] = _locked_liquidity[staker_address].add(liquidity); // Need to call to update the combined weights _updateRewardAndBalance(staker_address, false); // Needed for edge case if the staker only claims once, and after the lock expired if (lastRewardClaimTime[staker_address] == 0) lastRewardClaimTime[staker_address] = block.timestamp; emit StakeLocked(staker_address, liquidity, secs, kek_id, source_address); } // Two different withdrawLocked functions are needed because of delegateCall and msg.sender issues function withdrawLocked(bytes32 kek_id) nonReentrant public { require(withdrawalsPaused == false, "Withdrawals paused"); _withdrawLocked(msg.sender, msg.sender, kek_id); } // No withdrawer == msg.sender check needed since this is only internally callable and the checks are done in the wrapper // functions like withdraw() function _withdrawLocked(address staker_address, address destination_address, bytes32 kek_id) internal { // Collect rewards first and then update the balances _getReward(staker_address, destination_address); LockedStake memory thisStake; thisStake.liquidity = 0; uint theArrayIndex; for (uint256 i = 0; i < lockedStakes[staker_address].length; i++){ if (kek_id == lockedStakes[staker_address][i].kek_id){ thisStake = lockedStakes[staker_address][i]; theArrayIndex = i; break; } } require(thisStake.kek_id == kek_id, "Stake not found"); require(block.timestamp >= thisStake.ending_timestamp || stakesUnlocked == true, "Stake is still locked!"); uint256 liquidity = thisStake.liquidity; if (liquidity > 0) { // Update liquidities _total_liquidity_locked = _total_liquidity_locked.sub(liquidity); _locked_liquidity[staker_address] = _locked_liquidity[staker_address].sub(liquidity); // Remove the stake from the array delete lockedStakes[staker_address][theArrayIndex]; // Need to call to update the combined weights _updateRewardAndBalance(staker_address, false); // Give the tokens to the destination_address // Should throw if insufficient balance stakingToken.transfer(destination_address, liquidity); emit WithdrawLocked(staker_address, liquidity, kek_id, destination_address); } } // Two different getReward functions are needed because of delegateCall and msg.sender issues function getReward() external nonReentrant returns (uint256[] memory) { require(rewardsCollectionPaused == false,"Rewards collection paused"); return _getReward(msg.sender, msg.sender); } // No withdrawer == msg.sender check needed since this is only internally callable function _getReward(address rewardee, address destination_address) internal updateRewardAndBalance(rewardee, true) returns (uint256[] memory rewards_before) { // Update the rewards array and distribute rewards rewards_before = new uint256[](rewardTokens.length); for (uint256 i = 0; i < rewardTokens.length; i++){ rewards_before[i] = rewards[rewardee][i]; rewards[rewardee][i] = 0; //use SafeERC20.transfer IERC20(rewardTokens[i]).transfer(destination_address, rewards_before[i]); emit RewardPaid(rewardee, rewards_before[i], rewardTokens[i], destination_address); } lastRewardClaimTime[rewardee] = block.timestamp; } // If the period expired, DON'T renew it function retroCatchUp() internal { // Failsafe check require(block.timestamp > periodFinish, "Period has not expired yet!"); // Ensure the provided reward amount is not more than the balance in the contract. // This keeps the reward rate in the right range, preventing overflows due to // very high values of rewardRate in the earned and rewardsPerToken functions; // Reward + leftover must be less than 2^256 / 10^18 to avoid overflow. // uint256 num_periods_elapsed = uint256(block.timestamp.sub(periodFinish)) / rewardsDuration; // Floor division to the nearest period // // Make sure there are enough tokens to renew the reward period // for (uint256 i = 0; i < rewardTokens.length; i++){ // require(rewardRates[i].mul(rewardsDuration).mul(num_periods_elapsed + 1) <= IERC20(rewardTokens[i]).balanceOf(address(this)), string(abi.encodePacked("Not enough reward tokens available: ", rewardTokens[i])) ); // } // uint256 old_lastUpdateTime = lastUpdateTime; // uint256 new_lastUpdateTime = block.timestamp; // lastUpdateTime = periodFinish; //periodFinish = periodFinish.add((num_periods_elapsed.add(1)).mul(rewardsDuration)); _updateStoredRewardsAndTime(); //emit RewardsPeriodRenewed(address(stakingToken)); } function _updateStoredRewardsAndTime() internal { // Get the rewards uint256[] memory rewards_per_token = rewardsPerToken(); // Update the rewardsPerTokenStored for (uint256 i = 0; i < rewardsPerTokenStored.length; i++){ rewardsPerTokenStored[i] = rewards_per_token[i]; } // Update the last stored time lastUpdateTime = lastTimeRewardApplicable(); } function sync() public { if (block.timestamp > periodFinish) { retroCatchUp(); } else { _updateStoredRewardsAndTime(); } } /* ========== RESTRICTED FUNCTIONS ========== */ // Added to support recovering LP Rewards and other mistaken tokens from other systems to be distributed to holders function recoverERC20(address tokenAddress, uint256 tokenAmount) external onlyTknMgrs(tokenAddress) { // Cannot rug the staking / LP tokens require(tokenAddress != address(stakingToken), "Cannot rug staking / LP tokens"); // Check if the desired token is a reward token bool isRewardToken = false; for (uint256 i = 0; i < rewardTokens.length; i++){ if (rewardTokens[i] == tokenAddress) { isRewardToken = true; break; } } // Only the reward managers can take back their reward tokens if (isRewardToken && rewardManagers[tokenAddress] == msg.sender){ IERC20(tokenAddress).transfer(msg.sender, tokenAmount); emit Recovered(msg.sender, tokenAddress, tokenAmount); return; } // Other tokens, like airdrops or accidental deposits, can be withdrawn by the owner else if (!isRewardToken && (msg.sender == owner)){ IERC20(tokenAddress).transfer(msg.sender, tokenAmount); emit Recovered(msg.sender, tokenAddress, tokenAmount); return; } // If none of the above conditions are true else { revert("No valid tokens to recover"); } } function setRewardsDuration(uint256 _rewardsDuration) external onlyByOwner { require(_rewardsDuration >= 86400, "Rewards duration too short"); require( periodFinish == 0 || block.timestamp > periodFinish, "Reward period incomplete" ); rewardsDuration = _rewardsDuration; emit RewardsDurationUpdated(rewardsDuration); } function setMultipliers(uint256 _lock_max_multiplier) external onlyByOwner { require(_lock_max_multiplier >= uint256(1e18), "Multiplier must be greater than or equal to 1e18"); lock_max_multiplier = _lock_max_multiplier; emit LockedStakeMaxMultiplierUpdated(lock_max_multiplier); } function setLockedStakeTimeForMinAndMaxMultiplier(uint256 _lock_time_for_max_multiplier, uint256 _lock_time_min) external onlyByOwner { require(_lock_time_for_max_multiplier >= 1, "Mul max time must be >= 1"); require(_lock_time_min >= 1, "Mul min time must be >= 1"); lock_time_for_max_multiplier = _lock_time_for_max_multiplier; lock_time_min = _lock_time_min; emit LockedStakeTimeForMaxMultiplier(lock_time_for_max_multiplier); emit LockedStakeMinTime(_lock_time_min); } function greylistAddress(address _address) external onlyByOwner { greylist[_address] = !(greylist[_address]); } function unlockStakes() external onlyByOwner { stakesUnlocked = !stakesUnlocked; } function toggleStaking() external onlyByOwner { stakingPaused = !stakingPaused; } function toggleWithdrawals() external onlyByOwner { withdrawalsPaused = !withdrawalsPaused; } function toggleRewardsCollection() external onlyByOwner { rewardsCollectionPaused = !rewardsCollectionPaused; } // The owner or the reward token managers can set reward rates function setRewardRate(address reward_token_address, uint256 new_rate, bool sync_too) external onlyTknMgrs(reward_token_address) { rewardRates[rewardTokenAddrToIdx[reward_token_address]] = new_rate; if (sync_too){ sync(); } } // The owner or the reward token managers can change managers function changeTokenManager(address reward_token_address, address new_manager_address) external onlyTknMgrs(reward_token_address) { rewardManagers[reward_token_address] = new_manager_address; } /* ========== EVENTS ========== */ event StakeLocked(address indexed user, uint256 amount, uint256 secs, bytes32 kek_id, address source_address); event WithdrawLocked(address indexed user, uint256 amount, bytes32 kek_id, address destination_address); event RewardPaid(address indexed user, uint256 reward, address token_address, address destination_address); event RewardsDurationUpdated(uint256 newDuration); event Recovered(address destination_address, address token, uint256 amount); event RewardsPeriodRenewed(address token); event LockedStakeMaxMultiplierUpdated(uint256 multiplier); event LockedStakeTimeForMaxMultiplier(uint256 secs); event LockedStakeMinTime(uint256 secs); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.11 <0.9.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // 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 // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.11; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return payable(msg.sender); } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.11; import "./Context.sol"; import "./SafeMath.sol"; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.11; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) function sqrt(uint y) internal pure returns (uint z) { if (y > 3) { z = y; uint x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.6.11; // https://docs.synthetix.io/contracts/Owned contract Owned { address public owner; address public nominatedOwner; constructor (address _owner) public { require(_owner != address(0), "Owner address cannot be 0"); owner = _owner; emit OwnerChanged(address(0), _owner); } function nominateNewOwner(address _owner) external onlyOwner { nominatedOwner = _owner; emit OwnerNominated(_owner); } function acceptOwnership() external { require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership"); emit OwnerChanged(owner, nominatedOwner); owner = nominatedOwner; nominatedOwner = address(0); } modifier onlyOwner { require(msg.sender == owner, "Only the contract owner may perform this action"); _; } event OwnerNominated(address newOwner); event OwnerChanged(address oldOwner, address newOwner); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.11; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor () internal { _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 make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.11; import "./IERC20.sol"; import "./SafeMath.sol"; import "./Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.11; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.11; // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false library TransferHelper { function safeApprove(address token, address to, uint value) internal { // bytes4(keccak256(bytes('approve(address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED'); } function safeTransfer(address token, address to, uint value) internal { // bytes4(keccak256(bytes('transfer(address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED'); } function safeTransferFrom(address token, address from, address to, uint value) internal { // bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED'); } function safeTransferETH(address to, uint value) internal { (bool success,) = to.call{value:value}(new bytes(0)); require(success, 'TransferHelper: ETH_TRANSFER_FAILED'); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.4.22 <0.9.0; library console { address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); function _sendLogPayload(bytes memory payload) private view { uint256 payloadLength = payload.length; address consoleAddress = CONSOLE_ADDRESS; /// @solidity memory-safe-assembly assembly { let payloadStart := add(payload, 32) let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) } } function log() internal view { _sendLogPayload(abi.encodeWithSignature("log()")); } function logInt(int p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(int)", p0)); } function logUint(uint p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); } function logString(string memory p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); } function logBool(bool p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); } function logAddress(address p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); } function logBytes(bytes memory p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); } function logBytes1(bytes1 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); } function logBytes2(bytes2 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); } function logBytes3(bytes3 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); } function logBytes4(bytes4 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); } function logBytes5(bytes5 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); } function logBytes6(bytes6 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); } function logBytes7(bytes7 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); } function logBytes8(bytes8 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); } function logBytes9(bytes9 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); } function logBytes10(bytes10 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); } function logBytes11(bytes11 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); } function logBytes12(bytes12 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); } function logBytes13(bytes13 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); } function logBytes14(bytes14 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); } function logBytes15(bytes15 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); } function logBytes16(bytes16 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); } function logBytes17(bytes17 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); } function logBytes18(bytes18 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); } function logBytes19(bytes19 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); } function logBytes20(bytes20 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); } function logBytes21(bytes21 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); } function logBytes22(bytes22 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); } function logBytes23(bytes23 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); } function logBytes24(bytes24 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); } function logBytes25(bytes25 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); } function logBytes26(bytes26 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); } function logBytes27(bytes27 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); } function logBytes28(bytes28 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); } function logBytes29(bytes29 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); } function logBytes30(bytes30 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); } function logBytes31(bytes31 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); } function logBytes32(bytes32 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); } function log(uint p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); } function log(string memory p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); } function log(bool p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); } function log(address p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); } function log(uint p0, uint p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1)); } function log(uint p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1)); } function log(uint p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1)); } function log(uint p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1)); } function log(string memory p0, uint p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1)); } function log(string memory p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); } function log(string memory p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); } function log(string memory p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); } function log(bool p0, uint p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1)); } function log(bool p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); } function log(bool p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); } function log(bool p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); } function log(address p0, uint p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1)); } function log(address p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); } function log(address p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); } function log(address p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); } function log(uint p0, uint p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2)); } function log(uint p0, uint p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2)); } function log(uint p0, uint p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2)); } function log(uint p0, uint p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2)); } function log(uint p0, string memory p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2)); } function log(uint p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2)); } function log(uint p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2)); } function log(uint p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2)); } function log(uint p0, bool p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2)); } function log(uint p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2)); } function log(uint p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2)); } function log(uint p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2)); } function log(uint p0, address p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2)); } function log(uint p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2)); } function log(uint p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2)); } function log(uint p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2)); } function log(string memory p0, uint p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2)); } function log(string memory p0, uint p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2)); } function log(string memory p0, uint p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2)); } function log(string memory p0, uint p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2)); } function log(string memory p0, string memory p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2)); } function log(string memory p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); } function log(string memory p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); } function log(string memory p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); } function log(string memory p0, bool p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2)); } function log(string memory p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); } function log(string memory p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); } function log(string memory p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); } function log(string memory p0, address p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2)); } function log(string memory p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); } function log(string memory p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); } function log(string memory p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); } function log(bool p0, uint p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2)); } function log(bool p0, uint p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2)); } function log(bool p0, uint p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2)); } function log(bool p0, uint p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2)); } function log(bool p0, string memory p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2)); } function log(bool p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); } function log(bool p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); } function log(bool p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); } function log(bool p0, bool p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2)); } function log(bool p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); } function log(bool p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); } function log(bool p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); } function log(bool p0, address p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2)); } function log(bool p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); } function log(bool p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); } function log(bool p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); } function log(address p0, uint p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2)); } function log(address p0, uint p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2)); } function log(address p0, uint p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2)); } function log(address p0, uint p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2)); } function log(address p0, string memory p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2)); } function log(address p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); } function log(address p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); } function log(address p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); } function log(address p0, bool p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2)); } function log(address p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); } function log(address p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); } function log(address p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); } function log(address p0, address p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2)); } function log(address p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); } function log(address p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); } function log(address p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); } function log(uint p0, uint p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3)); } function log(uint p0, uint p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3)); } function log(uint p0, uint p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3)); } function log(uint p0, uint p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3)); } function log(uint p0, uint p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3)); } function log(uint p0, uint p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3)); } function log(uint p0, uint p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3)); } function log(uint p0, uint p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3)); } function log(uint p0, uint p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3)); } function log(uint p0, uint p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3)); } function log(uint p0, uint p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3)); } function log(uint p0, uint p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3)); } function log(uint p0, uint p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3)); } function log(uint p0, uint p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3)); } function log(uint p0, uint p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3)); } function log(uint p0, uint p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3)); } function log(uint p0, bool p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3)); } function log(uint p0, bool p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3)); } function log(uint p0, bool p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3)); } function log(uint p0, bool p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3)); } function log(uint p0, bool p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3)); } function log(uint p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3)); } function log(uint p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3)); } function log(uint p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3)); } function log(uint p0, bool p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3)); } function log(uint p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3)); } function log(uint p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3)); } function log(uint p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3)); } function log(uint p0, bool p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3)); } function log(uint p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3)); } function log(uint p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3)); } function log(uint p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3)); } function log(uint p0, address p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3)); } function log(uint p0, address p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3)); } function log(uint p0, address p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3)); } function log(uint p0, address p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3)); } function log(uint p0, address p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3)); } function log(uint p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3)); } function log(uint p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3)); } function log(uint p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3)); } function log(uint p0, address p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3)); } function log(uint p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3)); } function log(uint p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3)); } function log(uint p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3)); } function log(uint p0, address p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3)); } function log(uint p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3)); } function log(uint p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3)); } function log(uint p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); } function log(bool p0, uint p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3)); } function log(bool p0, uint p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3)); } function log(bool p0, uint p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3)); } function log(bool p0, uint p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3)); } function log(bool p0, uint p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3)); } function log(bool p0, uint p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3)); } function log(bool p0, uint p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3)); } function log(bool p0, uint p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3)); } function log(bool p0, uint p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3)); } function log(bool p0, uint p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3)); } function log(bool p0, uint p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, uint p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3)); } function log(bool p0, uint p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3)); } function log(bool p0, uint p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3)); } function log(bool p0, uint p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3)); } function log(bool p0, uint p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); } function log(address p0, uint p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3)); } function log(address p0, uint p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3)); } function log(address p0, uint p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3)); } function log(address p0, uint p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3)); } function log(address p0, uint p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3)); } function log(address p0, uint p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3)); } function log(address p0, uint p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3)); } function log(address p0, uint p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3)); } function log(address p0, uint p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3)); } function log(address p0, uint p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3)); } function log(address p0, uint p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3)); } function log(address p0, uint p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3)); } function log(address p0, uint p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3)); } function log(address p0, uint p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3)); } function log(address p0, uint p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3)); } function log(address p0, uint p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); } function log(address p0, address p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3)); } function log(address p0, address p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3)); } function log(address p0, address p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; /// Common mathematical functions used in both SD59x18 and UD60x18. Note that these global functions do not /// always operate with SD59x18 and UD60x18 numbers. /*////////////////////////////////////////////////////////////////////////// CUSTOM ERRORS //////////////////////////////////////////////////////////////////////////*/ /// @notice Emitted when the ending result in the fixed-point version of `mulDiv` would overflow uint256. error PRBMath__MulDiv18Overflow(uint256 x, uint256 y); /// @notice Emitted when the ending result in `mulDiv` would overflow uint256. error PRBMath__MulDivOverflow(uint256 x, uint256 y, uint256 denominator); /// @notice Emitted when attempting to run `mulDiv` with one of the inputs `type(int256).min`. error PRBMath__MulDivSignedInputTooSmall(); /// @notice Emitted when the ending result in the signed version of `mulDiv` would overflow int256. error PRBMath__MulDivSignedOverflow(int256 x, int256 y); /*////////////////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////////////////*/ /// @dev How many trailing decimals can be represented. uint256 constant UNIT = 1e18; /// @dev Largest power of two that is a divisor of `UNIT`. uint256 constant UNIT_LPOTD = 262144; /// @dev The `UNIT` number inverted mod 2^256. uint256 constant UNIT_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281; /*////////////////////////////////////////////////////////////////////////// FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /// @notice Finds the zero-based index of the first one in the binary representation of x. /// @dev See the note on msb in the "Find First Set" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set /// /// Each of the steps in this implementation is equivalent to this high-level code: /// /// ```solidity /// if (x >= 2 ** 128) { /// x >>= 128; /// result += 128; /// } /// ``` /// /// Where 128 is swapped with each respective power of two factor. See the full high-level implementation here: /// https://gist.github.com/paulrberg/f932f8693f2733e30c4d479e8e980948 /// /// A list of the Yul instructions used below: /// - "gt" is "greater than" /// - "or" is the OR bitwise operator /// - "shl" is "shift left" /// - "shr" is "shift right" /// /// @param x The uint256 number for which to find the index of the most significant bit. /// @return result The index of the most significant bit as an uint256. function msb(uint256 x) pure returns (uint256 result) { // 2^128 assembly { let factor := shl(7, gt(x, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) x := shr(factor, x) result := or(result, factor) } // 2^64 assembly { let factor := shl(6, gt(x, 0xFFFFFFFFFFFFFFFF)) x := shr(factor, x) result := or(result, factor) } // 2^32 assembly { let factor := shl(5, gt(x, 0xFFFFFFFF)) x := shr(factor, x) result := or(result, factor) } // 2^16 assembly { let factor := shl(4, gt(x, 0xFFFF)) x := shr(factor, x) result := or(result, factor) } // 2^8 assembly { let factor := shl(3, gt(x, 0xFF)) x := shr(factor, x) result := or(result, factor) } // 2^4 assembly { let factor := shl(2, gt(x, 0xF)) x := shr(factor, x) result := or(result, factor) } // 2^2 assembly { let factor := shl(1, gt(x, 0x3)) x := shr(factor, x) result := or(result, factor) } // 2^1 // No need to shift x any more. assembly { let factor := gt(x, 0x1) result := or(result, factor) } } /// @notice Calculates floor(x*y÷denominator) with full precision. /// /// @dev Credits to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv. /// /// Requirements: /// - The denominator cannot be zero. /// - The result must fit within uint256. /// /// Caveats: /// - This function does not work with fixed-point numbers. /// /// @param x The multiplicand as an uint256. /// @param y The multiplier as an uint256. /// @param denominator The divisor as an uint256. /// @return result The result as an uint256. function mulDiv(uint256 x, uint256 y, uint256 denominator) pure returns (uint256 result) { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { unchecked { return prod0 / denominator; } } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (prod1 >= denominator) { revert PRBMath__MulDivOverflow(x, y, denominator); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using the mulmod Yul instruction. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. unchecked { // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 lpotdod = denominator & (~denominator + 1); assembly { // Divide denominator by lpotdod. denominator := div(denominator, lpotdod) // Divide [prod1 prod0] by lpotdod. prod0 := div(prod0, lpotdod) // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one. lpotdod := add(div(sub(0, lpotdod), lpotdod), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * lpotdod; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; } } /// @notice Calculates floor(x*y÷1e18) with full precision. /// /// @dev Variant of `mulDiv` with constant folding, i.e. in which the denominator is always 1e18. Before returning the /// final result, we add 1 if `(x * y) % UNIT >= HALF_UNIT`. Without this adjustment, 6.6e-19 would be truncated to 0 /// instead of being rounded to 1e-18. See "Listing 6" and text above it at https://accu.org/index.php/journals/1717. /// /// Requirements: /// - The result must fit within uint256. /// /// Caveats: /// - The body is purposely left uncommented; to understand how this works, see the NatSpec comments in `mulDiv`. /// - It is assumed that the result can never be `type(uint256).max` when x and y solve the following two equations: /// 1. x * y = type(uint256).max * UNIT /// 2. (x * y) % UNIT >= UNIT / 2 /// /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number. /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function mulDiv18(uint256 x, uint256 y) pure returns (uint256 result) { uint256 prod0; uint256 prod1; assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } if (prod1 >= UNIT) { revert PRBMath__MulDiv18Overflow(x, y); } uint256 remainder; assembly { remainder := mulmod(x, y, UNIT) } if (prod1 == 0) { unchecked { return prod0 / UNIT; } } assembly { result := mul( or( div(sub(prod0, remainder), UNIT_LPOTD), mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, UNIT_LPOTD), UNIT_LPOTD), 1)) ), UNIT_INVERSE ) } } /// @notice Calculates floor(x*y÷denominator) with full precision. /// /// @dev An extension of `mulDiv` for signed numbers. Works by computing the signs and the absolute values separately. /// /// Requirements: /// - None of the inputs can be `type(int256).min`. /// - The result must fit within int256. /// /// @param x The multiplicand as an int256. /// @param y The multiplier as an int256. /// @param denominator The divisor as an int256. /// @return result The result as an int256. function mulDivSigned(int256 x, int256 y, int256 denominator) pure returns (int256 result) { if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) { revert PRBMath__MulDivSignedInputTooSmall(); } // Get hold of the absolute values of x, y and the denominator. uint256 absX; uint256 absY; uint256 absD; unchecked { absX = x < 0 ? uint256(-x) : uint256(x); absY = y < 0 ? uint256(-y) : uint256(y); absD = denominator < 0 ? uint256(-denominator) : uint256(denominator); } // Compute the absolute value of (x*y)÷denominator. The result must fit within int256. uint256 rAbs = mulDiv(absX, absY, absD); if (rAbs > uint256(type(int256).max)) { revert PRBMath__MulDivSignedOverflow(x, y); } // Get the signs of x, y and the denominator. uint256 sx; uint256 sy; uint256 sd; assembly { // This works thanks to two's complement. // "sgt" stands for "signed greater than" and "sub(0,1)" is max uint256. sx := sgt(x, sub(0, 1)) sy := sgt(y, sub(0, 1)) sd := sgt(denominator, sub(0, 1)) } // XOR over sx, sy and sd. What this does is to check whether there are 1 or 3 negative signs in the inputs. // If there are, the result should be negative. Otherwise, it should be positive. unchecked { result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs); } } /// @notice Calculates the binary exponent of x using the binary fraction method. /// @dev Has to use 192.64-bit fixed-point numbers. /// See https://ethereum.stackexchange.com/a/96594/24693. /// @param x The exponent as an unsigned 192.64-bit fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function prbExp2(uint256 x) pure returns (uint256 result) { unchecked { // Start from 0.5 in the 192.64-bit fixed-point format. result = 0x800000000000000000000000000000000000000000000000; // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows // because the initial result is 2^191 and all magic factors are less than 2^65. if (x & 0xFF00000000000000 > 0) { if (x & 0x8000000000000000 > 0) { result = (result * 0x16A09E667F3BCC909) >> 64; } if (x & 0x4000000000000000 > 0) { result = (result * 0x1306FE0A31B7152DF) >> 64; } if (x & 0x2000000000000000 > 0) { result = (result * 0x1172B83C7D517ADCE) >> 64; } if (x & 0x1000000000000000 > 0) { result = (result * 0x10B5586CF9890F62A) >> 64; } if (x & 0x800000000000000 > 0) { result = (result * 0x1059B0D31585743AE) >> 64; } if (x & 0x400000000000000 > 0) { result = (result * 0x102C9A3E778060EE7) >> 64; } if (x & 0x200000000000000 > 0) { result = (result * 0x10163DA9FB33356D8) >> 64; } if (x & 0x100000000000000 > 0) { result = (result * 0x100B1AFA5ABCBED61) >> 64; } } if (x & 0xFF000000000000 > 0) { if (x & 0x80000000000000 > 0) { result = (result * 0x10058C86DA1C09EA2) >> 64; } if (x & 0x40000000000000 > 0) { result = (result * 0x1002C605E2E8CEC50) >> 64; } if (x & 0x20000000000000 > 0) { result = (result * 0x100162F3904051FA1) >> 64; } if (x & 0x10000000000000 > 0) { result = (result * 0x1000B175EFFDC76BA) >> 64; } if (x & 0x8000000000000 > 0) { result = (result * 0x100058BA01FB9F96D) >> 64; } if (x & 0x4000000000000 > 0) { result = (result * 0x10002C5CC37DA9492) >> 64; } if (x & 0x2000000000000 > 0) { result = (result * 0x1000162E525EE0547) >> 64; } if (x & 0x1000000000000 > 0) { result = (result * 0x10000B17255775C04) >> 64; } } if (x & 0xFF0000000000 > 0) { if (x & 0x800000000000 > 0) { result = (result * 0x1000058B91B5BC9AE) >> 64; } if (x & 0x400000000000 > 0) { result = (result * 0x100002C5C89D5EC6D) >> 64; } if (x & 0x200000000000 > 0) { result = (result * 0x10000162E43F4F831) >> 64; } if (x & 0x100000000000 > 0) { result = (result * 0x100000B1721BCFC9A) >> 64; } if (x & 0x80000000000 > 0) { result = (result * 0x10000058B90CF1E6E) >> 64; } if (x & 0x40000000000 > 0) { result = (result * 0x1000002C5C863B73F) >> 64; } if (x & 0x20000000000 > 0) { result = (result * 0x100000162E430E5A2) >> 64; } if (x & 0x10000000000 > 0) { result = (result * 0x1000000B172183551) >> 64; } } if (x & 0xFF00000000 > 0) { if (x & 0x8000000000 > 0) { result = (result * 0x100000058B90C0B49) >> 64; } if (x & 0x4000000000 > 0) { result = (result * 0x10000002C5C8601CC) >> 64; } if (x & 0x2000000000 > 0) { result = (result * 0x1000000162E42FFF0) >> 64; } if (x & 0x1000000000 > 0) { result = (result * 0x10000000B17217FBB) >> 64; } if (x & 0x800000000 > 0) { result = (result * 0x1000000058B90BFCE) >> 64; } if (x & 0x400000000 > 0) { result = (result * 0x100000002C5C85FE3) >> 64; } if (x & 0x200000000 > 0) { result = (result * 0x10000000162E42FF1) >> 64; } if (x & 0x100000000 > 0) { result = (result * 0x100000000B17217F8) >> 64; } } if (x & 0xFF00000000 > 0) { if (x & 0x80000000 > 0) { result = (result * 0x10000000058B90BFC) >> 64; } if (x & 0x40000000 > 0) { result = (result * 0x1000000002C5C85FE) >> 64; } if (x & 0x20000000 > 0) { result = (result * 0x100000000162E42FF) >> 64; } if (x & 0x10000000 > 0) { result = (result * 0x1000000000B17217F) >> 64; } if (x & 0x8000000 > 0) { result = (result * 0x100000000058B90C0) >> 64; } if (x & 0x4000000 > 0) { result = (result * 0x10000000002C5C860) >> 64; } if (x & 0x2000000 > 0) { result = (result * 0x1000000000162E430) >> 64; } if (x & 0x1000000 > 0) { result = (result * 0x10000000000B17218) >> 64; } } if (x & 0xFF0000 > 0) { if (x & 0x800000 > 0) { result = (result * 0x1000000000058B90C) >> 64; } if (x & 0x400000 > 0) { result = (result * 0x100000000002C5C86) >> 64; } if (x & 0x200000 > 0) { result = (result * 0x10000000000162E43) >> 64; } if (x & 0x100000 > 0) { result = (result * 0x100000000000B1721) >> 64; } if (x & 0x80000 > 0) { result = (result * 0x10000000000058B91) >> 64; } if (x & 0x40000 > 0) { result = (result * 0x1000000000002C5C8) >> 64; } if (x & 0x20000 > 0) { result = (result * 0x100000000000162E4) >> 64; } if (x & 0x10000 > 0) { result = (result * 0x1000000000000B172) >> 64; } } if (x & 0xFF00 > 0) { if (x & 0x8000 > 0) { result = (result * 0x100000000000058B9) >> 64; } if (x & 0x4000 > 0) { result = (result * 0x10000000000002C5D) >> 64; } if (x & 0x2000 > 0) { result = (result * 0x1000000000000162E) >> 64; } if (x & 0x1000 > 0) { result = (result * 0x10000000000000B17) >> 64; } if (x & 0x800 > 0) { result = (result * 0x1000000000000058C) >> 64; } if (x & 0x400 > 0) { result = (result * 0x100000000000002C6) >> 64; } if (x & 0x200 > 0) { result = (result * 0x10000000000000163) >> 64; } if (x & 0x100 > 0) { result = (result * 0x100000000000000B1) >> 64; } } if (x & 0xFF > 0) { if (x & 0x80 > 0) { result = (result * 0x10000000000000059) >> 64; } if (x & 0x40 > 0) { result = (result * 0x1000000000000002C) >> 64; } if (x & 0x20 > 0) { result = (result * 0x10000000000000016) >> 64; } if (x & 0x10 > 0) { result = (result * 0x1000000000000000B) >> 64; } if (x & 0x8 > 0) { result = (result * 0x10000000000000006) >> 64; } if (x & 0x4 > 0) { result = (result * 0x10000000000000003) >> 64; } if (x & 0x2 > 0) { result = (result * 0x10000000000000001) >> 64; } if (x & 0x1 > 0) { result = (result * 0x10000000000000001) >> 64; } } // We're doing two things at the same time: // // 1. Multiply the result by 2^n + 1, where "2^n" is the integer part and the one is added to account for // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191 // rather than 192. // 2. Convert the result to the unsigned 60.18-decimal fixed-point format. // // This works because 2^(191-ip) = 2^ip / 2^191, where "ip" is the integer part "2^n". result *= UNIT; result >>= (191 - (x >> 64)); } } /// @notice Calculates the square root of x, rounding down if x is not a perfect square. /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// Credits to OpenZeppelin for the explanations in code comments below. /// /// Caveats: /// - This function does not work with fixed-point numbers. /// /// @param x The uint256 number for which to calculate the square root. /// @return result The result as an uint256. function prbSqrt(uint256 x) pure returns (uint256 result) { if (x == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of x. // // We know that the "msb" (most significant bit) of x is a power of 2 such that we have: // // $$ // msb(x) <= x <= 2*msb(x)$ // $$ // // We write $msb(x)$ as $2^k$ and we get: // // $$ // k = log_2(x) // $$ // // Thus we can write the initial inequality as: // // $$ // 2^{log_2(x)} <= x <= 2*2^{log_2(x)+1} \\ // sqrt(2^k) <= sqrt(x) < sqrt(2^{k+1}) \\ // 2^{k/2} <= sqrt(x) < 2^{(k+1)/2} <= 2^{(k/2)+1} // $$ // // Consequently, $2^{log_2(x) /2}` is a good first approximation of sqrt(x) with at least one correct bit. uint256 xAux = uint256(x); result = 1; if (xAux >= 2 ** 128) { xAux >>= 128; result <<= 64; } if (xAux >= 2 ** 64) { xAux >>= 64; result <<= 32; } if (xAux >= 2 ** 32) { xAux >>= 32; result <<= 16; } if (xAux >= 2 ** 16) { xAux >>= 16; result <<= 8; } if (xAux >= 2 ** 8) { xAux >>= 8; result <<= 4; } if (xAux >= 2 ** 4) { xAux >>= 4; result <<= 2; } if (xAux >= 2 ** 2) { result <<= 1; } // At this point, `result` is an estimation with at least one bit of precision. We know the true value has at // most 128 bits, since it is the square root of a uint256. Newton's method converges quadratically (precision // doubles at every iteration). We thus need at most 7 iteration to turn our partial result with one bit of // precision into the expected uint128 result. unchecked { result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; // Round down the result in case x is not a perfect square. uint256 roundedDownResult = x / result; if (result >= roundedDownResult) { result = roundedDownResult; } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.13; import { msb, mulDiv, mulDiv18, prbExp2, prbSqrt } from "./Core.sol"; /// @notice The unsigned 60.18-decimal fixed-point number representation, which can have up to 60 digits and up to 18 decimals. /// The values of this are bound by the minimum and the maximum values permitted by the Solidity type uint256. type UD60x18 is uint256; /*////////////////////////////////////////////////////////////////////////// CUSTOM ERRORS //////////////////////////////////////////////////////////////////////////*/ /// @notice Emitted when adding two numbers overflows UD60x18. error PRBMathUD60x18__AddOverflow(uint256 x, UD60x18 y); /// @notice Emitted when ceiling a number overflows UD60x18. error PRBMathUD60x18__CeilOverflow(UD60x18 x); /// @notice Emitted when taking the natural exponent of a base greater than 133.084258667509499441. error PRBMathUD60x18__ExpInputTooBig(UD60x18 x); /// @notice Emitted when taking the binary exponent of a base greater than 192. error PRBMathUD60x18__Exp2InputTooBig(UD60x18 x); /// @notice Emitted when taking the geometric mean of two numbers and multiplying them overflows UD60x18. error PRBMathUD60x18__GmOverflow(UD60x18 x, UD60x18 y); /// @notice Emitted when taking the logarithm of a number less than 1. error PRBMathUD60x18__LogInputTooSmall(UD60x18 x); /// @notice Emitted when calculating the square root overflows UD60x18. error PRBMathUD60x18__SqrtOverflow(UD60x18 x); /// @notice Emitted when subtracting one number from another underflows UD60x18. error PRBMathUD60x18__SubUnderflow(UD60x18 x, UD60x18 y); /// @notice Emitted when converting a basic integer to the fixed-point format overflows UD60x18. error PRBMathUD60x18__ToUD60x18Overflow(uint256 x); /*////////////////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////////////////*/ /// NOTICE: the "u" prefix stands for "unwrapped". /// @dev Euler's number as an UD60x18 number. UD60x18 constant E = UD60x18.wrap(2_718281828459045235); /// @dev Half the UNIT number. uint256 constant uHALF_UNIT = 0.5e18; UD60x18 constant HALF_UNIT = UD60x18.wrap(uHALF_UNIT); /// @dev log2(10) as an UD60x18 number. uint256 constant uLOG2_10 = 3_321928094887362347; UD60x18 constant LOG2_10 = UD60x18.wrap(uLOG2_10); /// @dev log2(e) as an UD60x18 number. uint256 constant uLOG2_E = 1_442695040888963407; UD60x18 constant LOG2_E = UD60x18.wrap(uLOG2_E); /// @dev The maximum value an UD60x18 number can have. uint256 constant uMAX_UD60x18 = 115792089237316195423570985008687907853269984665640564039457_584007913129639935; UD60x18 constant MAX_UD60x18 = UD60x18.wrap(uMAX_UD60x18); /// @dev The maximum whole value an UD60x18 number can have. uint256 constant uMAX_WHOLE_UD60x18 = 115792089237316195423570985008687907853269984665640564039457_000000000000000000; UD60x18 constant MAX_WHOLE_UD60x18 = UD60x18.wrap(uMAX_WHOLE_UD60x18); /// @dev PI as an UD60x18 number. UD60x18 constant PI = UD60x18.wrap(3_141592653589793238); /// @dev The unit amount which implies how many trailing decimals can be represented. uint256 constant uUNIT = 1e18; UD60x18 constant UNIT = UD60x18.wrap(uUNIT); /// @dev Zero as an UD60x18 number. UD60x18 constant ZERO = UD60x18.wrap(0); /*////////////////////////////////////////////////////////////////////////// MATHEMATICAL FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ using { avg, ceil, div, exp, exp2, floor, frac, gm, inv, ln, log10, log2, mul, pow, powu, sqrt } for UD60x18 global; /// @notice Calculates the arithmetic average of x and y, rounding down. /// /// @dev Based on the formula: /// /// $$ /// avg(x, y) = (x & y) + ((xUint ^ yUint) / 2) /// $$ // /// In English, what this formula does is: /// /// 1. AND x and y. /// 2. Calculate half of XOR x and y. /// 3. Add the two results together. /// /// This technique is known as SWAR, which stands for "SIMD within a register". You can read more about it here: /// https://devblogs.microsoft.com/oldnewthing/20220207-00/?p=106223 /// /// @param x The first operand as an UD60x18 number. /// @param y The second operand as an UD60x18 number. /// @return result The arithmetic average as an UD60x18 number. function avg(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { uint256 xUint = unwrap(x); uint256 yUint = unwrap(y); unchecked { result = wrap((xUint & yUint) + ((xUint ^ yUint) >> 1)); } } /// @notice Yields the smallest whole UD60x18 number greater than or equal to x. /// /// @dev This is optimized for fractional value inputs, because for every whole value there are "1e18 - 1" fractional /// counterparts. See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions. /// /// Requirements: /// - x must be less than or equal to `MAX_WHOLE_UD60x18`. /// /// @param x The UD60x18 number to ceil. /// @param result The least number greater than or equal to x, as an UD60x18 number. function ceil(UD60x18 x) pure returns (UD60x18 result) { uint256 xUint = unwrap(x); if (xUint > uMAX_WHOLE_UD60x18) { revert PRBMathUD60x18__CeilOverflow(x); } assembly { // Equivalent to "x % UNIT" but faster. let remainder := mod(x, uUNIT) // Equivalent to "UNIT - remainder" but faster. let delta := sub(uUNIT, remainder) // Equivalent to "x + delta * (remainder > 0 ? 1 : 0)" but faster. result := add(x, mul(delta, gt(remainder, 0))) } } /// @notice Divides two UD60x18 numbers, returning a new UD60x18 number. Rounds towards zero. /// /// @dev Uses `mulDiv` to enable overflow-safe multiplication and division. /// /// Requirements: /// - The denominator cannot be zero. /// /// @param x The numerator as an UD60x18 number. /// @param y The denominator as an UD60x18 number. /// @param result The quotient as an UD60x18 number. function div(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(mulDiv(unwrap(x), uUNIT, unwrap(y))); } /// @notice Calculates the natural exponent of x. /// /// @dev Based on the formula: /// /// $$ /// e^x = 2^{x * log_2{e}} /// $$ /// /// Requirements: /// - All from `log2`. /// - x must be less than 133.084258667509499441. /// /// @param x The exponent as an UD60x18 number. /// @return result The result as an UD60x18 number. function exp(UD60x18 x) pure returns (UD60x18 result) { uint256 xUint = unwrap(x); // Without this check, the value passed to `exp2` would be greater than 192. if (xUint >= 133_084258667509499441) { revert PRBMathUD60x18__ExpInputTooBig(x); } unchecked { // We do the fixed-point multiplication inline rather than via the `mul` function to save gas. uint256 doubleUnitProduct = xUint * uLOG2_E; result = exp2(wrap(doubleUnitProduct / uUNIT)); } } /// @notice Calculates the binary exponent of x using the binary fraction method. /// /// @dev See https://ethereum.stackexchange.com/q/79903/24693. /// /// Requirements: /// - x must be 192 or less. /// - The result must fit within `MAX_UD60x18`. /// /// @param x The exponent as an UD60x18 number. /// @return result The result as an UD60x18 number. function exp2(UD60x18 x) pure returns (UD60x18 result) { uint256 xUint = unwrap(x); // Numbers greater than or equal to 2^192 don't fit within the 192.64-bit format. if (xUint >= 192e18) { revert PRBMathUD60x18__Exp2InputTooBig(x); } // Convert x to the 192.64-bit fixed-point format. uint256 x_192x64 = (xUint << 64) / uUNIT; // Pass x to the `prbExp2` function, which uses the 192.64-bit fixed-point number representation. result = wrap(prbExp2(x_192x64)); } /// @notice Yields the greatest whole UD60x18 number less than or equal to x. /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts. /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions. /// @param x The UD60x18 number to floor. /// @param result The greatest integer less than or equal to x, as an UD60x18 number. function floor(UD60x18 x) pure returns (UD60x18 result) { assembly { // Equivalent to "x % UNIT" but faster. let remainder := mod(x, uUNIT) // Equivalent to "x - remainder * (remainder > 0 ? 1 : 0)" but faster. result := sub(x, mul(remainder, gt(remainder, 0))) } } /// @notice Yields the excess beyond the floor of x. /// @dev Based on the odd function definition https://en.wikipedia.org/wiki/Fractional_part. /// @param x The UD60x18 number to get the fractional part of. /// @param result The fractional part of x as an UD60x18 number. function frac(UD60x18 x) pure returns (UD60x18 result) { assembly { result := mod(x, uUNIT) } } /// @notice Calculates the geometric mean of x and y, i.e. $$sqrt(x * y)$$, rounding down. /// /// @dev Requirements: /// - x * y must fit within `MAX_UD60x18`, lest it overflows. /// /// @param x The first operand as an UD60x18 number. /// @param y The second operand as an UD60x18 number. /// @return result The result as an UD60x18 number. function gm(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { uint256 xUint = unwrap(x); uint256 yUint = unwrap(y); if (xUint == 0 || yUint == 0) { return ZERO; } unchecked { // Checking for overflow this way is faster than letting Solidity do it. uint256 xyUint = xUint * yUint; if (xyUint / xUint != yUint) { revert PRBMathUD60x18__GmOverflow(x, y); } // We don't need to multiply the result by `UNIT` here because the x*y product had picked up a factor of `UNIT` // during multiplication. See the comments in the `prbSqrt` function. result = wrap(prbSqrt(xyUint)); } } /// @notice Calculates 1 / x, rounding toward zero. /// /// @dev Requirements: /// - x cannot be zero. /// /// @param x The UD60x18 number for which to calculate the inverse. /// @return result The inverse as an UD60x18 number. function inv(UD60x18 x) pure returns (UD60x18 result) { unchecked { // 1e36 is UNIT * UNIT. result = wrap(1e36 / unwrap(x)); } } /// @notice Calculates the natural logarithm of x. /// /// @dev Based on the formula: /// /// $$ /// ln{x} = log_2{x} / log_2{e}$$. /// $$ /// /// Requirements: /// - All from `log2`. /// /// Caveats: /// - All from `log2`. /// - This doesn't return exactly 1 for 2.718281828459045235, for that more fine-grained precision is needed. /// /// @param x The UD60x18 number for which to calculate the natural logarithm. /// @return result The natural logarithm as an UD60x18 number. function ln(UD60x18 x) pure returns (UD60x18 result) { unchecked { // We do the fixed-point multiplication inline to save gas. This is overflow-safe because the maximum value // that `log2` can return is 196.205294292027477728. result = wrap((unwrap(log2(x)) * uUNIT) / uLOG2_E); } } /// @notice Calculates the common logarithm of x. /// /// @dev First checks if x is an exact power of ten and it stops if yes. If it's not, calculates the common /// logarithm based on the formula: /// /// $$ /// log_{10}{x} = log_2{x} / log_2{10} /// $$ /// /// Requirements: /// - All from `log2`. /// /// Caveats: /// - All from `log2`. /// /// @param x The UD60x18 number for which to calculate the common logarithm. /// @return result The common logarithm as an UD60x18 number. function log10(UD60x18 x) pure returns (UD60x18 result) { uint256 xUint = unwrap(x); if (xUint < uUNIT) { revert PRBMathUD60x18__LogInputTooSmall(x); } // Note that the `mul` in this assembly block is the assembly multiplication operation, not the UD60x18 `mul`. // prettier-ignore assembly { switch x case 1 { result := mul(uUNIT, sub(0, 18)) } case 10 { result := mul(uUNIT, sub(1, 18)) } case 100 { result := mul(uUNIT, sub(2, 18)) } case 1000 { result := mul(uUNIT, sub(3, 18)) } case 10000 { result := mul(uUNIT, sub(4, 18)) } case 100000 { result := mul(uUNIT, sub(5, 18)) } case 1000000 { result := mul(uUNIT, sub(6, 18)) } case 10000000 { result := mul(uUNIT, sub(7, 18)) } case 100000000 { result := mul(uUNIT, sub(8, 18)) } case 1000000000 { result := mul(uUNIT, sub(9, 18)) } case 10000000000 { result := mul(uUNIT, sub(10, 18)) } case 100000000000 { result := mul(uUNIT, sub(11, 18)) } case 1000000000000 { result := mul(uUNIT, sub(12, 18)) } case 10000000000000 { result := mul(uUNIT, sub(13, 18)) } case 100000000000000 { result := mul(uUNIT, sub(14, 18)) } case 1000000000000000 { result := mul(uUNIT, sub(15, 18)) } case 10000000000000000 { result := mul(uUNIT, sub(16, 18)) } case 100000000000000000 { result := mul(uUNIT, sub(17, 18)) } case 1000000000000000000 { result := 0 } case 10000000000000000000 { result := uUNIT } case 100000000000000000000 { result := mul(uUNIT, 2) } case 1000000000000000000000 { result := mul(uUNIT, 3) } case 10000000000000000000000 { result := mul(uUNIT, 4) } case 100000000000000000000000 { result := mul(uUNIT, 5) } case 1000000000000000000000000 { result := mul(uUNIT, 6) } case 10000000000000000000000000 { result := mul(uUNIT, 7) } case 100000000000000000000000000 { result := mul(uUNIT, 8) } case 1000000000000000000000000000 { result := mul(uUNIT, 9) } case 10000000000000000000000000000 { result := mul(uUNIT, 10) } case 100000000000000000000000000000 { result := mul(uUNIT, 11) } case 1000000000000000000000000000000 { result := mul(uUNIT, 12) } case 10000000000000000000000000000000 { result := mul(uUNIT, 13) } case 100000000000000000000000000000000 { result := mul(uUNIT, 14) } case 1000000000000000000000000000000000 { result := mul(uUNIT, 15) } case 10000000000000000000000000000000000 { result := mul(uUNIT, 16) } case 100000000000000000000000000000000000 { result := mul(uUNIT, 17) } case 1000000000000000000000000000000000000 { result := mul(uUNIT, 18) } case 10000000000000000000000000000000000000 { result := mul(uUNIT, 19) } case 100000000000000000000000000000000000000 { result := mul(uUNIT, 20) } case 1000000000000000000000000000000000000000 { result := mul(uUNIT, 21) } case 10000000000000000000000000000000000000000 { result := mul(uUNIT, 22) } case 100000000000000000000000000000000000000000 { result := mul(uUNIT, 23) } case 1000000000000000000000000000000000000000000 { result := mul(uUNIT, 24) } case 10000000000000000000000000000000000000000000 { result := mul(uUNIT, 25) } case 100000000000000000000000000000000000000000000 { result := mul(uUNIT, 26) } case 1000000000000000000000000000000000000000000000 { result := mul(uUNIT, 27) } case 10000000000000000000000000000000000000000000000 { result := mul(uUNIT, 28) } case 100000000000000000000000000000000000000000000000 { result := mul(uUNIT, 29) } case 1000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 30) } case 10000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 31) } case 100000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 32) } case 1000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 33) } case 10000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 34) } case 100000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 35) } case 1000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 36) } case 10000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 37) } case 100000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 38) } case 1000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 39) } case 10000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 40) } case 100000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 41) } case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 42) } case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 43) } case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 44) } case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 45) } case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 46) } case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 47) } case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 48) } case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 49) } case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 50) } case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 51) } case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 52) } case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 53) } case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 54) } case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 55) } case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 56) } case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 57) } case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 58) } case 100000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 59) } default { result := uMAX_UD60x18 } } if (unwrap(result) == uMAX_UD60x18) { unchecked { // Do the fixed-point division inline to save gas. result = wrap((unwrap(log2(x)) * uUNIT) / uLOG2_10); } } } /// @notice Calculates the binary logarithm of x. /// /// @dev Based on the iterative approximation algorithm. /// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation /// /// Requirements: /// - x must be greater than or equal to UNIT, otherwise the result would be negative. /// /// Caveats: /// - The results are nor perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation. /// /// @param x The UD60x18 number for which to calculate the binary logarithm. /// @return result The binary logarithm as an UD60x18 number. function log2(UD60x18 x) pure returns (UD60x18 result) { uint256 xUint = unwrap(x); if (xUint < uUNIT) { revert PRBMathUD60x18__LogInputTooSmall(x); } unchecked { // Calculate the integer part of the logarithm, add it to the result and finally calculate y = x * 2^(-n). uint256 n = msb(xUint / uUNIT); // This is the integer part of the logarithm as an UD60x18 number. The operation can't overflow because n // n is maximum 255 and UNIT is 1e18. uint256 resultUint = n * uUNIT; // This is $y = x * 2^{-n}$. uint256 y = xUint >> n; // If y is 1, the fractional part is zero. if (y == uUNIT) { return wrap(resultUint); } // Calculate the fractional part via the iterative approximation. // The "delta.rshift(1)" part is equivalent to "delta /= 2", but shifting bits is faster. uint256 DOUBLE_UNIT = 2e18; for (uint256 delta = uHALF_UNIT; delta > 0; delta >>= 1) { y = (y * y) / uUNIT; // Is y^2 > 2 and so in the range [2,4)? if (y >= DOUBLE_UNIT) { // Add the 2^{-m} factor to the logarithm. resultUint += delta; // Corresponds to z/2 on Wikipedia. y >>= 1; } } result = wrap(resultUint); } } /// @notice Multiplies two UD60x18 numbers together, returning a new UD60x18 number. /// @dev See the documentation for the `Core/mulDiv18` function. /// @param x The multiplicand as an UD60x18 number. /// @param y The multiplier as an UD60x18 number. /// @return result The product as an UD60x18 number. function mul(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(mulDiv18(unwrap(x), unwrap(y))); } /// @notice Raises x to the power of y. /// /// @dev Based on the formula: /// /// $$ /// x^y = 2^{log_2{x} * y} /// $$ /// /// Requirements: /// - All from `exp2`, `log2` and `mul`. /// /// Caveats: /// - All from `exp2`, `log2` and `mul`. /// - Assumes 0^0 is 1. /// /// @param x Number to raise to given power y, as an UD60x18 number. /// @param y Exponent to raise x to, as an UD60x18 number. /// @return result x raised to power y, as an UD60x18 number. function pow(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { uint256 xUint = unwrap(x); uint256 yUint = unwrap(y); if (xUint == 0) { result = yUint == 0 ? UNIT : ZERO; } else { if (yUint == uUNIT) { result = x; } else { result = exp2(mul(log2(x), y)); } } } /// @notice Raises x (an UD60x18 number) to the power y (unsigned basic integer) using the famous algorithm /// "exponentiation by squaring". /// /// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring /// /// Requirements: /// - The result must fit within `MAX_UD60x18`. /// /// Caveats: /// - All from "Core/mulDiv18". /// - Assumes 0^0 is 1. /// /// @param x The base as an UD60x18 number. /// @param y The exponent as an uint256. /// @return result The result as an UD60x18 number. function powu(UD60x18 x, uint256 y) pure returns (UD60x18 result) { // Calculate the first iteration of the loop in advance. uint256 xUint = unwrap(x); uint256 resultUint = y & 1 > 0 ? xUint : uUNIT; // Equivalent to "for(y /= 2; y > 0; y /= 2)" but faster. for (y >>= 1; y > 0; y >>= 1) { xUint = mulDiv18(xUint, xUint); // Equivalent to "y % 2 == 1" but faster. if (y & 1 > 0) { resultUint = mulDiv18(resultUint, xUint); } } result = wrap(resultUint); } /// @notice Calculates the square root of x, rounding down. /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// /// Requirements: /// - x must be less than `MAX_UD60x18` divided by `UNIT`. /// /// @param x The UD60x18 number for which to calculate the square root. /// @return result The result as an UD60x18 number. function sqrt(UD60x18 x) pure returns (UD60x18 result) { uint256 xUint = unwrap(x); unchecked { if (xUint > uMAX_UD60x18 / uUNIT) { revert PRBMathUD60x18__SqrtOverflow(x); } // Multiply x by `UNIT` to account for the factor of `UNIT` that is picked up when multiplying two UD60x18 // numbers together (in this case, the two numbers are both the square root). result = wrap(prbSqrt(xUint * uUNIT)); } } /*////////////////////////////////////////////////////////////////////////// CONVERSION FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /// @notice Converts an UD60x18 number to a simple integer by dividing it by `UNIT`. Rounds towards zero in the process. /// @dev Rounds down in the process. /// @param x The UD60x18 number to convert. /// @return result The same number in basic integer form. function fromUD60x18(UD60x18 x) pure returns (uint256 result) { result = unwrap(x) / uUNIT; } /// @notice Converts a simple integer to UD60x18 by multiplying it by `UNIT`. /// /// @dev Requirements: /// - x must be less than or equal to `MAX_UD60x18` divided by `UNIT`. /// /// @param x The basic integer to convert. /// @param result The same number converted to UD60x18. function toUD60x18(uint256 x) pure returns (UD60x18 result) { if (x > uMAX_UD60x18 / uUNIT) { revert PRBMathUD60x18__ToUD60x18Overflow(x); } unchecked { result = wrap(x * uUNIT); } } /// @notice Wraps an unsigned integer into the UD60x18 type. function ud(uint256 x) pure returns (UD60x18 result) { result = wrap(x); } /// @notice Wraps an unsigned integer into the UD60x18 type. /// @dev Alias for the "ud" function defined above. function ud60x18(uint256 x) pure returns (UD60x18 result) { result = wrap(x); } /// @notice Unwraps an UD60x18 number into the underlying unsigned integer. function unwrap(UD60x18 x) pure returns (uint256 result) { result = UD60x18.unwrap(x); } /// @notice Wraps an unsigned integer into the UD60x18 type. function wrap(uint256 x) pure returns (UD60x18 result) { result = UD60x18.wrap(x); } /*////////////////////////////////////////////////////////////////////////// GLOBAL-SCOPED HELPER FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ using { add, and, eq, gt, gte, isZero, lshift, lt, lte, mod, neq, or, rshift, sub, uncheckedAdd, uncheckedSub, xor } for UD60x18 global; /// @notice Implements the checked addition operation (+) in the UD60x18 type. function add(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(unwrap(x) + unwrap(y)); } /// @notice Implements the AND (&) bitwise operation in the UD60x18 type. function and(UD60x18 x, uint256 bits) pure returns (UD60x18 result) { result = wrap(unwrap(x) & bits); } /// @notice Implements the equal operation (==) in the UD60x18 type. function eq(UD60x18 x, UD60x18 y) pure returns (bool result) { result = unwrap(x) == unwrap(y); } /// @notice Implements the greater than operation (>) in the UD60x18 type. function gt(UD60x18 x, UD60x18 y) pure returns (bool result) { result = unwrap(x) > unwrap(y); } /// @notice Implements the greater than or equal to operation (>=) in the UD60x18 type. function gte(UD60x18 x, UD60x18 y) pure returns (bool result) { result = unwrap(x) >= unwrap(y); } /// @notice Implements a zero comparison check function in the UD60x18 type. function isZero(UD60x18 x) pure returns (bool result) { // This wouldn't work if x could be negative. result = unwrap(x) == 0; } /// @notice Implements the left shift operation (<<) in the UD60x18 type. function lshift(UD60x18 x, uint256 bits) pure returns (UD60x18 result) { result = wrap(unwrap(x) << bits); } /// @notice Implements the lower than operation (<) in the UD60x18 type. function lt(UD60x18 x, UD60x18 y) pure returns (bool result) { result = unwrap(x) < unwrap(y); } /// @notice Implements the lower than or equal to operation (<=) in the UD60x18 type. function lte(UD60x18 x, UD60x18 y) pure returns (bool result) { result = unwrap(x) <= unwrap(y); } /// @notice Implements the checked modulo operation (%) in the UD60x18 type. function mod(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(unwrap(x) % unwrap(y)); } /// @notice Implements the not equal operation (!=) in the UD60x18 type function neq(UD60x18 x, UD60x18 y) pure returns (bool result) { result = unwrap(x) != unwrap(y); } /// @notice Implements the OR (|) bitwise operation in the UD60x18 type. function or(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(unwrap(x) | unwrap(y)); } /// @notice Implements the right shift operation (>>) in the UD60x18 type. function rshift(UD60x18 x, uint256 bits) pure returns (UD60x18 result) { result = wrap(unwrap(x) >> bits); } /// @notice Implements the checked subtraction operation (-) in the UD60x18 type. function sub(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(unwrap(x) - unwrap(y)); } /// @notice Implements the unchecked addition operation (+) in the UD60x18 type. function uncheckedAdd(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { unchecked { result = wrap(unwrap(x) + unwrap(y)); } } /// @notice Implements the unchecked subtraction operation (-) in the UD60x18 type. function uncheckedSub(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { unchecked { result = wrap(unwrap(x) - unwrap(y)); } } /// @notice Implements the XOR (^) bitwise operation in the UD60x18 type. function xor(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(unwrap(x) ^ unwrap(y)); } /*////////////////////////////////////////////////////////////////////////// FILE-SCOPED HELPER FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ using { uncheckedDiv, uncheckedMul } for UD60x18; /// @notice Implements the unchecked standard division operation in the UD60x18 type. function uncheckedDiv(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { unchecked { result = wrap(unwrap(x) / unwrap(y)); } } /// @notice Implements the unchecked standard multiplication operation in the UD60x18 type. function uncheckedMul(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { unchecked { result = wrap(unwrap(x) * unwrap(y)); } }
{ "remappings": [ "@prb/math/=lib/prb-math/src/", "@prb/test/=lib/prb-math/lib/prb-test/src/", "communal/=lib/communal/", "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "local/=src/", "openzeppelin/=lib/openzeppelin/", "prb-math/=lib/prb-math/src/", "prb-test/=lib/prb-math/lib/prb-test/src/", "src/=lib/prb-math/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_stakingToken","type":"address"},{"internalType":"address","name":"_LSDRegistry","type":"address"},{"internalType":"uint256","name":"_shanghaiTime","type":"uint256"},{"internalType":"address","name":"_darknetAddress","type":"address"},{"internalType":"string[]","name":"_rewardSymbols","type":"string[]"},{"internalType":"address[]","name":"_rewardTokens","type":"address[]"},{"internalType":"address[]","name":"_rewardManagers","type":"address[]"},{"internalType":"uint256[]","name":"_rewardRates","type":"uint256[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"UD60x18","name":"x","type":"uint256"}],"name":"PRBMathUD60x18__Exp2InputTooBig","type":"error"},{"inputs":[{"internalType":"UD60x18","name":"x","type":"uint256"}],"name":"PRBMathUD60x18__ExpInputTooBig","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"name":"PRBMath__MulDiv18Overflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"PRBMath__MulDivOverflow","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"multiplier","type":"uint256"}],"name":"LockedStakeMaxMultiplierUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"secs","type":"uint256"}],"name":"LockedStakeMinTime","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"secs","type":"uint256"}],"name":"LockedStakeTimeForMaxMultiplier","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"destination_address","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Recovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"},{"indexed":false,"internalType":"address","name":"token_address","type":"address"},{"indexed":false,"internalType":"address","name":"destination_address","type":"address"}],"name":"RewardPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"RewardsDurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"}],"name":"RewardsPeriodRenewed","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":"secs","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"kek_id","type":"bytes32"},{"indexed":false,"internalType":"address","name":"source_address","type":"address"}],"name":"StakeLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"kek_id","type":"bytes32"},{"indexed":false,"internalType":"address","name":"destination_address","type":"address"}],"name":"WithdrawLocked","type":"event"},{"inputs":[],"name":"LSDRegistryAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LSDVaultAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"calcCurCombinedWeight","outputs":[{"internalType":"uint256","name":"old_combined_weight","type":"uint256"},{"internalType":"uint256","name":"new_combined_weight","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"reward_token_address","type":"address"},{"internalType":"address","name":"new_manager_address","type":"address"}],"name":"changeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"combinedWeightOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"coordinationMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"darknetAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"earned","outputs":[{"internalType":"uint256[]","name":"new_earned","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllRewardRates","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllRewardTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReward","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getRewardForDuration","outputs":[{"internalType":"uint256[]","name":"rewards_per_duration_arr","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardSymbols","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"greylist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"greylistAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"caller_addr","type":"address"},{"internalType":"address","name":"reward_token_addr","type":"address"}],"name":"isTokenManagerFor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"secs","type":"uint256"}],"name":"lockMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lock_max_multiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lock_time_for_max_multiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lock_time_min","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"lockedLiquidityOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"lockedStakesOf","outputs":[{"components":[{"internalType":"bytes32","name":"kek_id","type":"bytes32"},{"internalType":"uint256","name":"start_timestamp","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"ending_timestamp","type":"uint256"},{"internalType":"uint256","name":"lock_multiplier","type":"uint256"}],"internalType":"struct EuclideanFarm.LockedStake[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"max_cord_multiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"max_nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"min_cord_multiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"periodFinish","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardManagers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardRates","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardSymbols","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardTokenAddrToIdx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsCollectionPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsPerToken","outputs":[{"internalType":"uint256[]","name":"newRewardsPerTokenStored","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lock_time_for_max_multiplier","type":"uint256"},{"internalType":"uint256","name":"_lock_time_min","type":"uint256"}],"name":"setLockedStakeTimeForMinAndMaxMultiplier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lock_max_multiplier","type":"uint256"}],"name":"setMultipliers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"reward_token_address","type":"address"},{"internalType":"uint256","name":"new_rate","type":"uint256"},{"internalType":"bool","name":"sync_too","type":"bool"}],"name":"setRewardRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rewardsDuration","type":"uint256"}],"name":"setRewardsDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shanghaiTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"}],"name":"stakeLocked","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakesUnlocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sync","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"synchronize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleRewardsCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleStaking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalCombinedWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalLiquidityLocked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unlockStakes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"kek_id","type":"bytes32"}],"name":"withdrawLocked","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040526729a2241af62c00006006556729a2241af62c0000600955670de0b6b3a7640000600a556000600b556002600c553480156200003f57600080fd5b5060405162005148380380620051488339810160408190526200006291620009ad565b886001600160a01b038116620000bf5760405162461bcd60e51b815260206004820152601960248201527f4f776e657220616464726573732063616e6e6f7420626520300000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03831690811782556040805192835260208301919091527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a15060016002556001600160a01b038716620001695760405162461bcd60e51b815260206004820152601260248201527104c53445265676973747279206973203078360741b6044820152606401620000b6565b600d80546001600160a01b0319166001600160a01b03891690811790915560408051632185f84560e11b8152905163430bf08a916004808201926020929091908290030181865afa158015620001c3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001e9919062000abc565b600e80546001600160a01b0319166001600160a01b03928316179055600d54604080516368fbd31560e01b8152905191909216916368fbd3159160048083019260209291908290030181865afa15801562000248573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200026e919062000ada565b8614620002be5760405162461bcd60e51b815260206004820152601560248201527f7368616e6768616954696d65206d69736d6174636800000000000000000000006044820152606401620000b6565b600f869055600380546001600160a01b0319166001600160a01b038a81169190911790915560208054600160201b600160c01b0319166401000000009288169290920291909117815583516200031b91601191908601906200052f565b5080516200033190601290602084019062000599565b50835162000347906013906020870190620005d7565b5042600f5462000358919062000b0a565b60158190556200036d90620151809062000b0a565b60075560005b83518110156200048a57806014600086848151811062000397576200039762000b24565b6020908102919091018101516001600160a01b03168252810191909152604001600090812091909155601680546001810182559082527fd833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b51242890155825183908290811062000407576200040762000b24565b60200260200101516010600086848151811062000428576200042862000b24565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055508080620004819062000b3a565b91505062000373565b506020805460ff19168155426005819055601554620004b2926200226e620004c5821b17901c565b6004555062000bad975050505050505050565b600080620004d4838562000b56565b905083811015620005285760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401620000b6565b9392505050565b82805482825590600052602060002090810192821562000587579160200282015b828111156200058757825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019062000550565b506200059592915062000637565b5090565b82805482825590600052602060002090810192821562000587579160200282015b8281111562000587578251825591602001919060010190620005ba565b82805482825590600052602060002090810192821562000629579160200282015b82811115620006295782518051620006189184916020909101906200064e565b5091602001919060010190620005f8565b5062000595929150620006ca565b5b8082111562000595576000815560010162000638565b8280546200065c9062000b71565b90600052602060002090601f01602090048101928262000680576000855562000587565b82601f106200069b57805160ff191683800117855562000587565b8280016001018555821562000587579182018281111562000587578251825591602001919060010190620005ba565b8082111562000595576000620006e18282620006eb565b50600101620006ca565b508054620006f99062000b71565b6000825580601f106200070a575050565b601f0160209004906000526020600020908101906200072a919062000637565b50565b80516001600160a01b03811681146200074557600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156200078b576200078b6200074a565b604052919050565b60006001600160401b03821115620007af57620007af6200074a565b5060051b60200190565b6000601f8381840112620007cc57600080fd5b82516020620007e5620007df8362000793565b62000760565b82815260059290921b850181019181810190878411156200080557600080fd5b8287015b84811015620008c95780516001600160401b03808211156200082b5760008081fd5b818a0191508a603f830112620008415760008081fd5b85820151818111156200085857620008586200074a565b6200086b818a01601f1916880162000760565b915080825260408c81838601011115620008855760008081fd5b60005b82811015620008a5578481018201518482018a0152880162000888565b82811115620008b75760008984860101525b50505084525091830191830162000809565b50979650505050505050565b600082601f830112620008e757600080fd5b81516020620008fa620007df8362000793565b82815260059290921b840181019181810190868411156200091a57600080fd5b8286015b84811015620009405762000932816200072d565b83529183019183016200091e565b509695505050505050565b600082601f8301126200095d57600080fd5b8151602062000970620007df8362000793565b82815260059290921b840181019181810190868411156200099057600080fd5b8286015b8481101562000940578051835291830191830162000994565b60008060008060008060008060006101208a8c031215620009cd57600080fd5b620009d88a6200072d565b9850620009e860208b016200072d565b9750620009f860408b016200072d565b965060608a0151955062000a0f60808b016200072d565b60a08b01519095506001600160401b038082111562000a2d57600080fd5b62000a3b8d838e01620007b9565b955060c08c015191508082111562000a5257600080fd5b62000a608d838e01620008d5565b945060e08c015191508082111562000a7757600080fd5b62000a858d838e01620008d5565b93506101008c015191508082111562000a9d57600080fd5b5062000aac8c828d016200094b565b9150509295985092959850929598565b60006020828403121562000acf57600080fd5b62000528826200072d565b60006020828403121562000aed57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b60008282101562000b1f5762000b1f62000af4565b500390565b634e487b7160e01b600052603260045260246000fd5b60006001820162000b4f5762000b4f62000af4565b5060010190565b6000821982111562000b6c5762000b6c62000af4565b500190565b600181811c9082168062000b8657607f821691505b60208210810362000ba757634e487b7160e01b600052602260045260246000fd5b50919050565b61458b8062000bbd6000396000f3fe608060405234801561001057600080fd5b50600436106103a35760003560e01c806379313225116101e9578063c8f33c911161010f578063e01f62bf116100ad578063f2caeb1e1161007c578063f2caeb1e146107cb578063f4315553146107de578063f64be1b1146107e6578063fff6cae9146107ee57600080fd5b8063e01f62bf146107a0578063e1ba95d2146107a8578063e9f2838e146107b0578063ebe2b12b146107c257600080fd5b8063d239f003116100e9578063d239f00314610749578063d9f96e8d14610751578063de1a65511461077a578063dfc117da1461078d57600080fd5b8063c8f33c9114610724578063cc1a378f1461072d578063cdc82e801461074057600080fd5b8063941d9f6511610187578063affed0e011610156578063affed0e0146106e3578063b669de8b146106ec578063b94c4dcb14610707578063bbb781cc1461071057600080fd5b8063941d9f65146106a85780639637927f146106bb5780639a97b349146106c8578063af00f4e2146106d057600080fd5b80637bb7bed1116101c35780637bb7bed1146106475780638980f11f1461065a5780638bad86a71461066d5780638da5cb5b1461069557600080fd5b8063793132251461062e57806379ba5097146106375780637b31c19a1461063f57600080fd5b80633d18b912116102ce57806362cc445c1161026c578063693392451161023b57806369339245146105ea5780636e27cef91461060a57806370641a361461061357806372f702f31461061b57600080fd5b806362cc445c146105b157806364f2c060146105c457806366e9e9b3146105cc57806368fbd315146105e157600080fd5b806350401ac0116102a857806350401ac01461056f578063507bd8031461057857806351e3fc171461058b57806353a47bb71461059e57600080fd5b80633d18b9121461051357806341a16f3f1461051b57806347b9bc221461055c57600080fd5b80631f5848de11610346578063323331ca11610315578063323331ca146104c657806336f89af2146104d9578063386a9525146105025780633b8105b31461050b57600080fd5b80631f5848de14610464578063231b68dc146104775780632d47cf221461049a57806331ca208c146104a357600080fd5b80631627540c116103825780631627540c146104075780631c1f78eb1461041c5780631e090f01146104245780631e3689801461044457600080fd5b80628cc262146103a85780630d7bac4f146103d157806312edb24c146103f2575b600080fd5b6103bb6103b6366004613df4565b6107f6565b6040516103c89190613e11565b60405180910390f35b6103e46103df366004613e55565b61099b565b6040519081526020016103c8565b6103fa6109f4565b6040516103c89190613e6e565b61041a610415366004613df4565b610a56565b005b6103bb610b22565b610437610432366004613df4565b610bde565b6040516103c89190613eaf565b610457610452366004613e55565b610c85565b6040516103c89190613f75565b61041a610472366004613f96565b610d31565b61048a610485366004613fd8565b610dbb565b60405190151581526020016103c8565b6103e4600a5481565b61048a6104b1366004613df4565b601f6020526000908152604090205460ff1681565b60205461048a9062010000900460ff1681565b6103e46104e7366004613df4565b6001600160a01b03166000908152601d602052604090205490565b6103e460155481565b61041a610e0f565b6103bb610e5a565b610544610529366004613df4565b6010602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020016103c8565b61041a61056a366004613e55565b610eee565b6103e4600c5481565b600e54610544906001600160a01b031681565b61041a610599366004613e55565b610fbe565b600154610544906001600160a01b031681565b61041a6105bf366004613e55565b611043565b601b546103e4565b6105d4611074565b6040516103c89190614011565b6103e4600f5481565b6103e46105f8366004613df4565b60146020526000908152604090205481565b6103e460085481565b6103bb61114d565b600354610544906001600160a01b031681565b6103e460095481565b61041a6112b9565b61041a6113a3565b610544610655366004613e55565b6113ec565b61041a610668366004614073565b611416565b61068061067b366004613df4565b61169b565b604080519283526020830191909152016103c8565b600054610544906001600160a01b031681565b61041a6106b6366004613df4565b6118ce565b60205461048a9060ff1681565b61041a611921565b61041a6106de36600461409f565b6119e4565b6103e4600b5481565b6020546105449064010000000090046001600160a01b031681565b6103e460075481565b60205461048a906301000000900460ff1681565b6103e460055481565b61041a61073b366004613e55565b611b24565b6103e460065481565b61041a611c32565b6103e461075f366004613df4565b6001600160a01b03166000908152601c602052604090205490565b61041a610788366004613fd8565b611c79565b600d54610544906001600160a01b031681565b601a546103e4565b61041a611ce4565b60205461048a90610100900460ff1681565b6103e460045481565b6103e46107d9366004613e55565b611d22565b6103bb611d43565b6103e4611d99565b61041a612252565b6060600061080261114d565b60115490915067ffffffffffffffff811115610820576108206140c1565b604051908082528060200260200182016040528015610849578160200160208202803683370190505b506001600160a01b0384166000908152601d6020526040812054919350036108af5760005b6011548110156108a957600083828151811061088c5761088c6140d7565b6020908102919091010152806108a181614103565b91505061086e565b50610995565b60005b601154811015610993576001600160a01b0384166000818152601860209081526040808320858452825280832054938352601782528083208584529091529020548351610964929161095e91670de0b6b3a764000091610958916109399190899089908110610923576109236140d7565b60200260200101516122d490919063ffffffff16565b6001600160a01b038a166000908152601d602052604090205490612316565b90612398565b9061226e565b838281518110610976576109766140d7565b60209081029190910101528061098b81614103565b9150506108b2565b505b50919050565b6000806109dd6109ce6007546109586109c7670de0b6b3a76400006006546122d490919063ffffffff16565b8790612316565b670de0b6b3a76400009061226e565b90506006548111156109ee57506006545b92915050565b60606011805480602002602001604051908101604052809291908181526020018280548015610a4c57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610a2e575b5050505050905090565b6000546001600160a01b03163314610acd5760405162461bcd60e51b815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201526e37b936903a3434b99030b1ba34b7b760891b60648201526084015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22906020015b60405180910390a150565b60125460609067ffffffffffffffff811115610b4057610b406140c1565b604051908082528060200260200182016040528015610b69578160200160208202803683370190505b50905060005b601254811015610bda57610bab60155460128381548110610b9257610b926140d7565b906000526020600020015461231690919063ffffffff16565b828281518110610bbd57610bbd6140d7565b602090810291909101015280610bd281614103565b915050610b6f565b5090565b6001600160a01b0381166000908152601e60209081526040808320805482518185028101850190935280835260609492939192909184015b82821015610c7a57838290600052602060002090600502016040518060a00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505081526020019060010190610c16565b505050509050919050565b60138181548110610c9557600080fd5b906000526020600020016000915090508054610cb09061411c565b80601f0160208091040260200160405190810160405280929190818152602001828054610cdc9061411c565b8015610d295780601f10610cfe57610100808354040283529160200191610d29565b820191906000526020600020905b815481529060010190602001808311610d0c57829003601f168201915b505050505081565b60005483906001600160a01b0316331480610d515750610d513382610dbb565b610d6d5760405162461bcd60e51b8152600401610ac490614150565b6001600160a01b038416600090815260146020526040902054601280548592908110610d9b57610d9b6140d7565b6000918252602090912001558115610db557610db5612252565b50505050565b600080546001600160a01b0390811690841603610dda575060016109ee565b6001600160a01b03828116600090815260106020526040902054818516911603610e06575060016109ee565b50600092915050565b6000546001600160a01b03163314610e395760405162461bcd60e51b8152600401610ac49061417e565b6020805463ff00000019811663010000009182900460ff1615909102179055565b60606002805403610e7d5760405162461bcd60e51b8152600401610ac4906141a5565b6002805560205462010000900460ff1615610eda5760405162461bcd60e51b815260206004820152601960248201527f5265776172647320636f6c6c656374696f6e20706175736564000000000000006044820152606401610ac4565b610ee433336123da565b9050600160025590565b6000546001600160a01b03163314610f185760405162461bcd60e51b8152600401610ac49061417e565b670de0b6b3a7640000811015610f895760405162461bcd60e51b815260206004820152603060248201527f4d756c7469706c696572206d7573742062652067726561746572207468616e2060448201526f0dee440cae2eac2d840e8de4062ca62760831b6064820152608401610ac4565b60068190556040518181527fa1676084a9eea08c6f205b60799323b364a1bd8e10aba89f0fbd94cfbf68b5dd90602001610b17565b6002805403610fdf5760405162461bcd60e51b8152600401610ac4906141a5565b60028055602054610100900460ff16156110305760405162461bcd60e51b815260206004820152601260248201527115da5d1a191c985dd85b1cc81c185d5cd95960721b6044820152606401610ac4565b61103b33338361263a565b506001600255565b60028054036110645760405162461bcd60e51b8152600401610ac4906141a5565b6002805561103b33808342612994565b60606013805480602002602001604051908101604052809291908181526020016000905b828210156111445783829060005260206000200180546110b79061411c565b80601f01602080910402602001604051908101604052809291908181526020018280546110e39061411c565b80156111305780601f1061110557610100808354040283529160200191611130565b820191906000526020600020905b81548152906001019060200180831161111357829003601f168201915b505050505081526020019060010190611098565b50505050905090565b6060601a54600014806111605750601b54155b156111ba576016805480602002602001604051908101604052809291908181526020018280548015610a4c57602002820191906000526020600020905b81548152602001906001019080831161119d575050505050905090565b60115467ffffffffffffffff8111156111d5576111d56140c1565b6040519080825280602002602001820160405280156111fe578160200160208202803683370190505b50905060005b601654811015610bda5761128a61125e601b54610958670de0b6b3a764000061125860128781548110611239576112396140d7565b9060005260206000200154611258600554611252612cb0565b906122d4565b90612316565b60168381548110611271576112716140d7565b906000526020600020015461226e90919063ffffffff16565b82828151811061129c5761129c6140d7565b6020908102919091010152806112b181614103565b915050611204565b6001546001600160a01b031633146113315760405162461bcd60e51b815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527402063616e20616363657074206f776e65727368697605c1b6064820152608401610ac4565b600054600154604080516001600160a01b0393841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6000546001600160a01b031633146113cd5760405162461bcd60e51b8152600401610ac49061417e565b6020805462ff0000198116620100009182900460ff1615909102179055565b601181815481106113fc57600080fd5b6000918252602090912001546001600160a01b0316905081565b60005482906001600160a01b031633148061143657506114363382610dbb565b6114525760405162461bcd60e51b8152600401610ac490614150565b6003546001600160a01b03908116908416036114b05760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f7420727567207374616b696e67202f204c5020746f6b656e7300006044820152606401610ac4565b6000805b60115481101561151057846001600160a01b0316601182815481106114db576114db6140d7565b6000918252602090912001546001600160a01b0316036114fe5760019150611510565b8061150881614103565b9150506114b4565b5080801561153757506001600160a01b038481166000908152601060205260409020541633145b156115fe5760405163a9059cbb60e01b8152336004820152602481018490526001600160a01b0385169063a9059cbb906044015b6020604051808303816000875af115801561158a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ae91906141dc565b50604080513381526001600160a01b03861660208201529081018490527ffff3b3844276f57024e0b42afec1a37f75db36511e43819a4f2a63ab7862b6489060600160405180910390a150505050565b8015801561161657506000546001600160a01b031633145b1561164e5760405163a9059cbb60e01b8152336004820152602481018490526001600160a01b0385169063a9059cbb9060440161156b565b60405162461bcd60e51b815260206004820152601a60248201527f4e6f2076616c696420746f6b656e7320746f207265636f7665720000000000006044820152606401610ac4565b505050565b6001600160a01b0381166000908152601d602052604081205490805b6001600160a01b0384166000908152601e60205260409020548110156118c8576001600160a01b0384166000908152601e60205260408120805483908110611701576117016140d7565b600091825260208083206040805160a08101825260059094029091018054845260018101549284019290925260028201549083015260038101546060830152600401546080820181905290925090611757611d99565b90508060000361179c5760405162461bcd60e51b815260206004820152601060248201526f26bab63a34b83634b2b91032b93937b960811b6044820152606401610ac4565b600a5481116117aa5750600a545b4283606001511161186a5760608301516001600160a01b038816600090815260196020526040902054101561185e576001600160a01b0387166000908152601960205260408120546060850151611800916122d4565b9050600061181b8560600151426122d490919063ffffffff16565b9050600061183e611834670de0b6b3a764000084612316565b61095e8786612316565b905061185461184d848461226e565b8290612398565b945050505061186a565b670de0b6b3a764000091505b60408301516000611887670de0b6b3a76400006109588487612316565b905060006118a1670de0b6b3a76400006109588487612316565b90506118ad888261226e565b975050505050505080806118c090614103565b9150506116b7565b50915091565b6000546001600160a01b031633146118f85760405162461bcd60e51b8152600401610ac49061417e565b6001600160a01b03166000908152601f60205260409020805460ff19811660ff90911615179055565b600d546040805163057ff68760e51b815290516000926001600160a01b03169163affed0e09160048083019260209291908290030181865afa15801561196b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061198f91906141f9565b905080600b54036119d95760405162461bcd60e51b8152602060048201526014602482015273105b1c9958591e481cde5b98da1c9bdb9a5e995960621b6044820152606401610ac4565b6119e1612cc3565b50565b6000546001600160a01b03163314611a0e5760405162461bcd60e51b8152600401610ac49061417e565b6001821015611a5f5760405162461bcd60e51b815260206004820152601960248201527f4d756c206d61782074696d65206d757374206265203e3d2031000000000000006044820152606401610ac4565b6001811015611ab05760405162461bcd60e51b815260206004820152601960248201527f4d756c206d696e2074696d65206d757374206265203e3d2031000000000000006044820152606401610ac4565b600782905560088190556040518281527f0e3e3fae480c6f92291358a02bc83f04ee1971d5488596bffda7929d57ab470f9060200160405180910390a16040518181527f0534d208d75dfdbfacc1204745dd9b3c4c37e8cfc05eb5e8e3ae538aedb0a9fa9060200160405180910390a15050565b6000546001600160a01b03163314611b4e5760405162461bcd60e51b8152600401610ac49061417e565b62015180811015611ba15760405162461bcd60e51b815260206004820152601a60248201527f52657761726473206475726174696f6e20746f6f2073686f72740000000000006044820152606401610ac4565b6004541580611bb1575060045442115b611bfd5760405162461bcd60e51b815260206004820152601860248201527f52657761726420706572696f6420696e636f6d706c65746500000000000000006044820152606401610ac4565b60158190556040518181527ffb46ca5a5e06d4540d6387b930a7c978bce0db5f449ec6b3f5d07c6e1d44f2d390602001610b17565b6000546001600160a01b03163314611c5c5760405162461bcd60e51b8152600401610ac49061417e565b6020805461ff001981166101009182900460ff1615909102179055565b60005482906001600160a01b0316331480611c995750611c993382610dbb565b611cb55760405162461bcd60e51b8152600401610ac490614150565b506001600160a01b03918216600090815260106020526040902080546001600160a01b03191691909216179055565b6000546001600160a01b03163314611d0e5760405162461bcd60e51b8152600401610ac49061417e565b6020805460ff19811660ff90911615179055565b60128181548110611d3257600080fd5b600091825260209091200154905081565b60606012805480602002602001604051908101604052809291908181526020018280548015610a4c576020028201919060005260206000209081548152602001906001019080831161119d575050505050905090565b600080600d60009054906101000a90046001600160a01b03166001600160a01b0316635a08bd176040518163ffffffff1660e01b8152600401600060405180830381865afa158015611def573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611e179190810190614267565b90506000600d60009054906101000a90046001600160a01b03166001600160a01b031663dad601f66040518163ffffffff1660e01b8152600401600060405180830381865afa158015611e6e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611e9691908101906142f2565b90508051825114611efe5760405162461bcd60e51b815260206004820152602c60248201527f746172676574526174696f20616e64206c7364416464726573736573206c656e60448201526b0cee8d040dad2e6dac2e8c6d60a31b6064820152608401610ac4565b8051611f0981612d2f565b60008167ffffffffffffffff811115611f2457611f246140c1565b604051908082528060200260200182016040528015611f4d578160200160208202803683370190505b509050611f5a8151612d2f565b600e54611f6f906001600160a01b0316612d74565b600e546040805163357ce51160e01b815290516000926001600160a01b03169163357ce5119160048083019260209291908290030181865afa158015611fb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fdd91906141f9565b9050611fe881612d2f565b60005b83811015612173576000858281518110612007576120076140d7565b6020908102919091010151600e546040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa15801561205b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061207f91906141f9565b90506000602060049054906101000a90046001600160a01b03166001600160a01b031663d45d15be8885815181106120b9576120b96140d7565b60200260200101516040518263ffffffff1660e01b81526004016120ec91906001600160a01b0391909116815260200190565b602060405180830381865afa158015612109573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061212d91906141f9565b9050600061213c838387612dbc565b905080868581518110612151576121516140d7565b602002602001018181525050505050808061216b90614103565b915050611feb565b5060006121808684612e8f565b90506000612196826722b1c8c1227a0000612fbf565b905060006121bc6121a683613073565b6121b7670de0b6b3a7640000613073565b61307b565b905060006121c982613093565b905060006121fc6121d985613073565b6121f66121e5856130ef565b6121f66729a2241af62c0000613073565b90613112565b9050600061221f61220e836003613121565b6121b7673782dace9d900000613073565b905061224261223f612238670de0b6b3a7640000613073565b8390613186565b90565b9b50505050505050505050505090565b60045442111561226657612264613195565b565b6122646131e6565b60008061227b8385614381565b9050838110156122cd5760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401610ac4565b9392505050565b60006122cd83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613259565b600082600003612328575060006109ee565b60006123348385614399565b90508261234185836143ce565b146122cd5760405162461bcd60e51b815260206004820152602160248201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6044820152607760f81b6064820152608401610ac4565b60006122cd83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061328a565b60608260016123e982826132b8565b60115467ffffffffffffffff811115612404576124046140c1565b60405190808252806020026020018201604052801561242d578160200160208202803683370190505b50925060005b601154811015612617576001600160a01b03861660009081526018602090815260408083208484529091529020548451859083908110612475576124756140d7565b6020908102919091018101919091526001600160a01b03871660009081526018825260408082208483529092529081205560118054829081106124ba576124ba6140d7565b9060005260206000200160009054906101000a90046001600160a01b03166001600160a01b031663a9059cbb868684815181106124f9576124f96140d7565b60200260200101516040518363ffffffff1660e01b81526004016125329291906001600160a01b03929092168252602082015260400190565b6020604051808303816000875af1158015612551573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061257591906141dc565b50856001600160a01b03167f1d2f2ca53af5d2f333bd32fdd45f9c52ad8ebe31414f7792912077fcb3876dff8583815181106125b3576125b36140d7565b6020026020010151601184815481106125ce576125ce6140d7565b60009182526020918290200154604080519384526001600160a01b039182169284019290925289169082015260600160405180910390a28061260f81614103565b915050612433565b5050506001600160a01b0390921660009081526019602052604090204290555090565b61264483836123da565b5061267a6040518060a0016040528060008019168152602001600081526020016000815260200160008152602001600081525090565b600060408201819052805b6001600160a01b0386166000908152601e6020526040902054811015612778576001600160a01b0386166000908152601e602052604090208054829081106126cf576126cf6140d7565b9060005260206000209060050201600001548403612766576001600160a01b0386166000908152601e60205260409020805482908110612711576127116140d7565b90600052602060002090600502016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250509250809150612778565b8061277081614103565b915050612685565b50815183146127bb5760405162461bcd60e51b815260206004820152600f60248201526e14dd185ad9481b9bdd08199bdd5b99608a1b6044820152606401610ac4565b8160600151421015806127d5575060205460ff1615156001145b61281a5760405162461bcd60e51b81526020600482015260166024820152755374616b65206973207374696c6c206c6f636b65642160501b6044820152606401610ac4565b6040820151801561298c57601a5461283290826122d4565b601a556001600160a01b0386166000908152601c602052604090205461285890826122d4565b6001600160a01b0387166000908152601c6020908152604080832093909355601e90522080548390811061288e5761288e6140d7565b6000918252602082206005909102018181556001810182905560028101829055600381018290556004018190556128c69087906132b8565b60035460405163a9059cbb60e01b81526001600160a01b038781166004830152602482018490529091169063a9059cbb906044016020604051808303816000875af1158015612919573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061293d91906141dc565b5060408051828152602081018690526001600160a01b03878116828401529151918816917f1d9308f6b22a2754a1c622bb30889e8f8f956c83e524d039e9d65d5f052eb9089181900360600190a25b505050505050565b8360016129a182826132b8565b6020546301000000900460ff16156129ec5760405162461bcd60e51b815260206004820152600e60248201526d14dd185ada5b99c81c185d5cd95960921b6044820152606401610ac4565b60008411612a3c5760405162461bcd60e51b815260206004820152601960248201527f4d757374207374616b65206d6f7265207468616e207a65726f000000000000006044820152606401610ac4565b6001600160a01b0386166000908152601f602052604090205460ff1615612aa55760405162461bcd60e51b815260206004820152601b60248201527f4164647265737320686173206265656e20677265796c697374656400000000006044820152606401610ac4565b600042600f54612ab591906143f0565b90506000612ac28261099b565b6001600160a01b0389166000908152601c602090815260408083205490516bffffffffffffffffffffffff1960608e901b169281019290925260348201899052605482018a905260748201529192509060940160408051601f1981840301815282825280516020918201206001600160a01b03808e166000908152601e845284812060a0870186528387528685018d81529587018e8152600f5460608901908152608089018b8152835460018181018655948652979094209851600590970290980195865595519085015593516002840155935160038084019190915592516004909201919091559054909250612bbc911689308a613387565b601a54612bc9908861226e565b601a556001600160a01b0389166000908152601c6020526040902054612bef908861226e565b6001600160a01b038a166000908152601c6020526040812091909155612c16908a906132b8565b6001600160a01b0389166000908152601960205260408120549003612c51576001600160a01b03891660009081526019602052604090204290555b60408051888152602081018590529081018290526001600160a01b0389811660608301528a16907ff400e72e69ef4402819dfc57eeddc66f5eb69bf405e0e8098b1946ec1ac14a229060800160405180910390a2505050505050505050565b6000612cbe426004546134af565b905090565b6000670de0b6b3a76400006012600081548110612ce257612ce26140d7565b9060005260206000200154612cf5611d99565b612cff9190614399565b612d0991906143ce565b9050806012600081548110612d2057612d206140d7565b60009182526020909120015550565b6119e181604051602401612d4591815260200190565b60408051601f198184030181529190526020810180516001600160e01b031663f5b1bba960e01b1790526134c5565b6040516001600160a01b03821660248201526119e19060440160408051601f198184030181529190526020810180516001600160e01b031663161765e160e11b1790526134c5565b6000808060001985870985870292508281108382030391505080600003612df657838281612dec57612dec6143b8565b04925050506122cd565b838110612e27576040516307639aaf60e41b8152600481018790526024810186905260448101859052606401610ac4565b600084868809600260036001881981018916988990049182028318808302840302808302840302808302840302808302840302808302840302918202909203026000889003889004909101858311909403939093029303949094049190911702949350505050565b60008151835114612eda5760405162461bcd60e51b8152602060048201526015602482015274082e4e4c2f240d8cadccee8d040dad2e6dac2e8c6d605b1b6044820152606401610ac4565b60008060008060005b8751811015612f995766038d7ea4c68000888281518110612f0657612f066140d7565b6020026020010151612f1891906143ce565b945066038d7ea4c68000878281518110612f3457612f346140d7565b6020026020010151612f4691906143ce565b9350838513612f5e57612f598585614407565b612f68565b612f688486614407565b91506000612f7760028461452a565b9050612f838185614381565b9350508080612f9190614103565b915050612ee3565b50612fa3826134e6565b612fb49066038d7ea4c68000614399565b979650505050505050565b60008080600019848609848602925082811083820303915050670de0b6b3a7640000811061300a5760405163090638d560e41b81526004810186905260248101859052604401610ac4565b6000670de0b6b3a7640000858709905081600003613036575050670de0b6b3a7640000900490506109ee565b620400008184030492109003600160ee1b02177faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066902905092915050565b6000816109ee565b60006122cd61223f84670de0b6b3a764000085612dbc565b600081680736ea4425c11ac63181106130c25760405163062bb40d60e31b815260048101849052602401610ac4565b6714057b7ef767814f81026130e76130e2670de0b6b3a7640000835b0490565b613550565b949350505050565b60006109ee826ec097ce7bc90715b34b9f1000000000816130de576130de6143b8565b60006122cd61223f83856143f0565b600082816001841661313b57670de0b6b3a764000061313d565b815b9050600184901c93505b831561317b576131578283612fbf565b9150600184161561316f5761316c8183612fbf565b90505b600184901c9350613147565b805b95945050505050565b60006122cd61223f8385614381565b60045442116122665760405162461bcd60e51b815260206004820152601b60248201527f506572696f6420686173206e6f742065787069726564207965742100000000006044820152606401610ac4565b60006131f061114d565b905060005b60165481101561324a57818181518110613211576132116140d7565b60200260200101516016828154811061322c5761322c6140d7565b6000918252602090912001558061324281614103565b9150506131f5565b50613253612cb0565b60055550565b6000818484111561327d5760405162461bcd60e51b8152600401610ac49190613f75565b50600061317d84866143f0565b600081836132ab5760405162461bcd60e51b8152600401610ac49190613f75565b50600061317d84866143ce565b80156132c6576132c6612252565b6001600160a01b03821615613383576000806132e18461169b565b915091506132ee846135a5565b81811061333d57600061330182846122d4565b601b54909150613311908261226e565b601b5561331e838261226e565b6001600160a01b0386166000908152601d602052604090205550610db5565b600061334983836122d4565b601b5490915061335990826122d4565b601b5561336683826122d4565b6001600160a01b0386166000908152601d60205260409020555050505b5050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916133eb9190614539565b6000604051808303816000865af19150503d8060008114613428576040519150601f19603f3d011682016040523d82523d6000602084013e61342d565b606091505b509150915081801561345757508051158061345757508080602001905181019061345791906141dc565b61298c5760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b6064820152608401610ac4565b60008183106134be57816122cd565b5090919050565b80516a636f6e736f6c652e6c6f67602083016000808483855afa5050505050565b6000600382111561354157508060006135006002836143ce565b61350b906001614381565b90505b818110156109955790508060028161352681866143ce565b6135309190614381565b61353a91906143ce565b905061350e565b811561354b575060015b919050565b600081680a688906bd8b000000811061357f57604051634a4f26f160e01b815260048101849052602401610ac4565b6000613597670de0b6b3a7640000604084901b6143ce565b90506130e761223f8261367e565b6001600160a01b038116156119e15760006135bf826107f6565b905060005b8151811015613620578181815181106135df576135df6140d7565b6020908102919091018101516001600160a01b038516600090815260188352604080822085835290935291909120558061361881614103565b9150506135c4565b5060005b81518110156116965760168181548110613640576136406140d7565b60009182526020808320909101546001600160a01b03861683526017825260408084208585529092529120558061367681614103565b915050613624565b600160bf1b67ff0000000000000082161561378b576780000000000000008216156136b25768016a09e667f3bcc9090260401c5b6740000000000000008216156136d1576801306fe0a31b7152df0260401c5b6720000000000000008216156136f0576801172b83c7d517adce0260401c5b67100000000000000082161561370f5768010b5586cf9890f62a0260401c5b67080000000000000082161561372e576801059b0d31585743ae0260401c5b67040000000000000082161561374d57680102c9a3e778060ee70260401c5b67020000000000000082161561376c5768010163da9fb33356d80260401c5b67010000000000000082161561378b57680100b1afa5abcbed610260401c5b66ff00000000000082161561388a5766800000000000008216156137b85768010058c86da1c09ea20260401c5b66400000000000008216156137d6576801002c605e2e8cec500260401c5b66200000000000008216156137f457680100162f3904051fa10260401c5b6610000000000000821615613812576801000b175effdc76ba0260401c5b660800000000000082161561383057680100058ba01fb9f96d0260401c5b660400000000000082161561384e5768010002c5cc37da94920260401c5b660200000000000082161561386c576801000162e525ee05470260401c5b660100000000000082161561388a5768010000b17255775c040260401c5b65ff000000000082161561398057658000000000008216156138b5576801000058b91b5bc9ae0260401c5b654000000000008216156138d257680100002c5c89d5ec6d0260401c5b652000000000008216156138ef5768010000162e43f4f8310260401c5b6510000000000082161561390c57680100000b1721bcfc9a0260401c5b650800000000008216156139295768010000058b90cf1e6e0260401c5b65040000000000821615613946576801000002c5c863b73f0260401c5b6502000000000082161561396357680100000162e430e5a20260401c5b65010000000000821615613980576801000000b1721835510260401c5b64ff00000000821615613a6d576480000000008216156139a957680100000058b90c0b490260401c5b6440000000008216156139c55768010000002c5c8601cc0260401c5b6420000000008216156139e1576801000000162e42fff00260401c5b6410000000008216156139fd5768010000000b17217fbb0260401c5b640800000000821615613a19576801000000058b90bfce0260401c5b640400000000821615613a3557680100000002c5c85fe30260401c5b640200000000821615613a515768010000000162e42ff10260401c5b640100000000821615613a6d57680100000000b17217f80260401c5b64ff00000000821615613b52576380000000821615613a955768010000000058b90bfc0260401c5b6340000000821615613ab0576801000000002c5c85fe0260401c5b6320000000821615613acb57680100000000162e42ff0260401c5b6310000000821615613ae6576801000000000b17217f0260401c5b6308000000821615613b0157680100000000058b90c00260401c5b6304000000821615613b1c5768010000000002c5c8600260401c5b6302000000821615613b37576801000000000162e4300260401c5b6301000000821615613b525768010000000000b172180260401c5b62ff0000821615613c2d5762800000821615613b77576801000000000058b90c0260401c5b62400000821615613b9157680100000000002c5c860260401c5b62200000821615613bab5768010000000000162e430260401c5b62100000821615613bc557680100000000000b17210260401c5b62080000821615613bdf5768010000000000058b910260401c5b62040000821615613bf9576801000000000002c5c80260401c5b62020000821615613c1357680100000000000162e40260401c5b62010000821615613c2d576801000000000000b1720260401c5b61ff00821615613cff57618000821615613c5057680100000000000058b90260401c5b614000821615613c695768010000000000002c5d0260401c5b612000821615613c82576801000000000000162e0260401c5b611000821615613c9b5768010000000000000b170260401c5b610800821615613cb4576801000000000000058c0260401c5b610400821615613ccd57680100000000000002c60260401c5b610200821615613ce657680100000000000001630260401c5b610100821615613cff57680100000000000000b10260401c5b60ff821615613dc8576080821615613d2057680100000000000000590260401c5b6040821615613d38576801000000000000002c0260401c5b6020821615613d5057680100000000000000160260401c5b6010821615613d68576801000000000000000b0260401c5b6008821615613d8057680100000000000000060260401c5b6004821615613d9857680100000000000000030260401c5b6002821615613db057680100000000000000010260401c5b6001821615613dc857680100000000000000010260401c5b670de0b6b3a76400000260409190911c60bf031c90565b6001600160a01b03811681146119e157600080fd5b600060208284031215613e0657600080fd5b81356122cd81613ddf565b6020808252825182820181905260009190848201906040850190845b81811015613e4957835183529284019291840191600101613e2d565b50909695505050505050565b600060208284031215613e6757600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b81811015613e495783516001600160a01b031683529284019291840191600101613e8a565b602080825282518282018190526000919060409081850190868401855b82811015613f105781518051855286810151878601528581015186860152606080820151908601526080908101519085015260a09093019290850190600101613ecc565b5091979650505050505050565b60005b83811015613f38578181015183820152602001613f20565b83811115610db55750506000910152565b60008151808452613f61816020860160208601613f1d565b601f01601f19169290920160200192915050565b6020815260006122cd6020830184613f49565b80151581146119e157600080fd5b600080600060608486031215613fab57600080fd5b8335613fb681613ddf565b9250602084013591506040840135613fcd81613f88565b809150509250925092565b60008060408385031215613feb57600080fd5b8235613ff681613ddf565b9150602083013561400681613ddf565b809150509250929050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561406657603f19888603018452614054858351613f49565b94509285019290850190600101614038565b5092979650505050505050565b6000806040838503121561408657600080fd5b823561409181613ddf565b946020939093013593505050565b600080604083850312156140b257600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201614115576141156140ed565b5060010190565b600181811c9082168061413057607f821691505b60208210810361099557634e487b7160e01b600052602260045260246000fd5b6020808252601490820152732737ba1037bbb732b91037b9103a35b71036b3b960611b604082015260600190565b6020808252600d908201526c2737ba103a34329037bbb732b960991b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6000602082840312156141ee57600080fd5b81516122cd81613f88565b60006020828403121561420b57600080fd5b5051919050565b604051601f8201601f1916810167ffffffffffffffff8111828210171561423b5761423b6140c1565b604052919050565b600067ffffffffffffffff82111561425d5761425d6140c1565b5060051b60200190565b6000602080838503121561427a57600080fd5b825167ffffffffffffffff81111561429157600080fd5b8301601f810185136142a257600080fd5b80516142b56142b082614243565b614212565b81815260059190911b820183019083810190878311156142d457600080fd5b928401925b82841015612fb4578351825292840192908401906142d9565b6000602080838503121561430557600080fd5b825167ffffffffffffffff81111561431c57600080fd5b8301601f8101851361432d57600080fd5b805161433b6142b082614243565b81815260059190911b8201830190838101908783111561435a57600080fd5b928401925b82841015612fb457835161437281613ddf565b8252928401929084019061435f565b60008219821115614394576143946140ed565b500190565b60008160001904831182151516156143b3576143b36140ed565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826143eb57634e487b7160e01b600052601260045260246000fd5b500490565b600082821015614402576144026140ed565b500390565b60008083128015600160ff1b850184121615614425576144256140ed565b6001600160ff1b0384018313811615614440576144406140ed565b50500390565b600181815b80851115614481578160001904821115614467576144676140ed565b8085161561447457918102915b93841c939080029061444b565b509250929050565b600082614498575060016109ee565b816144a5575060006109ee565b81600181146144bb57600281146144c5576144e1565b60019150506109ee565b60ff8411156144d6576144d66140ed565b50506001821b6109ee565b5060208310610133831016604e8410600b8410161715614504575081810a6109ee565b61450e8383614446565b8060001904821115614522576145226140ed565b029392505050565b60006122cd60ff841683614489565b6000825161454b818460208701613f1d565b919091019291505056fea2646970667358221220ef25dd6c2a442ca803fe5bc13cc68dc2eb126a5956e64f7c7612b2537715a34d64736f6c634300080d0033000000000000000000000000d88e7d30f7548b7a7c6bfe513629724916449e6d000000000000000000000000846982c0a47b0e9f4c13f3251ba972bb8d32a8ca000000000000000000000000a857904691bbdeca2e768b318b5f6b9bfa698b7c00000000000000000000000000000000000000000000000000000000642773ff000000000000000000000000e8ef2e07e2fca3305372cb0345c686efbec75658000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000355534800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000e60779cc1b2c1d0580611c526a8df0e3f870ec480000000000000000000000000000000000000000000000000000000000000001000000000000000000000000d88e7d30f7548b7a7c6bfe513629724916449e6d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000004ba24a1fe9e10000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103a35760003560e01c806379313225116101e9578063c8f33c911161010f578063e01f62bf116100ad578063f2caeb1e1161007c578063f2caeb1e146107cb578063f4315553146107de578063f64be1b1146107e6578063fff6cae9146107ee57600080fd5b8063e01f62bf146107a0578063e1ba95d2146107a8578063e9f2838e146107b0578063ebe2b12b146107c257600080fd5b8063d239f003116100e9578063d239f00314610749578063d9f96e8d14610751578063de1a65511461077a578063dfc117da1461078d57600080fd5b8063c8f33c9114610724578063cc1a378f1461072d578063cdc82e801461074057600080fd5b8063941d9f6511610187578063affed0e011610156578063affed0e0146106e3578063b669de8b146106ec578063b94c4dcb14610707578063bbb781cc1461071057600080fd5b8063941d9f65146106a85780639637927f146106bb5780639a97b349146106c8578063af00f4e2146106d057600080fd5b80637bb7bed1116101c35780637bb7bed1146106475780638980f11f1461065a5780638bad86a71461066d5780638da5cb5b1461069557600080fd5b8063793132251461062e57806379ba5097146106375780637b31c19a1461063f57600080fd5b80633d18b912116102ce57806362cc445c1161026c578063693392451161023b57806369339245146105ea5780636e27cef91461060a57806370641a361461061357806372f702f31461061b57600080fd5b806362cc445c146105b157806364f2c060146105c457806366e9e9b3146105cc57806368fbd315146105e157600080fd5b806350401ac0116102a857806350401ac01461056f578063507bd8031461057857806351e3fc171461058b57806353a47bb71461059e57600080fd5b80633d18b9121461051357806341a16f3f1461051b57806347b9bc221461055c57600080fd5b80631f5848de11610346578063323331ca11610315578063323331ca146104c657806336f89af2146104d9578063386a9525146105025780633b8105b31461050b57600080fd5b80631f5848de14610464578063231b68dc146104775780632d47cf221461049a57806331ca208c146104a357600080fd5b80631627540c116103825780631627540c146104075780631c1f78eb1461041c5780631e090f01146104245780631e3689801461044457600080fd5b80628cc262146103a85780630d7bac4f146103d157806312edb24c146103f2575b600080fd5b6103bb6103b6366004613df4565b6107f6565b6040516103c89190613e11565b60405180910390f35b6103e46103df366004613e55565b61099b565b6040519081526020016103c8565b6103fa6109f4565b6040516103c89190613e6e565b61041a610415366004613df4565b610a56565b005b6103bb610b22565b610437610432366004613df4565b610bde565b6040516103c89190613eaf565b610457610452366004613e55565b610c85565b6040516103c89190613f75565b61041a610472366004613f96565b610d31565b61048a610485366004613fd8565b610dbb565b60405190151581526020016103c8565b6103e4600a5481565b61048a6104b1366004613df4565b601f6020526000908152604090205460ff1681565b60205461048a9062010000900460ff1681565b6103e46104e7366004613df4565b6001600160a01b03166000908152601d602052604090205490565b6103e460155481565b61041a610e0f565b6103bb610e5a565b610544610529366004613df4565b6010602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020016103c8565b61041a61056a366004613e55565b610eee565b6103e4600c5481565b600e54610544906001600160a01b031681565b61041a610599366004613e55565b610fbe565b600154610544906001600160a01b031681565b61041a6105bf366004613e55565b611043565b601b546103e4565b6105d4611074565b6040516103c89190614011565b6103e4600f5481565b6103e46105f8366004613df4565b60146020526000908152604090205481565b6103e460085481565b6103bb61114d565b600354610544906001600160a01b031681565b6103e460095481565b61041a6112b9565b61041a6113a3565b610544610655366004613e55565b6113ec565b61041a610668366004614073565b611416565b61068061067b366004613df4565b61169b565b604080519283526020830191909152016103c8565b600054610544906001600160a01b031681565b61041a6106b6366004613df4565b6118ce565b60205461048a9060ff1681565b61041a611921565b61041a6106de36600461409f565b6119e4565b6103e4600b5481565b6020546105449064010000000090046001600160a01b031681565b6103e460075481565b60205461048a906301000000900460ff1681565b6103e460055481565b61041a61073b366004613e55565b611b24565b6103e460065481565b61041a611c32565b6103e461075f366004613df4565b6001600160a01b03166000908152601c602052604090205490565b61041a610788366004613fd8565b611c79565b600d54610544906001600160a01b031681565b601a546103e4565b61041a611ce4565b60205461048a90610100900460ff1681565b6103e460045481565b6103e46107d9366004613e55565b611d22565b6103bb611d43565b6103e4611d99565b61041a612252565b6060600061080261114d565b60115490915067ffffffffffffffff811115610820576108206140c1565b604051908082528060200260200182016040528015610849578160200160208202803683370190505b506001600160a01b0384166000908152601d6020526040812054919350036108af5760005b6011548110156108a957600083828151811061088c5761088c6140d7565b6020908102919091010152806108a181614103565b91505061086e565b50610995565b60005b601154811015610993576001600160a01b0384166000818152601860209081526040808320858452825280832054938352601782528083208584529091529020548351610964929161095e91670de0b6b3a764000091610958916109399190899089908110610923576109236140d7565b60200260200101516122d490919063ffffffff16565b6001600160a01b038a166000908152601d602052604090205490612316565b90612398565b9061226e565b838281518110610976576109766140d7565b60209081029190910101528061098b81614103565b9150506108b2565b505b50919050565b6000806109dd6109ce6007546109586109c7670de0b6b3a76400006006546122d490919063ffffffff16565b8790612316565b670de0b6b3a76400009061226e565b90506006548111156109ee57506006545b92915050565b60606011805480602002602001604051908101604052809291908181526020018280548015610a4c57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610a2e575b5050505050905090565b6000546001600160a01b03163314610acd5760405162461bcd60e51b815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201526e37b936903a3434b99030b1ba34b7b760891b60648201526084015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22906020015b60405180910390a150565b60125460609067ffffffffffffffff811115610b4057610b406140c1565b604051908082528060200260200182016040528015610b69578160200160208202803683370190505b50905060005b601254811015610bda57610bab60155460128381548110610b9257610b926140d7565b906000526020600020015461231690919063ffffffff16565b828281518110610bbd57610bbd6140d7565b602090810291909101015280610bd281614103565b915050610b6f565b5090565b6001600160a01b0381166000908152601e60209081526040808320805482518185028101850190935280835260609492939192909184015b82821015610c7a57838290600052602060002090600502016040518060a00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505081526020019060010190610c16565b505050509050919050565b60138181548110610c9557600080fd5b906000526020600020016000915090508054610cb09061411c565b80601f0160208091040260200160405190810160405280929190818152602001828054610cdc9061411c565b8015610d295780601f10610cfe57610100808354040283529160200191610d29565b820191906000526020600020905b815481529060010190602001808311610d0c57829003601f168201915b505050505081565b60005483906001600160a01b0316331480610d515750610d513382610dbb565b610d6d5760405162461bcd60e51b8152600401610ac490614150565b6001600160a01b038416600090815260146020526040902054601280548592908110610d9b57610d9b6140d7565b6000918252602090912001558115610db557610db5612252565b50505050565b600080546001600160a01b0390811690841603610dda575060016109ee565b6001600160a01b03828116600090815260106020526040902054818516911603610e06575060016109ee565b50600092915050565b6000546001600160a01b03163314610e395760405162461bcd60e51b8152600401610ac49061417e565b6020805463ff00000019811663010000009182900460ff1615909102179055565b60606002805403610e7d5760405162461bcd60e51b8152600401610ac4906141a5565b6002805560205462010000900460ff1615610eda5760405162461bcd60e51b815260206004820152601960248201527f5265776172647320636f6c6c656374696f6e20706175736564000000000000006044820152606401610ac4565b610ee433336123da565b9050600160025590565b6000546001600160a01b03163314610f185760405162461bcd60e51b8152600401610ac49061417e565b670de0b6b3a7640000811015610f895760405162461bcd60e51b815260206004820152603060248201527f4d756c7469706c696572206d7573742062652067726561746572207468616e2060448201526f0dee440cae2eac2d840e8de4062ca62760831b6064820152608401610ac4565b60068190556040518181527fa1676084a9eea08c6f205b60799323b364a1bd8e10aba89f0fbd94cfbf68b5dd90602001610b17565b6002805403610fdf5760405162461bcd60e51b8152600401610ac4906141a5565b60028055602054610100900460ff16156110305760405162461bcd60e51b815260206004820152601260248201527115da5d1a191c985dd85b1cc81c185d5cd95960721b6044820152606401610ac4565b61103b33338361263a565b506001600255565b60028054036110645760405162461bcd60e51b8152600401610ac4906141a5565b6002805561103b33808342612994565b60606013805480602002602001604051908101604052809291908181526020016000905b828210156111445783829060005260206000200180546110b79061411c565b80601f01602080910402602001604051908101604052809291908181526020018280546110e39061411c565b80156111305780601f1061110557610100808354040283529160200191611130565b820191906000526020600020905b81548152906001019060200180831161111357829003601f168201915b505050505081526020019060010190611098565b50505050905090565b6060601a54600014806111605750601b54155b156111ba576016805480602002602001604051908101604052809291908181526020018280548015610a4c57602002820191906000526020600020905b81548152602001906001019080831161119d575050505050905090565b60115467ffffffffffffffff8111156111d5576111d56140c1565b6040519080825280602002602001820160405280156111fe578160200160208202803683370190505b50905060005b601654811015610bda5761128a61125e601b54610958670de0b6b3a764000061125860128781548110611239576112396140d7565b9060005260206000200154611258600554611252612cb0565b906122d4565b90612316565b60168381548110611271576112716140d7565b906000526020600020015461226e90919063ffffffff16565b82828151811061129c5761129c6140d7565b6020908102919091010152806112b181614103565b915050611204565b6001546001600160a01b031633146113315760405162461bcd60e51b815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527402063616e20616363657074206f776e65727368697605c1b6064820152608401610ac4565b600054600154604080516001600160a01b0393841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6000546001600160a01b031633146113cd5760405162461bcd60e51b8152600401610ac49061417e565b6020805462ff0000198116620100009182900460ff1615909102179055565b601181815481106113fc57600080fd5b6000918252602090912001546001600160a01b0316905081565b60005482906001600160a01b031633148061143657506114363382610dbb565b6114525760405162461bcd60e51b8152600401610ac490614150565b6003546001600160a01b03908116908416036114b05760405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f7420727567207374616b696e67202f204c5020746f6b656e7300006044820152606401610ac4565b6000805b60115481101561151057846001600160a01b0316601182815481106114db576114db6140d7565b6000918252602090912001546001600160a01b0316036114fe5760019150611510565b8061150881614103565b9150506114b4565b5080801561153757506001600160a01b038481166000908152601060205260409020541633145b156115fe5760405163a9059cbb60e01b8152336004820152602481018490526001600160a01b0385169063a9059cbb906044015b6020604051808303816000875af115801561158a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ae91906141dc565b50604080513381526001600160a01b03861660208201529081018490527ffff3b3844276f57024e0b42afec1a37f75db36511e43819a4f2a63ab7862b6489060600160405180910390a150505050565b8015801561161657506000546001600160a01b031633145b1561164e5760405163a9059cbb60e01b8152336004820152602481018490526001600160a01b0385169063a9059cbb9060440161156b565b60405162461bcd60e51b815260206004820152601a60248201527f4e6f2076616c696420746f6b656e7320746f207265636f7665720000000000006044820152606401610ac4565b505050565b6001600160a01b0381166000908152601d602052604081205490805b6001600160a01b0384166000908152601e60205260409020548110156118c8576001600160a01b0384166000908152601e60205260408120805483908110611701576117016140d7565b600091825260208083206040805160a08101825260059094029091018054845260018101549284019290925260028201549083015260038101546060830152600401546080820181905290925090611757611d99565b90508060000361179c5760405162461bcd60e51b815260206004820152601060248201526f26bab63a34b83634b2b91032b93937b960811b6044820152606401610ac4565b600a5481116117aa5750600a545b4283606001511161186a5760608301516001600160a01b038816600090815260196020526040902054101561185e576001600160a01b0387166000908152601960205260408120546060850151611800916122d4565b9050600061181b8560600151426122d490919063ffffffff16565b9050600061183e611834670de0b6b3a764000084612316565b61095e8786612316565b905061185461184d848461226e565b8290612398565b945050505061186a565b670de0b6b3a764000091505b60408301516000611887670de0b6b3a76400006109588487612316565b905060006118a1670de0b6b3a76400006109588487612316565b90506118ad888261226e565b975050505050505080806118c090614103565b9150506116b7565b50915091565b6000546001600160a01b031633146118f85760405162461bcd60e51b8152600401610ac49061417e565b6001600160a01b03166000908152601f60205260409020805460ff19811660ff90911615179055565b600d546040805163057ff68760e51b815290516000926001600160a01b03169163affed0e09160048083019260209291908290030181865afa15801561196b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061198f91906141f9565b905080600b54036119d95760405162461bcd60e51b8152602060048201526014602482015273105b1c9958591e481cde5b98da1c9bdb9a5e995960621b6044820152606401610ac4565b6119e1612cc3565b50565b6000546001600160a01b03163314611a0e5760405162461bcd60e51b8152600401610ac49061417e565b6001821015611a5f5760405162461bcd60e51b815260206004820152601960248201527f4d756c206d61782074696d65206d757374206265203e3d2031000000000000006044820152606401610ac4565b6001811015611ab05760405162461bcd60e51b815260206004820152601960248201527f4d756c206d696e2074696d65206d757374206265203e3d2031000000000000006044820152606401610ac4565b600782905560088190556040518281527f0e3e3fae480c6f92291358a02bc83f04ee1971d5488596bffda7929d57ab470f9060200160405180910390a16040518181527f0534d208d75dfdbfacc1204745dd9b3c4c37e8cfc05eb5e8e3ae538aedb0a9fa9060200160405180910390a15050565b6000546001600160a01b03163314611b4e5760405162461bcd60e51b8152600401610ac49061417e565b62015180811015611ba15760405162461bcd60e51b815260206004820152601a60248201527f52657761726473206475726174696f6e20746f6f2073686f72740000000000006044820152606401610ac4565b6004541580611bb1575060045442115b611bfd5760405162461bcd60e51b815260206004820152601860248201527f52657761726420706572696f6420696e636f6d706c65746500000000000000006044820152606401610ac4565b60158190556040518181527ffb46ca5a5e06d4540d6387b930a7c978bce0db5f449ec6b3f5d07c6e1d44f2d390602001610b17565b6000546001600160a01b03163314611c5c5760405162461bcd60e51b8152600401610ac49061417e565b6020805461ff001981166101009182900460ff1615909102179055565b60005482906001600160a01b0316331480611c995750611c993382610dbb565b611cb55760405162461bcd60e51b8152600401610ac490614150565b506001600160a01b03918216600090815260106020526040902080546001600160a01b03191691909216179055565b6000546001600160a01b03163314611d0e5760405162461bcd60e51b8152600401610ac49061417e565b6020805460ff19811660ff90911615179055565b60128181548110611d3257600080fd5b600091825260209091200154905081565b60606012805480602002602001604051908101604052809291908181526020018280548015610a4c576020028201919060005260206000209081548152602001906001019080831161119d575050505050905090565b600080600d60009054906101000a90046001600160a01b03166001600160a01b0316635a08bd176040518163ffffffff1660e01b8152600401600060405180830381865afa158015611def573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611e179190810190614267565b90506000600d60009054906101000a90046001600160a01b03166001600160a01b031663dad601f66040518163ffffffff1660e01b8152600401600060405180830381865afa158015611e6e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611e9691908101906142f2565b90508051825114611efe5760405162461bcd60e51b815260206004820152602c60248201527f746172676574526174696f20616e64206c7364416464726573736573206c656e60448201526b0cee8d040dad2e6dac2e8c6d60a31b6064820152608401610ac4565b8051611f0981612d2f565b60008167ffffffffffffffff811115611f2457611f246140c1565b604051908082528060200260200182016040528015611f4d578160200160208202803683370190505b509050611f5a8151612d2f565b600e54611f6f906001600160a01b0316612d74565b600e546040805163357ce51160e01b815290516000926001600160a01b03169163357ce5119160048083019260209291908290030181865afa158015611fb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fdd91906141f9565b9050611fe881612d2f565b60005b83811015612173576000858281518110612007576120076140d7565b6020908102919091010151600e546040516370a0823160e01b81526001600160a01b0391821660048201529116906370a0823190602401602060405180830381865afa15801561205b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061207f91906141f9565b90506000602060049054906101000a90046001600160a01b03166001600160a01b031663d45d15be8885815181106120b9576120b96140d7565b60200260200101516040518263ffffffff1660e01b81526004016120ec91906001600160a01b0391909116815260200190565b602060405180830381865afa158015612109573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061212d91906141f9565b9050600061213c838387612dbc565b905080868581518110612151576121516140d7565b602002602001018181525050505050808061216b90614103565b915050611feb565b5060006121808684612e8f565b90506000612196826722b1c8c1227a0000612fbf565b905060006121bc6121a683613073565b6121b7670de0b6b3a7640000613073565b61307b565b905060006121c982613093565b905060006121fc6121d985613073565b6121f66121e5856130ef565b6121f66729a2241af62c0000613073565b90613112565b9050600061221f61220e836003613121565b6121b7673782dace9d900000613073565b905061224261223f612238670de0b6b3a7640000613073565b8390613186565b90565b9b50505050505050505050505090565b60045442111561226657612264613195565b565b6122646131e6565b60008061227b8385614381565b9050838110156122cd5760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401610ac4565b9392505050565b60006122cd83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613259565b600082600003612328575060006109ee565b60006123348385614399565b90508261234185836143ce565b146122cd5760405162461bcd60e51b815260206004820152602160248201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6044820152607760f81b6064820152608401610ac4565b60006122cd83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061328a565b60608260016123e982826132b8565b60115467ffffffffffffffff811115612404576124046140c1565b60405190808252806020026020018201604052801561242d578160200160208202803683370190505b50925060005b601154811015612617576001600160a01b03861660009081526018602090815260408083208484529091529020548451859083908110612475576124756140d7565b6020908102919091018101919091526001600160a01b03871660009081526018825260408082208483529092529081205560118054829081106124ba576124ba6140d7565b9060005260206000200160009054906101000a90046001600160a01b03166001600160a01b031663a9059cbb868684815181106124f9576124f96140d7565b60200260200101516040518363ffffffff1660e01b81526004016125329291906001600160a01b03929092168252602082015260400190565b6020604051808303816000875af1158015612551573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061257591906141dc565b50856001600160a01b03167f1d2f2ca53af5d2f333bd32fdd45f9c52ad8ebe31414f7792912077fcb3876dff8583815181106125b3576125b36140d7565b6020026020010151601184815481106125ce576125ce6140d7565b60009182526020918290200154604080519384526001600160a01b039182169284019290925289169082015260600160405180910390a28061260f81614103565b915050612433565b5050506001600160a01b0390921660009081526019602052604090204290555090565b61264483836123da565b5061267a6040518060a0016040528060008019168152602001600081526020016000815260200160008152602001600081525090565b600060408201819052805b6001600160a01b0386166000908152601e6020526040902054811015612778576001600160a01b0386166000908152601e602052604090208054829081106126cf576126cf6140d7565b9060005260206000209060050201600001548403612766576001600160a01b0386166000908152601e60205260409020805482908110612711576127116140d7565b90600052602060002090600502016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250509250809150612778565b8061277081614103565b915050612685565b50815183146127bb5760405162461bcd60e51b815260206004820152600f60248201526e14dd185ad9481b9bdd08199bdd5b99608a1b6044820152606401610ac4565b8160600151421015806127d5575060205460ff1615156001145b61281a5760405162461bcd60e51b81526020600482015260166024820152755374616b65206973207374696c6c206c6f636b65642160501b6044820152606401610ac4565b6040820151801561298c57601a5461283290826122d4565b601a556001600160a01b0386166000908152601c602052604090205461285890826122d4565b6001600160a01b0387166000908152601c6020908152604080832093909355601e90522080548390811061288e5761288e6140d7565b6000918252602082206005909102018181556001810182905560028101829055600381018290556004018190556128c69087906132b8565b60035460405163a9059cbb60e01b81526001600160a01b038781166004830152602482018490529091169063a9059cbb906044016020604051808303816000875af1158015612919573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061293d91906141dc565b5060408051828152602081018690526001600160a01b03878116828401529151918816917f1d9308f6b22a2754a1c622bb30889e8f8f956c83e524d039e9d65d5f052eb9089181900360600190a25b505050505050565b8360016129a182826132b8565b6020546301000000900460ff16156129ec5760405162461bcd60e51b815260206004820152600e60248201526d14dd185ada5b99c81c185d5cd95960921b6044820152606401610ac4565b60008411612a3c5760405162461bcd60e51b815260206004820152601960248201527f4d757374207374616b65206d6f7265207468616e207a65726f000000000000006044820152606401610ac4565b6001600160a01b0386166000908152601f602052604090205460ff1615612aa55760405162461bcd60e51b815260206004820152601b60248201527f4164647265737320686173206265656e20677265796c697374656400000000006044820152606401610ac4565b600042600f54612ab591906143f0565b90506000612ac28261099b565b6001600160a01b0389166000908152601c602090815260408083205490516bffffffffffffffffffffffff1960608e901b169281019290925260348201899052605482018a905260748201529192509060940160408051601f1981840301815282825280516020918201206001600160a01b03808e166000908152601e845284812060a0870186528387528685018d81529587018e8152600f5460608901908152608089018b8152835460018181018655948652979094209851600590970290980195865595519085015593516002840155935160038084019190915592516004909201919091559054909250612bbc911689308a613387565b601a54612bc9908861226e565b601a556001600160a01b0389166000908152601c6020526040902054612bef908861226e565b6001600160a01b038a166000908152601c6020526040812091909155612c16908a906132b8565b6001600160a01b0389166000908152601960205260408120549003612c51576001600160a01b03891660009081526019602052604090204290555b60408051888152602081018590529081018290526001600160a01b0389811660608301528a16907ff400e72e69ef4402819dfc57eeddc66f5eb69bf405e0e8098b1946ec1ac14a229060800160405180910390a2505050505050505050565b6000612cbe426004546134af565b905090565b6000670de0b6b3a76400006012600081548110612ce257612ce26140d7565b9060005260206000200154612cf5611d99565b612cff9190614399565b612d0991906143ce565b9050806012600081548110612d2057612d206140d7565b60009182526020909120015550565b6119e181604051602401612d4591815260200190565b60408051601f198184030181529190526020810180516001600160e01b031663f5b1bba960e01b1790526134c5565b6040516001600160a01b03821660248201526119e19060440160408051601f198184030181529190526020810180516001600160e01b031663161765e160e11b1790526134c5565b6000808060001985870985870292508281108382030391505080600003612df657838281612dec57612dec6143b8565b04925050506122cd565b838110612e27576040516307639aaf60e41b8152600481018790526024810186905260448101859052606401610ac4565b600084868809600260036001881981018916988990049182028318808302840302808302840302808302840302808302840302808302840302918202909203026000889003889004909101858311909403939093029303949094049190911702949350505050565b60008151835114612eda5760405162461bcd60e51b8152602060048201526015602482015274082e4e4c2f240d8cadccee8d040dad2e6dac2e8c6d605b1b6044820152606401610ac4565b60008060008060005b8751811015612f995766038d7ea4c68000888281518110612f0657612f066140d7565b6020026020010151612f1891906143ce565b945066038d7ea4c68000878281518110612f3457612f346140d7565b6020026020010151612f4691906143ce565b9350838513612f5e57612f598585614407565b612f68565b612f688486614407565b91506000612f7760028461452a565b9050612f838185614381565b9350508080612f9190614103565b915050612ee3565b50612fa3826134e6565b612fb49066038d7ea4c68000614399565b979650505050505050565b60008080600019848609848602925082811083820303915050670de0b6b3a7640000811061300a5760405163090638d560e41b81526004810186905260248101859052604401610ac4565b6000670de0b6b3a7640000858709905081600003613036575050670de0b6b3a7640000900490506109ee565b620400008184030492109003600160ee1b02177faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066902905092915050565b6000816109ee565b60006122cd61223f84670de0b6b3a764000085612dbc565b600081680736ea4425c11ac63181106130c25760405163062bb40d60e31b815260048101849052602401610ac4565b6714057b7ef767814f81026130e76130e2670de0b6b3a7640000835b0490565b613550565b949350505050565b60006109ee826ec097ce7bc90715b34b9f1000000000816130de576130de6143b8565b60006122cd61223f83856143f0565b600082816001841661313b57670de0b6b3a764000061313d565b815b9050600184901c93505b831561317b576131578283612fbf565b9150600184161561316f5761316c8183612fbf565b90505b600184901c9350613147565b805b95945050505050565b60006122cd61223f8385614381565b60045442116122665760405162461bcd60e51b815260206004820152601b60248201527f506572696f6420686173206e6f742065787069726564207965742100000000006044820152606401610ac4565b60006131f061114d565b905060005b60165481101561324a57818181518110613211576132116140d7565b60200260200101516016828154811061322c5761322c6140d7565b6000918252602090912001558061324281614103565b9150506131f5565b50613253612cb0565b60055550565b6000818484111561327d5760405162461bcd60e51b8152600401610ac49190613f75565b50600061317d84866143f0565b600081836132ab5760405162461bcd60e51b8152600401610ac49190613f75565b50600061317d84866143ce565b80156132c6576132c6612252565b6001600160a01b03821615613383576000806132e18461169b565b915091506132ee846135a5565b81811061333d57600061330182846122d4565b601b54909150613311908261226e565b601b5561331e838261226e565b6001600160a01b0386166000908152601d602052604090205550610db5565b600061334983836122d4565b601b5490915061335990826122d4565b601b5561336683826122d4565b6001600160a01b0386166000908152601d60205260409020555050505b5050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916133eb9190614539565b6000604051808303816000865af19150503d8060008114613428576040519150601f19603f3d011682016040523d82523d6000602084013e61342d565b606091505b509150915081801561345757508051158061345757508080602001905181019061345791906141dc565b61298c5760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b6064820152608401610ac4565b60008183106134be57816122cd565b5090919050565b80516a636f6e736f6c652e6c6f67602083016000808483855afa5050505050565b6000600382111561354157508060006135006002836143ce565b61350b906001614381565b90505b818110156109955790508060028161352681866143ce565b6135309190614381565b61353a91906143ce565b905061350e565b811561354b575060015b919050565b600081680a688906bd8b000000811061357f57604051634a4f26f160e01b815260048101849052602401610ac4565b6000613597670de0b6b3a7640000604084901b6143ce565b90506130e761223f8261367e565b6001600160a01b038116156119e15760006135bf826107f6565b905060005b8151811015613620578181815181106135df576135df6140d7565b6020908102919091018101516001600160a01b038516600090815260188352604080822085835290935291909120558061361881614103565b9150506135c4565b5060005b81518110156116965760168181548110613640576136406140d7565b60009182526020808320909101546001600160a01b03861683526017825260408084208585529092529120558061367681614103565b915050613624565b600160bf1b67ff0000000000000082161561378b576780000000000000008216156136b25768016a09e667f3bcc9090260401c5b6740000000000000008216156136d1576801306fe0a31b7152df0260401c5b6720000000000000008216156136f0576801172b83c7d517adce0260401c5b67100000000000000082161561370f5768010b5586cf9890f62a0260401c5b67080000000000000082161561372e576801059b0d31585743ae0260401c5b67040000000000000082161561374d57680102c9a3e778060ee70260401c5b67020000000000000082161561376c5768010163da9fb33356d80260401c5b67010000000000000082161561378b57680100b1afa5abcbed610260401c5b66ff00000000000082161561388a5766800000000000008216156137b85768010058c86da1c09ea20260401c5b66400000000000008216156137d6576801002c605e2e8cec500260401c5b66200000000000008216156137f457680100162f3904051fa10260401c5b6610000000000000821615613812576801000b175effdc76ba0260401c5b660800000000000082161561383057680100058ba01fb9f96d0260401c5b660400000000000082161561384e5768010002c5cc37da94920260401c5b660200000000000082161561386c576801000162e525ee05470260401c5b660100000000000082161561388a5768010000b17255775c040260401c5b65ff000000000082161561398057658000000000008216156138b5576801000058b91b5bc9ae0260401c5b654000000000008216156138d257680100002c5c89d5ec6d0260401c5b652000000000008216156138ef5768010000162e43f4f8310260401c5b6510000000000082161561390c57680100000b1721bcfc9a0260401c5b650800000000008216156139295768010000058b90cf1e6e0260401c5b65040000000000821615613946576801000002c5c863b73f0260401c5b6502000000000082161561396357680100000162e430e5a20260401c5b65010000000000821615613980576801000000b1721835510260401c5b64ff00000000821615613a6d576480000000008216156139a957680100000058b90c0b490260401c5b6440000000008216156139c55768010000002c5c8601cc0260401c5b6420000000008216156139e1576801000000162e42fff00260401c5b6410000000008216156139fd5768010000000b17217fbb0260401c5b640800000000821615613a19576801000000058b90bfce0260401c5b640400000000821615613a3557680100000002c5c85fe30260401c5b640200000000821615613a515768010000000162e42ff10260401c5b640100000000821615613a6d57680100000000b17217f80260401c5b64ff00000000821615613b52576380000000821615613a955768010000000058b90bfc0260401c5b6340000000821615613ab0576801000000002c5c85fe0260401c5b6320000000821615613acb57680100000000162e42ff0260401c5b6310000000821615613ae6576801000000000b17217f0260401c5b6308000000821615613b0157680100000000058b90c00260401c5b6304000000821615613b1c5768010000000002c5c8600260401c5b6302000000821615613b37576801000000000162e4300260401c5b6301000000821615613b525768010000000000b172180260401c5b62ff0000821615613c2d5762800000821615613b77576801000000000058b90c0260401c5b62400000821615613b9157680100000000002c5c860260401c5b62200000821615613bab5768010000000000162e430260401c5b62100000821615613bc557680100000000000b17210260401c5b62080000821615613bdf5768010000000000058b910260401c5b62040000821615613bf9576801000000000002c5c80260401c5b62020000821615613c1357680100000000000162e40260401c5b62010000821615613c2d576801000000000000b1720260401c5b61ff00821615613cff57618000821615613c5057680100000000000058b90260401c5b614000821615613c695768010000000000002c5d0260401c5b612000821615613c82576801000000000000162e0260401c5b611000821615613c9b5768010000000000000b170260401c5b610800821615613cb4576801000000000000058c0260401c5b610400821615613ccd57680100000000000002c60260401c5b610200821615613ce657680100000000000001630260401c5b610100821615613cff57680100000000000000b10260401c5b60ff821615613dc8576080821615613d2057680100000000000000590260401c5b6040821615613d38576801000000000000002c0260401c5b6020821615613d5057680100000000000000160260401c5b6010821615613d68576801000000000000000b0260401c5b6008821615613d8057680100000000000000060260401c5b6004821615613d9857680100000000000000030260401c5b6002821615613db057680100000000000000010260401c5b6001821615613dc857680100000000000000010260401c5b670de0b6b3a76400000260409190911c60bf031c90565b6001600160a01b03811681146119e157600080fd5b600060208284031215613e0657600080fd5b81356122cd81613ddf565b6020808252825182820181905260009190848201906040850190845b81811015613e4957835183529284019291840191600101613e2d565b50909695505050505050565b600060208284031215613e6757600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b81811015613e495783516001600160a01b031683529284019291840191600101613e8a565b602080825282518282018190526000919060409081850190868401855b82811015613f105781518051855286810151878601528581015186860152606080820151908601526080908101519085015260a09093019290850190600101613ecc565b5091979650505050505050565b60005b83811015613f38578181015183820152602001613f20565b83811115610db55750506000910152565b60008151808452613f61816020860160208601613f1d565b601f01601f19169290920160200192915050565b6020815260006122cd6020830184613f49565b80151581146119e157600080fd5b600080600060608486031215613fab57600080fd5b8335613fb681613ddf565b9250602084013591506040840135613fcd81613f88565b809150509250925092565b60008060408385031215613feb57600080fd5b8235613ff681613ddf565b9150602083013561400681613ddf565b809150509250929050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561406657603f19888603018452614054858351613f49565b94509285019290850190600101614038565b5092979650505050505050565b6000806040838503121561408657600080fd5b823561409181613ddf565b946020939093013593505050565b600080604083850312156140b257600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201614115576141156140ed565b5060010190565b600181811c9082168061413057607f821691505b60208210810361099557634e487b7160e01b600052602260045260246000fd5b6020808252601490820152732737ba1037bbb732b91037b9103a35b71036b3b960611b604082015260600190565b6020808252600d908201526c2737ba103a34329037bbb732b960991b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6000602082840312156141ee57600080fd5b81516122cd81613f88565b60006020828403121561420b57600080fd5b5051919050565b604051601f8201601f1916810167ffffffffffffffff8111828210171561423b5761423b6140c1565b604052919050565b600067ffffffffffffffff82111561425d5761425d6140c1565b5060051b60200190565b6000602080838503121561427a57600080fd5b825167ffffffffffffffff81111561429157600080fd5b8301601f810185136142a257600080fd5b80516142b56142b082614243565b614212565b81815260059190911b820183019083810190878311156142d457600080fd5b928401925b82841015612fb4578351825292840192908401906142d9565b6000602080838503121561430557600080fd5b825167ffffffffffffffff81111561431c57600080fd5b8301601f8101851361432d57600080fd5b805161433b6142b082614243565b81815260059190911b8201830190838101908783111561435a57600080fd5b928401925b82841015612fb457835161437281613ddf565b8252928401929084019061435f565b60008219821115614394576143946140ed565b500190565b60008160001904831182151516156143b3576143b36140ed565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826143eb57634e487b7160e01b600052601260045260246000fd5b500490565b600082821015614402576144026140ed565b500390565b60008083128015600160ff1b850184121615614425576144256140ed565b6001600160ff1b0384018313811615614440576144406140ed565b50500390565b600181815b80851115614481578160001904821115614467576144676140ed565b8085161561447457918102915b93841c939080029061444b565b509250929050565b600082614498575060016109ee565b816144a5575060006109ee565b81600181146144bb57600281146144c5576144e1565b60019150506109ee565b60ff8411156144d6576144d66140ed565b50506001821b6109ee565b5060208310610133831016604e8410600b8410161715614504575081810a6109ee565b61450e8383614446565b8060001904821115614522576145226140ed565b029392505050565b60006122cd60ff841683614489565b6000825161454b818460208701613f1d565b919091019291505056fea2646970667358221220ef25dd6c2a442ca803fe5bc13cc68dc2eb126a5956e64f7c7612b2537715a34d64736f6c634300080d0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000d88e7d30f7548b7a7c6bfe513629724916449e6d000000000000000000000000846982c0a47b0e9f4c13f3251ba972bb8d32a8ca000000000000000000000000a857904691bbdeca2e768b318b5f6b9bfa698b7c00000000000000000000000000000000000000000000000000000000642773ff000000000000000000000000e8ef2e07e2fca3305372cb0345c686efbec75658000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000355534800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000e60779cc1b2c1d0580611c526a8df0e3f870ec480000000000000000000000000000000000000000000000000000000000000001000000000000000000000000d88e7d30f7548b7a7c6bfe513629724916449e6d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000004ba24a1fe9e10000
-----Decoded View---------------
Arg [0] : _owner (address): 0xD88e7D30f7548B7a7C6BFE513629724916449e6D
Arg [1] : _stakingToken (address): 0x846982C0a47b0e9f4c13F3251ba972Bb8D32a8cA
Arg [2] : _LSDRegistry (address): 0xA857904691bbdEca2e768B318B5f6b9bfA698b7C
Arg [3] : _shanghaiTime (uint256): 1680307199
Arg [4] : _darknetAddress (address): 0xE8EF2E07E2FCa3305372Cb0345C686EFbec75658
Arg [5] : _rewardSymbols (string[]): USH
Arg [6] : _rewardTokens (address[]): 0xE60779CC1b2c1d0580611c526a8DF0E3f870EC48
Arg [7] : _rewardManagers (address[]): 0xD88e7D30f7548B7a7C6BFE513629724916449e6D
Arg [8] : _rewardRates (uint256[]): 5450000000000000000
-----Encoded View---------------
19 Constructor Arguments found :
Arg [0] : 000000000000000000000000d88e7d30f7548b7a7c6bfe513629724916449e6d
Arg [1] : 000000000000000000000000846982c0a47b0e9f4c13f3251ba972bb8d32a8ca
Arg [2] : 000000000000000000000000a857904691bbdeca2e768b318b5f6b9bfa698b7c
Arg [3] : 00000000000000000000000000000000000000000000000000000000642773ff
Arg [4] : 000000000000000000000000e8ef2e07e2fca3305372cb0345c686efbec75658
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [6] : 00000000000000000000000000000000000000000000000000000000000001a0
Arg [7] : 00000000000000000000000000000000000000000000000000000000000001e0
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000220
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [12] : 5553480000000000000000000000000000000000000000000000000000000000
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [14] : 000000000000000000000000e60779cc1b2c1d0580611c526a8df0e3f870ec48
Arg [15] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [16] : 000000000000000000000000d88e7d30f7548b7a7c6bfe513629724916449e6d
Arg [17] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [18] : 0000000000000000000000000000000000000000000000004ba24a1fe9e10000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $0.001139 | 91,428.4217 | $104.18 |
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.