Source Code
Advanced mode: Intended for advanced users or developers and will display all Internal Transactions including zero value transfers.
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | ||||
|---|---|---|---|---|---|---|---|
| 31380843 | 5 mins ago | 0 FRAX | |||||
| 31380843 | 5 mins ago | 0 FRAX | |||||
| 31380843 | 5 mins ago | 0 FRAX | |||||
| 31380843 | 5 mins ago | 0 FRAX | |||||
| 31380843 | 5 mins ago | 0 FRAX | |||||
| 31380843 | 5 mins ago | 0 FRAX | |||||
| 31380843 | 5 mins ago | 0 FRAX | |||||
| 31380843 | 5 mins ago | 0 FRAX | |||||
| 31380843 | 5 mins ago | 0 FRAX | |||||
| 31380843 | 5 mins ago | 0 FRAX | |||||
| 31380843 | 5 mins ago | 0 FRAX | |||||
| 31380843 | 5 mins ago | 0 FRAX | |||||
| 31380843 | 5 mins ago | 0 FRAX | |||||
| 31380843 | 5 mins ago | 0 FRAX | |||||
| 31380575 | 14 mins ago | 0 FRAX | |||||
| 31380575 | 14 mins ago | 0 FRAX | |||||
| 31380575 | 14 mins ago | 0 FRAX | |||||
| 31380575 | 14 mins ago | 0 FRAX | |||||
| 31380575 | 14 mins ago | 0 FRAX | |||||
| 31380575 | 14 mins ago | 0 FRAX | |||||
| 31380575 | 14 mins ago | 0 FRAX | |||||
| 31380575 | 14 mins ago | 0 FRAX | |||||
| 31380575 | 14 mins ago | 0 FRAX | |||||
| 31380575 | 14 mins ago | 0 FRAX | |||||
| 31380575 | 14 mins ago | 0 FRAX |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
VestedFXS
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 10000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
// @version 0.2.8
pragma solidity >=0.8.0;
/**
* ====================================================================
* | ______ _______ |
* | / _____________ __ __ / ____(_____ ____ _____ ________ |
* | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
* | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
* | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
* | |
* ====================================================================
* ============================= VestedFXS ============================
* ====================================================================
* Solidity conversion of Frax's ETH Mainnet veFXS.vy
* Frax Finance: https://github.com/FraxFinance
*/
/**
*
* Voting escrow to have time-weighted votes
* Votes have a weight depending on time, so that users are committed
* to the future of (whatever they are voting for).
* The weight in this implementation is linear, and lock cannot be more than maxtime:
* w ^
* 1 + /
* | /
* | /
* | /
* |/
* 0 +--------+------> time
* maxtime (4 years?)
*/
/* solhint-disable max-line-length, not-rely-on-time */
import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { ERC20Burnable } from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import { IveFXSEvents } from "./IveFXSEvents.sol";
import { IveFXSStructs } from "./IveFXSStructs.sol";
import { VestedFXSUtils } from "./VestedFXSUtils.sol";
import "forge-std/console2.sol";
/**
* @title Vote Escrowed FXS (veFXS)
* @author Frax Finance
* @notice Votes have a weight depending on time, so that users are
* committed to the future of (whatever they are voting for)
* @dev Vote weight decays linearly over time. Lock time cannot be
* more than `MAXTIME_INT128` (4 years).
* @dev Original idea and credit:
* Curve Finance's veCRV
* https://resources.curve.fi/faq/vote-locking-boost
* https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/VotingEscrow.vy
* veFXS is basically a fork, with the key difference that 1 FXS locked for 1 second would be ~ 1 veFXS,
* As opposed to ~ 0 veFXS (as it is with veCRV)
* @dev Frax Reviewer(s) / Contributor(s)
* Jan Turk: https://github.com/ThunderDeliverer
* Travis Moore: https://github.com/FortisFortuna
* Sam Kazemian: https://github.com/samkazemian
* Carter Carlson: https://github.com/pegahcarter
*/
contract VestedFXS is ReentrancyGuard, IveFXSStructs, IveFXSEvents {
// ==============================================================================
// Constants
// ==============================================================================
// _depositFor codes
// -------------------------------------------
/// @notice _depositFor code for depositFor
uint128 private constant DEPOSIT_FOR_TYPE = 0;
/// @notice _depositFor code for createLock
uint128 private constant CREATE_LOCK_TYPE = 1;
/// @notice _depositFor code for increaseAmount
uint128 private constant INCREASE_LOCK_AMOUNT = 2;
/// @notice _depositFor code for increaseUnlockTime
uint128 private constant INCREASE_UNLOCK_TIME = 3;
// Other constants
// -------------------------------------------
/// @notice Minimum size you can createLock or increaseAmount
/// @dev Meant to help prevent rounding issues
uint256 public constant MIN_LOCK_AMOUNT = 1000 gwei; // 0.000001e18
/// @notice Multiplier used in various math operations
uint256 public constant MULTIPLIER_UINT256 = 10 ** 18;
/// @notice One week, in uint256 seconds
uint256 public constant WEEK_UINT256 = 7 * 86_400; // all future times are rounded by week
/// @notice One week, in uint128 seconds
uint128 public constant WEEK_UINT128 = 7 * 86_400; // all future times are rounded by week
/// @notice Maximum lock time, in int128 seconds
int128 public constant MAXTIME_INT128 = 4 * 365 * 86_400; // 4 years
/// @notice Maximum lock time, in uint256 seconds
uint256 public constant MAXTIME_UINT256 = 4 * 365 * 86_400; // 4 years
/// @notice Vote weight multiplier, in int128
int128 public constant VOTE_WEIGHT_MULTIPLIER_INT128 = 4 - 1; // 4x gives 300% boost at 4 years
/// @notice Vote weight multiplier, in uint256
uint256 public constant VOTE_WEIGHT_MULTIPLIER_UINT256 = 4 - 1; // 4x gives 300% boost at 4 years
/// @notice The maximum active locks a user can create for themselves
/// @dev If the user already has 8 locks (and some are created by Flox contributors), they can still create a new lock
uint8 public constant MAX_USER_LOCKS = 8;
/// @notice The maximum total number of active locks Flox contributors can create for a single user
/// @dev If the user already has 8 locks (and some are created by the user), the Flox contributor can still create a new lock
uint8 public constant MAX_CONTRIBUTOR_LOCKS = 8;
// ==============================================================================
// MUTABLE STATE VARIABLES
// ==============================================================================
/// @notice The VestedFXSUtils contract with extra helper functions
VestedFXSUtils public veFxsUtils;
/// @notice Whether key functions are paused
bool public isPaused;
/// @notice The address of the token being staked
address public token;
/// @notice The total FXS supply being locked. NOT the total veFXS. Use totalSupply() for that
uint256 public supply;
/// @notice Lock info for a given user and lock id. user -> ID -> LockedBalance
mapping(address user => mapping(uint256 id => LockedBalance lockedInfo)) public locked;
/// @notice Helper function to get a lock ID from a lock index. user -> index -> ID
mapping(address user => mapping(uint128 index => uint256 id)) public indicesToIds;
/// @notice Helper function to get a lock index from a lock ID. user -> ID -> LockIdInfo.
/// @dev Be careful and check isInUse beforehand to avoid index 0 vs null. If in doubt, use getLockIndexById
mapping(address user => mapping(uint256 id => LockIdIdxInfo info)) private idsToIndices;
/// @notice The indicator of whether a lock was created by a Flox contributor (`true`) or the user (`false`)
mapping(address user => mapping(uint256 id => bool createdByFloxContributor)) public isLockCreatedByFloxContributor;
/// @notice The number of user's currently active locks created by the user
mapping(address user => uint8 numberOfLocks) public numberOfUserCreatedLocks;
/// @notice The number of user's currently active locks created by Flox contributors
mapping(address user => uint8 numberOfLocks) public numberOfFloxContributorCreatedLocks;
/// @notice The next lock ID to use for a given user. user -> next ID
mapping(address user => uint256 nextId) public nextId;
// TODO: Check numLocks = 0 wrong assertions and weird scenarios
/// @notice The number of locks a user has
mapping(address user => uint128 numLocks) public numLocks;
/// @notice The current epoch you are in.
uint256 public epoch;
/// @notice The contract's Point information at a given epoch. epoch -> Point
mapping(uint256 epoch => Point) public pointHistory;
/// @notice A user's Point information at a given lock id and epoch. user -> ID -> epoch -> Point
mapping(address user => mapping(uint256 id => mapping(uint256 epoch => Point point))) public userPointHistory;
/// @notice A user's epoch for a given lock id. user address -> ID -> user's epoch
mapping(address user => mapping(uint256 id => uint256 epoch)) public userPointEpoch;
/// @notice Slope changes at a given time. time -> signed slope change
mapping(uint256 time => int128 slopeChange) public slopeChanges;
/// @notice If the emergency unlock is active
bool public emergencyUnlockActive;
// ERC20 related
string public name;
string public symbol;
string public version;
uint256 public decimals;
/// @notice Admin of this contract
address public admin;
/// @notice Future admin of this contract, if applicable
address public futureAdmin;
/// @notice If a given address is a Flox Contributor. contributor => isContributor
mapping(address contributor => bool isContributor) public floxContributors;
/// @dev reserve extra storage for future upgrades
uint256[50] private __gap;
// ==============================================================================
// CONSTRUCTOR
// ==============================================================================
constructor() {}
/**
* @notice Initialize contract
* @dev Same values are set to proxy and implementation.
* @param _admin Initial admin of the smart contract
* @param _tokenAddr `FXS` token address
* @param _name Token name
* @param _symbol Token symbol
* @param _version Contract version - required for Aragon compatibility
*/
function initialize(
address _admin,
address _tokenAddr,
string memory _name,
string memory _symbol,
string memory _version
) public {
// Safety checks - no validation on admin in case this is initialized without admin
if (_tokenAddr == address(0) || token != address(0)) {
revert InitializeFailed();
}
admin = _admin;
// Initialize the 0th pointHistory
pointHistory[0].blk = block.number;
pointHistory[0].ts = block.timestamp;
pointHistory[0].fxsAmt = 0;
// Initialize other variables
name = _name;
symbol = _symbol;
version = _version;
// Set up decimals
uint256 _decimals = IERC20Metadata(_tokenAddr).decimals();
if (_decimals > 255) revert DecimalsExceedMaximumValue();
token = _tokenAddr;
decimals = uint8(_decimals);
}
// ==============================================================================
// PUBLIC/EXTERNAL VIEWS
// ==============================================================================
/**
* The following ERC20/minime-compatible methods are not real balanceOf and supply!
* They measure the weights for the purpose of voting, so they don't represent
* real coins.
* FRAX adds minimal 1-1 FXS/veFXS, as well as a voting multiplier
*/
/**
* @notice Get current voting power (veFXS) of `_addr`. Uses all locks.
* @dev If `emergencyUnlock` is active, the FXS locked in all of the `_addr`'s locks is returned. If an external
* smart contract is using this function, make sure that it can handle this case.
* @param _addr Address of the user
* @return _balance Total voting power (veFXS) of the user
*/
function balanceOf(address _addr) public view returns (uint256 _balance) {
return balanceOfAllLocksAtTime(_addr, block.timestamp);
}
/**
* @notice Same as balanceOfAllLocksAtBlock for backwards compatibility. Measures the total voting power (veFXS) of
* `_addr` at `_block`.
* @dev If `emergencyUnlock` is active, the FXS locked in all of the `_addr`'s locks is returned. If an external
* smart contract is using this function, make sure that it can handle this case.
* @param _addr Address of the user
* @param _block Block number at which to measure voting power
* @return _balance Total voting power (veFXS) of the user
*/
function balanceOfAt(address _addr, uint256 _block) public view returns (uint256 _balance) {
return balanceOfAllLocksAtBlock(_addr, _block);
}
/**
* @notice Measure the total voting power (veFXS) of `_addr` at `_block`.
* @dev If `emergencyUnlock` is active, the FXS locked in all of the `_addr`'s locks is returned. If an external
* smart contract is using this function, make sure that it can handle this case.
* @param _addr Address of the user
* @param _block Block number at which to measure voting power
* @return _balance Total voting power (veFXS) of the user
*/
function balanceOfAllLocksAtBlock(address _addr, uint256 _block) public view returns (uint256 _balance) {
// Get the total number of locks
uint128 _numLocks = numLocks[_addr];
// Loop through all of the locks
for (uint128 i = 0; i < _numLocks; ) {
_balance += balanceOfOneLockAtBlock(_addr, i, _block);
unchecked {
++i;
}
}
}
/**
* @notice Get voting power (veFXS) of `_addr` at a specific time.
* @dev If `emergencyUnlock` is active, the FXS locked in all of the `_addr`'s locks is returned. If an external
* smart contract is using this function, make sure that it can handle this case.
* @param _addr Address of the user
* @param _timestamp Epoch time to return the voting power at
* @return _balance Total voting power (veFXS) of the user
*/
function balanceOfAllLocksAtTime(address _addr, uint256 _timestamp) public view returns (uint256 _balance) {
// Get the total number of locks
uint128 _numLocks = numLocks[_addr];
// Loop through all of the locks
for (uint128 i = 0; i < _numLocks; ) {
_balance += balanceOfOneLockAtTime(_addr, i, _timestamp);
unchecked {
++i;
}
}
}
/**
* @notice Measure voting power (veFXS) of `addr`'s specific lock at block height `_block`
* @dev If `emergencyUnlock` is active, the FXS locked in the lock is returned. If an external smart contract is
* using this function, make sure that it can handle this case.
* @param _addr User's wallet address
* @param _lockIndex Index of the user's lock that is getting measured
* @param _block Block to calculate the voting power at
* @return _balance Total voting power (veFXS) of the user
*/
function balanceOfOneLockAtBlock(
address _addr,
uint128 _lockIndex,
uint256 _block
) public view returns (uint256 _balance) {
if (emergencyUnlockActive) {
return uint256(uint128(locked[_addr][indicesToIds[_addr][_lockIndex]].amount));
}
if (_block > block.number) revert InvalidBlockNumber();
uint256 lockId = indicesToIds[_addr][_lockIndex];
// Binary search
uint256 _min = 0;
uint256 _max = userPointEpoch[_addr][lockId];
for (uint256 i; i < 128; ) {
// Will be always enough for 128-bit numbers
if (_min >= _max) {
break;
}
uint256 _mid = (_min + _max + 1) / 2;
if (userPointHistory[_addr][lockId][_mid].blk <= _block) {
_min = _mid;
} else {
_max = _mid - 1;
}
unchecked {
++i;
}
}
Point memory upoint = userPointHistory[_addr][lockId][_min];
uint256 maxEpoch = epoch;
uint256 _epoch = findBlockEpoch(_block, maxEpoch);
Point memory point0 = pointHistory[_epoch];
uint256 dBlock = 0;
uint256 dT = 0;
if (_epoch < maxEpoch) {
Point memory point1 = pointHistory[_epoch + 1];
dBlock = point1.blk - point0.blk;
dT = point1.ts - point0.ts;
} else {
dBlock = block.number - point0.blk;
dT = block.timestamp - point0.ts;
}
uint256 blockTime = point0.ts;
if (dBlock != 0) {
blockTime += (dT * (_block - point0.blk)) / dBlock;
}
upoint.bias -= upoint.slope * int128(int256(blockTime - upoint.ts));
// Check bias
if (upoint.bias < int256(upoint.fxsAmt)) _balance = upoint.fxsAmt;
else _balance = uint256(uint128(upoint.bias));
}
/**
* @notice Find the latest epoch at a past timestamp
* @param _addr User wallet address
* @param _lockId ID of the user's lock that is getting measured
* @param _ts The timestamp to check at
* @return _min The latest user's epoch assume you traveled back in time to the timestamp
*/
function findUserTimestampEpoch(address _addr, uint256 _lockId, uint256 _ts) public view returns (uint256 _min) {
// Get the most current user's epoch (not the contract epoch)
uint256 _max = userPointEpoch[_addr][_lockId];
// Find the latest epoch as of the time _ts
for (uint256 i = 0; i < 128; i++) {
if (_min >= _max) {
break;
}
uint256 mid = (_min + _max + 1) / 2;
if (userPointHistory[_addr][_lockId][mid].ts <= _ts) {
_min = mid;
} else {
_max = mid - 1;
}
}
return _min;
}
/**
* @notice Get the voting power (veFXS) for `addr`'s specific lock at the specified time
* @dev If `emergencyUnlock` is active, the FXS locked in the lock is returned. If an external smart contract is
* using this function, make sure that it can handle this case.
* @param _addr User wallet address
* @param _lockIndex Index of the user's lock that is getting measured
* @param _timestamp Epoch time to return voting power at
* @return _balance Total voting power (veFXS) of the user
*/
function balanceOfOneLockAtTime(
address _addr,
uint128 _lockIndex,
uint256 _timestamp
) public view returns (uint256 _balance) {
if (emergencyUnlockActive) {
return uint256(uint128(locked[_addr][indicesToIds[_addr][_lockIndex]].amount));
}
_timestamp = _timestamp == 0 ? block.timestamp : _timestamp; // Default to current timestamp if _timestamp is 0
uint256 _lockId = indicesToIds[_addr][_lockIndex];
// uint256 _epoch = userPointEpoch[_addr][_lockId];
uint256 _epoch = findUserTimestampEpoch(_addr, _lockId, _timestamp);
// if (_epoch == 0 || locked[_addr][_lockId].end == 0) {
// return 0;
// } else {
if (_epoch == 0) {
return 0;
} else {
// Yearn Fix: https://etherscan.io/address/0x90c1f9220d90d3966fbee24045edd73e1d588ad5#code
// Extra Finance: https://optimistic.etherscan.io/address/0xe0bec4f45aef64cec9dcb9010d4beffb13e91466#code
// Point memory lastPoint = userPointHistory[_addr][_lockId][_epoch];
Point memory lastPoint;
// {
// uint256 _min = 0;
// uint256 _max = userPointEpoch[_addr][_lockId];
// for (uint256 i; i < 128; ) {
// // Will be always enough for 128-bit numbers
// if (_min >= _max) {
// break;
// }
// uint256 _mid = (_min + _max + 1) / 2;
// if (userPointHistory[_addr][_lockId][_mid].ts <= _timestamp) {
// _min = _mid;
// } else {
// _max = _mid - 1;
// }
// unchecked {
// ++i;
// }
// }
// lastPoint = userPointHistory[_addr][_lockId][_min];
lastPoint = userPointHistory[_addr][_lockId][_epoch];
// }
lastPoint.bias -= lastPoint.slope * int128(uint128(_timestamp - lastPoint.ts));
if (lastPoint.bias < 0) {
lastPoint.bias = 0;
}
_balance = uint256(uint128(lastPoint.bias)); // Original from veCRV
if (_balance < lastPoint.fxsAmt) {
_balance = lastPoint.fxsAmt;
}
}
}
/**
* @notice Get the total amount of FXS locked for a user
* @param _addr User account address
* @return _balanceOfLockedFxs The total amount of FXS locked for the user
*/
function balanceOfLockedFxs(address _addr) public view returns (uint256 _balanceOfLockedFxs) {
uint128 _numLocks = numLocks[_addr];
for (uint128 i = 0; i < _numLocks; ) {
_balanceOfLockedFxs += uint256(uint128(locked[_addr][indicesToIds[_addr][i]].amount));
unchecked {
++i;
}
}
}
/**
* @notice Binary search to estimate timestamp for block number
* @param _block Block to find
* @param _maxEpoch Don't go beyond this epoch
* @return Approximate timestamp for block
*/
function findBlockEpoch(uint256 _block, uint256 _maxEpoch) public view returns (uint256) {
// Binary search
uint256 _min = 0;
uint256 _max = _maxEpoch;
uint256 _mid;
for (uint256 i; i < 128; ) {
// Will be always enough for 128-bit numbers
if (_min >= _max) {
break;
}
_mid = (_min + _max + 1) / 2;
if (pointHistory[_mid].blk <= _block) {
_min = _mid;
} else {
_max = _mid - 1;
}
unchecked {
++i;
}
}
return _min;
}
/**
* @notice Get the earliest and latest timestamps createLock can use
* @return _earliestLockEnd Earliest timestamp
* @return _latestLockEnd Latest timestamp
* @dev The truncation in these operations is desired
*/
function getCreateLockTsBounds() external view returns (uint128 _earliestLockEnd, uint128 _latestLockEnd) {
_earliestLockEnd = WEEK_UINT128 + ((uint128(block.timestamp) / WEEK_UINT128) * WEEK_UINT128); // Cannot be in the current epoch week
// _latestLockEnd = (WEEK_UINT128 * (uint128(block.timestamp) + uint128(MAXTIME_UINT256))) / WEEK_UINT128;
_latestLockEnd = ((uint128(block.timestamp) + uint128(MAXTIME_UINT256)) / WEEK_UINT128) * WEEK_UINT128;
}
/**
* @notice Get the earliest and latest timestamps increaseUnlockTime can use
* @dev If this is called in the first week after the lock is created and if the lock duration is for maximum time,
* the returned `_latestLockEnd` will be the same as the lock's end time. This will cause the extension of the lock
* to revet. If a smart contract is using this function, make sure that it can handle this case.
* @return _earliestLockEnd Earliest timestamp
* @return _latestLockEnd Latest timestamp
* @dev The truncation in these operations is desired
*/
function getIncreaseUnlockTimeTsBounds(
address _user,
uint256 _id
) external view returns (uint128 _earliestLockEnd, uint128 _latestLockEnd) {
// Calculate the earliest end (current end + leftover time to get into next epoch week)
_earliestLockEnd = WEEK_UINT128 + ((locked[_user][_id].end / WEEK_UINT128) * WEEK_UINT128); // Cannot be in the current epoch week
// Calculate the latest end (same as getCreateLockTsBounds result)
_latestLockEnd = (WEEK_UINT128 * (uint128(block.timestamp) + uint128(MAXTIME_UINT256))) / WEEK_UINT128;
// Corner case near expiry
if (_earliestLockEnd >= _latestLockEnd) _earliestLockEnd = _latestLockEnd;
}
/**
* @return _lastPoint The most recent point for this specific lock index
*/
function getLastGlobalPoint() external view returns (Point memory _lastPoint) {
_lastPoint = pointHistory[epoch];
}
/**
* @notice Get the user's Point for `_addr` at the specified epoch
* @param _addr Address of the user wallet
* @param _lockIndex Index of the user's lock that is getting measured
* @param _uepoch The epoch of the user to get the point at
* @return _lastPoint The most recent point for this specific lock index
*/
function getUserPointAtEpoch(
address _addr,
uint128 _lockIndex,
uint256 _uepoch
) external view returns (Point memory _lastPoint) {
uint256 lockId = indicesToIds[_addr][_lockIndex];
_lastPoint = userPointHistory[_addr][lockId][_uepoch];
}
/**
* @notice Get the most recently recorded Point for `_addr`
* @param _addr Address of the user wallet
* @param _lockIndex Index of the user's lock that is getting measured
* @return _lastPoint The most recent point for this specific lock index
*/
function getLastUserPoint(address _addr, uint128 _lockIndex) external view returns (Point memory _lastPoint) {
uint256 lockId = indicesToIds[_addr][_lockIndex];
uint256 uepoch = userPointEpoch[_addr][lockId];
_lastPoint = userPointHistory[_addr][lockId][uepoch];
}
/**
* @notice Get the most recently recorded rate of voting power decrease for `_addr`
* @param _addr Address of the user wallet
* @param _lockIndex Index of the user's lock that is getting measured
* @return Value of the slope
*/
function getLastUserSlope(address _addr, uint128 _lockIndex) external view returns (int128) {
uint256 lockId = indicesToIds[_addr][_lockIndex];
uint256 uepoch = userPointEpoch[_addr][lockId];
return userPointHistory[_addr][lockId][uepoch].slope;
}
/**
* @notice Get locked amount and ending timestamp for a specific user and lock ID (not lock index). Same as locked()
* @param _addr User address
* @param _id User lock ID (not lock index)
* @return _amount The amount locked
* @return _end The timestamp when the lock expires/ends
*/
function lockedById(address _addr, uint256 _id) public view returns (int128 _amount, uint128 _end) {
LockedBalance memory _lockInfo = locked[_addr][_id];
_amount = _lockInfo.amount;
_end = _lockInfo.end;
}
/**
* @notice Get locked amount and ending timestamp for a specific user and lock index (not lock ID)
* @param _addr User address
* @param _index User lock index (not lock ID)
* @return _amount The amount locked
* @return _end The timestamp when the lock expires/ends
*/
function lockedByIndex(address _addr, uint128 _index) public view returns (int128 _amount, uint128 _end) {
LockedBalance memory _lockInfo = locked[_addr][indicesToIds[_addr][_index]];
_amount = _lockInfo.amount;
_end = _lockInfo.end;
}
/**
* @notice Same as lockedById but returns a LockedBalanceExtended struct. Will revert if the ID is not in use
* @param _addr User address
* @param _id User lock ID (not lock index)
* @return _extendedLockInfo The LockedBalanceExtended
*/
function lockedByIdExtended(
address _addr,
uint256 _id
) public view returns (LockedBalanceExtended memory _extendedLockInfo) {
LockedBalance memory _lockInfo = locked[_addr][_id];
_extendedLockInfo.id = _id;
_extendedLockInfo.index = getLockIndexById(_addr, _id);
_extendedLockInfo.amount = _lockInfo.amount;
_extendedLockInfo.end = _lockInfo.end;
}
/**
* @notice Get timestamp when `_addr`'s lock finishes
* @dev If the emergency unlock is active, the current timestamp is returned. If an external smart contract is using
* this function, make sure that it can handle this case.
* @param _addr User wallet
* @param _index User lock index
* @return Epoch time of the lock end
*/
function lockedEnd(address _addr, uint128 _index) external view returns (uint256) {
if (emergencyUnlockActive) {
return block.timestamp;
}
uint256 lockId = indicesToIds[_addr][_index];
return locked[_addr][lockId].end;
}
/**
* @notice Get the lock index given a lock id. Reverts if the ID is not in use
* @param _addr User address
* @param _id User lock ID (not lock index)
* @return _index The index of the lock
*/
function getLockIndexById(address _addr, uint256 _id) public view returns (uint128 _index) {
// Get the lock ID info
LockIdIdxInfo memory _info = idsToIndices[_addr][_id];
if (!_info.isInUse) revert LockIDNotInUse();
// Set the index to return
_index = _info.index;
}
/**
* @notice Calculate total voting power at some point in the past
* @dev If `emergencyUnlock` is active, the total FXS supply is returned. If an external smart contract is using
* this function, make sure that it can handle this case.
* @param _point The point (bias/slope) to start search from
* @param _t Time to calculate the total voting power at
* @return Total voting power at that time
*/
function supplyAt(Point memory _point, uint256 _t) public view returns (uint256) {
if (emergencyUnlockActive) {
return totalFXSSupply();
}
Point memory lastPoint = _point;
uint256 tI = (lastPoint.ts / WEEK_UINT256) * WEEK_UINT256;
if (lastPoint.ts > _t) revert InvalidTimestamp();
for (uint256 i; i < 255; ) {
tI += WEEK_UINT256;
int128 dSlope = 0;
if (tI > _t) {
tI = _t;
} else {
dSlope = slopeChanges[tI];
}
lastPoint.bias -= lastPoint.slope * int128(uint128(tI - lastPoint.ts));
if (tI == _t) {
break;
}
lastPoint.slope += dSlope;
lastPoint.ts = tI;
unchecked {
++i;
}
}
if (lastPoint.bias < 0) {
lastPoint.bias = 0;
}
uint256 weightedSupply = uint256(uint128(lastPoint.bias));
if (weightedSupply < lastPoint.fxsAmt) {
weightedSupply = lastPoint.fxsAmt;
}
return weightedSupply;
}
/**
* @notice Calculates FXS supply of veFXS contract.
* @dev Adheres to the ERC20 `totalSupply` interface.
* @return Total FXS supply
*/
function totalFXSSupply() public view returns (uint256) {
return IERC20Metadata(token).balanceOf(address(this));
}
/**
* @notice Calculate total FXS at some point in the past
* @param _block Block to calculate the total voting power at
* @return Total FXS supply at `_block`
*/
function totalFXSSupplyAt(uint256 _block) external view returns (uint256) {
if (_block > block.number) revert InvalidBlockNumber();
uint256 targetEpoch = findBlockEpoch(_block, epoch);
Point memory point = pointHistory[targetEpoch];
return point.fxsAmt;
}
/**
* @notice Calculate total voting power at the current time
* @dev Adheres to the ERC20 `totalSupply` interface for Aragon compatibility
* @return Total voting power
*/
function totalSupply() external view returns (uint256) {
return totalSupply(block.timestamp);
}
/**
* @notice Calculate total voting power
* @dev Adheres to the ERC20 `totalSupply` interface for Aragon compatibility
* @dev If `emergencyUnlock` is active, the total FXS supply is returned. If an external smart contract is using
* this function, make sure that it can handle this case.
* @param _timestamp Time to calculate the total voting power at (default: block.timestamp)
* @return Total voting power
*/
function totalSupply(uint256 _timestamp) public view returns (uint256) {
if (emergencyUnlockActive) {
return totalFXSSupply();
}
_timestamp = _timestamp == 0 ? block.timestamp : _timestamp; // Default to current timestamp if t is 0
uint256 _min = 0;
uint256 _max = epoch;
uint256 _mid;
for (uint256 i; i < 128; ) {
// Will be always enough for 128-bit numbers
if (_min >= _max) {
break;
}
_mid = (_min + _max + 1) / 2;
if (pointHistory[_mid].ts <= _timestamp) {
_min = _mid;
} else {
_max = _mid - 1;
}
unchecked {
++i;
}
}
Point memory lastPoint = pointHistory[_min];
return supplyAt(lastPoint, _timestamp);
}
/**
* @notice Calculate total voting power at some point in the past
* @dev If `emergencyUnlock` is active, the total FXS supply is returned. If an external smart contract is using
* this function, make sure that it can handle this case.
* @param _block Block to calculate the total voting power at
* @return Total voting power at `_block`
*/
function totalSupplyAt(uint256 _block) external view returns (uint256) {
if (_block > block.number) revert InvalidBlockNumber();
uint256 targetEpoch = findBlockEpoch(_block, epoch);
Point memory point = pointHistory[targetEpoch];
uint256 dt = 0;
if (targetEpoch < epoch) {
Point memory pointNext = pointHistory[targetEpoch + 1];
if (point.blk != pointNext.blk) {
dt = ((_block - point.blk) * (pointNext.ts - point.ts)) / (pointNext.blk - point.blk);
}
} else {
if (point.blk != block.number) {
dt = ((_block - point.blk) * (block.timestamp - point.ts)) / (block.number - point.blk);
}
}
// Now dt contains info on how far are we beyond point
return supplyAt(point, point.ts + dt);
}
/**
* @notice Get the timestamp for checkpoint `_idx` for `_addr`
* @param _addr User wallet address
* @param _lockIndex Index of the user's lock that is getting measured
* @param _idx User epoch number
* @return Timestamp of the checkpoint
*/
function userPointHistoryTs(address _addr, uint128 _lockIndex, uint256 _idx) external view returns (uint256) {
uint256 lockId = indicesToIds[_addr][_lockIndex];
return userPointHistory[_addr][lockId][_idx].ts;
}
// ==============================================================================
// INTERNAL FUNCTIONS
// ==============================================================================
/**
* @notice Record global and per-user data to checkpoint
* @param _addr User's wallet address. No user checkpoint if 0x0
* @param _oldLocked Previous locked amount / end lock time for the user
* @param _newLocked New locked amount / end lock time for the user
* @param _lockIndex Index of a lock being modified
*/
function _checkpoint(
address _addr,
LockedBalance memory _oldLocked,
LockedBalance memory _newLocked,
uint128 _lockIndex
) internal {
Point memory uOld = Point({ bias: 0, slope: 0, ts: 0, blk: 0, fxsAmt: 0 });
Point memory uNew = Point({ bias: 0, slope: 0, ts: 0, blk: 0, fxsAmt: 0 });
int128 oldGlobalDslope;
int128 newGlobalDslope;
uint256 _epoch = epoch;
if (_addr != address(0)) {
// Calculate slopes and biases
// Kept at zero when they have to
if (_oldLocked.end > block.timestamp && _oldLocked.amount > 0) {
uOld.slope = (_oldLocked.amount * VOTE_WEIGHT_MULTIPLIER_INT128) / MAXTIME_INT128;
// @dev: Cannot overflow as _newLocked maximum cannot exceed 4 years.
uOld.bias = _oldLocked.amount + uOld.slope * int128(uint128(_oldLocked.end - block.timestamp));
}
if (_newLocked.end > block.timestamp && _newLocked.amount > 0) {
uNew.slope = (_newLocked.amount * VOTE_WEIGHT_MULTIPLIER_INT128) / MAXTIME_INT128;
// @dev: Cannot overflow as _newLocked maximum cannot exceed 4 years.
uNew.bias = _newLocked.amount + uNew.slope * int128(uint128(_newLocked.end - block.timestamp));
}
// Read values of scheduled changes in the slope
// _oldLocked.end can be in the past and in the future
// _newLocked.end can ONLY be in the FUTURE unless everything expired: than zeros
oldGlobalDslope = slopeChanges[_oldLocked.end];
if (_newLocked.end != 0) {
if (_newLocked.end == _oldLocked.end) {
newGlobalDslope = oldGlobalDslope;
} else {
newGlobalDslope = slopeChanges[_newLocked.end];
}
}
}
Point memory lastPoint = Point({ bias: 0, slope: 0, ts: block.timestamp, blk: block.number, fxsAmt: 0 });
if (_epoch > 0) {
lastPoint = pointHistory[_epoch];
}
uint128 lastCheckpoint = uint128(lastPoint.ts);
// initialLastPoint is used for extrapolation to calculate block number
// (approximately, for *At methods) and save them
// as we cannot figure that out exactly from inside the contract
Point memory initialLastPoint = Point({
bias: lastPoint.bias,
slope: lastPoint.slope,
ts: lastPoint.ts,
blk: lastPoint.blk,
fxsAmt: lastPoint.fxsAmt
});
uint256 blockSlope = 0; // dblock/dt
if (block.timestamp > lastPoint.ts) {
blockSlope = (MULTIPLIER_UINT256 * (block.number - lastPoint.blk)) / (block.timestamp - lastCheckpoint);
}
// If the last point is already recorded in this block, slope=0
// But that's ok b/c we know the block in such case
// Go over weeks to fill history and calculate what the current point is
lastPoint = _fillHistoryAndCalculateCurrentPoint(
lastCheckpoint,
lastPoint,
initialLastPoint,
blockSlope,
_epoch
);
// Now pointHistory is filled until t=now
if (_addr != address(0)) {
// If the last point was in this block, the slope change has been applied already
// But in such case we have 0 slope(s)
lastPoint.slope += (uNew.slope - uOld.slope);
lastPoint.bias += (uNew.bias - uOld.bias);
if (_newLocked.amount > _oldLocked.amount) {
lastPoint.fxsAmt += uint256(uint128(_newLocked.amount - _oldLocked.amount));
}
if (_newLocked.amount < _oldLocked.amount) {
lastPoint.fxsAmt -= uint256(uint128(_oldLocked.amount - _newLocked.amount));
// if (_newLocked.amount == 0 && !emergencyUnlockActive) {
if (_newLocked.amount == 0 && _oldLocked.end <= block.timestamp) {
lastPoint.bias -= _oldLocked.amount;
}
}
if (lastPoint.slope < 0) {
lastPoint.slope = 0;
}
if (lastPoint.bias < 0) {
lastPoint.bias = 0;
}
}
// Record the changed point into history
pointHistory[epoch] = lastPoint;
if (_addr != address(0)) {
// Schedule the slope changes (slope is going down)
// We subtract new_user_slope from [_newLocked.end]
// and add old_user_slope to [_oldLocked.end]
if (_oldLocked.end > block.timestamp) {
// old_dslope was <something> - uOld.slope, so we cancel that
oldGlobalDslope += uOld.slope;
if (_newLocked.end == _oldLocked.end) {
oldGlobalDslope -= uNew.slope; // It was a new deposit, not an extension
}
slopeChanges[_oldLocked.end] = oldGlobalDslope;
}
if (_newLocked.end > block.timestamp) {
if (_newLocked.end > _oldLocked.end) {
newGlobalDslope -= uNew.slope; // old slope disappeared at this point
slopeChanges[_newLocked.end] = newGlobalDslope;
} // The alternative is already recorded in the old_dslope
}
// Now handle every user
_fillUserPointHistory(_addr, uNew, _lockIndex);
}
}
/**
* @notice Deposit `_value` tokens for `_addr` and add to the lock
* @dev Anyone (even a smart contract) can deposit for someone else, but cannot extend their locktime and deposit for a brand new user
* @dev WARNING: Since the `_value` is of `uint256` type and the `amount` in `LockedBalance` is of `int128` type,
* there is a risk of overflow. This does not impact veFXS as the maximum supply of FXS is 100M, but it could
* provide a risk for protocols forking this smart contract if their maximum supply is higher than maximum value of
* `int128`.
* @param _addr User's wallet address
* @param _value Amount to add to user's lock
* @param _unlockTime Unix timestamp of when the lock expires
* @param _lockedBalance The user's current locked balance
* @param _depositType The type of deposit being made
* @param _lockIdx The index of the user's lock that the deposit is being made to
*/
function _depositFor(
address _addr,
uint256 _value,
uint128 _unlockTime,
LockedBalance memory _lockedBalance,
uint128 _depositType,
uint128 _lockIdx
) internal {
// Revert if you are in an emergency
if (emergencyUnlockActive) revert EmergencyUnlockActive();
// Pull the tokens before modifying state
require(IERC20Metadata(token).transferFrom(msg.sender, address(this), _value));
LockedBalance memory oldLocked = _lockedBalance;
uint256 supplyBefore = supply;
LockedBalance memory newLocked = LockedBalance({ amount: oldLocked.amount, end: oldLocked.end });
supply = supplyBefore + _value;
// Adding to existing lock, or if a lock is expired - creating a new one
// WARNING: If you are forking this smart contract, make sure that the downcast from uint256 to uint128, and to
// int128, is safe
newLocked.amount += int128(uint128(_value));
if (_unlockTime != 0) {
newLocked.end = _unlockTime;
}
locked[_addr][indicesToIds[_addr][_lockIdx]] = newLocked;
// Possibilities:
// Both oldLocked.end could be current or expired (>/< block.timestamp)
// value == 0 (extend lock) or value > 0 (add to lock or extend lock)
// _locked.end > block.timestamp (always)
_checkpoint(_addr, oldLocked, newLocked, _lockIdx);
emit Deposit(_addr, msg.sender, newLocked.end, _value, _depositType, block.timestamp);
emit Supply(supplyBefore, supplyBefore + _value);
}
/**
* @notice Go over weeks to fill history and calculate what the current point is
* @param _lastCheckpoint Timestamp of the last checkpoint
* @param _lastPoint Last point object
* @param _initialLastPoint Initial last point object
* @param _blockSlope Block slope
* @param _epoch Epoch
* @return The latest `Point` object
*/
function _fillHistoryAndCalculateCurrentPoint(
uint128 _lastCheckpoint,
Point memory _lastPoint,
Point memory _initialLastPoint,
uint256 _blockSlope,
uint256 _epoch
) private returns (Point memory) {
uint128 tI = uint128((uint256(_lastCheckpoint) / WEEK_UINT256) * WEEK_UINT256);
for (uint256 i; i < 255; ) {
tI += WEEK_UINT128;
int128 dSlope = 0;
// Ensure that tI does not exceed the current block timestamp
if (uint256(tI) > block.timestamp) {
tI = uint128(block.timestamp);
} else {
dSlope = slopeChanges[tI];
}
_lastPoint.bias -= _lastPoint.slope * int128(tI - _lastCheckpoint);
_lastPoint.slope += dSlope;
// Ensure non-negativity of bias and slope
if (_lastPoint.bias < 0) {
_lastPoint.bias = 0;
}
if (_lastPoint.slope < 0) {
_lastPoint.slope = 0;
}
_lastCheckpoint = tI;
_lastPoint.ts = tI;
_lastPoint.blk =
_initialLastPoint.blk +
(uint128(_blockSlope) * (tI - _initialLastPoint.ts)) /
MULTIPLIER_UINT256;
// TODO: does _epoch get incremented every single time checkpoint is called, or some other weird math?
_epoch += 1;
if (tI == uint128(block.timestamp)) {
_lastPoint.blk = block.number;
break;
} else {
// Store the point in history
pointHistory[_epoch] = _lastPoint;
}
unchecked {
++i;
}
}
epoch = _epoch;
return _lastPoint;
}
/**
* @notice Fill user point history
* @param _addr User's wallet address
* @param _point Latest user's point
* @param _lockIndex Index of a lock being modified
*/
function _fillUserPointHistory(address _addr, Point memory _point, uint128 _lockIndex) internal {
uint256 lockId = indicesToIds[_addr][_lockIndex];
uint256 userEpoch = userPointEpoch[_addr][lockId] + 1;
userPointEpoch[_addr][lockId] = userEpoch;
_point.ts = block.timestamp;
_point.blk = block.number;
_point.fxsAmt = uint256(uint128(locked[_addr][lockId].amount));
userPointHistory[_addr][lockId][userEpoch] = _point;
}
/**
* @notice Withdraw all tokens for `msg.sender`'s lock with the given `_lockIndex`
* @dev Only possible if the lock has expired or if the emergency unlock is active
* @param _staker The user address being withdrawn.
* @param _recipient The recipient of the withdrawn tokens.
* @param _lockIndex Index of the user's lock that is getting withdrawn
* @return _value How much FXS was withdrawn
*/
function _withdraw(
address _staker,
address _recipient,
uint128 _lockIndex
) internal nonReentrant returns (uint256 _value) {
// Revert if it would be an array out-of-bounds
if (_lockIndex >= numLocks[_staker]) revert InvalidLockIndex();
// Revert if paused
if (isPaused) revert OperationIsPaused();
// Get old lock information
uint256 lockId = indicesToIds[_staker][_lockIndex];
LockedBalance memory oldLocked = locked[_staker][lockId];
// Revert if the lock is not expired yet, unless you are in an emergency unlock
if ((uint128(block.timestamp) < oldLocked.end) && !emergencyUnlockActive) {
revert LockDidNotExpire();
}
// Instantiate new lock info
_value = uint256(uint128(oldLocked.amount));
LockedBalance memory newLocked = LockedBalance({ amount: 0, end: 0 });
// oldLocked can have either expired <= timestamp or zero end
// newLocked has only 0 end
// Both can have >= 0 amount
_checkpoint(_staker, oldLocked, newLocked, _lockIndex);
/**
* This effectively moves the last lock to the place of the one being withdrawn. Doing so allows for keeping all
* of the active indices without the gaps and allows for easier tracking of locks and the data attached to them.
* The shift is done by moving the ID of the last lock and the accompanying userPointHistory and userPointEpoch
* to the index of the lock being withdrawn.
*/
// Example (indicesToIds): [4, 2, 1, 10, 5]
// Withdraw lock ID 2 at index 1
// lockIndex = 1
// lastLockId = 5, at index 4
// -->>
// indicesToIds becomes: [4, 5, 1, 10]
// idsToIndices for ID 5 updated to index 1
// idsToIndices for ID 2 deleted
// Update indicesToIds
uint256 lastLockId = indicesToIds[_staker][numLocks[_staker] - 1];
indicesToIds[_staker][_lockIndex] = lastLockId;
delete indicesToIds[_staker][numLocks[_staker] - 1];
// Update idsToIndices
idsToIndices[_staker][lastLockId].index = _lockIndex;
idsToIndices[_staker][lastLockId].isInUse = true;
delete idsToIndices[_staker][lockId]; // If lastLockId = lockId, like in the case of numLocks = 1, then isInUse will become false here too
// Update numLocks
numLocks[_staker] -= 1;
// Update lock creator tracking
if (!isLockCreatedByFloxContributor[_staker][lockId]) {
// NOTE: Negation is used, so that if the user is also Flox contributor, the behaviour of lock creation tracking is inverse of the one in the `createLock`
numberOfUserCreatedLocks[_staker] -= 1;
} else {
numberOfFloxContributorCreatedLocks[_staker] -= 1;
}
uint256 supplyBefore = supply;
supply = supplyBefore - _value;
require(IERC20Metadata(token).transfer(_recipient, _value), "Transfer failed");
// Global checkpoint if the emergency unlock is active
if (emergencyUnlockActive) {
_checkpoint(address(0), LockedBalance(0, 0), LockedBalance(0, 0), 2 ** 128 - 1);
}
emit Withdraw(_staker, _recipient, _value, block.timestamp);
emit Supply(supplyBefore, supply);
}
// ==============================================================================
// PUBLIC/EXTERNAL MUTABLE FUNCTIONS
// ==============================================================================
/**
* @notice Record global data to checkpoint
*/
function checkpoint() external {
// Revert if the contract is paused
if (isPaused) revert OperationIsPaused();
// Revert if you are in an emergency
if (emergencyUnlockActive) revert EmergencyUnlockActive();
// Do the checkpoint
_checkpoint(address(0), LockedBalance(0, 0), LockedBalance(0, 0), 2 ** 128 - 1);
}
/**
* @notice Deposit `_value` tokens for `msg.sender` and lock until `_unlockTime`
* @dev Users should only be allowed to create locks for themselves, the only exemption being Flow contibutors that
* can create locks for other users.
* @dev Flox contributors can only create 8 locks for themselves. Even if they are Flox contributors, they cannot
* create contributor locks for themselves.
* @param _addr Address of the user for which the lock is being created
* @param _value Amount to deposit
* @param _unlockTime Epoch time when tokens unlock, rounded down to whole weeks
* @return _index Index of the user's lock that was created
* @return _newLockId ID of the user's lock that was created
*/
function createLock(
address _addr,
uint256 _value,
uint128 _unlockTime
) external nonReentrant returns (uint128 _index, uint256 _newLockId) {
if (isPaused) revert OperationIsPaused();
if (_value < MIN_LOCK_AMOUNT) revert MinLockAmount();
if (msg.sender != _addr && !floxContributors[msg.sender]) revert NotLockingForSelfOrFloxContributor();
if (msg.sender == _addr && numberOfUserCreatedLocks[_addr] >= MAX_USER_LOCKS) revert MaximumUserLocksReached();
if (
floxContributors[msg.sender] &&
msg.sender != _addr &&
numberOfFloxContributorCreatedLocks[_addr] >= MAX_CONTRIBUTOR_LOCKS
) {
revert MaximumFloxContributorLocksReached();
}
nextId[_addr] += 1; // This is done so that the lock with ID 0 is always empty. It allows for checking if a lock exists by checking if the ID is 0
_newLockId = nextId[_addr];
uint128 unlockTime = (_unlockTime / WEEK_UINT128) * WEEK_UINT128; // Locktime is rounded down to weeks
LockedBalance storage _locked = locked[_addr][_newLockId];
if (uint256(unlockTime) <= block.timestamp) revert MustBeInAFutureEpochWeek();
if (uint256(unlockTime) > block.timestamp + MAXTIME_UINT256) {
revert LockCanOnlyBeUpToFourYears();
}
// Using numLocks[_addr] (original)
{
// Update indicesToIds
indicesToIds[_addr][numLocks[_addr]] = _newLockId;
// Update idsToIndices
idsToIndices[_addr][_newLockId].id = _newLockId;
idsToIndices[_addr][_newLockId].index = numLocks[_addr];
idsToIndices[_addr][_newLockId].isInUse = true;
}
numLocks[_addr] += 1;
// Update the information about lock creator
if (msg.sender == _addr) {
// NOTE: If the user is also Flox contributor, the lock will be counted as user's lock
numberOfUserCreatedLocks[_addr] += 1;
} else {
numberOfFloxContributorCreatedLocks[_addr] += 1;
isLockCreatedByFloxContributor[_addr][_newLockId] = true;
}
_depositFor(_addr, _value, unlockTime, _locked, CREATE_LOCK_TYPE, numLocks[_addr] - 1);
return (numLocks[_addr] - 1, _newLockId);
}
/**
* @notice Deposit `_value` tokens for `_addr` and add to the lock
* @dev Anyone (even a smart contract) can deposit for someone else, but
* cannot extend their locktime and deposit for a brand new user
* @param _addr User's wallet address
* @param _value Amount to add to user's lock
* @param _lockIndex Index of the user's lock that the deposit is being made to
*/
function depositFor(address _addr, uint256 _value, uint128 _lockIndex) external nonReentrant {
if (isPaused) revert OperationIsPaused();
if (_value < MIN_LOCK_AMOUNT) revert MinLockAmount();
uint256 lockId = indicesToIds[_addr][_lockIndex];
LockedBalance storage _locked = locked[_addr][lockId];
if (_locked.amount <= 0) revert NoExistingLockFound();
if (_locked.end <= block.timestamp) revert LockExpired(); // Withdraw instead
_depositFor(_addr, _value, 0, locked[_addr][lockId], DEPOSIT_FOR_TYPE, _lockIndex);
}
/**
* @notice Deposit `_value` additional tokens for `msg.sender`
* without modifying the unlock time
* @param _value Amount of tokens to deposit and add to the lock
* @param _lockIndex Index of the user's lock that getting the increased amount
*/
function increaseAmount(uint256 _value, uint128 _lockIndex) external nonReentrant {
if (isPaused) revert OperationIsPaused();
if (_value < MIN_LOCK_AMOUNT) revert MinLockAmount();
uint256 lockId = indicesToIds[msg.sender][_lockIndex];
LockedBalance storage _locked = locked[msg.sender][lockId];
if (_locked.amount <= 0) revert NoExistingLockFound();
if (_locked.end <= uint128(block.timestamp)) revert LockExpired(); // Withdraw instead
_depositFor(msg.sender, _value, 0, _locked, INCREASE_LOCK_AMOUNT, _lockIndex);
}
/**
* @notice Extend the unlock time for `msg.sender` to `_unlockTime`
* @param _unlockTime New epoch time for unlocking
* @param _lockIndex Index of the user's lock that is getting the increased unlock time
*/
function increaseUnlockTime(uint128 _unlockTime, uint128 _lockIndex) external nonReentrant {
if (isPaused) revert OperationIsPaused();
uint256 lockId = indicesToIds[msg.sender][_lockIndex];
LockedBalance storage _locked = locked[msg.sender][lockId];
uint128 unlockTime = (_unlockTime / WEEK_UINT128) * WEEK_UINT128; // Locktime is rounded down to weeks
if (uint256(_locked.end) <= block.timestamp) revert LockExpired();
if (_locked.amount <= 0) revert NoExistingLockFound(); // TODO: This might be unreachable because of the validation above
if (unlockTime <= _locked.end) revert MustBeInAFutureEpochWeek();
if (uint256(unlockTime) > block.timestamp + MAXTIME_UINT256) {
revert LockCanOnlyBeUpToFourYears();
}
_depositFor(msg.sender, 0, unlockTime, _locked, INCREASE_UNLOCK_TIME, _lockIndex);
}
/**
* @notice Withdraw all tokens for `msg.sender`'s lock with the given `_lockIndex`
* @dev Only possible if the lock has expired or if the emergency unlock is active
* @param _lockIndex Index of the user's lock that is getting withdrawn
* @return _value How much FXS was withdrawn
*/
function withdraw(uint128 _lockIndex) external returns (uint256 _value) {
_value = _withdraw(msg.sender, msg.sender, _lockIndex);
}
// ==============================================================================
// ADMIN / PERMISSIONED ACTIONS
// ==============================================================================
/**
* @notice Apply ownership transfer. Only callable by the future admin. Do commitTransferOwnership first
*/
function acceptTransferOwnership() external {
if (msg.sender != futureAdmin) revert FutureAdminOnly();
address _admin = futureAdmin;
if (_admin == address(0)) revert AdminNotSet(); // This is now unreachable, but I don't mind leaving it for the extremely remote chance that someone figures out a way to execute calls from 0x0
admin = _admin;
futureAdmin = address(0);
emit ApplyOwnership(_admin);
}
/**
* @notice Transfer ownership of VotingEscrow contract to `addr`
* @param _addr Address to have ownership transferred to
*/
function commitTransferOwnership(address _addr) external {
if (msg.sender != admin) revert AdminOnly();
futureAdmin = _addr;
emit CommitOwnership(_addr);
}
/**
* @notice Used to recover non-FXS ERC20 tokens
* @param _tokenAddr Address of the ERC20 token to recover
* @param _amount Amount of tokens to recover
*/
function recoverIERC20(address _tokenAddr, uint256 _amount) external {
if (msg.sender != admin) revert AdminOnly();
if (_tokenAddr == token) revert UnableToRecoverFXS(); // Use `activateEmergencyUnlock` instead and have users pull theirs out individually
require(IERC20Metadata(_tokenAddr).transfer(admin, _amount));
}
/**
* @notice Set the address of a Flox contributor
* @param _floxContributor Address of a Flox contributor
* @param _isFloxContributor Boolean indicating if the address is a Flox contributor or not
*/
function setFloxContributor(address _floxContributor, bool _isFloxContributor) external {
if (msg.sender != admin) revert AdminOnly();
floxContributors[_floxContributor] = _isFloxContributor;
emit FloxContributorUpdate(_floxContributor, _isFloxContributor);
}
/**
* @notice Set the address of a VestedFXSUtils contract
* @param _veFxsUtilsAddr Address of the VestedFXSUtils contract
*/
function setVeFXSUtils(address _veFxsUtilsAddr) external {
if (msg.sender != admin) revert AdminOnly();
// Set the utils contract
veFxsUtils = VestedFXSUtils(_veFxsUtilsAddr);
emit VeFxsUtilsContractUpdated(_veFxsUtilsAddr);
}
/**
* @notice Pause/Unpause critical functions
*/
function toggleContractPause() external {
if (msg.sender != admin) revert AdminOnly();
isPaused = !isPaused;
emit ContractPause(isPaused);
}
/**
* @notice Used to allow early withdrawals of veFXS back into FXS, in case of an emergency. Only users themselves can pull out the FXS, not the admin. Once toggled, cannot be undone as slope/bias math will be permanently off going forward.
*/
function activateEmergencyUnlock() external {
if (msg.sender != admin) revert AdminOnly();
if (emergencyUnlockActive) revert EmergencyUnlockActive();
emergencyUnlockActive = true;
emit EmergencyUnlockActivated();
}
// ==============================================================================
// Errors
// ==============================================================================
/// @notice If the admin was never set
error AdminNotSet();
/// @notice Only the admin can call this function
error AdminOnly();
/// @notice You cannot merge a lock with itself
error CannotMergeLockWithItself();
/// @notice Your veToken cannot have more than 255 decimals
error DecimalsExceedMaximumValue();
/// @notice If you are in an emergency unlock
error EmergencyUnlockActive();
/// @notice Only the future admin can call this function
error FutureAdminOnly();
/// @notice Cannot initialize twice
error InitializeFailed();
/// @notice When you are trying to balanceOfAt for a future block
error InvalidBlockNumber();
/// @notice When the lock index is invalid
error InvalidLockIndex();
/// @notice When the timestamp is invalid (attempting to backwards extrapolate supplyAt)
error InvalidTimestamp();
/// @notice When you are trying to lock for more than 4 years. See getCreateLockTsBounds()
error LockCanOnlyBeUpToFourYears();
/// @notice When you are trying to withdraw before the lock expires
error LockDidNotExpire();
/// @notice If you are trying to extend or add to an already expired lock. Withdraw that lock and create a new one instead
error LockExpired();
/// @notice When you call getLockIdByIndex when the ID supplied is not in use
error LockIDNotInUse();
/// @notice When the operation would cause too many locks to be produced by the Flox contributors
error MaximumFloxContributorLocksReached();
/// @notice When the operation would cause too many locks to be produced by the user
error MaximumUserLocksReached();
/// @notice When you are not locking enough
error MinLockAmount();
/// @notice The new lock end timestamp needs to at least be in the next epoch week. See getCreateLockTsBounds()
error MustBeInAFutureEpochWeek();
/// @notice No existing lock found when you are trying to depositFor or increaseAmount
error NoExistingLockFound();
/// @notice You can only create a lock for yourself, unless you are a Flox Contributor
error NotLockingForSelfOrFloxContributor();
/// @notice When the function is paused
error OperationIsPaused();
/// @notice Admin is specifically not allowed to recover FXS. Users must pull it out themselves after activateEmergencyUnlock is called
error UnableToRecoverFXS();
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// 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
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)
pragma solidity ^0.8.0;
import "../ERC20.sol";
import "../../../utils/Context.sol";
/**
* @dev Extension of {ERC20} that allows token holders to destroy both their own
* tokens and those that they have an allowance for, in a way that can be
* recognized off-chain (via event analysis).
*/
abstract contract ERC20Burnable is Context, ERC20 {
/**
* @dev Destroys `amount` tokens from the caller.
*
* See {ERC20-_burn}.
*/
function burn(uint256 amount) public virtual {
_burn(_msgSender(), amount);
}
/**
* @dev Destroys `amount` tokens from `account`, deducting from the caller's
* allowance.
*
* See {ERC20-_burn} and {ERC20-allowance}.
*
* Requirements:
*
* - the caller must have allowance for ``accounts``'s tokens of at least
* `amount`.
*/
function burnFrom(address account, uint256 amount) public virtual {
_spendAllowance(account, _msgSender(), amount);
_burn(account, amount);
}
}// SPDX-License-Identifier: MIT
// @version 0.2.8
pragma solidity >=0.8.0;
/**
* ====================================================================
* | ______ _______ |
* | / _____________ __ __ / ____(_____ ____ _____ ________ |
* | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
* | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
* | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
* | |
* ====================================================================
* =============================== veFXS ==============================
* ====================================================================
* Events for VestedFXS (veFXS)
* Frax Finance: https://github.com/FraxFinance
*/
interface IveFXSEvents {
// ==============================================================================
// Events
// ==============================================================================
/// @notice When the new prospective admin accepts being the admin.
/// @param admin The address of the new admin
event ApplyOwnership(address admin);
/// @notice When a new admin is proposed by the existing admin. The prospective new admin will still have to accept via acceptTransferOwnership
/// @param admin The prospective new admin
event CommitOwnership(address admin);
/// @notice When key functions are paused or unpaused
/// @param isPaused The pause status that was set
event ContractPause(bool isPaused);
/// @notice When a deposit of FXS has occured
/// @param staker The address where the deposit is credited to
/// @param payor The address actually paying for the deposit
/// @param endingTimestamp The ending timestamp of the lock
/// @param value The amount of FXS to add
/// @param depositType The type of the traction. DEPOSIT_FOR_TYPE = 0, CREATE_LOCK_TYPE = 1, INCREASE_LOCK_AMOUNT = 2, INCREASE_UNLOCK_TIME = 3;
/// @param txTimestamp The timestamp that the deposit occured
event Deposit(
address indexed staker,
address indexed payor,
uint256 indexed endingTimestamp,
uint256 value,
uint128 depositType,
uint256 txTimestamp
);
/// @notice When the emergency unlock is activated
event EmergencyUnlockActivated();
/// @notice When an address is set, or unset, as a Flox Contributor
/// @param contributor The address
/// @param isContributor If the address is or is not a Flox Contributor
event FloxContributorUpdate(address indexed contributor, bool isContributor);
/// @notice When the veFXS supply changes
/// @param prevSupply The previous veFXS
/// @param supply The new veFXS
event Supply(uint256 prevSupply, uint256 supply);
/// @notice When the address of a VestedFXSUtils contract is changed
/// @param veFxsUtilsAddr Address of the VestedFXSUtils contract
event VeFxsUtilsContractUpdated(address veFxsUtilsAddr);
/// @notice When FXS is withdrawn
/// @param staker The address of the staker that is withdrawing
/// @param recipient The recipient of the withdrawn tokens
/// @param value The amount of FXS withdrawn
/// @param ts The timestamp of the withdrawal
event Withdraw(address indexed staker, address indexed recipient, uint256 value, uint256 ts);
}// SPDX-License-Identifier: MIT
// @version 0.2.8
pragma solidity >=0.8.0;
/**
* ====================================================================
* | ______ _______ |
* | / _____________ __ __ / ____(_____ ____ _____ ________ |
* | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
* | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
* | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
* | |
* ====================================================================
* =============================== veFXS ==============================
* ====================================================================
* Structs VestedFXS (veFXS)
* Frax Finance: https://github.com/FraxFinance
*/
interface IveFXSStructs {
/// @notice Detailed lock info for a user
/// @param user Address of the user
/// @param allLocks All of the locks of the user
/// @param numberOfLocks The total number of locks that the user has
/// @param activeLocks Only the active locks of the user
/// @param expiredLocks Only the expired locks of the user
/// @param totalFxs The total amount of FXS that the user has for all, active, and expired locks respectively
struct DetailedUserLockInfo {
address user;
uint256 numberOfLocks;
LockedBalanceExtended[] allLocks;
LockedBalanceExtended[] activeLocks;
LockedBalanceExtended[] expiredLocks;
int128[3] totalFxs;
}
/// @notice Basic information about a lock
/// @param amount The amount that is locked
/// @param end The ending timestamp for the lock
/// @dev We cannot really do block numbers per se b/c slope is per time, not per block and per block could be fairly bad b/c Ethereum changes blocktimes. What we can do is to extrapolate ***At functions
struct LockedBalance {
int128 amount;
uint128 end; // This should more than suffice for our needs and allows the struct to be packed
}
/// @notice Extended information about a lock
/// @param id The ID of the lock
/// @param index The index of the lock. If index is 0, do not trust it unless isInUse is also true
/// @param amount The amount that is locked
/// @param end The ending timestamp for the lock
/// @param isInUse If the lock ID is currently in use
struct LockedBalanceExtended {
uint256 id;
uint128 index;
int128 amount;
uint128 end;
}
/// @notice Lock ID Info. Cannot be a simple mapping because lock indeces are in constant flux and index 0 vs null is ambiguous.
/// @param id The ID of the lock
/// @param index The index of the lock. If index is 0, do not trust it unless isInUse is also true
/// @param isInUse If the lock ID is currently in use
struct LockIdIdxInfo {
uint256 id;
uint128 index;
bool isInUse;
}
struct Point {
int128 bias;
int128 slope; // - dweight / dt
uint256 ts;
uint256 blk; // block
uint256 fxsAmt;
}
}// SPDX-License-Identifier: MIT
// @version 0.2.8
pragma solidity >=0.8.0;
/**
* ====================================================================
* | ______ _______ |
* | / _____________ __ __ / ____(_____ ____ _____ ________ |
* | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
* | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
* | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
* | |
* ====================================================================
* ========================== VestedFXSUtils ==========================
* ====================================================================
* Helper and utility functions for VestedFXS
* Frax Finance: https://github.com/FraxFinance
*/
/**
*
* Voting escrow to have time-weighted votes
* Votes have a weight depending on time, so that users are committed
* to the future of (whatever they are voting for).
* The weight in this implementation is linear, and lock cannot be more than maxtime:
* w ^
* 1 + /
* | /
* | /
* | /
* |/
* 0 +--------+------> time
* maxtime (4 years?)
*/
import { IVestedFXS } from "src/contracts/VestedFXS-and-Flox/interfaces/IVestedFXS.sol";
import { IveFXSStructs } from "src/contracts/VestedFXS-and-Flox/VestedFXS/IveFXSStructs.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "forge-std/console2.sol";
/**
* @title VestedFXSUtils
* @author Frax Finance
* @notice This utility smart contract provides functions to get extended information from the VestedFXS contract.
*/
contract VestedFXSUtils is IveFXSStructs {
IVestedFXS public immutable veFXS;
IERC20Metadata public immutable token;
struct LongestLock {
LockedBalance lock;
uint128 lockIndex;
address user;
}
/**
* @notice Contract constructor
* @param _vestedFXS Address of the VestedFXS contract
*/
constructor(address _vestedFXS) {
veFXS = IVestedFXS(_vestedFXS);
token = IERC20Metadata(veFXS.token());
}
/**
* @notice Used to get all of the locks of a given user.
* @dev The locks are retrieved indiscriminately, regardless of whether they are active or expired.
* @param _user Address of the user
* @return _userLockInfo DetailedUserLockInfo for the user. Includes _allLocks, _activeLocks, _expiredLocks, and FXS totals for these respectively
* @dev This lives on Fraxtal and will mostly be read-called in UIs, so gas not really an issue here
*/
function getDetailedUserLockInfo(address _user) public view returns (DetailedUserLockInfo memory _userLockInfo) {
// Get the total number of locks
uint256 _totalLocks = veFXS.numLocks(_user);
uint128 _numberOfActiveLocks;
// Set the number locks for the user
_userLockInfo.numberOfLocks = _totalLocks;
// Set the user
_userLockInfo.user = _user;
// Initialize _allLocks
_userLockInfo.allLocks = new LockedBalanceExtended[](_totalLocks);
// Initial _isActive, which tracks if a given index is active
bool[] memory _isActive = new bool[](_totalLocks);
// Loop through all of the locks
for (uint256 i; i < _userLockInfo.allLocks.length; ) {
// Update the _allLocks return data
LockedBalance memory _thisLock = veFXS.lockedByIndex(_user, uint128(i));
_userLockInfo.allLocks[i].id = veFXS.indicesToIds(_user, uint128(i));
_userLockInfo.allLocks[i].index = uint128(i);
_userLockInfo.allLocks[i].amount = _thisLock.amount;
_userLockInfo.allLocks[i].end = _thisLock.end;
_userLockInfo.totalFxs[0] += _thisLock.amount;
// Determine whether it is active or expired
if (_thisLock.end > block.timestamp) {
// Update isActive tracking
_isActive[i] = true;
// Update _totalFxs for active locks
_userLockInfo.totalFxs[1] += _thisLock.amount;
unchecked {
++_numberOfActiveLocks;
}
} else {
// Update _totalFxs for expired locks
_userLockInfo.totalFxs[2] += _thisLock.amount;
}
unchecked {
++i;
}
}
// Initialize _activeLocks and _expiredLocks
_userLockInfo.activeLocks = new LockedBalanceExtended[](_numberOfActiveLocks);
_userLockInfo.expiredLocks = new LockedBalanceExtended[](_totalLocks - _numberOfActiveLocks);
// Loop through all of the locks again, this time for assigning to _activeLocks and _expiredLocks
uint128 _activeCounter;
uint128 _expiredCounter;
for (uint256 i; i < _userLockInfo.allLocks.length; ) {
// Get the lock info
LockedBalanceExtended memory _thisLock = _userLockInfo.allLocks[i];
// Sort the lock as either active or expired
if (_isActive[i]) {
// Active
_userLockInfo.activeLocks[_activeCounter] = _thisLock;
unchecked {
++_activeCounter;
}
} else {
// Expired
_userLockInfo.expiredLocks[_expiredCounter] = _thisLock;
unchecked {
++_expiredCounter;
}
}
unchecked {
++i;
}
}
}
/**
* @notice Used to get all of the locks of the given users. Same underlying code as getDetailedUserLockInfo
* @dev The locks are retrieved indiscriminately, regardless of whether they are active or expired.
* @param _users Addresses of the users
* @return _userLockInfos DetailedUserLockInfo[] for the users. Includes _allLocks, _activeLocks, _expiredLocks, and FXS totals for these respectively
* @dev This lives on Fraxtal and will mostly be read-called in UIs, so gas not really an issue here
*/
function getDetailedUserLockInfoBulk(
address[] memory _users
) public view returns (DetailedUserLockInfo[] memory _userLockInfos) {
// Save the number of user addresses
uint256 _numUsers = _users.length;
// Initialize the return array
_userLockInfos = new DetailedUserLockInfo[](_numUsers);
// Loop through all of the users and get their detailed lock info
for (uint256 i = 0; i < _numUsers; ) {
_userLockInfos[i] = getDetailedUserLockInfo(_users[i]);
unchecked {
i++;
}
}
}
/**
* @notice Used to get the longest lock of a given user.
* @dev The longest lock is the lock with the timestamp furthest in the future (can also be in the past if there are no active locks).
* @param user Address of the user
* @return The longest lock of the user
* @return The index of the longest lock
*/
function getLongestLock(address user) public view returns (LockedBalance memory, uint128) {
LockedBalance[] memory locks = new LockedBalance[](veFXS.numLocks(user));
LockedBalance memory longestLock;
uint128 longestLockIndex;
for (uint256 i = 0; i < locks.length; ) {
uint128 currentEnd = veFXS.lockedByIndex(user, uint128(i)).end;
if (currentEnd > longestLock.end) {
longestLock.end = currentEnd;
longestLock.amount = veFXS.lockedByIndex(user, uint128(i)).amount;
longestLockIndex = uint128(i);
}
unchecked {
i++;
}
}
return (longestLock, longestLockIndex);
}
/**
* @notice Used to get longest locks of muliple users.
* @dev This returns the longest lock indiscriminately, regardless of whether it is active or expired.
* @dev The return value is an array of LongestLock structs, which contain the lock, the index of the lock, and the user.
* @param users Array of addresses of the users
* @return The LongestLocks of the users
*/
function getLongestLockBulk(address[] memory users) public view returns (LongestLock[] memory) {
LongestLock[] memory longestLocks = new LongestLock[](users.length);
LockedBalance memory longestLock;
uint128 longestLockIndex;
for (uint256 i = 0; i < users.length; ) {
for (uint256 j; j < veFXS.numLocks(users[i]); ) {
uint128 currentEnd = veFXS.lockedByIndex(users[i], uint128(j)).end;
if (currentEnd > longestLock.end) {
longestLock.end = currentEnd;
longestLock.amount = veFXS.lockedByIndex(users[i], uint128(j)).amount;
longestLockIndex = uint128(j);
}
unchecked {
++j;
}
}
longestLocks[i] = LongestLock({ lock: longestLock, lockIndex: longestLockIndex, user: users[i] });
delete longestLock;
delete longestLockIndex;
unchecked {
++i;
}
}
return longestLocks;
}
/**
* @notice Calculate the APPROXIMATE amount of veFXS, given an FXS amount and a lock length. Cruder version of balanceOf math. Useful for sanity checks.
* @param _fxsAmount The amount of FXS
* @param _lockSecsU128 The length of the lock
* @return _expectedVeFXS The expected amount of veFXS. May be slightly off from actual (~1%)
* @dev Useful to compare to the slope/bias-based balancedOf to make sure the math is working
*/
function getCrudeExpectedVeFXSOneLock(
int128 _fxsAmount,
uint128 _lockSecsU128
) public view returns (uint256 _expectedVeFXS) {
// veFXS = FXS in emergency unlock situation
if (veFXS.emergencyUnlockActive()) return uint256(int256(_fxsAmount));
// Truncate _timeLeft down to the nearest week
int128 _lockSecsI128 = int128((_lockSecsU128 / veFXS.WEEK_UINT128()) * veFXS.WEEK_UINT128());
// Calculate the expected veFXS
_expectedVeFXS = uint256(uint128(_fxsAmount + ((3 * _fxsAmount * _lockSecsI128) / veFXS.MAXTIME_INT128())));
}
/**
* @notice Calculate the APPROXIMATE amount of veFXS, given FXS amounts and lock lengths. Cruder version of balanceOf math. Useful for sanity checks.
* @param _fxsAmounts The amounts of FXS
* @param _lockSecsU128 The length of the locks
* @return _expectedVeFXS The expected amount of veFXS (summed). May be slightly off from actual (~1%)
* @dev Useful to compare to the slope/bias-based balancedOf to make sure the math is working
*/
function getCrudeExpectedVeFXSMultiLock(
int128[] memory _fxsAmounts,
uint128[] memory _lockSecsU128
) public view returns (uint256 _expectedVeFXS) {
// See if you are in an emergency unlock situation
bool _isEmergencyUnlockActive = veFXS.emergencyUnlockActive();
// Loop through the locks
for (uint128 i = 0; i < _fxsAmounts.length; ++i) {
// veFXS = FXS in emergency unlock situation
if (_isEmergencyUnlockActive) _expectedVeFXS += uint256(int256(_fxsAmounts[i]));
else _expectedVeFXS += getCrudeExpectedVeFXSOneLock(_fxsAmounts[i], _lockSecsU128[i]);
}
}
/**
* @notice Calculate the APPROXIMATE amount of veFXS a specific user should have. Cruder version of balanceOf math. Useful for sanity checks.
* @param _user The address of the user
* @return _expectedVeFXS The expected amount of veFXS (summed). May be slightly off from actual (~1%)
* @dev Useful to compare to the slope/bias-based balancedOf to make sure the math is working
*/
function getCrudeExpectedVeFXSUser(address _user) public view returns (uint256 _expectedVeFXS) {
// Get all of the user's locks
DetailedUserLockInfo memory _userLockInfo = getDetailedUserLockInfo(_user);
// See if you are in an emergency unlock situation
bool _isEmergencyUnlockActive = veFXS.emergencyUnlockActive();
// Loop through all of the user's locks
for (uint128 i = 0; i < _userLockInfo.numberOfLocks; ) {
// Get the lock info
LockedBalanceExtended memory _lockInfo = _userLockInfo.allLocks[i];
// For the emergency unlock situation, veFXS = FXS
if (_isEmergencyUnlockActive) {
_expectedVeFXS += uint256(int256(_lockInfo.amount));
} else {
// Get the lock time to use
uint128 _lockSecsToUse;
if (_lockInfo.end < uint128(block.timestamp)) {
_lockSecsToUse = 0;
} else {
_lockSecsToUse = _lockInfo.end - uint128(block.timestamp);
}
// Get the approximate veFXS
_expectedVeFXS += getCrudeExpectedVeFXSOneLock(_lockInfo.amount, _lockSecsToUse);
}
unchecked {
++i;
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
/// @dev The original console.sol uses `int` and `uint` for computing function selectors, but it should
/// use `int256` and `uint256`. This modified version fixes that. This version is recommended
/// over `console.sol` if you don't need compatibility with Hardhat as the logs will show up in
/// forge stack traces. If you do need compatibility with Hardhat, you must use `console.sol`.
/// Reference: https://github.com/NomicFoundation/hardhat/issues/2178
library console2 {
address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);
function _castLogPayloadViewToPure(
function(bytes memory) internal view fnIn
) internal pure returns (function(bytes memory) internal pure fnOut) {
assembly {
fnOut := fnIn
}
}
function _sendLogPayload(bytes memory payload) internal pure {
_castLogPayloadViewToPure(_sendLogPayloadView)(payload);
}
function _sendLogPayloadView(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 pure {
_sendLogPayload(abi.encodeWithSignature("log()"));
}
function logInt(int256 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(int256)", p0));
}
function logUint(uint256 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
}
function logString(string memory p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string)", p0));
}
function logBool(bool p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
}
function logAddress(address p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address)", p0));
}
function logBytes(bytes memory p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
}
function logBytes1(bytes1 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
}
function logBytes2(bytes2 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
}
function logBytes3(bytes3 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
}
function logBytes4(bytes4 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
}
function logBytes5(bytes5 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
}
function logBytes6(bytes6 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
}
function logBytes7(bytes7 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
}
function logBytes8(bytes8 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
}
function logBytes9(bytes9 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
}
function logBytes10(bytes10 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
}
function logBytes11(bytes11 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
}
function logBytes12(bytes12 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
}
function logBytes13(bytes13 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
}
function logBytes14(bytes14 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
}
function logBytes15(bytes15 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
}
function logBytes16(bytes16 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
}
function logBytes17(bytes17 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
}
function logBytes18(bytes18 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
}
function logBytes19(bytes19 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
}
function logBytes20(bytes20 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
}
function logBytes21(bytes21 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
}
function logBytes22(bytes22 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
}
function logBytes23(bytes23 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
}
function logBytes24(bytes24 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
}
function logBytes25(bytes25 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
}
function logBytes26(bytes26 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
}
function logBytes27(bytes27 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
}
function logBytes28(bytes28 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
}
function logBytes29(bytes29 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
}
function logBytes30(bytes30 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
}
function logBytes31(bytes31 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
}
function logBytes32(bytes32 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
}
function log(uint256 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
}
function log(int256 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(int256)", p0));
}
function log(string memory p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string)", p0));
}
function log(bool p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
}
function log(address p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address)", p0));
}
function log(uint256 p0, uint256 p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1));
}
function log(uint256 p0, string memory p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1));
}
function log(uint256 p0, bool p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1));
}
function log(uint256 p0, address p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1));
}
function log(string memory p0, uint256 p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1));
}
function log(string memory p0, int256 p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,int256)", p0, p1));
}
function log(string memory p0, string memory p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
}
function log(string memory p0, bool p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
}
function log(string memory p0, address p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
}
function log(bool p0, uint256 p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1));
}
function log(bool p0, string memory p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
}
function log(bool p0, bool p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
}
function log(bool p0, address p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
}
function log(address p0, uint256 p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1));
}
function log(address p0, string memory p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
}
function log(address p0, bool p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
}
function log(address p0, address p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
}
function log(uint256 p0, uint256 p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2));
}
function log(uint256 p0, uint256 p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2));
}
function log(uint256 p0, uint256 p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2));
}
function log(uint256 p0, uint256 p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2));
}
function log(uint256 p0, string memory p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2));
}
function log(uint256 p0, string memory p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2));
}
function log(uint256 p0, string memory p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2));
}
function log(uint256 p0, string memory p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2));
}
function log(uint256 p0, bool p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2));
}
function log(uint256 p0, bool p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2));
}
function log(uint256 p0, bool p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2));
}
function log(uint256 p0, bool p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2));
}
function log(uint256 p0, address p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2));
}
function log(uint256 p0, address p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2));
}
function log(uint256 p0, address p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2));
}
function log(uint256 p0, address p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2));
}
function log(string memory p0, uint256 p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2));
}
function log(string memory p0, uint256 p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2));
}
function log(string memory p0, uint256 p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2));
}
function log(string memory p0, uint256 p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2));
}
function log(string memory p0, string memory p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2));
}
function log(string memory p0, string memory p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
}
function log(string memory p0, string memory p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
}
function log(string memory p0, string memory p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
}
function log(string memory p0, bool p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2));
}
function log(string memory p0, bool p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
}
function log(string memory p0, bool p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
}
function log(string memory p0, bool p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
}
function log(string memory p0, address p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2));
}
function log(string memory p0, address p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
}
function log(string memory p0, address p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
}
function log(string memory p0, address p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
}
function log(bool p0, uint256 p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2));
}
function log(bool p0, uint256 p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2));
}
function log(bool p0, uint256 p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2));
}
function log(bool p0, uint256 p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2));
}
function log(bool p0, string memory p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2));
}
function log(bool p0, string memory p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
}
function log(bool p0, string memory p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
}
function log(bool p0, string memory p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
}
function log(bool p0, bool p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2));
}
function log(bool p0, bool p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
}
function log(bool p0, bool p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
}
function log(bool p0, bool p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
}
function log(bool p0, address p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2));
}
function log(bool p0, address p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
}
function log(bool p0, address p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
}
function log(bool p0, address p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
}
function log(address p0, uint256 p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2));
}
function log(address p0, uint256 p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2));
}
function log(address p0, uint256 p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2));
}
function log(address p0, uint256 p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2));
}
function log(address p0, string memory p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2));
}
function log(address p0, string memory p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
}
function log(address p0, string memory p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
}
function log(address p0, string memory p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
}
function log(address p0, bool p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2));
}
function log(address p0, bool p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
}
function log(address p0, bool p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
}
function log(address p0, bool p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
}
function log(address p0, address p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2));
}
function log(address p0, address p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
}
function log(address p0, address p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
}
function log(address p0, address p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
}
function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, string memory p2, string memory p3) internal pure {
_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 pure {
_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 pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, bool p2, string memory p3) internal pure {
_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 pure {
_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 pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, address p2, string memory p3) internal pure {
_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 pure {
_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 pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, string memory p2, string memory p3) internal pure {
_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 pure {
_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 pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, string memory p2, string memory p3) internal pure {
_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 pure {
_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 pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, string memory p2, string memory p3) internal pure {
_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 pure {
_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 pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
}
function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3));
}
function log(bool p0, address p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3));
}
function log(bool p0, address p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3));
}
function log(bool p0, address p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3));
}
function log(bool p0, address p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3));
}
function log(bool p0, address p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
}
function log(bool p0, address p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
}
function log(bool p0, address p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
}
function log(bool p0, address p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3));
}
function log(bool p0, address p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
}
function log(bool p0, address p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
}
function log(bool p0, address p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
}
function log(bool p0, address p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3));
}
function log(bool p0, address p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
}
function log(bool p0, address p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
}
function log(bool p0, address p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, string memory p2, string memory p3) internal pure {
_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 pure {
_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 pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
}
function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3));
}
function log(address p0, bool p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3));
}
function log(address p0, bool p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3));
}
function log(address p0, bool p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3));
}
function log(address p0, bool p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3));
}
function log(address p0, bool p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
}
function log(address p0, bool p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
}
function log(address p0, bool p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
}
function log(address p0, bool p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3));
}
function log(address p0, bool p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
}
function log(address p0, bool p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
}
function log(address p0, bool p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
}
function log(address p0, bool p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3));
}
function log(address p0, bool p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
}
function log(address p0, bool p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
}
function log(address p0, bool p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
}
function log(address p0, address p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3));
}
function log(address p0, address p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3));
}
function log(address p0, address p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3));
}
function log(address p0, address p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3));
}
function log(address p0, address p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3));
}
function log(address p0, address p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
}
function log(address p0, address p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
}
function log(address p0, address p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
}
function log(address p0, address p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3));
}
function log(address p0, address p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
}
function log(address p0, address p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
}
function log(address p0, address p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
}
function log(address p0, address p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3));
}
function log(address p0, address p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
}
function log(address p0, address p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
}
function log(address p0, address p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* The default value of {decimals} is 18. To select a different value for
* {decimals} you should overload it.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless this function is
* overridden;
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += amount;
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// @version 0.2.8
pragma solidity >=0.8.0;
/**
* ====================================================================
* | ______ _______ |
* | / _____________ __ __ / ____(_____ ____ _____ ________ |
* | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
* | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
* | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
* | |
* ====================================================================
* ============================ IVestedFXS ============================
* ====================================================================
* Frax Finance: https://github.com/FraxFinance
*/
import "src/contracts/VestedFXS-and-Flox/VestedFXS/IveFXSStructs.sol";
interface IVestedFXS is IveFXSStructs {
function MAXTIME_INT128() external view returns (int128);
function MAXTIME_UINT256() external view returns (uint256);
function MAX_CONTRIBUTOR_LOCKS() external view returns (uint8);
function MAX_USER_LOCKS() external view returns (uint8);
function MULTIPLIER_UINT256() external view returns (uint256);
function VOTE_WEIGHT_MULTIPLIER_INT128() external view returns (int128);
function VOTE_WEIGHT_MULTIPLIER_UINT256() external view returns (uint256);
function WEEK_UINT128() external view returns (uint128);
function WEEK_UINT256() external view returns (uint256);
function acceptTransferOwnership() external;
function admin() external view returns (address);
function balanceOf(address _addr) external view returns (uint256 _balance);
function balanceOfAllLocksAtBlock(address _addr, uint256 _block) external view returns (uint256 _balance);
function balanceOfAllLocksAtTime(address _addr, uint256 _timestamp) external view returns (uint256 _balance);
function balanceOfAt(address _addr, uint256 _block) external view returns (uint256 _balance);
function balanceOfOneLockAtBlock(
address _addr,
uint128 _lockIndex,
uint256 _block
) external view returns (uint256 _balance);
function balanceOfOneLockAtTime(
address _addr,
uint128 _lockIndex,
uint256 _timestamp
) external view returns (uint256 _balance);
function checkpoint() external;
function commitTransferOwnership(address _addr) external;
function createLock(address _addr, uint256 _value, uint128 _unlockTime) external returns (uint128);
function decimals() external view returns (uint256);
function depositFor(address _addr, uint256 _value, uint128 _lockIndex) external;
function emergencyUnlockActive() external view returns (bool);
function epoch() external view returns (uint256);
function findBlockEpoch(uint256 _block, uint256 _maxEpoch) external view returns (uint256);
function floxContributors(address) external view returns (bool);
function futureAdmin() external view returns (address);
function getLastUserSlope(address _addr, uint128 _lockIndex) external view returns (int128);
function increaseAmount(uint256 _value, uint128 _lockIndex) external;
function increaseUnlockTime(uint128 _unlockTime, uint128 _lockIndex) external;
function indicesToIds(address, uint128) external view returns (uint256);
function isPaused() external view returns (bool);
function locked(address, uint256) external view returns (int128 amount, uint128 end);
function lockedById(address _addr, uint256 _id) external view returns (LockedBalance memory _lockInfo);
function lockedByIndex(address _addr, uint128 _index) external view returns (LockedBalance memory _lockInfo);
function lockedEnd(address _addr, uint128 _index) external view returns (uint256);
function name() external view returns (string memory);
function nextId(address) external view returns (uint256);
function numLocks(address) external view returns (uint128);
function pointHistory(
uint256
) external view returns (int128 bias, int128 slope, uint256 ts, uint256 blk, uint256 fxsAmt);
function recoverIERC20(address _tokenAddr, uint256 _amount) external;
function setFloxContributor(address _floxContributor, bool _isFloxContributor) external;
function setVeFXSUtils(address _veFxsUtilsAddr) external;
function slopeChanges(uint256) external view returns (int128);
function supply() external view returns (uint256);
function supplyAt(Point memory _point, uint256 _t) external view returns (uint256);
function symbol() external view returns (string memory);
function toggleContractPause() external;
function activateEmergencyUnlock() external;
function token() external view returns (address);
function totalFXSSupply() external view returns (uint256);
function totalFXSSupplyAt(uint256 _block) external view returns (uint256);
function totalSupply() external view returns (uint256);
function totalSupply(uint256 _timestamp) external view returns (uint256);
function totalSupplyAt(uint256 _block) external view returns (uint256);
function userPointEpoch(address, uint256) external view returns (uint256);
function userPointHistory(
address,
uint256,
uint256
) external view returns (int128 bias, int128 slope, uint256 ts, uint256 blk, uint256 fxsAmt);
function userPointHistoryTs(address _addr, uint128 _lockIndex, uint256 _idx) external view returns (uint256);
function veFxsUtils() external view returns (address);
function version() external view returns (string memory);
function withdraw(uint128 _lockIndex) external;
}{
"remappings": [
"frax-std/=lib/frax-standard-solidity/src/",
"@eth-optimism/=lib/optimism/packages/",
"lib/optimism/packages/contracts-bedrock:src/=lib/optimism/packages/contracts-bedrock/src/",
"src/=src/",
"@openzeppelin-4/=node_modules/@openzeppelin-4/",
"@openzeppelin-5/=node_modules/@openzeppelin-5/",
"@openzeppelin/=node_modules/@openzeppelin/",
"@rari-capital/=node_modules/@rari-capital/",
"clones-with-immutable-args/=lib/optimism/packages/contracts-bedrock/lib/clones-with-immutable-args/src/",
"ds-test/=lib/frax-standard-solidity/lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/frax-standard-solidity/lib/forge-std/src/",
"frax-standard-solidity/=lib/frax-standard-solidity/src/",
"kontrol-cheatcodes/=lib/optimism/packages/contracts-bedrock/lib/kontrol-cheatcodes/src/",
"lib-keccak/=lib/optimism/packages/contracts-bedrock/lib/lib-keccak/contracts/",
"openzeppelin-contracts-upgradeable/=lib/optimism/packages/contracts-bedrock/lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/optimism/packages/contracts-bedrock/lib/openzeppelin-contracts/",
"optimism/=lib/optimism/",
"safe-contracts/=lib/optimism/packages/contracts-bedrock/lib/safe-contracts/contracts/",
"solady/=lib/optimism/packages/contracts-bedrock/lib/solady/",
"solidity-bytes-utils/=lib/frax-standard-solidity/lib/solidity-bytes-utils/",
"solmate/=lib/optimism/packages/contracts-bedrock/lib/solmate/src/"
],
"optimizer": {
"enabled": true,
"runs": 10000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminNotSet","type":"error"},{"inputs":[],"name":"AdminOnly","type":"error"},{"inputs":[],"name":"CannotMergeLockWithItself","type":"error"},{"inputs":[],"name":"DecimalsExceedMaximumValue","type":"error"},{"inputs":[],"name":"EmergencyUnlockActive","type":"error"},{"inputs":[],"name":"FutureAdminOnly","type":"error"},{"inputs":[],"name":"InitializeFailed","type":"error"},{"inputs":[],"name":"InvalidBlockNumber","type":"error"},{"inputs":[],"name":"InvalidLockIndex","type":"error"},{"inputs":[],"name":"InvalidTimestamp","type":"error"},{"inputs":[],"name":"LockCanOnlyBeUpToFourYears","type":"error"},{"inputs":[],"name":"LockDidNotExpire","type":"error"},{"inputs":[],"name":"LockExpired","type":"error"},{"inputs":[],"name":"LockIDNotInUse","type":"error"},{"inputs":[],"name":"MaximumFloxContributorLocksReached","type":"error"},{"inputs":[],"name":"MaximumUserLocksReached","type":"error"},{"inputs":[],"name":"MinLockAmount","type":"error"},{"inputs":[],"name":"MustBeInAFutureEpochWeek","type":"error"},{"inputs":[],"name":"NoExistingLockFound","type":"error"},{"inputs":[],"name":"NotLockingForSelfOrFloxContributor","type":"error"},{"inputs":[],"name":"OperationIsPaused","type":"error"},{"inputs":[],"name":"UnableToRecoverFXS","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"ApplyOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"CommitOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isPaused","type":"bool"}],"name":"ContractPause","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"address","name":"payor","type":"address"},{"indexed":true,"internalType":"uint256","name":"endingTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"depositType","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"txTimestamp","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[],"name":"EmergencyUnlockActivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contributor","type":"address"},{"indexed":false,"internalType":"bool","name":"isContributor","type":"bool"}],"name":"FloxContributorUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"prevSupply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"supply","type":"uint256"}],"name":"Supply","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"veFxsUtilsAddr","type":"address"}],"name":"VeFxsUtilsContractUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ts","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"MAXTIME_INT128","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAXTIME_UINT256","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_CONTRIBUTOR_LOCKS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_USER_LOCKS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_LOCK_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MULTIPLIER_UINT256","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VOTE_WEIGHT_MULTIPLIER_INT128","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VOTE_WEIGHT_MULTIPLIER_UINT256","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WEEK_UINT128","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WEEK_UINT256","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptTransferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"activateEmergencyUnlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"_balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint256","name":"_block","type":"uint256"}],"name":"balanceOfAllLocksAtBlock","outputs":[{"internalType":"uint256","name":"_balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"balanceOfAllLocksAtTime","outputs":[{"internalType":"uint256","name":"_balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint256","name":"_block","type":"uint256"}],"name":"balanceOfAt","outputs":[{"internalType":"uint256","name":"_balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"balanceOfLockedFxs","outputs":[{"internalType":"uint256","name":"_balanceOfLockedFxs","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint128","name":"_lockIndex","type":"uint128"},{"internalType":"uint256","name":"_block","type":"uint256"}],"name":"balanceOfOneLockAtBlock","outputs":[{"internalType":"uint256","name":"_balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint128","name":"_lockIndex","type":"uint128"},{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"balanceOfOneLockAtTime","outputs":[{"internalType":"uint256","name":"_balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"checkpoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"commitTransferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint128","name":"_unlockTime","type":"uint128"}],"name":"createLock","outputs":[{"internalType":"uint128","name":"_index","type":"uint128"},{"internalType":"uint256","name":"_newLockId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint128","name":"_lockIndex","type":"uint128"}],"name":"depositFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyUnlockActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"epoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_block","type":"uint256"},{"internalType":"uint256","name":"_maxEpoch","type":"uint256"}],"name":"findBlockEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint256","name":"_lockId","type":"uint256"},{"internalType":"uint256","name":"_ts","type":"uint256"}],"name":"findUserTimestampEpoch","outputs":[{"internalType":"uint256","name":"_min","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contributor","type":"address"}],"name":"floxContributors","outputs":[{"internalType":"bool","name":"isContributor","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"futureAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCreateLockTsBounds","outputs":[{"internalType":"uint128","name":"_earliestLockEnd","type":"uint128"},{"internalType":"uint128","name":"_latestLockEnd","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"getIncreaseUnlockTimeTsBounds","outputs":[{"internalType":"uint128","name":"_earliestLockEnd","type":"uint128"},{"internalType":"uint128","name":"_latestLockEnd","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastGlobalPoint","outputs":[{"components":[{"internalType":"int128","name":"bias","type":"int128"},{"internalType":"int128","name":"slope","type":"int128"},{"internalType":"uint256","name":"ts","type":"uint256"},{"internalType":"uint256","name":"blk","type":"uint256"},{"internalType":"uint256","name":"fxsAmt","type":"uint256"}],"internalType":"struct IveFXSStructs.Point","name":"_lastPoint","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint128","name":"_lockIndex","type":"uint128"}],"name":"getLastUserPoint","outputs":[{"components":[{"internalType":"int128","name":"bias","type":"int128"},{"internalType":"int128","name":"slope","type":"int128"},{"internalType":"uint256","name":"ts","type":"uint256"},{"internalType":"uint256","name":"blk","type":"uint256"},{"internalType":"uint256","name":"fxsAmt","type":"uint256"}],"internalType":"struct IveFXSStructs.Point","name":"_lastPoint","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint128","name":"_lockIndex","type":"uint128"}],"name":"getLastUserSlope","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"getLockIndexById","outputs":[{"internalType":"uint128","name":"_index","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint128","name":"_lockIndex","type":"uint128"},{"internalType":"uint256","name":"_uepoch","type":"uint256"}],"name":"getUserPointAtEpoch","outputs":[{"components":[{"internalType":"int128","name":"bias","type":"int128"},{"internalType":"int128","name":"slope","type":"int128"},{"internalType":"uint256","name":"ts","type":"uint256"},{"internalType":"uint256","name":"blk","type":"uint256"},{"internalType":"uint256","name":"fxsAmt","type":"uint256"}],"internalType":"struct IveFXSStructs.Point","name":"_lastPoint","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint128","name":"_lockIndex","type":"uint128"}],"name":"increaseAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"_unlockTime","type":"uint128"},{"internalType":"uint128","name":"_lockIndex","type":"uint128"}],"name":"increaseUnlockTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint128","name":"index","type":"uint128"}],"name":"indicesToIds","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"},{"internalType":"address","name":"_tokenAddr","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"string","name":"_version","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"isLockCreatedByFloxContributor","outputs":[{"internalType":"bool","name":"createdByFloxContributor","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"locked","outputs":[{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"uint128","name":"end","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"lockedById","outputs":[{"internalType":"int128","name":"_amount","type":"int128"},{"internalType":"uint128","name":"_end","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"lockedByIdExtended","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint128","name":"index","type":"uint128"},{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"uint128","name":"end","type":"uint128"}],"internalType":"struct IveFXSStructs.LockedBalanceExtended","name":"_extendedLockInfo","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint128","name":"_index","type":"uint128"}],"name":"lockedByIndex","outputs":[{"internalType":"int128","name":"_amount","type":"int128"},{"internalType":"uint128","name":"_end","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint128","name":"_index","type":"uint128"}],"name":"lockedEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"nextId","outputs":[{"internalType":"uint256","name":"nextId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"numLocks","outputs":[{"internalType":"uint128","name":"numLocks","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"numberOfFloxContributorCreatedLocks","outputs":[{"internalType":"uint8","name":"numberOfLocks","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"numberOfUserCreatedLocks","outputs":[{"internalType":"uint8","name":"numberOfLocks","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"pointHistory","outputs":[{"internalType":"int128","name":"bias","type":"int128"},{"internalType":"int128","name":"slope","type":"int128"},{"internalType":"uint256","name":"ts","type":"uint256"},{"internalType":"uint256","name":"blk","type":"uint256"},{"internalType":"uint256","name":"fxsAmt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddr","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"recoverIERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_floxContributor","type":"address"},{"internalType":"bool","name":"_isFloxContributor","type":"bool"}],"name":"setFloxContributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_veFxsUtilsAddr","type":"address"}],"name":"setVeFXSUtils","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"time","type":"uint256"}],"name":"slopeChanges","outputs":[{"internalType":"int128","name":"slopeChange","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"supply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"int128","name":"bias","type":"int128"},{"internalType":"int128","name":"slope","type":"int128"},{"internalType":"uint256","name":"ts","type":"uint256"},{"internalType":"uint256","name":"blk","type":"uint256"},{"internalType":"uint256","name":"fxsAmt","type":"uint256"}],"internalType":"struct IveFXSStructs.Point","name":"_point","type":"tuple"},{"internalType":"uint256","name":"_t","type":"uint256"}],"name":"supplyAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"toggleContractPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalFXSSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_block","type":"uint256"}],"name":"totalFXSSupplyAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_block","type":"uint256"}],"name":"totalSupplyAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"userPointEpoch","outputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"userPointHistory","outputs":[{"internalType":"int128","name":"bias","type":"int128"},{"internalType":"int128","name":"slope","type":"int128"},{"internalType":"uint256","name":"ts","type":"uint256"},{"internalType":"uint256","name":"blk","type":"uint256"},{"internalType":"uint256","name":"fxsAmt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint128","name":"_lockIndex","type":"uint128"},{"internalType":"uint256","name":"_idx","type":"uint256"}],"name":"userPointHistoryTs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"veFxsUtils","outputs":[{"internalType":"contract VestedFXSUtils","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"_lockIndex","type":"uint128"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b5060016000556151df806100256000396000f3fe608060405234801561001057600080fd5b50600436106104f95760003560e01c80637c10d93a116102a1578063c3ad89561161016b578063e7ee4b79116100e3578063f851a44011610097578063fb2bc0b71161007c578063fb2bc0b714610dd2578063fc0c546a14610dda578063fc26cf3414610ded57600080fd5b8063f851a44014610db2578063f894648514610dc557600080fd5b8063ed669886116100c8578063ed66988614610d51578063ee1f785b14610d64578063f52a36f714610d8f57600080fd5b8063e7ee4b7914610652578063e97d35ae14610d3e57600080fd5b8063d72142131161013a578063dd764abf1161011f578063dd764abf14610d0c578063e13d7f9814610d18578063e1cebf0b14610d2b57600080fd5b8063d721421314610cfc578063d8399b7d14610d0457600080fd5b8063c3ad895614610ca7578063c67d526a14610caf578063cb3632d114610cb7578063d41a464114610cca57600080fd5b8063981b24d011610219578063b9ef0830116101cd578063bf7bab73116101b2578063bf7bab7314610c4b578063c052580714610c8c578063c2c4c5c114610c9f57600080fd5b8063b9ef083014610c0f578063bd85b03914610c3857600080fd5b8063a15d874a116101fe578063a15d874a14610bc4578063b0a0d79914610bd7578063b187bd2614610bea57600080fd5b8063981b24d014610b3657806399e9c19b14610b4957600080fd5b80638ad4c44711610270578063900cf0cf11610255578063900cf0cf14610b12578063929edf4514610b1b57806395d89b4114610b2e57600080fd5b80638ad4c44714610abc5780638b2e014e14610aff57600080fd5b80637c10d93a14610a5c57806386f9c86414610a7e57806387096bc014610a86578063890b4cfc14610aa957600080fd5b80634957e892116103e257806354fd4d501161035a5780636e083e7f1161030e57806377bc368c116102f357806377bc368c146109db5780637aa9b55614610a365780637b37110714610a5457600080fd5b80636e083e7f1461099557806370a08231146109c857600080fd5b80635ae3afa71161033f5780635ae3afa7146109445780635f96d4e71461095757806366d6bff91461098257600080fd5b806354fd4d50146109295780635552823c1461093157600080fd5b80634f8ab24f116103b157806350bb3fa41161039657806350bb3fa41461085e578063520221e9146108bf57806353974fcf146108ca57600080fd5b80634f8ab24f146108285780634fd9d1e01461083b57600080fd5b80634957e892146107885780634cb654af146107e05780634eb99c2d1461080b5780634ee2cd7e1461081557600080fd5b80632394c386116104755780633f2f5ee21161044457806346190ec41161042957806346190ec414610742578063466003b2146107625780634834d0891461077557600080fd5b80633f2f5ee2146106ab5780634545304a146106be57600080fd5b80632394c38614610652578063313ce5671461066c57806338dbff66146106755780633b9a760c1461068857600080fd5b80630e058678116104cc578063145925b6116104b1578063145925b6146105a857806318160ddd146105b757806321c984e9146105bf57600080fd5b80630e05867814610580578063111aa3991461059357600080fd5b806302387a7b146104fe578063047fc9aa146105245780630536a6081461052d57806306fdde031461056b575b600080fd5b61051161050c366004614847565b610df5565b6040519081526020015b60405180910390f35b61051160035481565b61055b61053b366004614879565b600760209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161051b565b610573610e08565b60405161051b91906148a3565b61051161058e366004614879565b610e96565b6105a66105a1366004614910565b610efb565b005b610511670de0b6b3a764000081565b610511611136565b6106306105cd36600461494c565b6001600160a01b039091166000908152600460209081526040808320600583528184206001600160801b0395861685528352818420548452825291829020825180840190935254600f81900b808452600160801b90910490931691018190529091565b60408051600f9390930b83526001600160801b0390911660208301520161051b565b61065a600881565b60405160ff909116815260200161051b565b61051160155481565b61051161068336600461497f565b611146565b61065a6106963660046149a1565b60096020526000908152604090205460ff1681565b6105a66106b9366004614a96565b6111c3565b6107126106cc366004614b40565b600e6020908152600093845260408085208252928452828420905282529020805460018201546002830154600390930154600f83810b94600160801b909404900b929085565b60408051600f96870b81529490950b6020850152938301919091526060820152608081019190915260a00161051b565b6105116107503660046149a1565b600a6020526000908152604090205481565b6105a6610770366004614879565b6113cf565b610511610783366004614b85565b6114f8565b61079b610796366004614879565b611663565b60405161051b9190815181526020808301516001600160801b0390811691830191909152604080840151600f0b90830152606092830151169181019190915260800190565b6017546107f3906001600160a01b031681565b6040516001600160a01b03909116815260200161051b565b61051162093a8081565b610511610823366004614879565b611704565b610511610836366004614c15565b611717565b61055b6108493660046149a1565b60186020526000908152604090205460ff1681565b61063061086c366004614879565b6001600160a01b0391909116600090815260046020908152604080832093835292815290829020825180840190935254600f81900b808452600160801b9091046001600160801b03169290910182905291565b610511630784ce0081565b6105116108d8366004614c2e565b6001600160a01b03831660008181526005602090815260408083206001600160801b0387168452825280832054938352600e8252808320938352928152828220848352905220600101549392505050565b6105736117c0565b6105a661093f3660046149a1565b6117cd565b610511610952366004614b40565b61187e565b61051161096536600461494c565b600560209081526000928352604080842090915290825290205481565b6001546107f3906001600160a01b031681565b6109a86109a3366004614879565b611938565b604080516001600160801b0393841681529290911660208301520161051b565b6105116109d63660046149a1565b6119e6565b6109ee6109e9366004614c2e565b6119f2565b60405161051b9190600060a0820190508251600f0b82526020830151600f0b602083015260408301516040830152606083015160608301526080830151608083015292915050565b610a41630784ce0081565b604051600f9190910b815260200161051b565b6105a6611abc565b610a6662093a8081565b6040516001600160801b03909116815260200161051b565b6105a6611bb3565b61065a610a943660046149a1565b60086020526000908152604090205460ff1681565b610511610ab7366004614c2e565b611c89565b610712610aca366004614c15565b600d602052600090815260409020805460018201546002830154600390930154600f83810b94600160801b909404900b929085565b610511610b0d366004614879565b611e51565b610511600c5481565b6105a6610b29366004614c6a565b611eae565b6105736120bd565b610511610b44366004614c15565b6120ca565b610a41610b5736600461494c565b6001600160a01b03821660008181526005602090815260408083206001600160801b0386168452825280832054848452600f808452828520828652845282852054958552600e845282852091855290835281842094845293909152902054600160801b9004900b92915050565b6109ee610bd236600461494c565b6122a0565b610a66610be5366004614879565b61237e565b60015461055b9074010000000000000000000000000000000000000000900460ff1681565b610a66610c1d3660046149a1565b600b602052600090815260409020546001600160801b031681565b610511610c46366004614c15565b612418565b610630610c59366004614879565b6004602090815260009283526040808420909152908252902054600f81900b90600160801b90046001600160801b031682565b6105a6610c9a366004614c9e565b61251d565b6105a66125de565b6105116126ac565b6109a8612732565b610511610cc53660046149a1565b612789565b610cdd610cd8366004614910565b612821565b604080516001600160801b03909316835260208301919091520161051b565b6109ee612df8565b6105a6612e8c565b61051164e8d4a5100081565b6105a6610d26366004614cd5565b612f63565b6105a6610d393660046149a1565b6131e0565b610511610d4c366004614c2e565b61328a565b610511610d5f36600461494c565b613629565b610511610d72366004614879565b600f60209081526000928352604080842090915290825290205481565b610a41610d9d366004614c15565b601060205260009081526040902054600f0b81565b6016546107f3906001600160a01b031681565b60115461055b9060ff1681565b610511600381565b6002546107f3906001600160a01b031681565b610a41600381565b6000610e0233338461368c565b92915050565b60128054610e1590614cf1565b80601f0160208091040260200160405190810160405280929190818152602001828054610e4190614cf1565b8015610e8e5780601f10610e6357610100808354040283529160200191610e8e565b820191906000526020600020905b815481529060010190602001808311610e7157829003601f168201915b505050505081565b6001600160a01b0382166000908152600b60205260408120546001600160801b0316815b816001600160801b0316816001600160801b03161015610ef357610edf85828661328a565b610ee99084614d73565b9250600101610eba565b505092915050565b600260005403610f6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b600260005560015474010000000000000000000000000000000000000000900460ff1615610fc6576040517f6087c16000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b64e8d4a51000821015611005576040517f24c09d8600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03831660008181526005602090815260408083206001600160801b038616845282528083205493835260048252808320848452909152812080549091600f9190910b13611085576040517f4331e8f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805442600160801b9091046001600160801b0316116110d0576040517ff6fafba000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03851660009081526004602090815260408083208584528252808320815180830190925254600f81900b8252600160801b90046001600160801b03169181019190915261112a9187918791908188613c88565b50506001600055505050565b600061114142612418565b905090565b6000808281805b60808110156111b857828410156111b857600261116a8486614d73565b611175906001614d73565b61117f9190614db5565b6000818152600d602052604090206002015490925087106111a2578193506111b0565b6111ad600183614dc9565b92505b60010161114d565b509195945050505050565b6001600160a01b03841615806111e357506002546001600160a01b031615155b1561121a576040517fd08e7ac200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601680547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0387161790556000808052600d602052437f81955a0a11e65eac625c29e8882660bae4e165a75d72780094acae8ece9a29f055427f81955a0a11e65eac625c29e8882660bae4e165a75d72780094acae8ece9a29ef557f81955a0a11e65eac625c29e8882660bae4e165a75d72780094acae8ece9a29f15560126112cb8482614e2d565b5060136112d88382614e2d565b5060146112e58282614e2d565b506000846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611326573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134a9190614f47565b60ff16905060ff81111561138a576040517ff20f57e600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03969096169590951790945550505060ff1660155550565b6016546001600160a01b03163314611413576040517fc15c60b400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002546001600160a01b039081169083160361145b576040517fab6e4ba600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6016546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152602481018390529083169063a9059cbb906044016020604051808303816000875af11580156114c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114eb9190614f6a565b6114f457600080fd5b5050565b60115460009060ff16156115155761150e6126ac565b9050610e02565b6000839050600062093a808083604001516115309190614db5565b61153a9190614f87565b9050838260400151111561157a576040517fb7d0949700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b60ff8110156116235761159362093a8083614d73565b91506000858311156115a7578592506115bb565b50600082815260106020526040902054600f0b5b60408401516115ca9084614dc9565b84602001516115d99190614f9e565b845185906115e8908390614fc5565b600f0b9052508583036115fb5750611623565b808460200181815161160d9190615013565b600f0b905250506040830182905260010161157d565b5060008260000151600f0b121561163957600082525b815160808301516001600160801b039091169081101561165a575060808201515b95945050505050565b6040805160808101825260008082526020808301829052828401829052606083018290526001600160a01b038616825260048152838220858352815290839020835180850190945254600f81900b8452600160801b90046001600160801b031690830152828152906116d5848461237e565b6001600160801b039081166020808501919091528251600f0b6040850152919091015116606082015292915050565b60006117108383610e96565b9392505050565b600043821115611753576040517f4e47846c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061176183600c54611146565b6000908152600d6020908152604091829020825160a0810184528154600f81810b8352600160801b909104900b928101929092526001810154928201929092526002820154606082015260039091015460809091018190529392505050565b60148054610e1590614cf1565b6016546001600160a01b03163314611811576040517fc15c60b400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f5bba814e5109ccee62df0b8a64259cfad631da3f947b48938174f31284263d75906020015b60405180910390a150565b6001600160a01b0383166000908152600f60209081526040808320858452909152812054815b608081101561192f578183101561192f57600060026118c38486614d73565b6118ce906001614d73565b6118d89190614db5565b6001600160a01b0388166000908152600e602090815260408083208a84528252808320848452909152902060010154909150851061191857809350611926565b611923600182614dc9565b92505b506001016118a4565b50509392505050565b6001600160a01b0382166000908152600460209081526040808320848452909152812054819062093a809061197e908290600160801b90046001600160801b0316615061565b6119889190615087565b6119959062093a806150aa565b915062093a806119a9630784ce00426150aa565b6119b69062093a80615087565b6119c09190615061565b9050806001600160801b0316826001600160801b0316106119df578091505b9250929050565b6000610e028242611e51565b611a2a6040518060a001604052806000600f0b81526020016000600f0b81526020016000815260200160008152602001600081525090565b506001600160a01b0390921660008181526005602090815260408083206001600160801b03909516835293815283822054928252600e815283822092825291825282812093815292815291819020815160a0810183528154600f81810b8352600160801b909104900b938101939093526001810154918301919091526002810154606083015260030154608082015290565b6017546001600160a01b03163314611b00576040517f0f89263400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6017546001600160a01b031680611b43576040517fe2db036000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601680546001600160a01b0383167fffffffffffffffffffffffff000000000000000000000000000000000000000091821681179092556017805490911690556040519081527febee2d5739011062cb4f14113f3b36bf0ffe3da5c0568f64189d1012a118910590602001611873565b6016546001600160a01b03163314611bf7576040517fc15c60b400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001805460ff7401000000000000000000000000000000000000000080830482161581027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff90931692909217928390556040517f79734b6e7debe05b78de4a5258ce230a8990ca364a016f0fbeabb8e6ca93394f93611c7f9390049091161515815260200190565b60405180910390a1565b60115460009060ff1615611cdc57506001600160a01b0383166000908152600460209081526040808320600583528184206001600160801b03808816865290845282852054855292529091205416611710565b8115611ce85781611cea565b425b6001600160a01b03851660009081526005602090815260408083206001600160801b0388168452909152812054919350611d2586838661187e565b905080600003611d3a57600092505050611710565b611d726040518060a001604052806000600f0b81526020016000600f0b81526020016000815260200160008152602001600081525090565b506001600160a01b0386166000908152600e602090815260408083208584528252808320848452825291829020825160a0810184528154600f81810b8352600160801b909104900b9281019290925260018101549282018390526002810154606083015260030154608082015290611dea9086614dc9565b8160200151611df99190614f9e565b81518290611e08908390614fc5565b600f90810b90915282516000910b12159050611e2357600081525b80600001516001600160801b031693508060800151841015611e4757806080015193505b5050509392505050565b6001600160a01b0382166000908152600b60205260408120546001600160801b0316815b816001600160801b0316816001600160801b03161015610ef357611e9a858286611c89565b611ea49084614d73565b9250600101611e75565b600260005403611f1a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610f63565b600260005560015474010000000000000000000000000000000000000000900460ff1615611f74576040517f6087c16000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b64e8d4a51000821015611fb3576040517f24c09d8600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360008181526005602090815260408083206001600160801b038616845282528083205493835260048252808320848452909152812080549091600f9190910b1361202a576040517f4331e8f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160801b03428116600160801b9092041611612077576040517ff6fafba000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518082019091528154600f81900b8252600160801b90046001600160801b031660208201526120b29033908690600090600288613c88565b505060016000555050565b60138054610e1590614cf1565b600043821115612106576040517f4e47846c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061211483600c54611146565b6000818152600d60209081526040808320815160a0810183528154600f81810b8352600160801b909104900b9381019390935260018101549183019190915260028101546060830152600301546080820152600c549293509183101561223d576000600d81612184866001614d73565b81526020808201929092526040908101600020815160a0810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600281015460608084018290526003909201546080840152908501519192501461223757826060015181606001516121fd9190614dc9565b836040015182604001516122119190614dc9565b60608501516122209089614dc9565b61222a9190614f87565b6122349190614db5565b91505b5061228c565b4382606001511461228c5760608201516122579043614dc9565b60408301516122669042614dc9565b60608401516122759088614dc9565b61227f9190614f87565b6122899190614db5565b90505b61165a828284604001516107839190614d73565b6122d86040518060a001604052806000600f0b81526020016000600f0b81526020016000815260200160008152602001600081525090565b506001600160a01b0390911660008181526005602090815260408083206001600160801b03909516835293815283822054838352600f808352858420828552835285842054948452600e835285842091845290825284832093835292815290839020835160a081018552815480850b8252600160801b900490930b9183019190915260018101549282019290925260028201546060820152600390910154608082015290565b6001600160a01b038216600090815260066020908152604080832084845282528083208151606081018352815481526001909101546001600160801b03811693820193909352600160801b90920460ff16151590820181905261240d576040517f8417403400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602001519392505050565b60115460009060ff161561242e57610e026126ac565b811561243a578161243c565b425b600c5490925060009081805b60808110156124b357828410156124b35760026124658486614d73565b612470906001614d73565b61247a9190614db5565b6000818152600d6020526040902060010154909250861061249d578193506124ab565b6124a8600183614dc9565b92505b600101612448565b506000838152600d6020908152604091829020825160a0810184528154600f81810b8352600160801b909104900b9281019290925260018101549282019290925260028201546060820152600390910154608082015261251381876114f8565b9695505050505050565b6016546001600160a01b03163314612561576040517fc15c60b400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03821660008181526018602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f1b6e6916bd76fb0e62ff02acf466a38852d02426c13ba96e69803693ac627d58910160405180910390a25050565b60015474010000000000000000000000000000000000000000900460ff1615612633576040517f6087c16000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60115460ff1615612670576040517ffcfb534f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051808201825260008082526020808301829052835180850190945281845283018190526126aa929091906001600160801b03613ef3565b565b6002546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa15801561270e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114191906150ca565b60008062093a806127438142615061565b61274d9190615087565b61275a9062093a806150aa565b915062093a808061276f630784ce00426150aa565b6127799190615061565b6127839190615087565b90509091565b6001600160a01b0381166000908152600b60205260408120546001600160801b0316815b816001600160801b0316816001600160801b0316101561281a576001600160a01b0384166000908152600460209081526040808320600583528184206001600160801b038087168652908452828520548552925290912054612810911684614d73565b92506001016127ad565b5050919050565b600080600260005403612890576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610f63565b600260005560015474010000000000000000000000000000000000000000900460ff16156128ea576040517f6087c16000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b64e8d4a51000841015612929576040517f24c09d8600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b0386161480159061295257503360009081526018602052604090205460ff16155b15612989576040517fe90513a400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b0386161480156129be57506001600160a01b03851660009081526008602081905260409091205460ff1610155b156129f5576040517f8d38fa5700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526018602052604090205460ff168015612a1d5750336001600160a01b03861614155b8015612a4757506001600160a01b038516600090815260096020526040902054600860ff90911610155b15612a7e576040517ffe39307800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0385166000908152600a60205260408120805460019290612aa7908490614d73565b9091555050506001600160a01b0384166000908152600a60205260408120549062093a80612ad58186615061565b612adf9190615087565b6001600160a01b03871660009081526004602090815260408083208684529091529020909150426001600160801b03831611612b47576040517f6df7c20200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b55630784ce0042614d73565b826001600160801b03161115612b97576040517ff245ec8e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0387166000818152600560209081526040808320600b80845282852080546001600160801b0390811687529285528386208a9055868652600685528386208a875285529285208981558354600191820180547fffffffffffffffffffffffffffffff00000000000000000000000000000000001691851691909117600160801b1790559585529092528054909291612c38918591166150aa565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550866001600160a01b0316336001600160a01b031603612cbe576001600160a01b0387166000908152600860205260408120805460019290612ca190849060ff166150e3565b92506101000a81548160ff021916908360ff160217905550612d54565b6001600160a01b0387166000908152600960205260408120805460019290612cea90849060ff166150e3565b825460ff9182166101009390930a9283029190920219909116179055506001600160a01b0387166000908152600760209081526040808320868452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b6040805180820182528254600f81900b82526001600160801b03600160801b90910481166020808401919091526001600160a01b038b166000908152600b9091529290922054612db8928a928a928792600191612db3918391166150fc565b613c88565b6001600160a01b0387166000908152600b6020526040902054612de6906001906001600160801b03166150fc565b60016000559792965091945050505050565b612e306040518060a001604052806000600f0b81526020016000600f0b81526020016000815260200160008152602001600081525090565b50600c546000908152600d6020908152604091829020825160a0810184528154600f81810b8352600160801b909104900b9281019290925260018101549282019290925260028201546060820152600390910154608082015290565b6016546001600160a01b03163314612ed0576040517fc15c60b400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60115460ff1615612f0d576040517ffcfb534f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040517f9961dd0c30c9f532f28144e481f13454df7edc16e55f83cdfa28cce1f3278df190600090a1565b600260005403612fcf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610f63565b600260005560015474010000000000000000000000000000000000000000900460ff1615613029576040517f6087c16000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360008181526005602090815260408083206001600160801b03861684528252808320549383526004825280832084845290915281209062093a8061306e8187615061565b6130789190615087565b825490915042600160801b9091046001600160801b0316116130c6576040517ff6fafba000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81546000600f9190910b13613107576040517f4331e8f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81546001600160801b03600160801b909104811690821611613155576040517f6df7c20200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613163630784ce0042614d73565b816001600160801b031611156131a5576040517ff245ec8e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518082019091528254600f81900b8252600160801b90046001600160801b0316602082015261112a9033906000908490600389613c88565b6016546001600160a01b03163314613224576040517fc15c60b400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f2f56810a6bf40af059b96d3aea4db54081f378029a518390491093a7b67032e990602001611873565b60115460009060ff16156132dd57506001600160a01b0383166000908152600460209081526040808320600583528184206001600160801b03808816865290845282852054855292529091205416611710565b43821115613317576040517f4e47846c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03841660008181526005602090815260408083206001600160801b0388168452825280832054938352600f8252808320848452909152812054815b60808110156133e457818310156133e457600060026133788486614d73565b613383906001614d73565b61338d9190614db5565b6001600160a01b038a166000908152600e60209081526040808320898452825280832084845290915290206002015490915087106133cd578093506133db565b6133d8600182614dc9565b92505b50600101613359565b506001600160a01b0387166000908152600e6020908152604080832086845282528083208584528252808320815160a0810183528154600f81810b8352600160801b909104900b9381019390935260018101549183019190915260028101546060830152600301546080820152600c5490916134608883611146565b6000818152600d60209081526040808320815160a0810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600281015460608301526003015460808201529192508084841015613556576000600d816134ce876001614d73565b81526020808201929092526040908101600020815160a0810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600281015460608084018290526003909201546080840152908601519192506135389190614dc9565b92508360400151816040015161354e9190614dc9565b91505061357a565b60608301516135659043614dc9565b91508260400151426135779190614dc9565b90505b604083015182156135b7578284606001518d6135969190614dc9565b6135a09084614f87565b6135aa9190614db5565b6135b49082614d73565b90505b60408701516135c69082614dc9565b87602001516135d59190614f9e565b875188906135e4908390614fc5565b600f90810b9091526080890151895190910b1215905061360a5786608001519a50613618565b86516001600160801b03169a505b505050505050505050509392505050565b60115460009060ff161561363e575042610e02565b506001600160a01b039190911660008181526005602090815260408083206001600160801b039586168452825280832054938352600482528083209383529290522054600160801b90041690565b60006002600054036136fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610f63565b600260009081556001600160a01b0385168152600b60205260409020546001600160801b039081169083161061375c576040517f7ecccce000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015474010000000000000000000000000000000000000000900460ff16156137b1576040517f6087c16000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03841660008181526005602090815260408083206001600160801b0380881685529083528184205494845260048352818420858552835292819020815180830190925254600f81900b8252600160801b90048316918101829052914216108015613825575060115460ff16155b1561385c576040517f143025ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160408051808201909152600080825260208201526001600160801b03909116935061388b87838388613ef3565b6001600160a01b0387166000908152600560209081526040808320600b90925282205482906138c5906001906001600160801b03166150fc565b6001600160801b03908116825260208083019390935260409182016000908120546001600160a01b038d16808352600586528483208c85168452808752858420839055908352600b909552928120549294509161392591600191166150fc565b6001600160801b039081168252602080830193909352604091820160009081208190556001600160a01b038c1680825260068552838220868352855283822060019081018054600160801b8e87167fffffffffffffffffffffffffffffff000000000000000000000000000000000092831617179091558a8452858420848155820180549091169055908252600b90945291822080549092916139ca918591166150fc565b82546001600160801b039182166101009390930a9283029190920219909116179055506001600160a01b038816600090815260076020908152604080832087845290915290205460ff16613a61576001600160a01b0388166000908152600860205260408120805460019290613a4490849060ff1661511c565b92506101000a81548160ff021916908360ff160217905550613aa6565b6001600160a01b0388166000908152600960205260408120805460019290613a8d90849060ff1661511c565b92506101000a81548160ff021916908360ff1602179055505b600354613ab38682614dc9565b6003556002546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b038a81166004830152602482018990529091169063a9059cbb906044016020604051808303816000875af1158015613b22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b469190614f6a565b613bac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5472616e73666572206661696c656400000000000000000000000000000000006044820152606401610f63565b60115460ff1615613bf1576040805180820182526000808252602080830182905283518085019094528184528301819052613bf1929091906001600160801b03613ef3565b604080518781524260208201526001600160a01b03808b1692908c16917ff341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567910160405180910390a36003546040805183815260208101929092527f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c910160405180910390a150506001600055509195945050505050565b60115460ff1615613cc5576040517ffcfb534f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002546040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018790526001600160a01b03909116906323b872dd906064016020604051808303816000875af1158015613d35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d599190614f6a565b613d6257600080fd5b600354604080518082019091528451600f0b81526020808601516001600160801b031690820152849190613d968883614d73565b600355805188908290613daa908390615013565b600f0b9052506001600160801b03871615613dcf576001600160801b03871660208201525b6001600160a01b0389166000908152600460209081526040808320600583528184206001600160801b03808a16865290845282852054855290835292208351918401518316600160801b0291909216179055613e2d89848387613ef3565b80602001516001600160801b0316336001600160a01b03168a6001600160a01b03167f14c0149cb9a81e88858fe68435647550d00aa572a036ef0d518745c27c61b9fc8b8942604051613e9c939291909283526001600160801b03919091166020830152604082015260600190565b60405180910390a47f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c82613ed08a82614d73565b6040805192835260208301919091520160405180910390a1505050505050505050565b6040805160a08082018352600080835260208084018290528385018290526060808501839052608080860184905286519485018752838552918401839052948301829052938201819052928101839052600c549192909181906001600160a01b038916156140ed574288602001516001600160801b0316118015613f7e575060008860000151600f0b135b15613fe5578751630784ce0090613f9790600390614f9e565b613fa19190615135565b600f0b602080870191909152880151613fc49042906001600160801b0316614dc9565b8560200151613fd39190614f9e565b8851613fdf9190615013565b600f0b85525b4287602001516001600160801b0316118015614008575060008760000151600f0b135b1561406f578651630784ce009061402190600390614f9e565b61402b9190615135565b600f0b60208086019190915287015161404e9042906001600160801b0316614dc9565b846020015161405d9190614f9e565b87516140699190615013565b600f0b84525b6020808901516001600160801b03908116600090815260108352604090205491890151600f9290920b945016156140ed5787602001516001600160801b031687602001516001600160801b0316036140c9578291506140ed565b6020808801516001600160801b0316600090815260109091526040902054600f0b91505b6040805160a08101825260008082526020820181905242928201929092524360608201526080810191909152811561417657506000818152600d6020908152604091829020825160a0810184528154600f81810b8352600160801b909104900b928101929092526001810154928201929092526002820154606082015260039091015460808201525b60008160400151905060006040518060a001604052808460000151600f0b81526020018460200151600f0b815260200184604001518152602001846060015181526020018460800151815250905060008360400151421115614213576141e56001600160801b03841642614dc9565b60608501516141f49043614dc9565b61420690670de0b6b3a7640000614f87565b6142109190614db5565b90505b614220838584848961451b565b93506001600160a01b038d161561436357886020015188602001516142459190614fc5565b846020018181516142569190615013565b600f0b9052508851885161426a9190614fc5565b84518590614279908390615013565b600f90810b9091528d518d5190820b910b131590506142be578b518b516142a09190614fc5565b6001600160801b0316846080018181516142ba9190614d73565b9052505b8b518b51600f91820b910b1215614336578a518c516142dd9190614fc5565b6001600160801b0316846080018181516142f79190614dc9565b9052508a51600f0b1580156143195750428c602001516001600160801b031611155b15614336578b518451859061432f908390614fc5565b600f0b9052505b60008460200151600f0b121561434e57600060208501525b60008460000151600f0b121561436357600084525b600c546000908152600d60209081526040918290208651918701516001600160801b03908116600160801b0292169190911781559085015160018201556060850151600282015560808501516003909101556001600160a01b038d161561450c57428c602001516001600160801b0316111561446b5760208901516143e89088615013565b96508b602001516001600160801b03168b602001516001600160801b03160361441d57602088015161441a9088614fc5565b96505b60208c8101516001600160801b0390811660009081526010909252604090912080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000169189169190911790555b428b602001516001600160801b03161115614501578b602001516001600160801b03168b602001516001600160801b031611156145015760208801516144b19087614fc5565b60208c8101516001600160801b0390811660009081526010909252604090912080547fffffffffffffffffffffffffffffffff000000000000000000000000000000001691831691909117905595505b61450c8d898c614738565b50505050505050505050505050565b6145536040518060a001604052806000600f0b81526020016000600f0b81526020016000815260200160008152602001600081525090565b600062093a8061456c816001600160801b038a16614db5565b6145769190614f87565b905060005b60ff81101561472a5761459162093a80836150aa565b9150600042836001600160801b031611156145ae574292506145cc565b506001600160801b038216600090815260106020526040902054600f0b5b6145d689846150fc565b88602001516145e59190614f9e565b885189906145f4908390614fc5565b600f0b90525060208801805182919061460e908390615013565b600f90810b90915289516000910b1215905061462957600088525b60008860200151600f0b121561464157600060208901525b6001600160801b0383166040808a018290528801519399508993670de0b6b3a76400009161466f9190614dc9565b614682906001600160801b038916614f87565b61468c9190614db5565b876060015161469b9190614d73565b60608901526146ab600186614d73565b9450426001600160801b0316836001600160801b0316036146d2575043606088015261472a565b6000858152600d60209081526040918290208a51918b01516001600160801b03908116600160801b0292169190911781559089015160018201556060890151600282015560808901516003909101555060010161457b565b505050600c55509092915050565b6001600160a01b03831660008181526005602090815260408083206001600160801b0386168452825280832054938352600f8252808320848452909152812054614783906001614d73565b6001600160a01b039095166000818152600f602090815260408083208684528252808320899055428882019081524360608a01908152858552600484528285208886528452828520546001600160801b0390811660808c01908152968652600e85528386209886529784528285209a85529983529220875197909101518516600160801b02969094169590951783559351600183015550925160028401555051600390910155565b80356001600160801b038116811461484257600080fd5b919050565b60006020828403121561485957600080fd5b6117108261482b565b80356001600160a01b038116811461484257600080fd5b6000806040838503121561488c57600080fd5b61489583614862565b946020939093013593505050565b60006020808352835180602085015260005b818110156148d1578581018301518582016040015282016148b5565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b60008060006060848603121561492557600080fd5b61492e84614862565b9250602084013591506149436040850161482b565b90509250925092565b6000806040838503121561495f57600080fd5b61496883614862565b91506149766020840161482b565b90509250929050565b6000806040838503121561499257600080fd5b50508035926020909101359150565b6000602082840312156149b357600080fd5b61171082614862565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f8301126149fc57600080fd5b813567ffffffffffffffff80821115614a1757614a176149bc565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715614a5d57614a5d6149bc565b81604052838152866020858801011115614a7657600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060a08688031215614aae57600080fd5b614ab786614862565b9450614ac560208701614862565b9350604086013567ffffffffffffffff80821115614ae257600080fd5b614aee89838a016149eb565b94506060880135915080821115614b0457600080fd5b614b1089838a016149eb565b93506080880135915080821115614b2657600080fd5b50614b33888289016149eb565b9150509295509295909350565b600080600060608486031215614b5557600080fd5b614b5e84614862565b95602085013595506040909401359392505050565b8035600f81900b811461484257600080fd5b60008082840360c0811215614b9957600080fd5b60a0811215614ba757600080fd5b5060405160a0810181811067ffffffffffffffff82111715614bcb57614bcb6149bc565b604052614bd784614b73565b8152614be560208501614b73565b60208201526040848101359082015260608085013590820152608080850135908201529460a09093013593505050565b600060208284031215614c2757600080fd5b5035919050565b600080600060608486031215614c4357600080fd5b614c4c84614862565b9250614c5a6020850161482b565b9150604084013590509250925092565b60008060408385031215614c7d57600080fd5b823591506149766020840161482b565b8015158114614c9b57600080fd5b50565b60008060408385031215614cb157600080fd5b614cba83614862565b91506020830135614cca81614c8d565b809150509250929050565b60008060408385031215614ce857600080fd5b6149688361482b565b600181811c90821680614d0557607f821691505b602082108103614d3e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610e0257610e02614d44565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082614dc457614dc4614d86565b500490565b81810381811115610e0257610e02614d44565b601f821115614e28576000816000526020600020601f850160051c81016020861015614e055750805b601f850160051c820191505b81811015614e2457828155600101614e11565b5050505b505050565b815167ffffffffffffffff811115614e4757614e476149bc565b614e5b81614e558454614cf1565b84614ddc565b602080601f831160018114614eae5760008415614e785750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555614e24565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015614efb57888601518255948401946001909101908401614edc565b5085821015614f3757878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215614f5957600080fd5b815160ff8116811461171057600080fd5b600060208284031215614f7c57600080fd5b815161171081614c8d565b8082028115828204841417610e0257610e02614d44565b600082600f0b82600f0b0280600f0b9150808214614fbe57614fbe614d44565b5092915050565b600f82810b9082900b037fffffffffffffffffffffffffffffffff8000000000000000000000000000000081126f7fffffffffffffffffffffffffffffff82131715610e0257610e02614d44565b600f81810b9083900b016f7fffffffffffffffffffffffffffffff81137fffffffffffffffffffffffffffffffff8000000000000000000000000000000082121715610e0257610e02614d44565b60006001600160801b038084168061507b5761507b614d86565b92169190910492915050565b6001600160801b03818116838216028082169190828114610ef357610ef3614d44565b6001600160801b03818116838216019080821115614fbe57614fbe614d44565b6000602082840312156150dc57600080fd5b5051919050565b60ff8181168382160190811115610e0257610e02614d44565b6001600160801b03828116828216039080821115614fbe57614fbe614d44565b60ff8281168282160390811115610e0257610e02614d44565b600081600f0b83600f0b8061514c5761514c614d86565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81147fffffffffffffffffffffffffffffffff80000000000000000000000000000000831416156151a0576151a0614d44565b9005939250505056fea26469706673582212201b76b1d1b061cfb15f3fd9d95a7e40191295fadef4116f958e15edbd2a1bc2a964736f6c63430008170033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106104f95760003560e01c80637c10d93a116102a1578063c3ad89561161016b578063e7ee4b79116100e3578063f851a44011610097578063fb2bc0b71161007c578063fb2bc0b714610dd2578063fc0c546a14610dda578063fc26cf3414610ded57600080fd5b8063f851a44014610db2578063f894648514610dc557600080fd5b8063ed669886116100c8578063ed66988614610d51578063ee1f785b14610d64578063f52a36f714610d8f57600080fd5b8063e7ee4b7914610652578063e97d35ae14610d3e57600080fd5b8063d72142131161013a578063dd764abf1161011f578063dd764abf14610d0c578063e13d7f9814610d18578063e1cebf0b14610d2b57600080fd5b8063d721421314610cfc578063d8399b7d14610d0457600080fd5b8063c3ad895614610ca7578063c67d526a14610caf578063cb3632d114610cb7578063d41a464114610cca57600080fd5b8063981b24d011610219578063b9ef0830116101cd578063bf7bab73116101b2578063bf7bab7314610c4b578063c052580714610c8c578063c2c4c5c114610c9f57600080fd5b8063b9ef083014610c0f578063bd85b03914610c3857600080fd5b8063a15d874a116101fe578063a15d874a14610bc4578063b0a0d79914610bd7578063b187bd2614610bea57600080fd5b8063981b24d014610b3657806399e9c19b14610b4957600080fd5b80638ad4c44711610270578063900cf0cf11610255578063900cf0cf14610b12578063929edf4514610b1b57806395d89b4114610b2e57600080fd5b80638ad4c44714610abc5780638b2e014e14610aff57600080fd5b80637c10d93a14610a5c57806386f9c86414610a7e57806387096bc014610a86578063890b4cfc14610aa957600080fd5b80634957e892116103e257806354fd4d501161035a5780636e083e7f1161030e57806377bc368c116102f357806377bc368c146109db5780637aa9b55614610a365780637b37110714610a5457600080fd5b80636e083e7f1461099557806370a08231146109c857600080fd5b80635ae3afa71161033f5780635ae3afa7146109445780635f96d4e71461095757806366d6bff91461098257600080fd5b806354fd4d50146109295780635552823c1461093157600080fd5b80634f8ab24f116103b157806350bb3fa41161039657806350bb3fa41461085e578063520221e9146108bf57806353974fcf146108ca57600080fd5b80634f8ab24f146108285780634fd9d1e01461083b57600080fd5b80634957e892146107885780634cb654af146107e05780634eb99c2d1461080b5780634ee2cd7e1461081557600080fd5b80632394c386116104755780633f2f5ee21161044457806346190ec41161042957806346190ec414610742578063466003b2146107625780634834d0891461077557600080fd5b80633f2f5ee2146106ab5780634545304a146106be57600080fd5b80632394c38614610652578063313ce5671461066c57806338dbff66146106755780633b9a760c1461068857600080fd5b80630e058678116104cc578063145925b6116104b1578063145925b6146105a857806318160ddd146105b757806321c984e9146105bf57600080fd5b80630e05867814610580578063111aa3991461059357600080fd5b806302387a7b146104fe578063047fc9aa146105245780630536a6081461052d57806306fdde031461056b575b600080fd5b61051161050c366004614847565b610df5565b6040519081526020015b60405180910390f35b61051160035481565b61055b61053b366004614879565b600760209081526000928352604080842090915290825290205460ff1681565b604051901515815260200161051b565b610573610e08565b60405161051b91906148a3565b61051161058e366004614879565b610e96565b6105a66105a1366004614910565b610efb565b005b610511670de0b6b3a764000081565b610511611136565b6106306105cd36600461494c565b6001600160a01b039091166000908152600460209081526040808320600583528184206001600160801b0395861685528352818420548452825291829020825180840190935254600f81900b808452600160801b90910490931691018190529091565b60408051600f9390930b83526001600160801b0390911660208301520161051b565b61065a600881565b60405160ff909116815260200161051b565b61051160155481565b61051161068336600461497f565b611146565b61065a6106963660046149a1565b60096020526000908152604090205460ff1681565b6105a66106b9366004614a96565b6111c3565b6107126106cc366004614b40565b600e6020908152600093845260408085208252928452828420905282529020805460018201546002830154600390930154600f83810b94600160801b909404900b929085565b60408051600f96870b81529490950b6020850152938301919091526060820152608081019190915260a00161051b565b6105116107503660046149a1565b600a6020526000908152604090205481565b6105a6610770366004614879565b6113cf565b610511610783366004614b85565b6114f8565b61079b610796366004614879565b611663565b60405161051b9190815181526020808301516001600160801b0390811691830191909152604080840151600f0b90830152606092830151169181019190915260800190565b6017546107f3906001600160a01b031681565b6040516001600160a01b03909116815260200161051b565b61051162093a8081565b610511610823366004614879565b611704565b610511610836366004614c15565b611717565b61055b6108493660046149a1565b60186020526000908152604090205460ff1681565b61063061086c366004614879565b6001600160a01b0391909116600090815260046020908152604080832093835292815290829020825180840190935254600f81900b808452600160801b9091046001600160801b03169290910182905291565b610511630784ce0081565b6105116108d8366004614c2e565b6001600160a01b03831660008181526005602090815260408083206001600160801b0387168452825280832054938352600e8252808320938352928152828220848352905220600101549392505050565b6105736117c0565b6105a661093f3660046149a1565b6117cd565b610511610952366004614b40565b61187e565b61051161096536600461494c565b600560209081526000928352604080842090915290825290205481565b6001546107f3906001600160a01b031681565b6109a86109a3366004614879565b611938565b604080516001600160801b0393841681529290911660208301520161051b565b6105116109d63660046149a1565b6119e6565b6109ee6109e9366004614c2e565b6119f2565b60405161051b9190600060a0820190508251600f0b82526020830151600f0b602083015260408301516040830152606083015160608301526080830151608083015292915050565b610a41630784ce0081565b604051600f9190910b815260200161051b565b6105a6611abc565b610a6662093a8081565b6040516001600160801b03909116815260200161051b565b6105a6611bb3565b61065a610a943660046149a1565b60086020526000908152604090205460ff1681565b610511610ab7366004614c2e565b611c89565b610712610aca366004614c15565b600d602052600090815260409020805460018201546002830154600390930154600f83810b94600160801b909404900b929085565b610511610b0d366004614879565b611e51565b610511600c5481565b6105a6610b29366004614c6a565b611eae565b6105736120bd565b610511610b44366004614c15565b6120ca565b610a41610b5736600461494c565b6001600160a01b03821660008181526005602090815260408083206001600160801b0386168452825280832054848452600f808452828520828652845282852054958552600e845282852091855290835281842094845293909152902054600160801b9004900b92915050565b6109ee610bd236600461494c565b6122a0565b610a66610be5366004614879565b61237e565b60015461055b9074010000000000000000000000000000000000000000900460ff1681565b610a66610c1d3660046149a1565b600b602052600090815260409020546001600160801b031681565b610511610c46366004614c15565b612418565b610630610c59366004614879565b6004602090815260009283526040808420909152908252902054600f81900b90600160801b90046001600160801b031682565b6105a6610c9a366004614c9e565b61251d565b6105a66125de565b6105116126ac565b6109a8612732565b610511610cc53660046149a1565b612789565b610cdd610cd8366004614910565b612821565b604080516001600160801b03909316835260208301919091520161051b565b6109ee612df8565b6105a6612e8c565b61051164e8d4a5100081565b6105a6610d26366004614cd5565b612f63565b6105a6610d393660046149a1565b6131e0565b610511610d4c366004614c2e565b61328a565b610511610d5f36600461494c565b613629565b610511610d72366004614879565b600f60209081526000928352604080842090915290825290205481565b610a41610d9d366004614c15565b601060205260009081526040902054600f0b81565b6016546107f3906001600160a01b031681565b60115461055b9060ff1681565b610511600381565b6002546107f3906001600160a01b031681565b610a41600381565b6000610e0233338461368c565b92915050565b60128054610e1590614cf1565b80601f0160208091040260200160405190810160405280929190818152602001828054610e4190614cf1565b8015610e8e5780601f10610e6357610100808354040283529160200191610e8e565b820191906000526020600020905b815481529060010190602001808311610e7157829003601f168201915b505050505081565b6001600160a01b0382166000908152600b60205260408120546001600160801b0316815b816001600160801b0316816001600160801b03161015610ef357610edf85828661328a565b610ee99084614d73565b9250600101610eba565b505092915050565b600260005403610f6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b600260005560015474010000000000000000000000000000000000000000900460ff1615610fc6576040517f6087c16000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b64e8d4a51000821015611005576040517f24c09d8600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03831660008181526005602090815260408083206001600160801b038616845282528083205493835260048252808320848452909152812080549091600f9190910b13611085576040517f4331e8f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805442600160801b9091046001600160801b0316116110d0576040517ff6fafba000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03851660009081526004602090815260408083208584528252808320815180830190925254600f81900b8252600160801b90046001600160801b03169181019190915261112a9187918791908188613c88565b50506001600055505050565b600061114142612418565b905090565b6000808281805b60808110156111b857828410156111b857600261116a8486614d73565b611175906001614d73565b61117f9190614db5565b6000818152600d602052604090206002015490925087106111a2578193506111b0565b6111ad600183614dc9565b92505b60010161114d565b509195945050505050565b6001600160a01b03841615806111e357506002546001600160a01b031615155b1561121a576040517fd08e7ac200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601680547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0387161790556000808052600d602052437f81955a0a11e65eac625c29e8882660bae4e165a75d72780094acae8ece9a29f055427f81955a0a11e65eac625c29e8882660bae4e165a75d72780094acae8ece9a29ef557f81955a0a11e65eac625c29e8882660bae4e165a75d72780094acae8ece9a29f15560126112cb8482614e2d565b5060136112d88382614e2d565b5060146112e58282614e2d565b506000846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611326573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134a9190614f47565b60ff16905060ff81111561138a576040517ff20f57e600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03969096169590951790945550505060ff1660155550565b6016546001600160a01b03163314611413576040517fc15c60b400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002546001600160a01b039081169083160361145b576040517fab6e4ba600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6016546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152602481018390529083169063a9059cbb906044016020604051808303816000875af11580156114c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114eb9190614f6a565b6114f457600080fd5b5050565b60115460009060ff16156115155761150e6126ac565b9050610e02565b6000839050600062093a808083604001516115309190614db5565b61153a9190614f87565b9050838260400151111561157a576040517fb7d0949700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b60ff8110156116235761159362093a8083614d73565b91506000858311156115a7578592506115bb565b50600082815260106020526040902054600f0b5b60408401516115ca9084614dc9565b84602001516115d99190614f9e565b845185906115e8908390614fc5565b600f0b9052508583036115fb5750611623565b808460200181815161160d9190615013565b600f0b905250506040830182905260010161157d565b5060008260000151600f0b121561163957600082525b815160808301516001600160801b039091169081101561165a575060808201515b95945050505050565b6040805160808101825260008082526020808301829052828401829052606083018290526001600160a01b038616825260048152838220858352815290839020835180850190945254600f81900b8452600160801b90046001600160801b031690830152828152906116d5848461237e565b6001600160801b039081166020808501919091528251600f0b6040850152919091015116606082015292915050565b60006117108383610e96565b9392505050565b600043821115611753576040517f4e47846c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061176183600c54611146565b6000908152600d6020908152604091829020825160a0810184528154600f81810b8352600160801b909104900b928101929092526001810154928201929092526002820154606082015260039091015460809091018190529392505050565b60148054610e1590614cf1565b6016546001600160a01b03163314611811576040517fc15c60b400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f5bba814e5109ccee62df0b8a64259cfad631da3f947b48938174f31284263d75906020015b60405180910390a150565b6001600160a01b0383166000908152600f60209081526040808320858452909152812054815b608081101561192f578183101561192f57600060026118c38486614d73565b6118ce906001614d73565b6118d89190614db5565b6001600160a01b0388166000908152600e602090815260408083208a84528252808320848452909152902060010154909150851061191857809350611926565b611923600182614dc9565b92505b506001016118a4565b50509392505050565b6001600160a01b0382166000908152600460209081526040808320848452909152812054819062093a809061197e908290600160801b90046001600160801b0316615061565b6119889190615087565b6119959062093a806150aa565b915062093a806119a9630784ce00426150aa565b6119b69062093a80615087565b6119c09190615061565b9050806001600160801b0316826001600160801b0316106119df578091505b9250929050565b6000610e028242611e51565b611a2a6040518060a001604052806000600f0b81526020016000600f0b81526020016000815260200160008152602001600081525090565b506001600160a01b0390921660008181526005602090815260408083206001600160801b03909516835293815283822054928252600e815283822092825291825282812093815292815291819020815160a0810183528154600f81810b8352600160801b909104900b938101939093526001810154918301919091526002810154606083015260030154608082015290565b6017546001600160a01b03163314611b00576040517f0f89263400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6017546001600160a01b031680611b43576040517fe2db036000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601680546001600160a01b0383167fffffffffffffffffffffffff000000000000000000000000000000000000000091821681179092556017805490911690556040519081527febee2d5739011062cb4f14113f3b36bf0ffe3da5c0568f64189d1012a118910590602001611873565b6016546001600160a01b03163314611bf7576040517fc15c60b400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001805460ff7401000000000000000000000000000000000000000080830482161581027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff90931692909217928390556040517f79734b6e7debe05b78de4a5258ce230a8990ca364a016f0fbeabb8e6ca93394f93611c7f9390049091161515815260200190565b60405180910390a1565b60115460009060ff1615611cdc57506001600160a01b0383166000908152600460209081526040808320600583528184206001600160801b03808816865290845282852054855292529091205416611710565b8115611ce85781611cea565b425b6001600160a01b03851660009081526005602090815260408083206001600160801b0388168452909152812054919350611d2586838661187e565b905080600003611d3a57600092505050611710565b611d726040518060a001604052806000600f0b81526020016000600f0b81526020016000815260200160008152602001600081525090565b506001600160a01b0386166000908152600e602090815260408083208584528252808320848452825291829020825160a0810184528154600f81810b8352600160801b909104900b9281019290925260018101549282018390526002810154606083015260030154608082015290611dea9086614dc9565b8160200151611df99190614f9e565b81518290611e08908390614fc5565b600f90810b90915282516000910b12159050611e2357600081525b80600001516001600160801b031693508060800151841015611e4757806080015193505b5050509392505050565b6001600160a01b0382166000908152600b60205260408120546001600160801b0316815b816001600160801b0316816001600160801b03161015610ef357611e9a858286611c89565b611ea49084614d73565b9250600101611e75565b600260005403611f1a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610f63565b600260005560015474010000000000000000000000000000000000000000900460ff1615611f74576040517f6087c16000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b64e8d4a51000821015611fb3576040517f24c09d8600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360008181526005602090815260408083206001600160801b038616845282528083205493835260048252808320848452909152812080549091600f9190910b1361202a576040517f4331e8f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160801b03428116600160801b9092041611612077576040517ff6fafba000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518082019091528154600f81900b8252600160801b90046001600160801b031660208201526120b29033908690600090600288613c88565b505060016000555050565b60138054610e1590614cf1565b600043821115612106576040517f4e47846c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061211483600c54611146565b6000818152600d60209081526040808320815160a0810183528154600f81810b8352600160801b909104900b9381019390935260018101549183019190915260028101546060830152600301546080820152600c549293509183101561223d576000600d81612184866001614d73565b81526020808201929092526040908101600020815160a0810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600281015460608084018290526003909201546080840152908501519192501461223757826060015181606001516121fd9190614dc9565b836040015182604001516122119190614dc9565b60608501516122209089614dc9565b61222a9190614f87565b6122349190614db5565b91505b5061228c565b4382606001511461228c5760608201516122579043614dc9565b60408301516122669042614dc9565b60608401516122759088614dc9565b61227f9190614f87565b6122899190614db5565b90505b61165a828284604001516107839190614d73565b6122d86040518060a001604052806000600f0b81526020016000600f0b81526020016000815260200160008152602001600081525090565b506001600160a01b0390911660008181526005602090815260408083206001600160801b03909516835293815283822054838352600f808352858420828552835285842054948452600e835285842091845290825284832093835292815290839020835160a081018552815480850b8252600160801b900490930b9183019190915260018101549282019290925260028201546060820152600390910154608082015290565b6001600160a01b038216600090815260066020908152604080832084845282528083208151606081018352815481526001909101546001600160801b03811693820193909352600160801b90920460ff16151590820181905261240d576040517f8417403400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602001519392505050565b60115460009060ff161561242e57610e026126ac565b811561243a578161243c565b425b600c5490925060009081805b60808110156124b357828410156124b35760026124658486614d73565b612470906001614d73565b61247a9190614db5565b6000818152600d6020526040902060010154909250861061249d578193506124ab565b6124a8600183614dc9565b92505b600101612448565b506000838152600d6020908152604091829020825160a0810184528154600f81810b8352600160801b909104900b9281019290925260018101549282019290925260028201546060820152600390910154608082015261251381876114f8565b9695505050505050565b6016546001600160a01b03163314612561576040517fc15c60b400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03821660008181526018602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f1b6e6916bd76fb0e62ff02acf466a38852d02426c13ba96e69803693ac627d58910160405180910390a25050565b60015474010000000000000000000000000000000000000000900460ff1615612633576040517f6087c16000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60115460ff1615612670576040517ffcfb534f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051808201825260008082526020808301829052835180850190945281845283018190526126aa929091906001600160801b03613ef3565b565b6002546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa15801561270e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114191906150ca565b60008062093a806127438142615061565b61274d9190615087565b61275a9062093a806150aa565b915062093a808061276f630784ce00426150aa565b6127799190615061565b6127839190615087565b90509091565b6001600160a01b0381166000908152600b60205260408120546001600160801b0316815b816001600160801b0316816001600160801b0316101561281a576001600160a01b0384166000908152600460209081526040808320600583528184206001600160801b038087168652908452828520548552925290912054612810911684614d73565b92506001016127ad565b5050919050565b600080600260005403612890576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610f63565b600260005560015474010000000000000000000000000000000000000000900460ff16156128ea576040517f6087c16000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b64e8d4a51000841015612929576040517f24c09d8600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b0386161480159061295257503360009081526018602052604090205460ff16155b15612989576040517fe90513a400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b0386161480156129be57506001600160a01b03851660009081526008602081905260409091205460ff1610155b156129f5576040517f8d38fa5700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526018602052604090205460ff168015612a1d5750336001600160a01b03861614155b8015612a4757506001600160a01b038516600090815260096020526040902054600860ff90911610155b15612a7e576040517ffe39307800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0385166000908152600a60205260408120805460019290612aa7908490614d73565b9091555050506001600160a01b0384166000908152600a60205260408120549062093a80612ad58186615061565b612adf9190615087565b6001600160a01b03871660009081526004602090815260408083208684529091529020909150426001600160801b03831611612b47576040517f6df7c20200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b55630784ce0042614d73565b826001600160801b03161115612b97576040517ff245ec8e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0387166000818152600560209081526040808320600b80845282852080546001600160801b0390811687529285528386208a9055868652600685528386208a875285529285208981558354600191820180547fffffffffffffffffffffffffffffff00000000000000000000000000000000001691851691909117600160801b1790559585529092528054909291612c38918591166150aa565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550866001600160a01b0316336001600160a01b031603612cbe576001600160a01b0387166000908152600860205260408120805460019290612ca190849060ff166150e3565b92506101000a81548160ff021916908360ff160217905550612d54565b6001600160a01b0387166000908152600960205260408120805460019290612cea90849060ff166150e3565b825460ff9182166101009390930a9283029190920219909116179055506001600160a01b0387166000908152600760209081526040808320868452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b6040805180820182528254600f81900b82526001600160801b03600160801b90910481166020808401919091526001600160a01b038b166000908152600b9091529290922054612db8928a928a928792600191612db3918391166150fc565b613c88565b6001600160a01b0387166000908152600b6020526040902054612de6906001906001600160801b03166150fc565b60016000559792965091945050505050565b612e306040518060a001604052806000600f0b81526020016000600f0b81526020016000815260200160008152602001600081525090565b50600c546000908152600d6020908152604091829020825160a0810184528154600f81810b8352600160801b909104900b9281019290925260018101549282019290925260028201546060820152600390910154608082015290565b6016546001600160a01b03163314612ed0576040517fc15c60b400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60115460ff1615612f0d576040517ffcfb534f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040517f9961dd0c30c9f532f28144e481f13454df7edc16e55f83cdfa28cce1f3278df190600090a1565b600260005403612fcf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610f63565b600260005560015474010000000000000000000000000000000000000000900460ff1615613029576040517f6087c16000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360008181526005602090815260408083206001600160801b03861684528252808320549383526004825280832084845290915281209062093a8061306e8187615061565b6130789190615087565b825490915042600160801b9091046001600160801b0316116130c6576040517ff6fafba000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81546000600f9190910b13613107576040517f4331e8f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81546001600160801b03600160801b909104811690821611613155576040517f6df7c20200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613163630784ce0042614d73565b816001600160801b031611156131a5576040517ff245ec8e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518082019091528254600f81900b8252600160801b90046001600160801b0316602082015261112a9033906000908490600389613c88565b6016546001600160a01b03163314613224576040517fc15c60b400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f2f56810a6bf40af059b96d3aea4db54081f378029a518390491093a7b67032e990602001611873565b60115460009060ff16156132dd57506001600160a01b0383166000908152600460209081526040808320600583528184206001600160801b03808816865290845282852054855292529091205416611710565b43821115613317576040517f4e47846c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03841660008181526005602090815260408083206001600160801b0388168452825280832054938352600f8252808320848452909152812054815b60808110156133e457818310156133e457600060026133788486614d73565b613383906001614d73565b61338d9190614db5565b6001600160a01b038a166000908152600e60209081526040808320898452825280832084845290915290206002015490915087106133cd578093506133db565b6133d8600182614dc9565b92505b50600101613359565b506001600160a01b0387166000908152600e6020908152604080832086845282528083208584528252808320815160a0810183528154600f81810b8352600160801b909104900b9381019390935260018101549183019190915260028101546060830152600301546080820152600c5490916134608883611146565b6000818152600d60209081526040808320815160a0810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600281015460608301526003015460808201529192508084841015613556576000600d816134ce876001614d73565b81526020808201929092526040908101600020815160a0810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600281015460608084018290526003909201546080840152908601519192506135389190614dc9565b92508360400151816040015161354e9190614dc9565b91505061357a565b60608301516135659043614dc9565b91508260400151426135779190614dc9565b90505b604083015182156135b7578284606001518d6135969190614dc9565b6135a09084614f87565b6135aa9190614db5565b6135b49082614d73565b90505b60408701516135c69082614dc9565b87602001516135d59190614f9e565b875188906135e4908390614fc5565b600f90810b9091526080890151895190910b1215905061360a5786608001519a50613618565b86516001600160801b03169a505b505050505050505050509392505050565b60115460009060ff161561363e575042610e02565b506001600160a01b039190911660008181526005602090815260408083206001600160801b039586168452825280832054938352600482528083209383529290522054600160801b90041690565b60006002600054036136fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610f63565b600260009081556001600160a01b0385168152600b60205260409020546001600160801b039081169083161061375c576040517f7ecccce000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015474010000000000000000000000000000000000000000900460ff16156137b1576040517f6087c16000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03841660008181526005602090815260408083206001600160801b0380881685529083528184205494845260048352818420858552835292819020815180830190925254600f81900b8252600160801b90048316918101829052914216108015613825575060115460ff16155b1561385c576040517f143025ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160408051808201909152600080825260208201526001600160801b03909116935061388b87838388613ef3565b6001600160a01b0387166000908152600560209081526040808320600b90925282205482906138c5906001906001600160801b03166150fc565b6001600160801b03908116825260208083019390935260409182016000908120546001600160a01b038d16808352600586528483208c85168452808752858420839055908352600b909552928120549294509161392591600191166150fc565b6001600160801b039081168252602080830193909352604091820160009081208190556001600160a01b038c1680825260068552838220868352855283822060019081018054600160801b8e87167fffffffffffffffffffffffffffffff000000000000000000000000000000000092831617179091558a8452858420848155820180549091169055908252600b90945291822080549092916139ca918591166150fc565b82546001600160801b039182166101009390930a9283029190920219909116179055506001600160a01b038816600090815260076020908152604080832087845290915290205460ff16613a61576001600160a01b0388166000908152600860205260408120805460019290613a4490849060ff1661511c565b92506101000a81548160ff021916908360ff160217905550613aa6565b6001600160a01b0388166000908152600960205260408120805460019290613a8d90849060ff1661511c565b92506101000a81548160ff021916908360ff1602179055505b600354613ab38682614dc9565b6003556002546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b038a81166004830152602482018990529091169063a9059cbb906044016020604051808303816000875af1158015613b22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b469190614f6a565b613bac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5472616e73666572206661696c656400000000000000000000000000000000006044820152606401610f63565b60115460ff1615613bf1576040805180820182526000808252602080830182905283518085019094528184528301819052613bf1929091906001600160801b03613ef3565b604080518781524260208201526001600160a01b03808b1692908c16917ff341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567910160405180910390a36003546040805183815260208101929092527f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c910160405180910390a150506001600055509195945050505050565b60115460ff1615613cc5576040517ffcfb534f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002546040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018790526001600160a01b03909116906323b872dd906064016020604051808303816000875af1158015613d35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d599190614f6a565b613d6257600080fd5b600354604080518082019091528451600f0b81526020808601516001600160801b031690820152849190613d968883614d73565b600355805188908290613daa908390615013565b600f0b9052506001600160801b03871615613dcf576001600160801b03871660208201525b6001600160a01b0389166000908152600460209081526040808320600583528184206001600160801b03808a16865290845282852054855290835292208351918401518316600160801b0291909216179055613e2d89848387613ef3565b80602001516001600160801b0316336001600160a01b03168a6001600160a01b03167f14c0149cb9a81e88858fe68435647550d00aa572a036ef0d518745c27c61b9fc8b8942604051613e9c939291909283526001600160801b03919091166020830152604082015260600190565b60405180910390a47f5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5c82613ed08a82614d73565b6040805192835260208301919091520160405180910390a1505050505050505050565b6040805160a08082018352600080835260208084018290528385018290526060808501839052608080860184905286519485018752838552918401839052948301829052938201819052928101839052600c549192909181906001600160a01b038916156140ed574288602001516001600160801b0316118015613f7e575060008860000151600f0b135b15613fe5578751630784ce0090613f9790600390614f9e565b613fa19190615135565b600f0b602080870191909152880151613fc49042906001600160801b0316614dc9565b8560200151613fd39190614f9e565b8851613fdf9190615013565b600f0b85525b4287602001516001600160801b0316118015614008575060008760000151600f0b135b1561406f578651630784ce009061402190600390614f9e565b61402b9190615135565b600f0b60208086019190915287015161404e9042906001600160801b0316614dc9565b846020015161405d9190614f9e565b87516140699190615013565b600f0b84525b6020808901516001600160801b03908116600090815260108352604090205491890151600f9290920b945016156140ed5787602001516001600160801b031687602001516001600160801b0316036140c9578291506140ed565b6020808801516001600160801b0316600090815260109091526040902054600f0b91505b6040805160a08101825260008082526020820181905242928201929092524360608201526080810191909152811561417657506000818152600d6020908152604091829020825160a0810184528154600f81810b8352600160801b909104900b928101929092526001810154928201929092526002820154606082015260039091015460808201525b60008160400151905060006040518060a001604052808460000151600f0b81526020018460200151600f0b815260200184604001518152602001846060015181526020018460800151815250905060008360400151421115614213576141e56001600160801b03841642614dc9565b60608501516141f49043614dc9565b61420690670de0b6b3a7640000614f87565b6142109190614db5565b90505b614220838584848961451b565b93506001600160a01b038d161561436357886020015188602001516142459190614fc5565b846020018181516142569190615013565b600f0b9052508851885161426a9190614fc5565b84518590614279908390615013565b600f90810b9091528d518d5190820b910b131590506142be578b518b516142a09190614fc5565b6001600160801b0316846080018181516142ba9190614d73565b9052505b8b518b51600f91820b910b1215614336578a518c516142dd9190614fc5565b6001600160801b0316846080018181516142f79190614dc9565b9052508a51600f0b1580156143195750428c602001516001600160801b031611155b15614336578b518451859061432f908390614fc5565b600f0b9052505b60008460200151600f0b121561434e57600060208501525b60008460000151600f0b121561436357600084525b600c546000908152600d60209081526040918290208651918701516001600160801b03908116600160801b0292169190911781559085015160018201556060850151600282015560808501516003909101556001600160a01b038d161561450c57428c602001516001600160801b0316111561446b5760208901516143e89088615013565b96508b602001516001600160801b03168b602001516001600160801b03160361441d57602088015161441a9088614fc5565b96505b60208c8101516001600160801b0390811660009081526010909252604090912080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000169189169190911790555b428b602001516001600160801b03161115614501578b602001516001600160801b03168b602001516001600160801b031611156145015760208801516144b19087614fc5565b60208c8101516001600160801b0390811660009081526010909252604090912080547fffffffffffffffffffffffffffffffff000000000000000000000000000000001691831691909117905595505b61450c8d898c614738565b50505050505050505050505050565b6145536040518060a001604052806000600f0b81526020016000600f0b81526020016000815260200160008152602001600081525090565b600062093a8061456c816001600160801b038a16614db5565b6145769190614f87565b905060005b60ff81101561472a5761459162093a80836150aa565b9150600042836001600160801b031611156145ae574292506145cc565b506001600160801b038216600090815260106020526040902054600f0b5b6145d689846150fc565b88602001516145e59190614f9e565b885189906145f4908390614fc5565b600f0b90525060208801805182919061460e908390615013565b600f90810b90915289516000910b1215905061462957600088525b60008860200151600f0b121561464157600060208901525b6001600160801b0383166040808a018290528801519399508993670de0b6b3a76400009161466f9190614dc9565b614682906001600160801b038916614f87565b61468c9190614db5565b876060015161469b9190614d73565b60608901526146ab600186614d73565b9450426001600160801b0316836001600160801b0316036146d2575043606088015261472a565b6000858152600d60209081526040918290208a51918b01516001600160801b03908116600160801b0292169190911781559089015160018201556060890151600282015560808901516003909101555060010161457b565b505050600c55509092915050565b6001600160a01b03831660008181526005602090815260408083206001600160801b0386168452825280832054938352600f8252808320848452909152812054614783906001614d73565b6001600160a01b039095166000818152600f602090815260408083208684528252808320899055428882019081524360608a01908152858552600484528285208886528452828520546001600160801b0390811660808c01908152968652600e85528386209886529784528285209a85529983529220875197909101518516600160801b02969094169590951783559351600183015550925160028401555051600390910155565b80356001600160801b038116811461484257600080fd5b919050565b60006020828403121561485957600080fd5b6117108261482b565b80356001600160a01b038116811461484257600080fd5b6000806040838503121561488c57600080fd5b61489583614862565b946020939093013593505050565b60006020808352835180602085015260005b818110156148d1578581018301518582016040015282016148b5565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b60008060006060848603121561492557600080fd5b61492e84614862565b9250602084013591506149436040850161482b565b90509250925092565b6000806040838503121561495f57600080fd5b61496883614862565b91506149766020840161482b565b90509250929050565b6000806040838503121561499257600080fd5b50508035926020909101359150565b6000602082840312156149b357600080fd5b61171082614862565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f8301126149fc57600080fd5b813567ffffffffffffffff80821115614a1757614a176149bc565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715614a5d57614a5d6149bc565b81604052838152866020858801011115614a7657600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060a08688031215614aae57600080fd5b614ab786614862565b9450614ac560208701614862565b9350604086013567ffffffffffffffff80821115614ae257600080fd5b614aee89838a016149eb565b94506060880135915080821115614b0457600080fd5b614b1089838a016149eb565b93506080880135915080821115614b2657600080fd5b50614b33888289016149eb565b9150509295509295909350565b600080600060608486031215614b5557600080fd5b614b5e84614862565b95602085013595506040909401359392505050565b8035600f81900b811461484257600080fd5b60008082840360c0811215614b9957600080fd5b60a0811215614ba757600080fd5b5060405160a0810181811067ffffffffffffffff82111715614bcb57614bcb6149bc565b604052614bd784614b73565b8152614be560208501614b73565b60208201526040848101359082015260608085013590820152608080850135908201529460a09093013593505050565b600060208284031215614c2757600080fd5b5035919050565b600080600060608486031215614c4357600080fd5b614c4c84614862565b9250614c5a6020850161482b565b9150604084013590509250925092565b60008060408385031215614c7d57600080fd5b823591506149766020840161482b565b8015158114614c9b57600080fd5b50565b60008060408385031215614cb157600080fd5b614cba83614862565b91506020830135614cca81614c8d565b809150509250929050565b60008060408385031215614ce857600080fd5b6149688361482b565b600181811c90821680614d0557607f821691505b602082108103614d3e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610e0257610e02614d44565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082614dc457614dc4614d86565b500490565b81810381811115610e0257610e02614d44565b601f821115614e28576000816000526020600020601f850160051c81016020861015614e055750805b601f850160051c820191505b81811015614e2457828155600101614e11565b5050505b505050565b815167ffffffffffffffff811115614e4757614e476149bc565b614e5b81614e558454614cf1565b84614ddc565b602080601f831160018114614eae5760008415614e785750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555614e24565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015614efb57888601518255948401946001909101908401614edc565b5085821015614f3757878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215614f5957600080fd5b815160ff8116811461171057600080fd5b600060208284031215614f7c57600080fd5b815161171081614c8d565b8082028115828204841417610e0257610e02614d44565b600082600f0b82600f0b0280600f0b9150808214614fbe57614fbe614d44565b5092915050565b600f82810b9082900b037fffffffffffffffffffffffffffffffff8000000000000000000000000000000081126f7fffffffffffffffffffffffffffffff82131715610e0257610e02614d44565b600f81810b9083900b016f7fffffffffffffffffffffffffffffff81137fffffffffffffffffffffffffffffffff8000000000000000000000000000000082121715610e0257610e02614d44565b60006001600160801b038084168061507b5761507b614d86565b92169190910492915050565b6001600160801b03818116838216028082169190828114610ef357610ef3614d44565b6001600160801b03818116838216019080821115614fbe57614fbe614d44565b6000602082840312156150dc57600080fd5b5051919050565b60ff8181168382160190811115610e0257610e02614d44565b6001600160801b03828116828216039080821115614fbe57614fbe614d44565b60ff8281168282160390811115610e0257610e02614d44565b600081600f0b83600f0b8061514c5761514c614d86565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81147fffffffffffffffffffffffffffffffff80000000000000000000000000000000831416156151a0576151a0614d44565b9005939250505056fea26469706673582212201b76b1d1b061cfb15f3fd9d95a7e40191295fadef4116f958e15edbd2a1bc2a964736f6c63430008170033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in FRAX
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.