Everyday giveaways up to 100 ETH, Lucky Spins. Deposit BONUS 300% and Cashbacks!
5000+ Slots & Live Casino Games, 50+cryptos. Register with Etherscan and get 760% deposit bonus. Win Big$, withdraw it fast.
5000+ Slots & Live Casino Games, 50+cryptos. Register with Etherscan and get 760% deposit bonus. Win Big$, withdraw it fast.
Dive into 100s of games and play anonymously with major cryptos. Join CryptoWins today!
Anonymous play on awesome games - sign up now for 25 free jackpot spins - worth $100s!
Overview
ETH Balance
Eth Value
$0.00Token Holdings
Could not find any matches!
- ERC-20 Tokens (3)244,076.572801 USDCUSDC (USDC)$244,026.78@0.99983,999.99 TokenERC-20 TOKEN*[Suspicious]3,999.99 TokenERC-20 TOKEN*[Suspicious]NFT Tokens (9)claim rewards on apyusd.netapyusd.netERC-1155ether-origin.comether-origin.comERC-1155
More Info
Private Name Tags
ContractCreator
Multichain Info
- Transactions
- Internal Transactions
- Token Transfers (ERC-20)
- NFT Transfers
- Contract
- Events
- Analytics
- Multichain Portfolio
- Filter by Tx Type:
- Tx
- Internal Tx
- ERC-20
- NFTs
Transaction Hash |
Method
|
Block
|
From
|
To
|
||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
0x2af508239c60b89a93a4f23c60ab1a02a4341cc921a765af54fdee3bc73b90f5 | Claim Tokens | (pending) | 2024-11-03 22:35:27 | 28 hrs ago | 1730673327 | IN | 0 ETH$0.00 | (Pending) | (Pending) | |||
Claim Tokens | 21113629 | 2024-11-04 10:16:47 | 16 hrs ago | 1730715407 | IN | 0 ETH$0.00 | 0.00359822 | 5.86313124 | ||||
Claim Tokens | 21107723 | 2024-11-03 14:30:23 | 36 hrs ago | 1730644223 | IN | 0 ETH$0.00 | 0.00529485 | 10.63103529 | ||||
Claim Tokens | 21107715 | 2024-11-03 14:28:47 | 36 hrs ago | 1730644127 | IN | 0 ETH$0.00 | 0.01351749 | 10.0246871 | ||||
Claim Tokens | 21106317 | 2024-11-03 9:48:11 | 41 hrs ago | 1730627291 | IN | 0 ETH$0.00 | 0.00216761 | 4.23949319 | ||||
Claim Tokens | 21106309 | 2024-11-03 9:46:35 | 41 hrs ago | 1730627195 | IN | 0 ETH$0.00 | 0.00548987 | 4.18897552 | ||||
Claim Tokens | 21101463 | 2024-11-02 17:31:47 | 2 days ago | 1730568707 | IN | 0 ETH$0.00 | 0.0045246 | 14.13129902 | ||||
Claim Tokens | 21099836 | 2024-11-02 12:04:11 | 2 days ago | 1730549051 | IN | 0 ETH$0.00 | 0.00099501 | 4.62570122 | ||||
Claim Tokens | 21099719 | 2024-11-02 11:40:47 | 2 days ago | 1730547647 | IN | 0 ETH$0.00 | 0.00134803 | 5.73253117 | ||||
Claim Tokens | 21099670 | 2024-11-02 11:30:47 | 2 days ago | 1730547047 | IN | 0 ETH$0.00 | 0.00668802 | 5 | ||||
Claim Tokens | 21098753 | 2024-11-02 8:25:35 | 2 days ago | 1730535935 | IN | 0 ETH$0.00 | 0.00204252 | 3.96477471 | ||||
Claim Tokens | 21098540 | 2024-11-02 7:42:35 | 2 days ago | 1730533355 | IN | 0 ETH$0.00 | 0.00343624 | 3.60085734 | ||||
Claim Tokens | 21095381 | 2024-11-01 21:07:11 | 3 days ago | 1730495231 | IN | 0 ETH$0.00 | 0.00571504 | 6.46482759 | ||||
Claim Tokens | 21095245 | 2024-11-01 20:39:59 | 3 days ago | 1730493599 | IN | 0 ETH$0.00 | 0.00415796 | 5.86702864 | ||||
Claim Tokens | 21095012 | 2024-11-01 19:52:59 | 3 days ago | 1730490779 | IN | 0 ETH$0.00 | 0.00189657 | 6.23584828 | ||||
Checkpoint User | 21094750 | 2024-11-01 19:00:23 | 3 days ago | 1730487623 | IN | 0 ETH$0.00 | 0.0015124 | 7.22780594 | ||||
Claim Tokens | 21088408 | 2024-10-31 21:47:35 | 4 days ago | 1730411255 | IN | 0 ETH$0.00 | 0.00529936 | 6.49262533 | ||||
Claim Tokens | 21087006 | 2024-10-31 17:06:23 | 4 days ago | 1730394383 | IN | 0 ETH$0.00 | 0.0288585 | 21.27483502 | ||||
Claim Tokens | 21085573 | 2024-10-31 12:19:23 | 4 days ago | 1730377163 | IN | 0 ETH$0.00 | 0.00216322 | 10.056618 | ||||
Claim Tokens | 21085568 | 2024-10-31 12:18:23 | 4 days ago | 1730377103 | IN | 0 ETH$0.00 | 0.00458319 | 9.20194017 | ||||
Claim Tokens | 21085525 | 2024-10-31 12:09:47 | 4 days ago | 1730376587 | IN | 0 ETH$0.00 | 0.01260452 | 7.93450508 | ||||
Claim Tokens | 21079526 | 2024-10-30 16:04:47 | 5 days ago | 1730304287 | IN | 0 ETH$0.00 | 0.0239091 | 25.32553595 | ||||
Claim Tokens | 21074814 | 2024-10-30 0:15:11 | 6 days ago | 1730247311 | IN | 0 ETH$0.00 | 0.01233523 | 9.19363287 | ||||
Claim Tokens | 21074318 | 2024-10-29 22:35:47 | 6 days ago | 1730241347 | IN | 0 ETH$0.00 | 0.00686319 | 8.06196247 | ||||
Claim Tokens | 21071051 | 2024-10-29 11:39:59 | 6 days ago | 1730201999 | IN | 0 ETH$0.00 | 0.00792606 | 6.86821314 |
View more zero value Internal Transactions in Advanced View mode
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; import "@openzeppelin-solc-0.7/contracts/utils/ReentrancyGuard.sol"; import "@openzeppelin-solc-0.7/contracts/math/Math.sol"; import "@openzeppelin-solc-0.7/contracts/math/SafeMath.sol"; import "@openzeppelin-solc-0.7/contracts/token/ERC20/SafeERC20.sol"; import "@openzeppelin-solc-0.7/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin-solc-0.7/contracts/access/Ownable.sol"; import "./interfaces/IFeeDistributor.sol"; import "./interfaces/IVotingEscrow.sol"; // solhint-disable not-rely-on-time /** * @title Fee Distributor * @author Balancer Labs. Original version https://github.com/balancer/balancer-v2-monorepo/blob/master/pkg/liquidity-mining/contracts/fee-distribution/FeeDistributor.sol * @notice Distributes any tokens transferred to the contract (e.g. Protocol fees) among veSTG * holders proportionally based on a snapshot of the week at which the tokens are sent to the FeeDistributor contract. * @dev Supports distributing arbitrarily many different tokens. In order to start distributing a new token to veSTG holders call `depositToken`. */ contract FeeDistributor is IFeeDistributor, Ownable, ReentrancyGuard { using SafeMath for uint256; using SafeERC20 for IERC20; // gas optimization uint256 private constant WEEK_MINUS_SECOND = 1 weeks - 1; IVotingEscrow private immutable _votingEscrow; uint256 private immutable _startTime; // Global State uint256 private _timeCursor; mapping(uint256 => uint256) private _veSupplyCache; // Token State // `startTime` and `timeCursor` are both timestamps so comfortably fit in a uint64. // `cachedBalance` will comfortably fit the total supply of any meaningful token. // Should more than 2^128 tokens be sent to this contract then checkpointing this token will fail until enough // tokens have been claimed to bring the total balance back below 2^128. struct TokenState { uint64 startTime; uint64 timeCursor; uint128 cachedBalance; } mapping(IERC20 => TokenState) private _tokenState; mapping(IERC20 => mapping(uint256 => uint256)) private _tokensPerWeek; mapping(IERC20 => bool) private _tokenClaimingEnabled; // User State // `startTime` and `timeCursor` are timestamps so will comfortably fit in a uint64. // For `lastEpochCheckpointed` to overflow would need over 2^128 transactions to the VotingEscrow contract. struct UserState { uint64 startTime; uint64 timeCursor; uint128 lastEpochCheckpointed; } mapping(address => UserState) internal _userState; mapping(address => mapping(uint256 => uint256)) private _userBalanceAtTimestamp; mapping(address => mapping(IERC20 => uint256)) private _userTokenTimeCursor; mapping(address => bool) private _onlyVeHolderClaimingEnabled; /** * @dev Reverts if only the VotingEscrow holder can claim their rewards and the given address is a third-party caller. * @param user - The address to validate as the only allowed caller. */ modifier userAllowedToClaim(address user) { if (_onlyVeHolderClaimingEnabled[user]) { require(msg.sender == user, "Claiming is not allowed"); } _; } /** * @dev Reverts if the given token cannot be claimed. * @param token - The token to check. */ modifier tokenCanBeClaimed(IERC20 token) { _checkIfClaimingEnabled(token); _; } /** * @dev Reverts if the given tokens cannot be claimed. * @param tokens - The tokens to check. */ modifier tokensCanBeClaimed(IERC20[] calldata tokens) { uint256 tokensLength = tokens.length; for (uint256 i = 0; i < tokensLength; ++i) { _checkIfClaimingEnabled(tokens[i]); } _; } constructor(IVotingEscrow votingEscrow, uint256 startTime) { _votingEscrow = votingEscrow; startTime = _roundDownTimestamp(startTime); uint256 currentWeek = _roundDownTimestamp(block.timestamp); require(startTime >= currentWeek, "Cannot start before current week"); IVotingEscrow.Point memory pt = votingEscrow.point_history(0); require(startTime > pt.ts, "Cannot start before VotingEscrow first epoch"); _startTime = startTime; _timeCursor = startTime; } /** * @notice Returns the VotingEscrow (veSTG) token contract */ function getVotingEscrow() external view override returns (IVotingEscrow) { return _votingEscrow; } /** * @notice Returns the time when fee distribution starts. */ function getStartTime() external view override returns (uint256) { return _startTime; } /** * @notice Returns the global time cursor representing the most earliest uncheckpointed week. */ function getTimeCursor() external view override returns (uint256) { return _timeCursor; } /** * @notice Returns the user-level start time representing the first week they're eligible to claim tokens. * @param user - The address of the user to query. */ function getUserStartTime(address user) external view override returns (uint256) { return _userState[user].startTime; } /** * @notice Returns the user-level time cursor representing the most earliest uncheckpointed week. * @param user - The address of the user to query. */ function getUserTimeCursor(address user) external view override returns (uint256) { return _userState[user].timeCursor; } /** * @notice Returns the user-level last checkpointed epoch. * @param user - The address of the user to query. */ function getUserLastEpochCheckpointed(address user) external view override returns (uint256) { return _userState[user].lastEpochCheckpointed; } /** * @notice True if the given token can be claimed, false otherwise. * @param token - The ERC20 token address to query. */ function canTokenBeClaimed(IERC20 token) external view override returns (bool) { return _tokenClaimingEnabled[token]; } /** * @notice Returns the token-level start time representing the timestamp users could start claiming this token * @param token - The ERC20 token address to query. */ function getTokenStartTime(IERC20 token) external view override returns (uint256) { return _tokenState[token].startTime; } /** * @notice Returns the token-level time cursor storing the timestamp at up to which tokens have been distributed. * @param token - The ERC20 token address to query. */ function getTokenTimeCursor(IERC20 token) external view override returns (uint256) { return _tokenState[token].timeCursor; } /** * @notice Returns the token-level cached balance. * @param token - The ERC20 token address to query. */ function getTokenCachedBalance(IERC20 token) external view override returns (uint256) { return _tokenState[token].cachedBalance; } /** * @notice Returns the user-level time cursor storing the timestamp of the latest token distribution claimed. * @param user - The address of the user to query. * @param token - The ERC20 token address to query. */ function getUserTokenTimeCursor(address user, IERC20 token) external view override returns (uint256) { return _getUserTokenTimeCursor(user, token); } /** * @notice Returns the user's cached balance of veSTG as of the provided timestamp. * @dev Only timestamps which fall on Thursdays 00:00:00 UTC will return correct values. * This function requires `user` to have been checkpointed past `timestamp` so that their balance is cached. * @param user - The address of the user of which to read the cached balance of. * @param timestamp - The timestamp at which to read the `user`'s cached balance at. */ function getUserBalanceAtTimestamp(address user, uint256 timestamp) external view override returns (uint256) { return _userBalanceAtTimestamp[user][timestamp]; } /** * @notice Returns the cached total supply of veSTG as of the provided timestamp. * @dev Only timestamps which fall on Thursdays 00:00:00 UTC will return correct values. * This function requires the contract to have been checkpointed past `timestamp` so that the supply is cached. * @param timestamp - The timestamp at which to read the cached total supply at. */ function getTotalSupplyAtTimestamp(uint256 timestamp) external view override returns (uint256) { return _veSupplyCache[timestamp]; } /** * @notice Returns the FeeDistributor's cached balance of `token`. */ function getTokenLastBalance(IERC20 token) external view override returns (uint256) { return _tokenState[token].cachedBalance; } /** * @notice Returns the amount of `token` which the FeeDistributor received in the week beginning at `timestamp`. * @param token - The ERC20 token address to query. * @param timestamp - The timestamp corresponding to the beginning of the week of interest. */ function getTokensDistributedInWeek(IERC20 token, uint256 timestamp) external view override returns (uint256) { return _tokensPerWeek[token][timestamp]; } // Preventing third-party claiming /** * @notice Enables / disables rewards claiming only by the VotingEscrow holder for the message sender. * @param enabled - True if only the VotingEscrow holder can claim their rewards, false otherwise. */ function enableOnlyVeHolderClaiming(bool enabled) external override { _onlyVeHolderClaimingEnabled[msg.sender] = enabled; emit OnlyVeHolderClaimingEnabled(msg.sender, enabled); } /** * @notice Returns true if only the VotingEscrow holder can claim their rewards, false otherwise. */ function onlyVeHolderClaimingEnabled(address user) external view override returns (bool) { return _onlyVeHolderClaimingEnabled[user]; } // Depositing /** * @notice Deposits tokens to be distributed in the current week. * @dev Sending tokens directly to the FeeDistributor instead of using `depositToken` may result in tokens being * retroactively distributed to past weeks, or for the distribution to carry over to future weeks. * * If for some reason `depositToken` cannot be called, in order to ensure that all tokens are correctly distributed * manually call `checkpointToken` before and after the token transfer. * @param token - The ERC20 token address to distribute. * @param amount - The amount of tokens to deposit. */ function depositToken(IERC20 token, uint256 amount) external override nonReentrant tokenCanBeClaimed(token) { _checkpointToken(token, false); token.safeTransferFrom(msg.sender, address(this), amount); _checkpointToken(token, true); } /** * @notice Deposits tokens to be distributed in the current week. * @dev A version of `depositToken` which supports depositing multiple `tokens` at once. * See `depositToken` for more details. * @param tokens - An array of ERC20 token addresses to distribute. * @param amounts - An array of token amounts to deposit. */ function depositTokens(IERC20[] calldata tokens, uint256[] calldata amounts) external override nonReentrant { require(tokens.length == amounts.length, "Input length mismatch"); uint256 length = tokens.length; for (uint256 i = 0; i < length; ++i) { _checkIfClaimingEnabled(tokens[i]); _checkpointToken(tokens[i], false); tokens[i].safeTransferFrom(msg.sender, address(this), amounts[i]); _checkpointToken(tokens[i], true); } } // Checkpointing /** * @notice Caches the total supply of veSTG at the beginning of each week. * This function will be called automatically before claiming tokens to ensure the contract is properly updated. */ function checkpoint() external override nonReentrant { _checkpointTotalSupply(); } /** * @notice Caches the user's balance of veSTG at the beginning of each week. * This function will be called automatically before claiming tokens to ensure the contract is properly updated. * @param user - The address of the user to be checkpointed. */ function checkpointUser(address user) external override nonReentrant { _checkpointUserBalance(user); } /** * @notice Assigns any newly-received tokens held by the FeeDistributor to weekly distributions. * @dev Any `token` balance held by the FeeDistributor above that which is returned by `getTokenLastBalance` * will be distributed evenly across the time period since `token` was last checkpointed. * * This function will be called automatically before claiming tokens to ensure the contract is properly updated. * @param token - The ERC20 token address to be checkpointed. */ function checkpointToken(IERC20 token) external override nonReentrant tokenCanBeClaimed(token) { _checkpointToken(token, true); } /** * @notice Assigns any newly-received tokens held by the FeeDistributor to weekly distributions. * @dev A version of `checkpointToken` which supports checkpointing multiple tokens. * See `checkpointToken` for more details. * @param tokens - An array of ERC20 token addresses to be checkpointed. */ function checkpointTokens(IERC20[] calldata tokens) external override nonReentrant { uint256 tokensLength = tokens.length; for (uint256 i = 0; i < tokensLength; ++i) { _checkIfClaimingEnabled(tokens[i]); _checkpointToken(tokens[i], true); } } // Claiming /** * @notice Claims all pending distributions of the provided token for a user. * @dev It's not necessary to explicitly checkpoint before calling this function, it will ensure the FeeDistributor * is up to date before calculating the amount of tokens to be claimed. * @param user - The user on behalf of which to claim. * @param token - The ERC20 token address to be claimed. * @return The amount of `token` sent to `user` as a result of claiming. */ function claimToken(address user, IERC20 token) external override nonReentrant userAllowedToClaim(user) tokenCanBeClaimed(token) returns (uint256) { _checkpointTotalSupply(); _checkpointUserBalance(user); _checkpointToken(token, false); return _claimToken(user, token); } /** * @notice Claims a number of tokens on behalf of a user. * @dev A version of `claimToken` which supports claiming multiple `tokens` on behalf of `user`. * See `claimToken` for more details. * @param user - The user on behalf of which to claim. * @param tokens - An array of ERC20 token addresses to be claimed. * @return An array of the amounts of each token in `tokens` sent to `user` as a result of claiming. */ function claimTokens(address user, IERC20[] calldata tokens) external override nonReentrant userAllowedToClaim(user) tokensCanBeClaimed(tokens) returns (uint256[] memory) { _checkpointTotalSupply(); _checkpointUserBalance(user); uint256 tokensLength = tokens.length; uint256[] memory amounts = new uint256[](tokensLength); for (uint256 i = 0; i < tokensLength; ++i) { _checkpointToken(tokens[i], false); amounts[i] = _claimToken(user, tokens[i]); } return amounts; } // Governance /** * @notice Withdraws the specified `amount` of the `token` from the contract to the `recipient`. Can be called only by Stargate DAO. * @param token - The token to withdraw. * @param amount - The amount to withdraw. * @param recipient - The address to transfer the tokens to. */ function withdrawToken(IERC20 token, uint256 amount, address recipient) external override onlyOwner { token.safeTransfer(recipient, amount); emit TokenWithdrawn(token, amount, recipient); } /** * @notice Enables or disables claiming of the given token. Can be called only by Stargate DAO. * @param token - The token to enable or disable claiming. * @param enable - True if the token can be claimed, false otherwise. */ function enableTokenClaiming(IERC20 token, bool enable) external override onlyOwner { _tokenClaimingEnabled[token] = enable; emit TokenClaimingEnabled(token, enable); } // Internal functions /** * @dev It is required that both the global, token and user state have been properly checkpointed * before calling this function. */ function _claimToken(address user, IERC20 token) internal returns (uint256) { TokenState storage tokenState = _tokenState[token]; uint256 nextUserTokenWeekToClaim = _getUserTokenTimeCursor(user, token); // The first week which cannot be correctly claimed is the earliest of: // - A) The global or user time cursor (whichever is earliest), rounded up to the end of the week. // - B) The token time cursor, rounded down to the beginning of the week. // // This prevents the two failure modes: // - A) A user may claim a week for which we have not processed their balance, resulting in tokens being locked. // - B) A user may claim a week which then receives more tokens to be distributed. However the user has // already claimed for that week so their share of these new tokens are lost. uint256 firstUnclaimableWeek = Math.min(_roundUpTimestamp(Math.min(_timeCursor, _userState[user].timeCursor)), _roundDownTimestamp(tokenState.timeCursor)); mapping(uint256 => uint256) storage tokensPerWeek = _tokensPerWeek[token]; mapping(uint256 => uint256) storage userBalanceAtTimestamp = _userBalanceAtTimestamp[user]; uint256 amount; for (uint256 i = 0; i < 20; ++i) { // We clearly cannot claim for `firstUnclaimableWeek` and so we break here. if (nextUserTokenWeekToClaim >= firstUnclaimableWeek) break; amount += (tokensPerWeek[nextUserTokenWeekToClaim] * userBalanceAtTimestamp[nextUserTokenWeekToClaim]) / _veSupplyCache[nextUserTokenWeekToClaim]; nextUserTokenWeekToClaim += 1 weeks; } // Update the stored user-token time cursor to prevent this user claiming this week again. _userTokenTimeCursor[user][token] = nextUserTokenWeekToClaim; if (amount > 0) { // For a token to be claimable it must have been added to the cached balance so this is safe. tokenState.cachedBalance = uint128(tokenState.cachedBalance - amount); token.safeTransfer(user, amount); emit TokensClaimed(user, token, amount, nextUserTokenWeekToClaim); } return amount; } /** * @dev Calculate the amount of `token` to be distributed to `_votingEscrow` holders since the last checkpoint. */ function _checkpointToken(IERC20 token, bool force) internal { TokenState storage tokenState = _tokenState[token]; uint256 lastTokenTime = tokenState.timeCursor; uint256 timeSinceLastCheckpoint; if (lastTokenTime == 0) { // Prevent someone from assigning tokens to an inaccessible week. require(block.timestamp > _startTime, "Fee distribution has not started yet"); // If it's the first time we're checkpointing this token then start distributing from now. // Also mark at which timestamp users should start attempts to claim this token from. lastTokenTime = block.timestamp; tokenState.startTime = uint64(_roundDownTimestamp(block.timestamp)); } else { timeSinceLastCheckpoint = block.timestamp - lastTokenTime; if (!force) { // Checkpointing N times within a single week is completely equivalent to checkpointing once at the end. // We then want to get as close as possible to a single checkpoint every Wed 23:59 UTC to save gas. // We then skip checkpointing if we're in the same week as the previous checkpoint. bool alreadyCheckpointedThisWeek = _roundDownTimestamp(block.timestamp) == _roundDownTimestamp(lastTokenTime); // However we want to ensure that all of this week's fees are assigned to the current week without // overspilling into the next week. To mitigate this, we checkpoint if we're near the end of the week. bool nearingEndOfWeek = _roundUpTimestamp(block.timestamp) - block.timestamp < 1 days; // This ensures that we checkpoint once at the beginning of the week and again for each user interaction // towards the end of the week to give an accurate final reading of the balance. if (alreadyCheckpointedThisWeek && !nearingEndOfWeek) { return; } } } tokenState.timeCursor = uint64(block.timestamp); uint256 tokenBalance = token.balanceOf(address(this)); uint256 newTokensToDistribute = tokenBalance.sub(tokenState.cachedBalance); if (newTokensToDistribute == 0) return; require(tokenBalance <= type(uint128).max, "Maximum token balance exceeded"); tokenState.cachedBalance = uint128(tokenBalance); uint256 firstIncompleteWeek = _roundDownTimestamp(lastTokenTime); uint256 nextWeek = 0; // Distribute `newTokensToDistribute` evenly across the time period from `lastTokenTime` to now. // These tokens are assigned to weeks proportionally to how much of this period falls into each week. mapping(uint256 => uint256) storage tokensPerWeek = _tokensPerWeek[token]; for (uint256 i = 0; i < 20; ++i) { // This is safe as we're incrementing a timestamp. nextWeek = firstIncompleteWeek + 1 weeks; if (block.timestamp < nextWeek) { // `firstIncompleteWeek` is now the beginning of the current week, i.e. this is the final iteration. if (timeSinceLastCheckpoint == 0 && block.timestamp == lastTokenTime) { tokensPerWeek[firstIncompleteWeek] += newTokensToDistribute; } else { // block.timestamp >= lastTokenTime by definition. tokensPerWeek[firstIncompleteWeek] += (newTokensToDistribute * (block.timestamp - lastTokenTime)) / timeSinceLastCheckpoint; } // As we've caught up to the present then we should now break. break; } else { // We've gone a full week or more without checkpointing so need to distribute tokens to previous weeks. if (timeSinceLastCheckpoint == 0 && nextWeek == lastTokenTime) { // It shouldn't be possible to enter this block tokensPerWeek[firstIncompleteWeek] += newTokensToDistribute; } else { // nextWeek > lastTokenTime by definition. tokensPerWeek[firstIncompleteWeek] += (newTokensToDistribute * (nextWeek - lastTokenTime)) / timeSinceLastCheckpoint; } } // We've now "checkpointed" up to the beginning of next week so must update timestamps appropriately. lastTokenTime = nextWeek; firstIncompleteWeek = nextWeek; } emit TokenCheckpointed(token, newTokensToDistribute, lastTokenTime); } /** * @dev Cache the `user`'s balance of `_votingEscrow` at the beginning of each new week */ function _checkpointUserBalance(address user) internal { uint256 maxUserEpoch = _votingEscrow.user_point_epoch(user); // If user has no epochs then they have never locked STG. // They clearly will not then receive fees. require(maxUserEpoch > 0, "veSTG balance is zero"); UserState storage userState = _userState[user]; // `nextWeekToCheckpoint` represents the timestamp of the beginning of the first week // which we haven't checkpointed the user's VotingEscrow balance yet. uint256 nextWeekToCheckpoint = userState.timeCursor; uint256 userEpoch; if (nextWeekToCheckpoint == 0) { // First checkpoint for user so need to do the initial binary search userEpoch = _findTimestampUserEpoch(user, _startTime, 0, maxUserEpoch); } else { if (nextWeekToCheckpoint >= block.timestamp) { // User has checkpointed the current week already so perform early return. // This prevents a user from processing epochs created later in this week, however this is not an issue // as if a significant number of these builds up then the user will skip past them with a binary search. return; } // Otherwise use the value saved from last time userEpoch = userState.lastEpochCheckpointed; // This optimizes a scenario common for power users, which have frequent `VotingEscrow` interactions in // the same week. We assume that any such user is also claiming fees every week, and so we only perform // a binary search here rather than integrating it into the main search algorithm, effectively skipping // most of the week's irrelevant checkpoints. // The slight tradeoff is that users who have multiple infrequent `VotingEscrow` interactions and also don't // claim frequently will also perform the binary search, despite it not leading to gas savings. if (maxUserEpoch - userEpoch > 20) { userEpoch = _findTimestampUserEpoch(user, nextWeekToCheckpoint, userEpoch, maxUserEpoch); } } // Epoch 0 is always empty so bump onto the next one so that we start on a valid epoch. if (userEpoch == 0) { userEpoch = 1; } IVotingEscrow.Point memory nextUserPoint = _votingEscrow.user_point_history(user, userEpoch); // If this is the first checkpoint for the user, calculate the first week they're eligible for. // i.e. the timestamp of the first Thursday after they locked. // If this is earlier then the first distribution then fast forward to then. if (nextWeekToCheckpoint == 0) { // Disallow checkpointing before `startTime`. require(block.timestamp > _startTime, "Fee distribution has not started yet"); nextWeekToCheckpoint = Math.max(_startTime, _roundUpTimestamp(nextUserPoint.ts)); userState.startTime = uint64(nextWeekToCheckpoint); } // It's safe to increment `userEpoch` and `nextWeekToCheckpoint` in this loop as epochs and timestamps // are always much smaller than 2^256 and are being incremented by small values. IVotingEscrow.Point memory currentUserPoint; for (uint256 i = 0; i < 50; ++i) { if (nextWeekToCheckpoint >= nextUserPoint.ts && userEpoch <= maxUserEpoch) { // The week being considered is contained in a user epoch after that described by `currentUserPoint`. // We then shift `nextUserPoint` into `currentUserPoint` and query the Point for the next user epoch. // We do this in order to step though epochs until we find the first epoch starting after // `nextWeekToCheckpoint`, making the previous epoch the one that contains `nextWeekToCheckpoint`. userEpoch += 1; currentUserPoint = nextUserPoint; if (userEpoch > maxUserEpoch) { nextUserPoint = IVotingEscrow.Point(0, 0, 0, 0); } else { nextUserPoint = _votingEscrow.user_point_history(user, userEpoch); } } else { // The week being considered lies inside the user epoch described by `oldUserPoint` // we can then use it to calculate the user's balance at the beginning of the week. if (nextWeekToCheckpoint >= block.timestamp) { // Break if we're trying to cache the user's balance at a timestamp in the future. // We only perform this check here to ensure that we can still process checkpoints created // in the current week. break; } int128 dt = int128(nextWeekToCheckpoint - currentUserPoint.ts); uint256 userBalance = currentUserPoint.bias > currentUserPoint.slope * dt ? uint256(currentUserPoint.bias - currentUserPoint.slope * dt) : 0; // User's lock has expired and they haven't relocked yet. if (userBalance == 0 && userEpoch > maxUserEpoch) { nextWeekToCheckpoint = _roundUpTimestamp(block.timestamp); break; } // User had a nonzero lock and so is eligible to collect fees. _userBalanceAtTimestamp[user][nextWeekToCheckpoint] = userBalance; nextWeekToCheckpoint += 1 weeks; } } // We subtract off 1 from the userEpoch to step back once so that on the next attempt to checkpoint // the current `currentUserPoint` will be loaded as `nextUserPoint`. This ensures that we can't skip over the // user epoch containing `nextWeekToCheckpoint`. // userEpoch > 0 so this is safe. userState.lastEpochCheckpointed = uint64(userEpoch - 1); userState.timeCursor = uint64(nextWeekToCheckpoint); } /** * @dev Cache the totalSupply of VotingEscrow token at the beginning of each new week */ function _checkpointTotalSupply() internal { uint256 nextWeekToCheckpoint = _timeCursor; uint256 weekStart = _roundDownTimestamp(block.timestamp); // We expect `timeCursor == weekStart + 1 weeks` when fully up to date. if (nextWeekToCheckpoint > weekStart || weekStart == block.timestamp) { // We've already checkpointed up to this week so perform early return return; } _votingEscrow.checkpoint(); // Step through the each week and cache the total supply at beginning of week on this contract for (uint256 i = 0; i < 20; ++i) { if (nextWeekToCheckpoint > weekStart) break; // NOTE: Replaced Balancer's logic with Solidly/Velodrome implementation due to the differences in the VotingEscrow totalSupply function // See https://github.com/velodrome-finance/v1/blob/master/contracts/RewardsDistributor.sol#L143 uint256 epoch = _findTimestampEpoch(nextWeekToCheckpoint); IVotingEscrow.Point memory pt = _votingEscrow.point_history(epoch); int128 dt = nextWeekToCheckpoint > pt.ts ? int128(nextWeekToCheckpoint - pt.ts) : 0; int128 supply = pt.bias - pt.slope * dt; _veSupplyCache[nextWeekToCheckpoint] = supply > 0 ? uint256(supply) : 0; // This is safe as we're incrementing a timestamp nextWeekToCheckpoint += 1 weeks; } // Update state to the end of the current week (`weekStart` + 1 weeks) _timeCursor = nextWeekToCheckpoint; } // Helper functions /** * @dev Wrapper around `_userTokenTimeCursor` which returns the start timestamp for `token` * if `user` has not attempted to interact with it previously. */ function _getUserTokenTimeCursor(address user, IERC20 token) internal view returns (uint256) { uint256 userTimeCursor = _userTokenTimeCursor[user][token]; if (userTimeCursor > 0) return userTimeCursor; // This is the first time that the user has interacted with this token. // We then start from the latest out of either when `user` first locked veSTG or `token` was first checkpointed. return Math.max(_userState[user].startTime, _tokenState[token].startTime); } /** * @dev Return the user epoch number for `user` corresponding to the provided `timestamp` */ function _findTimestampUserEpoch(address user, uint256 timestamp, uint256 minUserEpoch, uint256 maxUserEpoch) internal view returns (uint256) { uint256 min = minUserEpoch; uint256 max = maxUserEpoch; // Perform binary search through epochs to find epoch containing `timestamp` for (uint256 i = 0; i < 128; ++i) { if (min >= max) break; // Algorithm assumes that inputs are less than 2^128 so this operation is safe. // +2 avoids getting stuck in min == mid < max uint256 mid = (min + max + 2) / 2; IVotingEscrow.Point memory pt = _votingEscrow.user_point_history(user, mid); if (pt.ts <= timestamp) { min = mid; } else { // max > min so this is safe. max = mid - 1; } } return min; } /** * @dev Return the global epoch number corresponding to the provided `timestamp` */ function _findTimestampEpoch(uint256 timestamp) internal view returns (uint256) { uint256 min = 0; uint256 max = _votingEscrow.epoch(); // Perform binary search through epochs to find epoch containing `timestamp` for (uint256 i = 0; i < 128; i++) { if (min >= max) break; // Algorithm assumes that inputs are less than 2^128 so this operation is safe. // +2 avoids getting stuck in min == mid < max uint256 mid = (min + max + 2) / 2; IVotingEscrow.Point memory pt = _votingEscrow.point_history(mid); if (pt.ts <= timestamp) { min = mid; } else { max = mid - 1; } } return min; } /** * @dev Rounds the provided timestamp down to the beginning of the previous week (Thurs 00:00 UTC) */ function _roundDownTimestamp(uint256 timestamp) private pure returns (uint256) { // Division by zero or overflows are impossible here. return (timestamp / 1 weeks) * 1 weeks; } /** * @dev Rounds the provided timestamp up to the beginning of the next week (Thurs 00:00 UTC) */ function _roundUpTimestamp(uint256 timestamp) private pure returns (uint256) { // Overflows are impossible here for all realistic inputs. return _roundDownTimestamp(timestamp + WEEK_MINUS_SECOND); } /** * @dev Reverts if the provided token cannot be claimed. */ function _checkIfClaimingEnabled(IERC20 token) private view { require(_tokenClaimingEnabled[token], "Token is not allowed"); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () internal { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "./IERC20.sol"; import "../../math/SafeMath.sol"; import "../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.2 <0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <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 GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <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 () internal { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; import "@openzeppelin-solc-0.7/contracts/token/ERC20/IERC20.sol"; import "./IVotingEscrow.sol"; /** * @title Fee Distributor * @notice Distributes any tokens transferred to the contract (e.g. Protocol fees) among veSTG * holders proportionally based on a snapshot of the week at which the tokens are sent to the FeeDistributor contract. * @dev Supports distributing arbitrarily many different tokens. In order to start distributing a new token to veSTG * holders simply transfer the tokens to the `FeeDistributor` contract and then call `checkpointToken`. */ interface IFeeDistributor { event TokenCheckpointed(IERC20 token, uint256 amount, uint256 lastCheckpointTimestamp); event TokensClaimed(address user, IERC20 token, uint256 amount, uint256 userTokenTimeCursor); event TokenWithdrawn(IERC20 token, uint256 amount, address recipient); event TokenClaimingEnabled(IERC20 token, bool enabled); event OnlyVeHolderClaimingEnabled(address user, bool enabled); /** * @notice Returns the VotingEscrow (veSTG) token contract */ function getVotingEscrow() external view returns (IVotingEscrow); /** * @notice Returns the time when fee distribution starts. */ function getStartTime() external view returns (uint256); /** * @notice Returns the global time cursor representing the most earliest uncheckpointed week. */ function getTimeCursor() external view returns (uint256); /** * @notice Returns the user-level time cursor representing the most earliest uncheckpointed week. * @param user - The address of the user to query. */ function getUserTimeCursor(address user) external view returns (uint256); /** * @notice Returns the user-level start time representing the first week they're eligible to claim tokens. * @param user - The address of the user to query. */ function getUserStartTime(address user) external view returns (uint256); /** * @notice True if the given token can be claimed, false otherwise. * @param token - The ERC20 token address to query. */ function canTokenBeClaimed(IERC20 token) external view returns (bool); /** * @notice Returns the token-level start time representing the timestamp users could start claiming this token * @param token - The ERC20 token address to query. */ function getTokenStartTime(IERC20 token) external view returns (uint256); /** * @notice Returns the token-level time cursor storing the timestamp at up to which tokens have been distributed. * @param token - The ERC20 token address to query. */ function getTokenTimeCursor(IERC20 token) external view returns (uint256); /** * @notice Returns the token-level cached balance. * @param token - The ERC20 token address to query. */ function getTokenCachedBalance(IERC20 token) external view returns (uint256); /** * @notice Returns the user-level last checkpointed epoch. * @param user - The address of the user to query. */ function getUserLastEpochCheckpointed(address user) external view returns (uint256); /** * @notice Returns the user-level time cursor storing the timestamp of the latest token distribution claimed. * @param user - The address of the user to query. * @param token - The ERC20 token address to query. */ function getUserTokenTimeCursor(address user, IERC20 token) external view returns (uint256); /** * @notice Returns the user's cached balance of veSTG as of the provided timestamp. * @dev Only timestamps which fall on Thursdays 00:00:00 UTC will return correct values. * This function requires `user` to have been checkpointed past `timestamp` so that their balance is cached. * @param user - The address of the user of which to read the cached balance of. * @param timestamp - The timestamp at which to read the `user`'s cached balance at. */ function getUserBalanceAtTimestamp(address user, uint256 timestamp) external view returns (uint256); /** * @notice Returns the cached total supply of veSTG as of the provided timestamp. * @dev Only timestamps which fall on Thursdays 00:00:00 UTC will return correct values. * This function requires the contract to have been checkpointed past `timestamp` so that the supply is cached. * @param timestamp - The timestamp at which to read the cached total supply at. */ function getTotalSupplyAtTimestamp(uint256 timestamp) external view returns (uint256); /** * @notice Returns the FeeDistributor's cached balance of `token`. */ function getTokenLastBalance(IERC20 token) external view returns (uint256); /** * @notice Returns the amount of `token` which the FeeDistributor received in the week beginning at `timestamp`. * @param token - The ERC20 token address to query. * @param timestamp - The timestamp corresponding to the beginning of the week of interest. */ function getTokensDistributedInWeek(IERC20 token, uint256 timestamp) external view returns (uint256); // Preventing third-party claiming /** * @notice Enables / disables rewards claiming only by the VotingEscrow holder for the message sender. * @param enabled - True if only the VotingEscrow holder can claim their rewards, false otherwise. */ function enableOnlyVeHolderClaiming(bool enabled) external; /** * @notice Returns true if only the VotingEscrow holder can claim their rewards, false otherwise. */ function onlyVeHolderClaimingEnabled(address user) external view returns (bool); // Depositing /** * @notice Deposits tokens to be distributed in the current week. * @dev Sending tokens directly to the FeeDistributor instead of using `depositTokens` may result in tokens being * retroactively distributed to past weeks, or for the distribution to carry over to future weeks. * * If for some reason `depositTokens` cannot be called, in order to ensure that all tokens are correctly distributed * manually call `checkpointToken` before and after the token transfer. * @param token - The ERC20 token address to distribute. * @param amount - The amount of tokens to deposit. */ function depositToken(IERC20 token, uint256 amount) external; /** * @notice Deposits tokens to be distributed in the current week. * @dev A version of `depositToken` which supports depositing multiple `tokens` at once. * See `depositToken` for more details. * @param tokens - An array of ERC20 token addresses to distribute. * @param amounts - An array of token amounts to deposit. */ function depositTokens(IERC20[] calldata tokens, uint256[] calldata amounts) external; // Checkpointing /** * @notice Caches the total supply of veSTG at the beginning of each week. * This function will be called automatically before claiming tokens to ensure the contract is properly updated. */ function checkpoint() external; /** * @notice Caches the user's balance of veSTG at the beginning of each week. * This function will be called automatically before claiming tokens to ensure the contract is properly updated. * @param user - The address of the user to be checkpointed. */ function checkpointUser(address user) external; /** * @notice Assigns any newly-received tokens held by the FeeDistributor to weekly distributions. * @dev Any `token` balance held by the FeeDistributor above that which is returned by `getTokenLastBalance` * will be distributed evenly across the time period since `token` was last checkpointed. * * This function will be called automatically before claiming tokens to ensure the contract is properly updated. * @param token - The ERC20 token address to be checkpointed. */ function checkpointToken(IERC20 token) external; /** * @notice Assigns any newly-received tokens held by the FeeDistributor to weekly distributions. * @dev A version of `checkpointToken` which supports checkpointing multiple tokens. * See `checkpointToken` for more details. * @param tokens - An array of ERC20 token addresses to be checkpointed. */ function checkpointTokens(IERC20[] calldata tokens) external; // Claiming /** * @notice Claims all pending distributions of the provided token for a user. * @dev It's not necessary to explicitly checkpoint before calling this function, it will ensure the FeeDistributor * is up to date before calculating the amount of tokens to be claimed. * @param user - The user on behalf of which to claim. * @param token - The ERC20 token address to be claimed. * @return The amount of `token` sent to `user` as a result of claiming. */ function claimToken(address user, IERC20 token) external returns (uint256); /** * @notice Claims a number of tokens on behalf of a user. * @dev A version of `claimToken` which supports claiming multiple `tokens` on behalf of `user`. * See `claimToken` for more details. * @param user - The user on behalf of which to claim. * @param tokens - An array of ERC20 token addresses to be claimed. * @return An array of the amounts of each token in `tokens` sent to `user` as a result of claiming. */ function claimTokens(address user, IERC20[] calldata tokens) external returns (uint256[] memory); // Governance /** * @notice Withdraws the specified `amount` of the `token` from the contract to the `recipient`. Can be called only by Stargate DAO. * @param token - The token to withdraw. * @param amount - The amount to withdraw. * @param recipient - The address to transfer the tokens to. */ function withdrawToken(IERC20 token, uint256 amount, address recipient) external; /** * @notice Enables or disables claiming of the given token. Can be called only by Stargate DAO. * @param token - The token to enable or disable claiming. * @param enable - True if the token can be claimed, false otherwise. */ function enableTokenClaiming(IERC20 token, bool enable) external; }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; // For compatibility, we're keeping the same function names as in the original Curve code, including the mixed-case // naming convention. // solhint-disable func-name-mixedcase interface IVotingEscrow { struct Point { int128 bias; int128 slope; // - dweight / dt uint256 ts; uint256 blk; // block } function epoch() external view returns (uint256); function balanceOfAtT(address user, uint256 timestamp) external view returns (uint256); function totalSupplyAtT(uint256 timestamp) external view returns (uint256); function user_point_epoch(address user) external view returns (uint256); function point_history(uint256 timestamp) external view returns (Point memory); function user_point_history(address user, uint256 timestamp) external view returns (Point memory); function checkpoint() external; function locked__end(address user) external view returns (uint256); }
{ "evmVersion": "istanbul", "optimizer": { "enabled": true, "runs": 9999 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
[{"inputs":[{"internalType":"contract IVotingEscrow","name":"votingEscrow","type":"address"},{"internalType":"uint256","name":"startTime","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"OnlyVeHolderClaimingEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lastCheckpointTimestamp","type":"uint256"}],"name":"TokenCheckpointed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"TokenClaimingEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"}],"name":"TokenWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"userTokenTimeCursor","type":"uint256"}],"name":"TokensClaimed","type":"event"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"canTokenBeClaimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"checkpoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"checkpointToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"}],"name":"checkpointTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"checkpointUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"claimToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"}],"name":"claimTokens","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"depositTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"enableOnlyVeHolderClaiming","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"bool","name":"enable","type":"bool"}],"name":"enableTokenClaiming","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTimeCursor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"getTokenCachedBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"getTokenLastBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"getTokenStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"getTokenTimeCursor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getTokensDistributedInWeek","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getTotalSupplyAtTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getUserBalanceAtTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserLastEpochCheckpointed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserTimeCursor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"getUserTokenTimeCursor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVotingEscrow","outputs":[{"internalType":"contract IVotingEscrow","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"onlyVeHolderClaimingEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"withdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60c06040523480156200001157600080fd5b5060405162002fc638038062002fc68339810160408190526200003491620001cb565b600062000040620001a6565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350600180556001600160601b0319606083901b16608052620000ab81620001aa565b90506000620000ba42620001aa565b905080821015620000e85760405162461bcd60e51b8152600401620000df90620002ca565b60405180910390fd5b60405163d1febfb960e01b81526000906001600160a01b0385169063d1febfb9906200011990849060040162000275565b60806040518083038186803b1580156200013257600080fd5b505afa15801562000147573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016d919062000205565b905080604001518311620001955760405162461bcd60e51b8152600401620000df906200027e565b505060a081905260025550620002ff565b3390565b62093a80808204025b919050565b8051600f81900b8114620001b357600080fd5b60008060408385031215620001de578182fd5b82516001600160a01b0381168114620001f5578283fd5b6020939093015192949293505050565b60006080828403121562000217578081fd5b604051608081016001600160401b03811182821017156200023457fe5b6040526200024283620001b8565b81526200025260208401620001b8565b602082015260408301516040820152606083015160608201528091505092915050565b90815260200190565b6020808252602c908201527f43616e6e6f74207374617274206265666f726520566f74696e67457363726f7760408201526b040ccd2e4e6e840cae0dec6d60a31b606082015260800190565b6020808252818101527f43616e6e6f74207374617274206265666f72652063757272656e74207765656b604082015260600190565b60805160601c60a051612c646200036260003980610ce452806112085280611355528061139752806116df525080610405528061112252806112c5528061149d5280611c345280611ccf528061200b528061221052806122f55250612c646000f3fe608060405234801561001057600080fd5b50600436106101da5760003560e01c806389d11a5911610104578063c8a0f2d5116100a2578063de2283ab11610071578063de2283ab146103b7578063de681faf146103ca578063f14045ac146103dd578063f2fde38b146103f0576101da565b8063c8a0f2d514610232578063ca31879d1461037e578063cc08736414610391578063d3dc4ca1146103a4576101da565b8063a3208f82116100de578063a3208f821461033b578063acbc14281461035b578063c2c4c5c11461036e578063c828371e14610376576101da565b806389d11a591461030d5780638da5cb5b14610320578063905d10ac14610328576101da565b80633ccdbb281161017c5780638050a7ee1161014b5780638050a7ee146102bf57806382aa5ad4146102d2578063876e69a1146102da57806388720467146102ed576101da565b80633ccdbb281461027e5780634f3c509014610291578063715018a6146102a45780637b8d6221146102ac576101da565b80632308805b116101b85780632308805b14610232578063286d5e7f14610245578063338b5dea146102585780633902b9bc1461026b576101da565b806308b0308a146101df5780630c59ef34146101fd57806314866e081461021d575b600080fd5b6101e7610403565b6040516101f49190612932565b60405180910390f35b61021061020b36600461268d565b610427565b6040516101f49190612b9a565b61023061022b36600461268d565b610450565b005b61021061024036600461268d565b6104bd565b61021061025336600461268d565b6104fe565b610230610266366004612734565b61053f565b61023061027936600461268d565b6105da565b61023061028c366004612856565b610654565b61021061029f366004612902565b61071c565b61023061072e565b6102306102ba36600461279f565b610804565b6102106102cd3660046126fc565b610972565b610210610987565b6102106102e836600461268d565b61098d565b6103006102fb3660046126a9565b6109be565b6040516101f491906129a3565b61021061031b36600461268d565b610b5b565b6101e7610b80565b61023061033636600461275f565b610b8f565b61034e61034936600461268d565b610c28565b6040516101f491906129db565b61021061036936600461268d565b610c46565b610230610c77565b610210610ce2565b61021061038c3660046126fc565b610d06565b61023061039f366004612808565b610ded565b6102106103b2366004612734565b610e61565b61034e6103c536600461268d565b610e89565b6102106103d8366004612734565b610ea7565b6102306103eb366004612822565b610ecf565b6102306103fe36600461268d565b610fc3565b7f000000000000000000000000000000000000000000000000000000000000000090565b6001600160a01b03811660009081526007602052604090205467ffffffffffffffff165b919050565b600260015414156104a8576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026001556104b6816110ef565b5060018055565b6001600160a01b031660009081526004602052604090205470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1690565b6001600160a01b031660009081526007602052604090205470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1690565b60026001541415610597576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002600155816105a68161166c565b6105b18360006116a4565b6105c66001600160a01b038416333085611a74565b6105d18360016116a4565b50506001805550565b60026001541415610632576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002600155806106418161166c565b61064c8260016116a4565b505060018055565b61065c611b02565b6001600160a01b031661066d610b80565b6001600160a01b0316146106c8576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6106dc6001600160a01b0384168284611b06565b7fa0524ee0fd8662d6c046d199da2a6d3dc49445182cec055873a5bb9c2843c8e083838360405161070f939291906129e6565b60405180910390a1505050565b60009081526003602052604090205490565b610736611b02565b6001600160a01b0316610747610b80565b6001600160a01b0316146107a2576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b6002600154141561085c576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026001558281146108895760405162461bcd60e51b815260040161088090612b63565b60405180910390fd5b8260005b81811015610966576108be8686838181106108a457fe5b90506020020160208101906108b9919061268d565b61166c565b6108e98686838181106108cd57fe5b90506020020160208101906108e2919061268d565b60006116a4565b61093333308686858181106108fa57fe5b9050602002013589898681811061090d57fe5b9050602002016020810190610922919061268d565b6001600160a01b0316929190611a74565b61095e86868381811061094257fe5b9050602002016020810190610957919061268d565b60016116a4565b60010161088d565b50506001805550505050565b600061097e8383611b8b565b90505b92915050565b60025490565b6001600160a01b031660009081526007602052604090205468010000000000000000900467ffffffffffffffff1690565b606060026001541415610a18576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026001556001600160a01b0384166000908152600a6020526040902054849060ff1615610a6857336001600160a01b03821614610a685760405162461bcd60e51b815260040161088090612af5565b83838060005b81811015610a8d57610a858484838181106108a457fe5b600101610a6e565b50610a96611c09565b610a9f886110ef565b8560008167ffffffffffffffff81118015610ab957600080fd5b50604051908082528060200260200182016040528015610ae3578160200160208202803683370190505b50905060005b82811015610b4957610b008a8a838181106108cd57fe5b610b2a8b8b8b84818110610b1057fe5b9050602002016020810190610b25919061268d565b611dd8565b828281518110610b3657fe5b6020908102919091010152600101610ae9565b50600180559998505050505050505050565b6001600160a01b031660009081526004602052604090205467ffffffffffffffff1690565b6000546001600160a01b031690565b60026001541415610be7576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026001558060005b81811015610c1e57610c078484838181106108a457fe5b610c1684848381811061094257fe5b600101610bf0565b5050600180555050565b6001600160a01b03166000908152600a602052604090205460ff1690565b6001600160a01b031660009081526004602052604090205468010000000000000000900467ffffffffffffffff1690565b60026001541415610ccf576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002600155610cdc611c09565b60018055565b7f000000000000000000000000000000000000000000000000000000000000000090565b600060026001541415610d60576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026001556001600160a01b0383166000908152600a6020526040902054839060ff1615610db057336001600160a01b03821614610db05760405162461bcd60e51b815260040161088090612af5565b82610dba8161166c565b610dc2611c09565b610dcb856110ef565b610dd68460006116a4565b610de08585611dd8565b6001805595945050505050565b336000818152600a60205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016841515179055517f5df4db5082ff794d02e809cecb2c56f2ac683e734a0b4d1e03fd82b3da056c7191610e56918490612946565b60405180910390a150565b6001600160a01b03919091166000908152600560209081526040808320938352929052205490565b6001600160a01b031660009081526006602052604090205460ff1690565b6001600160a01b03919091166000908152600860209081526040808320938352929052205490565b610ed7611b02565b6001600160a01b0316610ee8610b80565b6001600160a01b031614610f43576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b0382166000908152600660205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016831515179055517f359cee3647456cdac70428f1f028ea08d4bafdc5703fc14df9625b49f4398c9d90610fb79084908490612946565b60405180910390a15050565b610fcb611b02565b6001600160a01b0316610fdc610b80565b6001600160a01b031614611037576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b03811661107c5760405162461bcd60e51b8152600401808060200182810382526026815260200180612bb96026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6040517f010ae7570000000000000000000000000000000000000000000000000000000081526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063010ae75790611157908590600401612932565b60206040518083038186803b15801561116f57600080fd5b505afa158015611183573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a7919061291a565b9050600081116111c95760405162461bcd60e51b815260040161088090612b2c565b6001600160a01b0382166000908152600760205260408120805490916801000000000000000090910467ffffffffffffffff1690816112365761122f857f0000000000000000000000000000000000000000000000000000000000000000600087611fb4565b9050611289565b4282106112465750505050611669565b50815470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16601481850311156112895761128685838387611fb4565b90505b80611292575060015b6040517f28d09d470000000000000000000000000000000000000000000000000000000081526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906328d09d47906112fc908990869060040161298a565b60806040518083038186803b15801561131457600080fd5b505afa158015611328573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134c9190612897565b9050826113fd577f000000000000000000000000000000000000000000000000000000000000000042116113925760405162461bcd60e51b815260040161088090612a98565b6113c87f00000000000000000000000000000000000000000000000000000000000000006113c383604001516120c4565b6120d4565b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff821617855592505b6114056125f4565b60005b60328110156115d057826040015185101580156114255750868411155b1561152c576001840193508291508684111561146d5760405180608001604052806000600f0b81526020016000600f0b81526020016000815260200160008152509250611527565b6040517f28d09d470000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906328d09d47906114d4908b90889060040161298a565b60806040518083038186803b1580156114ec57600080fd5b505afa158015611500573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115249190612897565b92505b6115c8565b428510611538576115d0565b6000826040015186039050600081846020015102600f0b8460000151600f0b13611563576000611574565b81846020015102846000015103600f0b5b90508015801561158357508886115b1561159a57611591426120c4565b965050506115d0565b6001600160a01b038a1660009081526008602090815260408083208a84529091529020555062093a80909401935b600101611408565b505083546fffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9290920167ffffffffffffffff90811670010000000000000000000000000000000002929092177fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000093909216929092021790915550505b50565b6001600160a01b03811660009081526006602052604090205460ff166116695760405162461bcd60e51b815260040161088090612a2a565b6001600160a01b0382166000908152600460205260408120805490916801000000000000000090910467ffffffffffffffff169081611761577f0000000000000000000000000000000000000000000000000000000000000000421161171c5760405162461bcd60e51b815260040161088090612a98565b429150611728426120eb565b83547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff919091161783556117b3565b8142039050836117b3576000611776836120eb565b61177f426120eb565b14905060006201518042611792426120c4565b031090508180156117a1575080155b156117b0575050505050611a70565b50505b82547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff16680100000000000000004267ffffffffffffffff16021783556040517f70a082310000000000000000000000000000000000000000000000000000000081526000906001600160a01b038716906370a0823190611838903090600401612932565b60206040518083038186803b15801561185057600080fd5b505afa158015611864573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611888919061291a565b84549091506000906118c190839070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff166120f7565b9050806118d2575050505050611a70565b6fffffffffffffffffffffffffffffffff8211156119025760405162461bcd60e51b815260040161088090612a61565b84546fffffffffffffffffffffffffffffffff808416700100000000000000000000000000000000029116178555600061193b856120eb565b6001600160a01b038916600090815260056020526040812091925090815b6014811015611a2b578362093a80019250824210156119c9578615801561197f57508742145b1561199d5760008481526020839052604090208054860190556119c4565b868842038602816119aa57fe5b600086815260208590526040902080549290910490910190555b611a2b565b861580156119d657508783145b156119f4576000848152602083905260409020805486019055611a1b565b86888403860281611a0157fe5b600086815260208590526040902080549290910490910190555b9196508692508291600101611959565b507f9b7f1a85a4c9b4e59e1b6527d9969c50cdfb3a1a467d0c4a51fb0ed8bf07f1308a8589604051611a5f93929190612a09565b60405180910390a150505050505050505b5050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052611afc908590612154565b50505050565b3390565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052611b86908490612154565b505050565b6001600160a01b0380831660009081526009602090815260408083209385168352929052908120548015611bc0579050610981565b6001600160a01b0380851660009081526007602090815260408083205493871683526004909152902054611c019167ffffffffffffffff90811691166120d4565b949350505050565b6002546000611c17426120eb565b905080821180611c2657504281145b15611c32575050611dd6565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c2c4c5c16040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611c8d57600080fd5b505af1158015611ca1573d6000803e3d6000fd5b5050505060005b6014811015611dd05781831115611cbe57611dd0565b6000611cc984612205565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d1febfb9836040518263ffffffff1660e01b8152600401611d199190612b9a565b60806040518083038186803b158015611d3157600080fd5b505afa158015611d45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d699190612897565b9050600081604001518611611d7f576000611d87565b816040015186035b60208301518351919250820290036000600f82900b13611da8576000611dad565b80600f0b5b600088815260036020526040902055505062093a80909401935050600101611ca8565b50506002555b565b6001600160a01b038116600090815260046020526040812081611dfb8585611b8b565b6002546001600160a01b03871660009081526007602052604081205492935091611e6e91611e4891611e43919068010000000000000000900467ffffffffffffffff166123a9565b6120c4565b8454611e699068010000000000000000900467ffffffffffffffff166120eb565b6123a9565b6001600160a01b038087166000908152600560209081526040808320938b16835260089091528120929350909190805b6014811015611ef257848610611eb357611ef2565b60008681526003602090815260408083205486835281842054928890529220540281611edb57fe5b62093a809790970196049190910190600101611e9e565b506001600160a01b03808a166000908152600960209081526040808320938c168352929052208590558015611fa85785546fffffffffffffffffffffffffffffffff70010000000000000000000000000000000080830482168490038216029116178655611f6a6001600160a01b0389168a83611b06565b7fff097c7d8b1957a4ff09ef1361b5fb54dcede3941ba836d0beb9d10bec725de689898388604051611f9f9493929190612961565b60405180910390a15b98975050505050505050565b60008282825b60808110156120b857818310611fcf576120b8565b6040517f28d09d470000000000000000000000000000000000000000000000000000000081526002838501810104906000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906328d09d4790612042908d90869060040161298a565b60806040518083038186803b15801561205a57600080fd5b505afa15801561206e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120929190612897565b9050888160400151116120a7578194506120ae565b6001820393505b5050600101611fba565b50909695505050505050565b600061098162093a7f83016120eb565b6000818310156120e4578161097e565b5090919050565b62093a80908190040290565b60008282111561214e576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60006121a9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166123b89092919063ffffffff16565b805190915015611b86578080602001905160208110156121c857600080fd5b5051611b865760405162461bcd60e51b815260040180806020018281038252602a815260200180612c05602a913960400191505060405180910390fd5b6000806000905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663900cf0cf6040518163ffffffff1660e01b815260040160206040518083038186803b15801561226757600080fd5b505afa15801561227b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229f919061291a565b905060005b60808110156123a0578183106122b9576123a0565b6040517fd1febfb90000000000000000000000000000000000000000000000000000000081526002838501810104906000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d1febfb99061232a908590600401612b9a565b60806040518083038186803b15801561234257600080fd5b505afa158015612356573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237a9190612897565b90508681604001511161238f57819450612396565b6001820393505b50506001016122a4565b50909392505050565b60008183106120e4578161097e565b60606123c784846000856123d1565b90505b9392505050565b6060824710156124125760405162461bcd60e51b8152600401808060200182810382526026815260200180612bdf6026913960400191505060405180910390fd5b61241b8561254a565b61246c576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b602083106124c857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161248b565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d806000811461252a576040519150601f19603f3d011682016040523d82523d6000602084013e61252f565b606091505b509150915061253f828286612550565b979650505050505050565b3b151590565b6060831561255f5750816123ca565b82511561256f5782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156125b95781810151838201526020016125a1565b50505050905090810190601f1680156125e65780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b60405180608001604052806000600f0b81526020016000600f0b815260200160008152602001600081525090565b60008083601f840112612633578182fd5b50813567ffffffffffffffff81111561264a578182fd5b602083019150836020808302850101111561266457600080fd5b9250929050565b8035801515811461044b57600080fd5b8051600f81900b811461044b57600080fd5b60006020828403121561269e578081fd5b81356123ca81612ba3565b6000806000604084860312156126bd578182fd5b83356126c881612ba3565b9250602084013567ffffffffffffffff8111156126e3578283fd5b6126ef86828701612622565b9497909650939450505050565b6000806040838503121561270e578182fd5b823561271981612ba3565b9150602083013561272981612ba3565b809150509250929050565b60008060408385031215612746578182fd5b823561275181612ba3565b946020939093013593505050565b60008060208385031215612771578182fd5b823567ffffffffffffffff811115612787578283fd5b61279385828601612622565b90969095509350505050565b600080600080604085870312156127b4578081fd5b843567ffffffffffffffff808211156127cb578283fd5b6127d788838901612622565b909650945060208701359150808211156127ef578283fd5b506127fc87828801612622565b95989497509550505050565b600060208284031215612819578081fd5b61097e8261266b565b60008060408385031215612834578182fd5b823561283f81612ba3565b915061284d6020840161266b565b90509250929050565b60008060006060848603121561286a578283fd5b833561287581612ba3565b925060208401359150604084013561288c81612ba3565b809150509250925092565b6000608082840312156128a8578081fd5b6040516080810181811067ffffffffffffffff821117156128c557fe5b6040526128d18361267b565b81526128df6020840161267b565b602082015260408301516040820152606083015160608201528091505092915050565b600060208284031215612913578081fd5b5035919050565b60006020828403121561292b578081fd5b5051919050565b6001600160a01b0391909116815260200190565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b818110156120b8578351835292840192918401916001016129bf565b901515815260200190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b6001600160a01b039390931683526020830191909152604082015260600190565b60208082526014908201527f546f6b656e206973206e6f7420616c6c6f776564000000000000000000000000604082015260600190565b6020808252601e908201527f4d6178696d756d20746f6b656e2062616c616e63652065786365656465640000604082015260600190565b60208082526024908201527f46656520646973747269627574696f6e20686173206e6f74207374617274656460408201527f2079657400000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526017908201527f436c61696d696e67206973206e6f7420616c6c6f776564000000000000000000604082015260600190565b60208082526015908201527f76655354472062616c616e6365206973207a65726f0000000000000000000000604082015260600190565b60208082526015908201527f496e707574206c656e677468206d69736d617463680000000000000000000000604082015260600190565b90815260200190565b6001600160a01b038116811461166957600080fdfe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c5361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a2646970667358221220ed016ceb092c9550649e4c44527b0d19d8e48c83a3744d0b7901b08f3419abb364736f6c634300070600330000000000000000000000000e42acbd23faee03249daff896b78d7e79fbd58e0000000000000000000000000000000000000000000000000000000064f91280
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101da5760003560e01c806389d11a5911610104578063c8a0f2d5116100a2578063de2283ab11610071578063de2283ab146103b7578063de681faf146103ca578063f14045ac146103dd578063f2fde38b146103f0576101da565b8063c8a0f2d514610232578063ca31879d1461037e578063cc08736414610391578063d3dc4ca1146103a4576101da565b8063a3208f82116100de578063a3208f821461033b578063acbc14281461035b578063c2c4c5c11461036e578063c828371e14610376576101da565b806389d11a591461030d5780638da5cb5b14610320578063905d10ac14610328576101da565b80633ccdbb281161017c5780638050a7ee1161014b5780638050a7ee146102bf57806382aa5ad4146102d2578063876e69a1146102da57806388720467146102ed576101da565b80633ccdbb281461027e5780634f3c509014610291578063715018a6146102a45780637b8d6221146102ac576101da565b80632308805b116101b85780632308805b14610232578063286d5e7f14610245578063338b5dea146102585780633902b9bc1461026b576101da565b806308b0308a146101df5780630c59ef34146101fd57806314866e081461021d575b600080fd5b6101e7610403565b6040516101f49190612932565b60405180910390f35b61021061020b36600461268d565b610427565b6040516101f49190612b9a565b61023061022b36600461268d565b610450565b005b61021061024036600461268d565b6104bd565b61021061025336600461268d565b6104fe565b610230610266366004612734565b61053f565b61023061027936600461268d565b6105da565b61023061028c366004612856565b610654565b61021061029f366004612902565b61071c565b61023061072e565b6102306102ba36600461279f565b610804565b6102106102cd3660046126fc565b610972565b610210610987565b6102106102e836600461268d565b61098d565b6103006102fb3660046126a9565b6109be565b6040516101f491906129a3565b61021061031b36600461268d565b610b5b565b6101e7610b80565b61023061033636600461275f565b610b8f565b61034e61034936600461268d565b610c28565b6040516101f491906129db565b61021061036936600461268d565b610c46565b610230610c77565b610210610ce2565b61021061038c3660046126fc565b610d06565b61023061039f366004612808565b610ded565b6102106103b2366004612734565b610e61565b61034e6103c536600461268d565b610e89565b6102106103d8366004612734565b610ea7565b6102306103eb366004612822565b610ecf565b6102306103fe36600461268d565b610fc3565b7f0000000000000000000000000e42acbd23faee03249daff896b78d7e79fbd58e90565b6001600160a01b03811660009081526007602052604090205467ffffffffffffffff165b919050565b600260015414156104a8576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026001556104b6816110ef565b5060018055565b6001600160a01b031660009081526004602052604090205470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1690565b6001600160a01b031660009081526007602052604090205470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1690565b60026001541415610597576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002600155816105a68161166c565b6105b18360006116a4565b6105c66001600160a01b038416333085611a74565b6105d18360016116a4565b50506001805550565b60026001541415610632576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002600155806106418161166c565b61064c8260016116a4565b505060018055565b61065c611b02565b6001600160a01b031661066d610b80565b6001600160a01b0316146106c8576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6106dc6001600160a01b0384168284611b06565b7fa0524ee0fd8662d6c046d199da2a6d3dc49445182cec055873a5bb9c2843c8e083838360405161070f939291906129e6565b60405180910390a1505050565b60009081526003602052604090205490565b610736611b02565b6001600160a01b0316610747610b80565b6001600160a01b0316146107a2576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b6002600154141561085c576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026001558281146108895760405162461bcd60e51b815260040161088090612b63565b60405180910390fd5b8260005b81811015610966576108be8686838181106108a457fe5b90506020020160208101906108b9919061268d565b61166c565b6108e98686838181106108cd57fe5b90506020020160208101906108e2919061268d565b60006116a4565b61093333308686858181106108fa57fe5b9050602002013589898681811061090d57fe5b9050602002016020810190610922919061268d565b6001600160a01b0316929190611a74565b61095e86868381811061094257fe5b9050602002016020810190610957919061268d565b60016116a4565b60010161088d565b50506001805550505050565b600061097e8383611b8b565b90505b92915050565b60025490565b6001600160a01b031660009081526007602052604090205468010000000000000000900467ffffffffffffffff1690565b606060026001541415610a18576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026001556001600160a01b0384166000908152600a6020526040902054849060ff1615610a6857336001600160a01b03821614610a685760405162461bcd60e51b815260040161088090612af5565b83838060005b81811015610a8d57610a858484838181106108a457fe5b600101610a6e565b50610a96611c09565b610a9f886110ef565b8560008167ffffffffffffffff81118015610ab957600080fd5b50604051908082528060200260200182016040528015610ae3578160200160208202803683370190505b50905060005b82811015610b4957610b008a8a838181106108cd57fe5b610b2a8b8b8b84818110610b1057fe5b9050602002016020810190610b25919061268d565b611dd8565b828281518110610b3657fe5b6020908102919091010152600101610ae9565b50600180559998505050505050505050565b6001600160a01b031660009081526004602052604090205467ffffffffffffffff1690565b6000546001600160a01b031690565b60026001541415610be7576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026001558060005b81811015610c1e57610c078484838181106108a457fe5b610c1684848381811061094257fe5b600101610bf0565b5050600180555050565b6001600160a01b03166000908152600a602052604090205460ff1690565b6001600160a01b031660009081526004602052604090205468010000000000000000900467ffffffffffffffff1690565b60026001541415610ccf576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002600155610cdc611c09565b60018055565b7f0000000000000000000000000000000000000000000000000000000064f9128090565b600060026001541415610d60576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026001556001600160a01b0383166000908152600a6020526040902054839060ff1615610db057336001600160a01b03821614610db05760405162461bcd60e51b815260040161088090612af5565b82610dba8161166c565b610dc2611c09565b610dcb856110ef565b610dd68460006116a4565b610de08585611dd8565b6001805595945050505050565b336000818152600a60205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016841515179055517f5df4db5082ff794d02e809cecb2c56f2ac683e734a0b4d1e03fd82b3da056c7191610e56918490612946565b60405180910390a150565b6001600160a01b03919091166000908152600560209081526040808320938352929052205490565b6001600160a01b031660009081526006602052604090205460ff1690565b6001600160a01b03919091166000908152600860209081526040808320938352929052205490565b610ed7611b02565b6001600160a01b0316610ee8610b80565b6001600160a01b031614610f43576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b0382166000908152600660205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016831515179055517f359cee3647456cdac70428f1f028ea08d4bafdc5703fc14df9625b49f4398c9d90610fb79084908490612946565b60405180910390a15050565b610fcb611b02565b6001600160a01b0316610fdc610b80565b6001600160a01b031614611037576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b03811661107c5760405162461bcd60e51b8152600401808060200182810382526026815260200180612bb96026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6040517f010ae7570000000000000000000000000000000000000000000000000000000081526000906001600160a01b037f0000000000000000000000000e42acbd23faee03249daff896b78d7e79fbd58e169063010ae75790611157908590600401612932565b60206040518083038186803b15801561116f57600080fd5b505afa158015611183573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a7919061291a565b9050600081116111c95760405162461bcd60e51b815260040161088090612b2c565b6001600160a01b0382166000908152600760205260408120805490916801000000000000000090910467ffffffffffffffff1690816112365761122f857f0000000000000000000000000000000000000000000000000000000064f91280600087611fb4565b9050611289565b4282106112465750505050611669565b50815470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16601481850311156112895761128685838387611fb4565b90505b80611292575060015b6040517f28d09d470000000000000000000000000000000000000000000000000000000081526000906001600160a01b037f0000000000000000000000000e42acbd23faee03249daff896b78d7e79fbd58e16906328d09d47906112fc908990869060040161298a565b60806040518083038186803b15801561131457600080fd5b505afa158015611328573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134c9190612897565b9050826113fd577f0000000000000000000000000000000000000000000000000000000064f9128042116113925760405162461bcd60e51b815260040161088090612a98565b6113c87f0000000000000000000000000000000000000000000000000000000064f912806113c383604001516120c4565b6120d4565b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff821617855592505b6114056125f4565b60005b60328110156115d057826040015185101580156114255750868411155b1561152c576001840193508291508684111561146d5760405180608001604052806000600f0b81526020016000600f0b81526020016000815260200160008152509250611527565b6040517f28d09d470000000000000000000000000000000000000000000000000000000081526001600160a01b037f0000000000000000000000000e42acbd23faee03249daff896b78d7e79fbd58e16906328d09d47906114d4908b90889060040161298a565b60806040518083038186803b1580156114ec57600080fd5b505afa158015611500573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115249190612897565b92505b6115c8565b428510611538576115d0565b6000826040015186039050600081846020015102600f0b8460000151600f0b13611563576000611574565b81846020015102846000015103600f0b5b90508015801561158357508886115b1561159a57611591426120c4565b965050506115d0565b6001600160a01b038a1660009081526008602090815260408083208a84529091529020555062093a80909401935b600101611408565b505083546fffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9290920167ffffffffffffffff90811670010000000000000000000000000000000002929092177fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000093909216929092021790915550505b50565b6001600160a01b03811660009081526006602052604090205460ff166116695760405162461bcd60e51b815260040161088090612a2a565b6001600160a01b0382166000908152600460205260408120805490916801000000000000000090910467ffffffffffffffff169081611761577f0000000000000000000000000000000000000000000000000000000064f91280421161171c5760405162461bcd60e51b815260040161088090612a98565b429150611728426120eb565b83547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff919091161783556117b3565b8142039050836117b3576000611776836120eb565b61177f426120eb565b14905060006201518042611792426120c4565b031090508180156117a1575080155b156117b0575050505050611a70565b50505b82547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff16680100000000000000004267ffffffffffffffff16021783556040517f70a082310000000000000000000000000000000000000000000000000000000081526000906001600160a01b038716906370a0823190611838903090600401612932565b60206040518083038186803b15801561185057600080fd5b505afa158015611864573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611888919061291a565b84549091506000906118c190839070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff166120f7565b9050806118d2575050505050611a70565b6fffffffffffffffffffffffffffffffff8211156119025760405162461bcd60e51b815260040161088090612a61565b84546fffffffffffffffffffffffffffffffff808416700100000000000000000000000000000000029116178555600061193b856120eb565b6001600160a01b038916600090815260056020526040812091925090815b6014811015611a2b578362093a80019250824210156119c9578615801561197f57508742145b1561199d5760008481526020839052604090208054860190556119c4565b868842038602816119aa57fe5b600086815260208590526040902080549290910490910190555b611a2b565b861580156119d657508783145b156119f4576000848152602083905260409020805486019055611a1b565b86888403860281611a0157fe5b600086815260208590526040902080549290910490910190555b9196508692508291600101611959565b507f9b7f1a85a4c9b4e59e1b6527d9969c50cdfb3a1a467d0c4a51fb0ed8bf07f1308a8589604051611a5f93929190612a09565b60405180910390a150505050505050505b5050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052611afc908590612154565b50505050565b3390565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052611b86908490612154565b505050565b6001600160a01b0380831660009081526009602090815260408083209385168352929052908120548015611bc0579050610981565b6001600160a01b0380851660009081526007602090815260408083205493871683526004909152902054611c019167ffffffffffffffff90811691166120d4565b949350505050565b6002546000611c17426120eb565b905080821180611c2657504281145b15611c32575050611dd6565b7f0000000000000000000000000e42acbd23faee03249daff896b78d7e79fbd58e6001600160a01b031663c2c4c5c16040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611c8d57600080fd5b505af1158015611ca1573d6000803e3d6000fd5b5050505060005b6014811015611dd05781831115611cbe57611dd0565b6000611cc984612205565b905060007f0000000000000000000000000e42acbd23faee03249daff896b78d7e79fbd58e6001600160a01b031663d1febfb9836040518263ffffffff1660e01b8152600401611d199190612b9a565b60806040518083038186803b158015611d3157600080fd5b505afa158015611d45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d699190612897565b9050600081604001518611611d7f576000611d87565b816040015186035b60208301518351919250820290036000600f82900b13611da8576000611dad565b80600f0b5b600088815260036020526040902055505062093a80909401935050600101611ca8565b50506002555b565b6001600160a01b038116600090815260046020526040812081611dfb8585611b8b565b6002546001600160a01b03871660009081526007602052604081205492935091611e6e91611e4891611e43919068010000000000000000900467ffffffffffffffff166123a9565b6120c4565b8454611e699068010000000000000000900467ffffffffffffffff166120eb565b6123a9565b6001600160a01b038087166000908152600560209081526040808320938b16835260089091528120929350909190805b6014811015611ef257848610611eb357611ef2565b60008681526003602090815260408083205486835281842054928890529220540281611edb57fe5b62093a809790970196049190910190600101611e9e565b506001600160a01b03808a166000908152600960209081526040808320938c168352929052208590558015611fa85785546fffffffffffffffffffffffffffffffff70010000000000000000000000000000000080830482168490038216029116178655611f6a6001600160a01b0389168a83611b06565b7fff097c7d8b1957a4ff09ef1361b5fb54dcede3941ba836d0beb9d10bec725de689898388604051611f9f9493929190612961565b60405180910390a15b98975050505050505050565b60008282825b60808110156120b857818310611fcf576120b8565b6040517f28d09d470000000000000000000000000000000000000000000000000000000081526002838501810104906000906001600160a01b037f0000000000000000000000000e42acbd23faee03249daff896b78d7e79fbd58e16906328d09d4790612042908d90869060040161298a565b60806040518083038186803b15801561205a57600080fd5b505afa15801561206e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120929190612897565b9050888160400151116120a7578194506120ae565b6001820393505b5050600101611fba565b50909695505050505050565b600061098162093a7f83016120eb565b6000818310156120e4578161097e565b5090919050565b62093a80908190040290565b60008282111561214e576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60006121a9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166123b89092919063ffffffff16565b805190915015611b86578080602001905160208110156121c857600080fd5b5051611b865760405162461bcd60e51b815260040180806020018281038252602a815260200180612c05602a913960400191505060405180910390fd5b6000806000905060007f0000000000000000000000000e42acbd23faee03249daff896b78d7e79fbd58e6001600160a01b031663900cf0cf6040518163ffffffff1660e01b815260040160206040518083038186803b15801561226757600080fd5b505afa15801561227b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229f919061291a565b905060005b60808110156123a0578183106122b9576123a0565b6040517fd1febfb90000000000000000000000000000000000000000000000000000000081526002838501810104906000906001600160a01b037f0000000000000000000000000e42acbd23faee03249daff896b78d7e79fbd58e169063d1febfb99061232a908590600401612b9a565b60806040518083038186803b15801561234257600080fd5b505afa158015612356573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237a9190612897565b90508681604001511161238f57819450612396565b6001820393505b50506001016122a4565b50909392505050565b60008183106120e4578161097e565b60606123c784846000856123d1565b90505b9392505050565b6060824710156124125760405162461bcd60e51b8152600401808060200182810382526026815260200180612bdf6026913960400191505060405180910390fd5b61241b8561254a565b61246c576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b602083106124c857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161248b565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d806000811461252a576040519150601f19603f3d011682016040523d82523d6000602084013e61252f565b606091505b509150915061253f828286612550565b979650505050505050565b3b151590565b6060831561255f5750816123ca565b82511561256f5782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156125b95781810151838201526020016125a1565b50505050905090810190601f1680156125e65780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b60405180608001604052806000600f0b81526020016000600f0b815260200160008152602001600081525090565b60008083601f840112612633578182fd5b50813567ffffffffffffffff81111561264a578182fd5b602083019150836020808302850101111561266457600080fd5b9250929050565b8035801515811461044b57600080fd5b8051600f81900b811461044b57600080fd5b60006020828403121561269e578081fd5b81356123ca81612ba3565b6000806000604084860312156126bd578182fd5b83356126c881612ba3565b9250602084013567ffffffffffffffff8111156126e3578283fd5b6126ef86828701612622565b9497909650939450505050565b6000806040838503121561270e578182fd5b823561271981612ba3565b9150602083013561272981612ba3565b809150509250929050565b60008060408385031215612746578182fd5b823561275181612ba3565b946020939093013593505050565b60008060208385031215612771578182fd5b823567ffffffffffffffff811115612787578283fd5b61279385828601612622565b90969095509350505050565b600080600080604085870312156127b4578081fd5b843567ffffffffffffffff808211156127cb578283fd5b6127d788838901612622565b909650945060208701359150808211156127ef578283fd5b506127fc87828801612622565b95989497509550505050565b600060208284031215612819578081fd5b61097e8261266b565b60008060408385031215612834578182fd5b823561283f81612ba3565b915061284d6020840161266b565b90509250929050565b60008060006060848603121561286a578283fd5b833561287581612ba3565b925060208401359150604084013561288c81612ba3565b809150509250925092565b6000608082840312156128a8578081fd5b6040516080810181811067ffffffffffffffff821117156128c557fe5b6040526128d18361267b565b81526128df6020840161267b565b602082015260408301516040820152606083015160608201528091505092915050565b600060208284031215612913578081fd5b5035919050565b60006020828403121561292b578081fd5b5051919050565b6001600160a01b0391909116815260200190565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b818110156120b8578351835292840192918401916001016129bf565b901515815260200190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b6001600160a01b039390931683526020830191909152604082015260600190565b60208082526014908201527f546f6b656e206973206e6f7420616c6c6f776564000000000000000000000000604082015260600190565b6020808252601e908201527f4d6178696d756d20746f6b656e2062616c616e63652065786365656465640000604082015260600190565b60208082526024908201527f46656520646973747269627574696f6e20686173206e6f74207374617274656460408201527f2079657400000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526017908201527f436c61696d696e67206973206e6f7420616c6c6f776564000000000000000000604082015260600190565b60208082526015908201527f76655354472062616c616e6365206973207a65726f0000000000000000000000604082015260600190565b60208082526015908201527f496e707574206c656e677468206d69736d617463680000000000000000000000604082015260600190565b90815260200190565b6001600160a01b038116811461166957600080fdfe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c5361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a2646970667358221220ed016ceb092c9550649e4c44527b0d19d8e48c83a3744d0b7901b08f3419abb364736f6c63430007060033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000e42acbd23faee03249daff896b78d7e79fbd58e0000000000000000000000000000000000000000000000000000000064f91280
-----Decoded View---------------
Arg [0] : votingEscrow (address): 0x0e42acBD23FAee03249DAFF896b78d7e79fBD58E
Arg [1] : startTime (uint256): 1694044800
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000000e42acbd23faee03249daff896b78d7e79fbd58e
Arg [1] : 0000000000000000000000000000000000000000000000000000000064f91280
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ARB | 46.44% | $0.999796 | 609,196.1935 | $609,071.92 | |
ETH | 18.60% | $0.999796 | 244,076.5728 | $244,026.78 | |
BSC | 12.28% | $0.999034 | 161,208.8892 | $161,053.16 | |
POL | 10.76% | $1 | 141,073.0424 | $141,073.04 | |
OP | 7.06% | $1 | 92,488.6278 | $92,581.12 | |
AVAX | 3.73% | $0.999796 | 48,980.5818 | $48,970.59 | |
FTM | 1.13% | $1 | 14,837.0424 | $14,851.88 |
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.
Address QR Code
My Address - Private Name Tag or Note
My Name Tag:
Private Note:
Please DO NOT store any passwords or private keys here.
The compiled contract might be susceptible to FullInlinerNonExpressionSplitArgumentEvaluationOrder (low-severity), MissingSideEffectsOnSelectorAccess (low-severity), AbiReencodingHeadOverflowWithStaticArrayCleanup (medium-severity), DirtyBytesArrayToStorage (low-severity), DataLocationChangeInInternalOverride (very low-severity), NestedCalldataArrayAbiReencodingSizeValidation (very low-severity), SignedImmutables (very low-severity), ABIDecodeTwoDimensionalArrayMemory (very low-severity), KeccakCaching (medium-severity) Solidity Compiler Bugs.
Connect a Wallet
Connect a Wallet
Connect a Wallet
Address Cards
Before You Copy
This website uses cookies to improve your experience. By continuing to use this website, you agree to its Terms and Privacy Policy.