More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0xb738ef9c46c2138425a114893e87a1a52a03ebe586540823a535d222a10dc3a1 | Withdraw All | (pending) | 34 hrs ago | IN | 0 ETH | (Pending) | |||
0x29189f9c2f07a46ab8bea2fc59ddb263fe12bc26392628944d85de14251bd978 | Withdraw All | (pending) | 15 days ago | IN | 0 ETH | (Pending) | |||
0xdbf8d49abad99268b13181374fca97fe257221355a83f34f225a109468465a91 | Withdraw All | (pending) | 15 days ago | IN | 0 ETH | (Pending) | |||
Withdraw All | 21463198 | 1 hr ago | IN | 0 ETH | 0.00094048 | ||||
Withdraw All | 21461020 | 8 hrs ago | IN | 0 ETH | 0.00163283 | ||||
Withdraw All | 21460588 | 10 hrs ago | IN | 0 ETH | 0.00170257 | ||||
Withdraw All | 21459964 | 12 hrs ago | IN | 0 ETH | 0.00151698 | ||||
Withdraw All | 21458056 | 18 hrs ago | IN | 0 ETH | 0.00156091 | ||||
Withdraw All | 21457171 | 21 hrs ago | IN | 0 ETH | 0.00117634 | ||||
Withdraw All | 21456669 | 23 hrs ago | IN | 0 ETH | 0.0012477 | ||||
Withdraw All | 21456194 | 25 hrs ago | IN | 0 ETH | 0.00165574 | ||||
Withdraw All | 21455438 | 27 hrs ago | IN | 0 ETH | 0.00150481 | ||||
Withdraw All | 21449859 | 46 hrs ago | IN | 0 ETH | 0.00209053 | ||||
Withdraw All | 21449343 | 2 days ago | IN | 0 ETH | 0.00167245 | ||||
Withdraw All | 21446579 | 2 days ago | IN | 0 ETH | 0.00296128 | ||||
Withdraw All | 21441496 | 3 days ago | IN | 0 ETH | 0.0016066 | ||||
Withdraw All | 21440435 | 3 days ago | IN | 0 ETH | 0.00211206 | ||||
Withdraw All | 21431545 | 4 days ago | IN | 0 ETH | 0.00439732 | ||||
Withdraw All | 21431050 | 4 days ago | IN | 0 ETH | 0.00490087 | ||||
Withdraw All | 21430835 | 4 days ago | IN | 0 ETH | 0.00596137 | ||||
Withdraw All | 21430067 | 4 days ago | IN | 0 ETH | 0.00502637 | ||||
Withdraw All | 21427009 | 5 days ago | IN | 0 ETH | 0.00253918 | ||||
Withdraw All | 21426914 | 5 days ago | IN | 0 ETH | 0.00248926 | ||||
Withdraw All | 21426549 | 5 days ago | IN | 0 ETH | 0.0022722 | ||||
Withdraw All | 21426300 | 5 days ago | IN | 0 ETH | 0.00222848 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
AggregatorFeeSharingWithUniswapV3
Compiler Version
v0.8.7+commit.e28d00a7
Optimization Enabled:
Yes with 888888 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol"; import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {ISwapRouter} from "./uniswap-interfaces/ISwapRouter.sol"; import {FeeSharingSystem} from "./FeeSharingSystem.sol"; /** * @title AggregatorFeeSharingWithUniswapV3 * @notice It sells WETH to LOOKS using Uniswap V3. * @dev Prime shares represent the number of shares in the FeeSharingSystem. When not specified, shares represent secondary shares in this contract. */ contract AggregatorFeeSharingWithUniswapV3 is Ownable, Pausable, ReentrancyGuard { using SafeERC20 for IERC20; // Maximum buffer between 2 harvests (in blocks) uint256 public constant MAXIMUM_HARVEST_BUFFER_BLOCKS = 6500; // FeeSharingSystem (handles the distribution of WETH for LOOKS stakers) FeeSharingSystem public immutable feeSharingSystem; // Router of Uniswap v3 ISwapRouter public immutable uniswapRouter; // Minimum deposit in LOOKS (it is derived from the FeeSharingSystem) uint256 public immutable MINIMUM_DEPOSIT_LOOKS; // LooksRare Token (LOOKS) IERC20 public immutable looksRareToken; // Reward token (WETH) IERC20 public immutable rewardToken; // Whether harvest and WETH selling is triggered automatically at user action bool public canHarvest; // Trading fee on Uniswap v3 (e.g., 3000 ---> 0.3%) uint24 public tradingFeeUniswapV3; // Buffer between two harvests (in blocks) uint256 public harvestBufferBlocks; // Last user action block uint256 public lastHarvestBlock; // Maximum price of LOOKS (in WETH) multiplied 1e18 (e.g., 0.0004 ETH --> 4e14) uint256 public maxPriceLOOKSInWETH; // Threshold amount (in rewardToken) uint256 public thresholdAmount; // Total number of shares outstanding uint256 public totalShares; // Keeps track of number of user shares mapping(address => uint256) public userInfo; event ConversionToLOOKS(uint256 amountSold, uint256 amountReceived); event Deposit(address indexed user, uint256 amount); event FailedConversion(); event HarvestStart(); event HarvestStop(); event NewHarvestBufferBlocks(uint256 harvestBufferBlocks); event NewMaximumPriceLOOKSInWETH(uint256 maxPriceLOOKSInWETH); event NewThresholdAmount(uint256 thresholdAmount); event NewTradingFeeUniswapV3(uint24 tradingFeeUniswapV3); event Withdraw(address indexed user, uint256 amount); /** * @notice Constructor * @param _feeSharingSystem address of the fee sharing system contract * @param _uniswapRouter address of the Uniswap v3 router */ constructor(address _feeSharingSystem, address _uniswapRouter) { address looksRareTokenAddress = address(FeeSharingSystem(_feeSharingSystem).looksRareToken()); address rewardTokenAddress = address(FeeSharingSystem(_feeSharingSystem).rewardToken()); looksRareToken = IERC20(looksRareTokenAddress); rewardToken = IERC20(rewardTokenAddress); feeSharingSystem = FeeSharingSystem(_feeSharingSystem); uniswapRouter = ISwapRouter(_uniswapRouter); IERC20(looksRareTokenAddress).approve(_feeSharingSystem, type(uint256).max); IERC20(rewardTokenAddress).approve(_uniswapRouter, type(uint256).max); tradingFeeUniswapV3 = 3000; MINIMUM_DEPOSIT_LOOKS = FeeSharingSystem(_feeSharingSystem).PRECISION_FACTOR(); } /** * @notice Deposit LOOKS tokens * @param amount amount to deposit (in LOOKS) * @dev There is a limit of 1 LOOKS per deposit to prevent potential manipulation of the shares */ function deposit(uint256 amount) external nonReentrant whenNotPaused { require(amount >= MINIMUM_DEPOSIT_LOOKS, "Deposit: Amount must be >= 1 LOOKS"); if (block.number > (lastHarvestBlock + harvestBufferBlocks) && canHarvest && totalShares != 0) { _harvestAndSellAndCompound(); } // Transfer LOOKS tokens to this address looksRareToken.safeTransferFrom(msg.sender, address(this), amount); // Fetch the total number of LOOKS staked by this contract uint256 totalAmountStaked = feeSharingSystem.calculateSharesValueInLOOKS(address(this)); uint256 currentShares = totalShares == 0 ? amount : (amount * totalShares) / totalAmountStaked; require(currentShares != 0, "Deposit: Fail"); // Adjust number of shares for user/total userInfo[msg.sender] += currentShares; totalShares += currentShares; // Deposit to FeeSharingSystem contract feeSharingSystem.deposit(amount, false); emit Deposit(msg.sender, amount); } /** * @notice Redeem shares for LOOKS tokens * @param shares number of shares to redeem */ function withdraw(uint256 shares) external nonReentrant { require( (shares > 0) && (shares <= userInfo[msg.sender]), "Withdraw: Shares equal to 0 or larger than user shares" ); _withdraw(shares); } /** * @notice Withdraw all shares of sender */ function withdrawAll() external nonReentrant { require(userInfo[msg.sender] > 0, "Withdraw: Shares equal to 0"); _withdraw(userInfo[msg.sender]); } /** * @notice Harvest pending WETH, sell them to LOOKS, and deposit LOOKS (if possible) * @dev Only callable by owner. */ function harvestAndSellAndCompound() external nonReentrant onlyOwner { require(totalShares != 0, "Harvest: No share"); require(block.number != lastHarvestBlock, "Harvest: Already done"); _harvestAndSellAndCompound(); } /** * @notice Adjust allowance if necessary * @dev Only callable by owner. */ function checkAndAdjustLOOKSTokenAllowanceIfRequired() external onlyOwner { looksRareToken.approve(address(feeSharingSystem), type(uint256).max); } /** * @notice Adjust allowance if necessary * @dev Only callable by owner. */ function checkAndAdjustRewardTokenAllowanceIfRequired() external onlyOwner { rewardToken.approve(address(uniswapRouter), type(uint256).max); } /** * @notice Update harvest buffer block * @param _newHarvestBufferBlocks buffer in blocks between two harvest operations * @dev Only callable by owner. */ function updateHarvestBufferBlocks(uint256 _newHarvestBufferBlocks) external onlyOwner { require( _newHarvestBufferBlocks <= MAXIMUM_HARVEST_BUFFER_BLOCKS, "Owner: Must be below MAXIMUM_HARVEST_BUFFER_BLOCKS" ); harvestBufferBlocks = _newHarvestBufferBlocks; emit NewHarvestBufferBlocks(_newHarvestBufferBlocks); } /** * @notice Start automatic harvest/selling transactions * @dev Only callable by owner */ function startHarvest() external onlyOwner { canHarvest = true; emit HarvestStart(); } /** * @notice Stop automatic harvest transactions * @dev Only callable by owner */ function stopHarvest() external onlyOwner { canHarvest = false; emit HarvestStop(); } /** * @notice Update maximum price of LOOKS in WETH * @param _newMaxPriceLOOKSInWETH new maximum price of LOOKS in WETH times 1e18 * @dev Only callable by owner */ function updateMaxPriceOfLOOKSInWETH(uint256 _newMaxPriceLOOKSInWETH) external onlyOwner { maxPriceLOOKSInWETH = _newMaxPriceLOOKSInWETH; emit NewMaximumPriceLOOKSInWETH(_newMaxPriceLOOKSInWETH); } /** * @notice Adjust trading fee for Uniswap v3 * @param _newTradingFeeUniswapV3 new tradingFeeUniswapV3 * @dev Only callable by owner. Can only be 10,000 (1%), 3000 (0.3%), or 500 (0.05%). */ function updateTradingFeeUniswapV3(uint24 _newTradingFeeUniswapV3) external onlyOwner { require( _newTradingFeeUniswapV3 == 10000 || _newTradingFeeUniswapV3 == 3000 || _newTradingFeeUniswapV3 == 500, "Owner: Fee invalid" ); tradingFeeUniswapV3 = _newTradingFeeUniswapV3; emit NewTradingFeeUniswapV3(_newTradingFeeUniswapV3); } /** * @notice Adjust threshold amount for periodic Uniswap v3 WETH --> LOOKS conversion * @param _newThresholdAmount new threshold amount (in WETH) * @dev Only callable by owner */ function updateThresholdAmount(uint256 _newThresholdAmount) external onlyOwner { thresholdAmount = _newThresholdAmount; emit NewThresholdAmount(_newThresholdAmount); } /** * @notice Pause * @dev Only callable by owner */ function pause() external onlyOwner whenNotPaused { _pause(); } /** * @notice Unpause * @dev Only callable by owner */ function unpause() external onlyOwner whenPaused { _unpause(); } /** * @notice Calculate price of one share (in LOOKS token) * Share price is expressed times 1e18 */ function calculateSharePriceInLOOKS() external view returns (uint256) { uint256 totalAmountStakedWithAggregator = feeSharingSystem.calculateSharesValueInLOOKS(address(this)); return totalShares == 0 ? MINIMUM_DEPOSIT_LOOKS : (totalAmountStakedWithAggregator * MINIMUM_DEPOSIT_LOOKS) / (totalShares); } /** * @notice Calculate price of one share (in prime share) * Share price is expressed times 1e18 */ function calculateSharePriceInPrimeShare() external view returns (uint256) { (uint256 totalNumberPrimeShares, , ) = feeSharingSystem.userInfo(address(this)); return totalShares == 0 ? MINIMUM_DEPOSIT_LOOKS : (totalNumberPrimeShares * MINIMUM_DEPOSIT_LOOKS) / totalShares; } /** * @notice Calculate shares value of a user (in LOOKS) * @param user address of the user */ function calculateSharesValueInLOOKS(address user) external view returns (uint256) { uint256 totalAmountStakedWithAggregator = feeSharingSystem.calculateSharesValueInLOOKS(address(this)); return totalShares == 0 ? 0 : (totalAmountStakedWithAggregator * userInfo[user]) / totalShares; } /** * @notice Harvest pending WETH, sell them to LOOKS, and deposit LOOKS (if possible) */ function _harvestAndSellAndCompound() internal { // Try/catch to prevent revertions if nothing to harvest try feeSharingSystem.harvest() {} catch {} uint256 amountToSell = rewardToken.balanceOf(address(this)); if (amountToSell >= thresholdAmount) { bool isExecuted = _sellRewardTokenToLOOKS(amountToSell); if (isExecuted) { uint256 adjustedAmount = looksRareToken.balanceOf(address(this)); if (adjustedAmount >= MINIMUM_DEPOSIT_LOOKS) { feeSharingSystem.deposit(adjustedAmount, false); } } } // Adjust last harvest block lastHarvestBlock = block.number; } /** * @notice Sell WETH to LOOKS * @param _amount amount of rewardToken to convert (WETH) * @return whether the transaction went through */ function _sellRewardTokenToLOOKS(uint256 _amount) internal returns (bool) { uint256 amountOutMinimum = maxPriceLOOKSInWETH != 0 ? (_amount * 1e18) / maxPriceLOOKSInWETH : 0; // Set the order parameters ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams( address(rewardToken), // tokenIn address(looksRareToken), // tokenOut tradingFeeUniswapV3, // fee address(this), // recipient block.timestamp, // deadline _amount, // amountIn amountOutMinimum, // amountOutMinimum 0 // sqrtPriceLimitX96 ); // Swap on Uniswap V3 try uniswapRouter.exactInputSingle(params) returns (uint256 amountOut) { emit ConversionToLOOKS(_amount, amountOut); return true; } catch { emit FailedConversion(); return false; } } /** * @notice Withdraw shares * @param _shares number of shares to redeem * @dev The difference between the two snapshots of LOOKS balances is used to know how many tokens to transfer to user. */ function _withdraw(uint256 _shares) internal { if (block.number > (lastHarvestBlock + harvestBufferBlocks) && canHarvest) { _harvestAndSellAndCompound(); } // Take snapshot of current LOOKS balance uint256 previousBalanceLOOKS = looksRareToken.balanceOf(address(this)); // Fetch total number of prime shares (uint256 totalNumberPrimeShares, , ) = feeSharingSystem.userInfo(address(this)); // Calculate number of prime shares to redeem based on existing shares (from this contract) uint256 currentNumberPrimeShares = (totalNumberPrimeShares * _shares) / totalShares; // Adjust number of shares for user/total userInfo[msg.sender] -= _shares; totalShares -= _shares; // Withdraw amount equivalent in prime shares feeSharingSystem.withdraw(currentNumberPrimeShares, false); // Calculate the difference between the current balance of LOOKS with the previous snapshot uint256 amountToTransfer = looksRareToken.balanceOf(address(this)) - previousBalanceLOOKS; // Transfer the LOOKS amount back to user looksRareToken.safeTransfer(msg.sender, amountToTransfer); emit Withdraw(msg.sender, amountToTransfer); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev 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 { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!paused(), "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(paused(), "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.7.5; pragma abicoder v2; import "./IUniswapV3SwapCallback.sol"; /// @title Router token swapping functionality /// @notice Functions for swapping tokens via Uniswap V3 interface ISwapRouter is IUniswapV3SwapCallback { struct ExactInputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; uint160 sqrtPriceLimitX96; } /// @notice Swaps `amountIn` of one token for as much as possible of another token /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata /// @return amountOut The amount of the received token function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut); struct ExactInputParams { bytes path; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; } /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata /// @return amountOut The amount of the received token function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); struct ExactOutputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountOut; uint256 amountInMaximum; uint160 sqrtPriceLimitX96; } /// @notice Swaps as little as possible of one token for `amountOut` of another token /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata /// @return amountIn The amount of the input token function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn); struct ExactOutputParams { bytes path; address recipient; uint256 deadline; uint256 amountOut; uint256 amountInMaximum; } /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed) /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata /// @return amountIn The amount of the input token function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {TokenDistributor} from "./TokenDistributor.sol"; /** * @title FeeSharingSystem * @notice It handles the distribution of fees using * WETH along with the auto-compounding of LOOKS. */ contract FeeSharingSystem is ReentrancyGuard, Ownable { using SafeERC20 for IERC20; struct UserInfo { uint256 shares; // shares of token staked uint256 userRewardPerTokenPaid; // user reward per token paid uint256 rewards; // pending rewards } // Precision factor for calculating rewards and exchange rate uint256 public constant PRECISION_FACTOR = 10**18; IERC20 public immutable looksRareToken; IERC20 public immutable rewardToken; TokenDistributor public immutable tokenDistributor; // Reward rate (block) uint256 public currentRewardPerBlock; // Last reward adjustment block number uint256 public lastRewardAdjustment; // Last update block for rewards uint256 public lastUpdateBlock; // Current end block for the current reward period uint256 public periodEndBlock; // Reward per token stored uint256 public rewardPerTokenStored; // Total existing shares uint256 public totalShares; mapping(address => UserInfo) public userInfo; event Deposit(address indexed user, uint256 amount, uint256 harvestedAmount); event Harvest(address indexed user, uint256 harvestedAmount); event NewRewardPeriod(uint256 numberBlocks, uint256 rewardPerBlock, uint256 reward); event Withdraw(address indexed user, uint256 amount, uint256 harvestedAmount); /** * @notice Constructor * @param _looksRareToken address of the token staked (LOOKS) * @param _rewardToken address of the reward token * @param _tokenDistributor address of the token distributor contract */ constructor( address _looksRareToken, address _rewardToken, address _tokenDistributor ) { rewardToken = IERC20(_rewardToken); looksRareToken = IERC20(_looksRareToken); tokenDistributor = TokenDistributor(_tokenDistributor); } /** * @notice Deposit staked tokens (and collect reward tokens if requested) * @param amount amount to deposit (in LOOKS) * @param claimRewardToken whether to claim reward tokens * @dev There is a limit of 1 LOOKS per deposit to prevent potential manipulation of current shares */ function deposit(uint256 amount, bool claimRewardToken) external nonReentrant { require(amount >= PRECISION_FACTOR, "Deposit: Amount must be >= 1 LOOKS"); // Auto compounds for everyone tokenDistributor.harvestAndCompound(); // Update reward for user _updateReward(msg.sender); // Retrieve total amount staked by this contract (uint256 totalAmountStaked, ) = tokenDistributor.userInfo(address(this)); // Transfer LOOKS tokens to this address looksRareToken.safeTransferFrom(msg.sender, address(this), amount); uint256 currentShares; // Calculate the number of shares to issue for the user if (totalShares != 0) { currentShares = (amount * totalShares) / totalAmountStaked; // This is a sanity check to prevent deposit for 0 shares require(currentShares != 0, "Deposit: Fail"); } else { currentShares = amount; } // Adjust internal shares userInfo[msg.sender].shares += currentShares; totalShares += currentShares; uint256 pendingRewards; if (claimRewardToken) { // Fetch pending rewards pendingRewards = userInfo[msg.sender].rewards; if (pendingRewards > 0) { userInfo[msg.sender].rewards = 0; rewardToken.safeTransfer(msg.sender, pendingRewards); } } // Verify LOOKS token allowance and adjust if necessary _checkAndAdjustLOOKSTokenAllowanceIfRequired(amount, address(tokenDistributor)); // Deposit user amount in the token distributor contract tokenDistributor.deposit(amount); emit Deposit(msg.sender, amount, pendingRewards); } /** * @notice Harvest reward tokens that are pending */ function harvest() external nonReentrant { // Auto compounds for everyone tokenDistributor.harvestAndCompound(); // Update reward for user _updateReward(msg.sender); // Retrieve pending rewards uint256 pendingRewards = userInfo[msg.sender].rewards; // If pending rewards are null, revert require(pendingRewards > 0, "Harvest: Pending rewards must be > 0"); // Adjust user rewards and transfer userInfo[msg.sender].rewards = 0; // Transfer reward token to sender rewardToken.safeTransfer(msg.sender, pendingRewards); emit Harvest(msg.sender, pendingRewards); } /** * @notice Withdraw staked tokens (and collect reward tokens if requested) * @param shares shares to withdraw * @param claimRewardToken whether to claim reward tokens */ function withdraw(uint256 shares, bool claimRewardToken) external nonReentrant { require( (shares > 0) && (shares <= userInfo[msg.sender].shares), "Withdraw: Shares equal to 0 or larger than user shares" ); _withdraw(shares, claimRewardToken); } /** * @notice Withdraw all staked tokens (and collect reward tokens if requested) * @param claimRewardToken whether to claim reward tokens */ function withdrawAll(bool claimRewardToken) external nonReentrant { _withdraw(userInfo[msg.sender].shares, claimRewardToken); } /** * @notice Update the reward per block (in rewardToken) * @dev Only callable by owner. Owner is meant to be another smart contract. */ function updateRewards(uint256 reward, uint256 rewardDurationInBlocks) external onlyOwner { // Adjust the current reward per block if (block.number >= periodEndBlock) { currentRewardPerBlock = reward / rewardDurationInBlocks; } else { currentRewardPerBlock = (reward + ((periodEndBlock - block.number) * currentRewardPerBlock)) / rewardDurationInBlocks; } lastUpdateBlock = block.number; periodEndBlock = block.number + rewardDurationInBlocks; emit NewRewardPeriod(rewardDurationInBlocks, currentRewardPerBlock, reward); } /** * @notice Calculate pending rewards (WETH) for a user * @param user address of the user */ function calculatePendingRewards(address user) external view returns (uint256) { return _calculatePendingRewards(user); } /** * @notice Calculate value of LOOKS for a user given a number of shares owned * @param user address of the user */ function calculateSharesValueInLOOKS(address user) external view returns (uint256) { // Retrieve amount staked (uint256 totalAmountStaked, ) = tokenDistributor.userInfo(address(this)); // Adjust for pending rewards totalAmountStaked += tokenDistributor.calculatePendingRewards(address(this)); // Return user pro-rata of total shares return userInfo[user].shares == 0 ? 0 : (totalAmountStaked * userInfo[user].shares) / totalShares; } /** * @notice Calculate price of one share (in LOOKS token) * Share price is expressed times 1e18 */ function calculateSharePriceInLOOKS() external view returns (uint256) { (uint256 totalAmountStaked, ) = tokenDistributor.userInfo(address(this)); // Adjust for pending rewards totalAmountStaked += tokenDistributor.calculatePendingRewards(address(this)); return totalShares == 0 ? PRECISION_FACTOR : (totalAmountStaked * PRECISION_FACTOR) / (totalShares); } /** * @notice Return last block where trading rewards were distributed */ function lastRewardBlock() external view returns (uint256) { return _lastRewardBlock(); } /** * @notice Calculate pending rewards for a user * @param user address of the user */ function _calculatePendingRewards(address user) internal view returns (uint256) { return ((userInfo[user].shares * (_rewardPerToken() - (userInfo[user].userRewardPerTokenPaid))) / PRECISION_FACTOR) + userInfo[user].rewards; } /** * @notice Check current allowance and adjust if necessary * @param _amount amount to transfer * @param _to token to transfer */ function _checkAndAdjustLOOKSTokenAllowanceIfRequired(uint256 _amount, address _to) internal { if (looksRareToken.allowance(address(this), _to) < _amount) { looksRareToken.approve(_to, type(uint256).max); } } /** * @notice Return last block where rewards must be distributed */ function _lastRewardBlock() internal view returns (uint256) { return block.number < periodEndBlock ? block.number : periodEndBlock; } /** * @notice Return reward per token */ function _rewardPerToken() internal view returns (uint256) { if (totalShares == 0) { return rewardPerTokenStored; } return rewardPerTokenStored + ((_lastRewardBlock() - lastUpdateBlock) * (currentRewardPerBlock * PRECISION_FACTOR)) / totalShares; } /** * @notice Update reward for a user account * @param _user address of the user */ function _updateReward(address _user) internal { if (block.number != lastUpdateBlock) { rewardPerTokenStored = _rewardPerToken(); lastUpdateBlock = _lastRewardBlock(); } userInfo[_user].rewards = _calculatePendingRewards(_user); userInfo[_user].userRewardPerTokenPaid = rewardPerTokenStored; } /** * @notice Withdraw staked tokens (and collect reward tokens if requested) * @param shares shares to withdraw * @param claimRewardToken whether to claim reward tokens */ function _withdraw(uint256 shares, bool claimRewardToken) internal { // Auto compounds for everyone tokenDistributor.harvestAndCompound(); // Update reward for user _updateReward(msg.sender); // Retrieve total amount staked and calculated current amount (in LOOKS) (uint256 totalAmountStaked, ) = tokenDistributor.userInfo(address(this)); uint256 currentAmount = (totalAmountStaked * shares) / totalShares; userInfo[msg.sender].shares -= shares; totalShares -= shares; // Withdraw amount equivalent in shares tokenDistributor.withdraw(currentAmount); uint256 pendingRewards; if (claimRewardToken) { // Fetch pending rewards pendingRewards = userInfo[msg.sender].rewards; if (pendingRewards > 0) { userInfo[msg.sender].rewards = 0; rewardToken.safeTransfer(msg.sender, pendingRewards); } } // Transfer LOOKS tokens to sender looksRareToken.safeTransfer(msg.sender, currentAmount); emit Withdraw(msg.sender, currentAmount, pendingRewards); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol) pragma solidity ^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 // OpenZeppelin Contracts v4.4.1 (utils/Address.sol) pragma solidity ^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; 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"); (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"); (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"); (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"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Callback for IUniswapV3PoolActions#swap /// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface interface IUniswapV3SwapCallback { /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap. /// @dev In the implementation you must pay the pool tokens owed for the swap. /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory. /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped. /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by /// the end of the swap. If positive, the callback must send that amount of token0 to the pool. /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by /// the end of the swap. If positive, the callback must send that amount of token1 to the pool. /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call function uniswapV3SwapCallback( int256 amount0Delta, int256 amount1Delta, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {ILooksRareToken} from "../interfaces/ILooksRareToken.sol"; /** * @title TokenDistributor * @notice It handles the distribution of LOOKS token. * It auto-adjusts block rewards over a set number of periods. */ contract TokenDistributor is ReentrancyGuard { using SafeERC20 for IERC20; using SafeERC20 for ILooksRareToken; struct StakingPeriod { uint256 rewardPerBlockForStaking; uint256 rewardPerBlockForOthers; uint256 periodLengthInBlock; } struct UserInfo { uint256 amount; // Amount of staked tokens provided by user uint256 rewardDebt; // Reward debt } // Precision factor for calculating rewards uint256 public constant PRECISION_FACTOR = 10**12; ILooksRareToken public immutable looksRareToken; address public immutable tokenSplitter; // Number of reward periods uint256 public immutable NUMBER_PERIODS; // Block number when rewards start uint256 public immutable START_BLOCK; // Accumulated tokens per share uint256 public accTokenPerShare; // Current phase for rewards uint256 public currentPhase; // Block number when rewards end uint256 public endBlock; // Block number of the last update uint256 public lastRewardBlock; // Tokens distributed per block for other purposes (team + treasury + trading rewards) uint256 public rewardPerBlockForOthers; // Tokens distributed per block for staking uint256 public rewardPerBlockForStaking; // Total amount staked uint256 public totalAmountStaked; mapping(uint256 => StakingPeriod) public stakingPeriod; mapping(address => UserInfo) public userInfo; event Compound(address indexed user, uint256 harvestedAmount); event Deposit(address indexed user, uint256 amount, uint256 harvestedAmount); event NewRewardsPerBlock( uint256 indexed currentPhase, uint256 startBlock, uint256 rewardPerBlockForStaking, uint256 rewardPerBlockForOthers ); event Withdraw(address indexed user, uint256 amount, uint256 harvestedAmount); /** * @notice Constructor * @param _looksRareToken LOOKS token address * @param _tokenSplitter token splitter contract address (for team and trading rewards) * @param _startBlock start block for reward program * @param _rewardsPerBlockForStaking array of rewards per block for staking * @param _rewardsPerBlockForOthers array of rewards per block for other purposes (team + treasury + trading rewards) * @param _periodLengthesInBlocks array of period lengthes * @param _numberPeriods number of periods with different rewards/lengthes (e.g., if 3 changes --> 4 periods) */ constructor( address _looksRareToken, address _tokenSplitter, uint256 _startBlock, uint256[] memory _rewardsPerBlockForStaking, uint256[] memory _rewardsPerBlockForOthers, uint256[] memory _periodLengthesInBlocks, uint256 _numberPeriods ) { require( (_periodLengthesInBlocks.length == _numberPeriods) && (_rewardsPerBlockForStaking.length == _numberPeriods) && (_rewardsPerBlockForStaking.length == _numberPeriods), "Distributor: Lengthes must match numberPeriods" ); // 1. Operational checks for supply uint256 nonCirculatingSupply = ILooksRareToken(_looksRareToken).SUPPLY_CAP() - ILooksRareToken(_looksRareToken).totalSupply(); uint256 amountTokensToBeMinted; for (uint256 i = 0; i < _numberPeriods; i++) { amountTokensToBeMinted += (_rewardsPerBlockForStaking[i] * _periodLengthesInBlocks[i]) + (_rewardsPerBlockForOthers[i] * _periodLengthesInBlocks[i]); stakingPeriod[i] = StakingPeriod({ rewardPerBlockForStaking: _rewardsPerBlockForStaking[i], rewardPerBlockForOthers: _rewardsPerBlockForOthers[i], periodLengthInBlock: _periodLengthesInBlocks[i] }); } require(amountTokensToBeMinted == nonCirculatingSupply, "Distributor: Wrong reward parameters"); // 2. Store values looksRareToken = ILooksRareToken(_looksRareToken); tokenSplitter = _tokenSplitter; rewardPerBlockForStaking = _rewardsPerBlockForStaking[0]; rewardPerBlockForOthers = _rewardsPerBlockForOthers[0]; START_BLOCK = _startBlock; endBlock = _startBlock + _periodLengthesInBlocks[0]; NUMBER_PERIODS = _numberPeriods; // Set the lastRewardBlock as the startBlock lastRewardBlock = _startBlock; } /** * @notice Deposit staked tokens and compounds pending rewards * @param amount amount to deposit (in LOOKS) */ function deposit(uint256 amount) external nonReentrant { require(amount > 0, "Deposit: Amount must be > 0"); // Update pool information _updatePool(); // Transfer LOOKS tokens to this contract looksRareToken.safeTransferFrom(msg.sender, address(this), amount); uint256 pendingRewards; // If not new deposit, calculate pending rewards (for auto-compounding) if (userInfo[msg.sender].amount > 0) { pendingRewards = ((userInfo[msg.sender].amount * accTokenPerShare) / PRECISION_FACTOR) - userInfo[msg.sender].rewardDebt; } // Adjust user information userInfo[msg.sender].amount += (amount + pendingRewards); userInfo[msg.sender].rewardDebt = (userInfo[msg.sender].amount * accTokenPerShare) / PRECISION_FACTOR; // Increase totalAmountStaked totalAmountStaked += (amount + pendingRewards); emit Deposit(msg.sender, amount, pendingRewards); } /** * @notice Compound based on pending rewards */ function harvestAndCompound() external nonReentrant { // Update pool information _updatePool(); // Calculate pending rewards uint256 pendingRewards = ((userInfo[msg.sender].amount * accTokenPerShare) / PRECISION_FACTOR) - userInfo[msg.sender].rewardDebt; // Return if no pending rewards if (pendingRewards == 0) { // It doesn't throw revertion (to help with the fee-sharing auto-compounding contract) return; } // Adjust user amount for pending rewards userInfo[msg.sender].amount += pendingRewards; // Adjust totalAmountStaked totalAmountStaked += pendingRewards; // Recalculate reward debt based on new user amount userInfo[msg.sender].rewardDebt = (userInfo[msg.sender].amount * accTokenPerShare) / PRECISION_FACTOR; emit Compound(msg.sender, pendingRewards); } /** * @notice Update pool rewards */ function updatePool() external nonReentrant { _updatePool(); } /** * @notice Withdraw staked tokens and compound pending rewards * @param amount amount to withdraw */ function withdraw(uint256 amount) external nonReentrant { require( (userInfo[msg.sender].amount >= amount) && (amount > 0), "Withdraw: Amount must be > 0 or lower than user balance" ); // Update pool _updatePool(); // Calculate pending rewards uint256 pendingRewards = ((userInfo[msg.sender].amount * accTokenPerShare) / PRECISION_FACTOR) - userInfo[msg.sender].rewardDebt; // Adjust user information userInfo[msg.sender].amount = userInfo[msg.sender].amount + pendingRewards - amount; userInfo[msg.sender].rewardDebt = (userInfo[msg.sender].amount * accTokenPerShare) / PRECISION_FACTOR; // Adjust total amount staked totalAmountStaked = totalAmountStaked + pendingRewards - amount; // Transfer LOOKS tokens to the sender looksRareToken.safeTransfer(msg.sender, amount); emit Withdraw(msg.sender, amount, pendingRewards); } /** * @notice Withdraw all staked tokens and collect tokens */ function withdrawAll() external nonReentrant { require(userInfo[msg.sender].amount > 0, "Withdraw: Amount must be > 0"); // Update pool _updatePool(); // Calculate pending rewards and amount to transfer (to the sender) uint256 pendingRewards = ((userInfo[msg.sender].amount * accTokenPerShare) / PRECISION_FACTOR) - userInfo[msg.sender].rewardDebt; uint256 amountToTransfer = userInfo[msg.sender].amount + pendingRewards; // Adjust total amount staked totalAmountStaked = totalAmountStaked - userInfo[msg.sender].amount; // Adjust user information userInfo[msg.sender].amount = 0; userInfo[msg.sender].rewardDebt = 0; // Transfer LOOKS tokens to the sender looksRareToken.safeTransfer(msg.sender, amountToTransfer); emit Withdraw(msg.sender, amountToTransfer, pendingRewards); } /** * @notice Calculate pending rewards for a user * @param user address of the user * @return Pending rewards */ function calculatePendingRewards(address user) external view returns (uint256) { if ((block.number > lastRewardBlock) && (totalAmountStaked != 0)) { uint256 multiplier = _getMultiplier(lastRewardBlock, block.number); uint256 tokenRewardForStaking = multiplier * rewardPerBlockForStaking; uint256 adjustedEndBlock = endBlock; uint256 adjustedCurrentPhase = currentPhase; // Check whether to adjust multipliers and reward per block while ((block.number > adjustedEndBlock) && (adjustedCurrentPhase < (NUMBER_PERIODS - 1))) { // Update current phase adjustedCurrentPhase++; // Update rewards per block uint256 adjustedRewardPerBlockForStaking = stakingPeriod[adjustedCurrentPhase].rewardPerBlockForStaking; // Calculate adjusted block number uint256 previousEndBlock = adjustedEndBlock; // Update end block adjustedEndBlock = previousEndBlock + stakingPeriod[adjustedCurrentPhase].periodLengthInBlock; // Calculate new multiplier uint256 newMultiplier = (block.number <= adjustedEndBlock) ? (block.number - previousEndBlock) : stakingPeriod[adjustedCurrentPhase].periodLengthInBlock; // Adjust token rewards for staking tokenRewardForStaking += (newMultiplier * adjustedRewardPerBlockForStaking); } uint256 adjustedTokenPerShare = accTokenPerShare + (tokenRewardForStaking * PRECISION_FACTOR) / totalAmountStaked; return (userInfo[user].amount * adjustedTokenPerShare) / PRECISION_FACTOR - userInfo[user].rewardDebt; } else { return (userInfo[user].amount * accTokenPerShare) / PRECISION_FACTOR - userInfo[user].rewardDebt; } } /** * @notice Update reward variables of the pool */ function _updatePool() internal { if (block.number <= lastRewardBlock) { return; } if (totalAmountStaked == 0) { lastRewardBlock = block.number; return; } // Calculate multiplier uint256 multiplier = _getMultiplier(lastRewardBlock, block.number); // Calculate rewards for staking and others uint256 tokenRewardForStaking = multiplier * rewardPerBlockForStaking; uint256 tokenRewardForOthers = multiplier * rewardPerBlockForOthers; // Check whether to adjust multipliers and reward per block while ((block.number > endBlock) && (currentPhase < (NUMBER_PERIODS - 1))) { // Update rewards per block _updateRewardsPerBlock(endBlock); uint256 previousEndBlock = endBlock; // Adjust the end block endBlock += stakingPeriod[currentPhase].periodLengthInBlock; // Adjust multiplier to cover the missing periods with other lower inflation schedule uint256 newMultiplier = _getMultiplier(previousEndBlock, block.number); // Adjust token rewards tokenRewardForStaking += (newMultiplier * rewardPerBlockForStaking); tokenRewardForOthers += (newMultiplier * rewardPerBlockForOthers); } // Mint tokens only if token rewards for staking are not null if (tokenRewardForStaking > 0) { // It allows protection against potential issues to prevent funds from being locked bool mintStatus = looksRareToken.mint(address(this), tokenRewardForStaking); if (mintStatus) { accTokenPerShare = accTokenPerShare + ((tokenRewardForStaking * PRECISION_FACTOR) / totalAmountStaked); } looksRareToken.mint(tokenSplitter, tokenRewardForOthers); } // Update last reward block only if it wasn't updated after or at the end block if (lastRewardBlock <= endBlock) { lastRewardBlock = block.number; } } /** * @notice Update rewards per block * @dev Rewards are halved by 2 (for staking + others) */ function _updateRewardsPerBlock(uint256 _newStartBlock) internal { // Update current phase currentPhase++; // Update rewards per block rewardPerBlockForStaking = stakingPeriod[currentPhase].rewardPerBlockForStaking; rewardPerBlockForOthers = stakingPeriod[currentPhase].rewardPerBlockForOthers; emit NewRewardsPerBlock(currentPhase, _newStartBlock, rewardPerBlockForStaking, rewardPerBlockForOthers); } /** * @notice Return reward multiplier over the given "from" to "to" block. * @param from block to start calculating reward * @param to block to finish calculating reward * @return the multiplier for the period */ function _getMultiplier(uint256 from, uint256 to) internal view returns (uint256) { if (to <= endBlock) { return to - from; } else if (from >= endBlock) { return 0; } else { return endBlock - from; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface ILooksRareToken is IERC20 { function SUPPLY_CAP() external view returns (uint256); function mint(address account, uint256 amount) external returns (bool); }
{ "optimizer": { "enabled": true, "runs": 888888 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_feeSharingSystem","type":"address"},{"internalType":"address","name":"_uniswapRouter","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amountSold","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountReceived","type":"uint256"}],"name":"ConversionToLOOKS","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[],"name":"FailedConversion","type":"event"},{"anonymous":false,"inputs":[],"name":"HarvestStart","type":"event"},{"anonymous":false,"inputs":[],"name":"HarvestStop","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"harvestBufferBlocks","type":"uint256"}],"name":"NewHarvestBufferBlocks","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxPriceLOOKSInWETH","type":"uint256"}],"name":"NewMaximumPriceLOOKSInWETH","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"thresholdAmount","type":"uint256"}],"name":"NewThresholdAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint24","name":"tradingFeeUniswapV3","type":"uint24"}],"name":"NewTradingFeeUniswapV3","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"MAXIMUM_HARVEST_BUFFER_BLOCKS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINIMUM_DEPOSIT_LOOKS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"calculateSharePriceInLOOKS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"calculateSharePriceInPrimeShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"calculateSharesValueInLOOKS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"canHarvest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"checkAndAdjustLOOKSTokenAllowanceIfRequired","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"checkAndAdjustRewardTokenAllowanceIfRequired","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeSharingSystem","outputs":[{"internalType":"contract FeeSharingSystem","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvestAndSellAndCompound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"harvestBufferBlocks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastHarvestBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"looksRareToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPriceLOOKSInWETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startHarvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stopHarvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"thresholdAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tradingFeeUniswapV3","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniswapRouter","outputs":[{"internalType":"contract ISwapRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newHarvestBufferBlocks","type":"uint256"}],"name":"updateHarvestBufferBlocks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newMaxPriceLOOKSInWETH","type":"uint256"}],"name":"updateMaxPriceOfLOOKSInWETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newThresholdAmount","type":"uint256"}],"name":"updateThresholdAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24","name":"_newTradingFeeUniswapV3","type":"uint24"}],"name":"updateTradingFeeUniswapV3","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userInfo","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawAll","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101206040523480156200001257600080fd5b506040516200351638038062003516833981016040819052620000359162000371565b620000403362000321565b6000805460ff60a01b191681556001805560408051631b6dcfd960e11b815290516001600160a01b038516916336db9fb2916004808301926020929190829003018186803b1580156200009257600080fd5b505afa158015620000a7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000cd9190620003db565b90506000836001600160a01b031663f7c618c16040518163ffffffff1660e01b815260040160206040518083038186803b1580156200010b57600080fd5b505afa15801562000120573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001469190620003db565b6001600160601b0319606084811b821660e05282811b82166101005286811b821660805285901b1660a05260405163095ea7b360e01b81526001600160a01b03808716600483015260001960248301529192509083169063095ea7b390604401602060405180830381600087803b158015620001c157600080fd5b505af1158015620001d6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001fc9190620003b0565b5060405163095ea7b360e01b81526001600160a01b038481166004830152600019602483015282169063095ea7b390604401602060405180830381600087803b1580156200024957600080fd5b505af11580156200025e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002849190620003b0565b506002805463ffffff001916620bb8001790556040805163ccd34cd560e01b815290516001600160a01b0386169163ccd34cd5916004808301926020929190829003018186803b158015620002d857600080fd5b505afa158015620002ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003139190620003fb565b60c052506200042e92505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080604083850312156200038557600080fd5b8251620003928162000415565b6020840151909250620003a58162000415565b809150509250929050565b600060208284031215620003c357600080fd5b81518015158114620003d457600080fd5b9392505050565b600060208284031215620003ee57600080fd5b8151620003d48162000415565b6000602082840312156200040e57600080fd5b5051919050565b6001600160a01b03811681146200042b57600080fd5b50565b60805160601c60a05160601c60c05160e05160601c6101005160601c612fda6200053c600039600081816104e501528181611d4b01528181611e2501526128040152600081816102f8015281816115580152818161190501528181611f03015281816120cc0152818161236e0152818161240e01526128290152600081816104870152818161087f015281816108b501528181610d34015281816114560152611f9601526000818161038801528181611cfd01526128f70152600081816103af015281816107ef01528181610ca6015281816111b7015281816115b10152818161174a015281816118b701528181611d7c01528181611ff1015281816121a401526122b50152612fda6000f3fe608060405234801561001057600080fd5b50600436106102415760003560e01c80638456cb5911610145578063b8984c86116100bd578063ea09c2a11161008c578063f7b0055311610071578063f7b00553146104d8578063f7c618c1146104e0578063fca3f55b1461050757600080fd5b8063ea09c2a1146104bc578063f2fde38b146104c557600080fd5b8063b8984c8614610452578063d7f8e43f1461045a578063d84e9ebb14610482578063db200bfa146104a957600080fd5b80639a59514111610114578063b10aa43a116100f9578063b10aa43a1461042e578063b3e7860814610436578063b6b55f251461043f57600080fd5b80639a59514114610408578063ab5e32af1461041b57600080fd5b80638456cb59146103d1578063853828b6146103d95780638b2aa597146103e15780638da5cb5b146103ea57600080fd5b80632e1a7d4d116101d85780635c975abb116101a7578063715018a61161018c578063715018a61461037b578063735de9f7146103835780637f085fd1146103aa57600080fd5b80635c975abb146103505780636de26e381461037357600080fd5b80632e1a7d4d146102e057806336db9fb2146102f35780633a98ef391461033f5780633f4ba83a1461034857600080fd5b8063130180de11610214578063130180de1461029b57806314b74d9a146102ae5780631959a002146102b757806328f4dbb6146102d757600080fd5b8063056f7a0f1461024657806305d26905146102505780630a738779146102635780631064ac151461027e575b600080fd5b61024e61050f565b005b61024e61025e366004612dd5565b6106ea565b61026b6107a7565b6040519081526020015b60405180910390f35b60025461028b9060ff1681565b6040519015158152602001610275565b61024e6102a9366004612dd5565b6108db565b61026b60045481565b61026b6102c5366004612d58565b60086020526000908152604090205481565b61026b60065481565b61024e6102ee366004612dd5565b610a23565b61031a7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610275565b61026b60075481565b61024e610b4f565b60005474010000000000000000000000000000000000000000900460ff1661028b565b61026b610c5e565b61024e610d59565b61031a7f000000000000000000000000000000000000000000000000000000000000000081565b61031a7f000000000000000000000000000000000000000000000000000000000000000081565b61024e610de4565b61024e610ef2565b61026b61196481565b60005473ffffffffffffffffffffffffffffffffffffffff1661031a565b61024e610416366004612db0565b610ff3565b61026b610429366004612d58565b61116f565b61024e611289565b61026b60035481565b61024e61044d366004612dd5565b61135d565b61024e6117f9565b60025461046e90610100900462ffffff1681565b60405162ffffff9091168152602001610275565b61026b7f000000000000000000000000000000000000000000000000000000000000000081565b61024e6104b7366004612dd5565b611985565b61026b60055481565b61024e6104d3366004612d58565b611a3b565b61024e611b68565b61031a7f000000000000000000000000000000000000000000000000000000000000000081565b61024e611c3f565b60026001541415610581576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b600260015560005473ffffffffffffffffffffffffffffffffffffffff163314610607576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b600754610670576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f486172766573743a204e6f2073686172650000000000000000000000000000006044820152606401610578565b6004544314156106dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f486172766573743a20416c726561647920646f6e6500000000000000000000006044820152606401610578565b6106e4611d7a565b60018055565b60005473ffffffffffffffffffffffffffffffffffffffff16331461076b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b60058190556040518181527fbb7d853f3ca3c528bd0d8658c87586e2aa72e909bf52350a2febebc3d86e6e92906020015b60405180910390a150565b6040517f1959a002000000000000000000000000000000000000000000000000000000008152306004820152600090819073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690631959a0029060240160606040518083038186803b15801561083157600080fd5b505afa158015610845573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108699190612e07565b505090506007546000146108b3576007546108a47f000000000000000000000000000000000000000000000000000000000000000083612ef5565b6108ae9190612eba565b6108d5565b7f00000000000000000000000000000000000000000000000000000000000000005b91505090565b60005473ffffffffffffffffffffffffffffffffffffffff16331461095c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b6119648111156109ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4f776e65723a204d7573742062652062656c6f77204d4158494d554d5f48415260448201527f564553545f4255464645525f424c4f434b5300000000000000000000000000006064820152608401610578565b60038190556040518181527f6d7e6751f19ef9993001812d2c797cbadcd5d28801195fc8865e1f89210388789060200161079c565b60026001541415610a90576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610578565b60026001558015801590610ab35750336000908152600860205260409020548111155b610b3f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f57697468647261773a2053686172657320657175616c20746f2030206f72206c60448201527f6172676572207468616e207573657220736861726573000000000000000000006064820152608401610578565b610b488161206e565b5060018055565b60005473ffffffffffffffffffffffffffffffffffffffff163314610bd0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b60005474010000000000000000000000000000000000000000900460ff16610c54576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610578565b610c5c612471565b565b6040517fab5e32af000000000000000000000000000000000000000000000000000000008152306004820152600090819073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063ab5e32af9060240160206040518083038186803b158015610ce857600080fd5b505afa158015610cfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d209190612dee565b90506007546000146108b3576007546108a47f000000000000000000000000000000000000000000000000000000000000000083612ef5565b60005473ffffffffffffffffffffffffffffffffffffffff163314610dda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b610c5c600061256a565b60005473ffffffffffffffffffffffffffffffffffffffff163314610e65576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b60005474010000000000000000000000000000000000000000900460ff1615610eea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610578565b610c5c6125df565b60026001541415610f5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610578565b600260015533600090815260086020526040902054610fda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f57697468647261773a2053686172657320657175616c20746f203000000000006044820152606401610578565b336000908152600860205260409020546106e49061206e565b60005473ffffffffffffffffffffffffffffffffffffffff163314611074576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b8062ffffff16612710148061108f57508062ffffff16610bb8145b806110a057508062ffffff166101f4145b611106576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f4f776e65723a2046656520696e76616c696400000000000000000000000000006044820152606401610578565b600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ff1661010062ffffff8416908102919091179091556040519081527f6ad74f3d67c0aaacc1d39a227db4945469415b7fbe576e134a5d6d5dbf0d889a9060200161079c565b6040517fab5e32af000000000000000000000000000000000000000000000000000000008152306004820152600090819073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063ab5e32af9060240160206040518083038186803b1580156111f957600080fd5b505afa15801561120d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112319190612dee565b905060075460001461127f5760075473ffffffffffffffffffffffffffffffffffffffff84166000908152600860205260409020546112709083612ef5565b61127a9190612eba565b611282565b60005b9392505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461130a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040517fac2c97b84646af77f8f38b20c67f88e77b613bb18dcff8dada6d85fc46bbb68590600090a1565b600260015414156113ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610578565b600260015560005474010000000000000000000000000000000000000000900460ff1615611454576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610578565b7f0000000000000000000000000000000000000000000000000000000000000000811015611504576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f4465706f7369743a20416d6f756e74206d757374206265203e3d2031204c4f4f60448201527f4b530000000000000000000000000000000000000000000000000000000000006064820152608401610578565b6003546004546115149190612ea2565b43118015611524575060025460ff165b8015611531575060075415155b1561153e5761153e611d7a565b61158073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163330846126cb565b6040517fab5e32af0000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063ab5e32af9060240160206040518083038186803b15801561160857600080fd5b505afa15801561161c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116409190612dee565b9050600060075460001461166c57816007548461165d9190612ef5565b6116679190612eba565b61166e565b825b9050806116d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4465706f7369743a204661696c000000000000000000000000000000000000006044820152606401610578565b33600090815260086020526040812080548392906116f6908490612ea2565b92505081905550806007600082825461170f9190612ea2565b90915550506040517f9a40832100000000000000000000000000000000000000000000000000000000815260048101849052600060248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690639a40832190604401600060405180830381600087803b1580156117a357600080fd5b505af11580156117b7573d6000803e3d6000fd5b50506040518581523392507fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c915060200160405180910390a250506001805550565b60005473ffffffffffffffffffffffffffffffffffffffff16331461187a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b6040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b3906044015b602060405180830381600087803b15801561194a57600080fd5b505af115801561195e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119829190612d8e565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314611a06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b60068190556040518181527f0c5f835c1112970802d2e3848cc0541d14975686d176cfc3439b7ac0a9ee28d09060200161079c565b60005473ffffffffffffffffffffffffffffffffffffffff163314611abc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b73ffffffffffffffffffffffffffffffffffffffff8116611b5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610578565b6119828161256a565b60005473ffffffffffffffffffffffffffffffffffffffff163314611be9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040517fd1051920bdffd26b2c190ffd77161a6611db762e9d0b4c2b87681f6a45af75ec90600090a1565b60005473ffffffffffffffffffffffffffffffffffffffff163314611cc0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b6040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401611930565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634641257d6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611de257600080fd5b505af1925050508015611df3575060015b506040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b158015611e7c57600080fd5b505afa158015611e90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eb49190612dee565b90506006548110612067576000611eca826127ad565b90508015612065576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b158015611f5a57600080fd5b505afa158015611f6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f929190612dee565b90507f00000000000000000000000000000000000000000000000000000000000000008110612063576040517f9a40832100000000000000000000000000000000000000000000000000000000815260048101829052600060248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690639a40832190604401600060405180830381600087803b15801561204a57600080fd5b505af115801561205e573d6000803e3d6000fd5b505050505b505b505b5043600455565b60035460045461207e9190612ea2565b4311801561208e575060025460ff165b1561209b5761209b611d7a565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b15801561212357600080fd5b505afa158015612137573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215b9190612dee565b6040517f1959a00200000000000000000000000000000000000000000000000000000000815230600482015290915060009073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690631959a0029060240160606040518083038186803b1580156121e657600080fd5b505afa1580156121fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061221e9190612e07565b50509050600060075484836122339190612ef5565b61223d9190612eba565b33600090815260086020526040812080549293508692909190612261908490612f32565b92505081905550836007600082825461227a9190612f32565b90915550506040517f38d0743600000000000000000000000000000000000000000000000000000000815260048101829052600060248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906338d0743690604401600060405180830381600087803b15801561230e57600080fd5b505af1158015612322573d6000803e3d6000fd5b50506040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000925085915073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906370a082319060240160206040518083038186803b1580156123b057600080fd5b505afa1580156123c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123e89190612dee565b6123f29190612f32565b905061243573ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163383612a07565b60405181815233907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a94243649060200160405180910390a25050505050565b60005474010000000000000000000000000000000000000000900460ff166124f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610578565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60005474010000000000000000000000000000000000000000900460ff1615612664576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610578565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586125403390565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526127a79085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612a62565b50505050565b600080600554600014156127c25760006127e1565b6005546127d784670de0b6b3a7640000612ef5565b6127e19190612eba565b60408051610100808201835273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811683527f000000000000000000000000000000000000000000000000000000000000000081166020840190815260025462ffffff93900483168486019081523060608601908152426080870190815260a087018c815260c088018a8152600060e08a0190815299517f414bf38900000000000000000000000000000000000000000000000000000000815289518816600482015295518716602487015293519096166044850152905184166064840152516084830152925160a4820152915160c48301529251831660e4820152929350917f00000000000000000000000000000000000000000000000000000000000000009091169063414bf3899061010401602060405180830381600087803b15801561293e57600080fd5b505af192505050801561298c575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261298991810190612dee565b60015b6129c3576040517faae67a130b4659edc2a47c783b84fd0693bf47710bfcf2ab37958b563676274190600090a15060009392505050565b60408051868152602081018390527fb69d773dde0af0af79dc63e6051ba81c5d8f46dfbd0c6f32e5537e97c2abf155910160405180910390a1506001949350505050565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052612a5d9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401612725565b505050565b6000612ac4826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612b6e9092919063ffffffff16565b805190915015612a5d5780806020019051810190612ae29190612d8e565b612a5d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610578565b6060612b7d8484600085612b85565b949350505050565b606082471015612c17576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610578565b843b612c7f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610578565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612ca89190612e35565b60006040518083038185875af1925050503d8060008114612ce5576040519150601f19603f3d011682016040523d82523d6000602084013e612cea565b606091505b5091509150612cfa828286612d05565b979650505050505050565b60608315612d14575081611282565b825115612d245782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105789190612e51565b600060208284031215612d6a57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461128257600080fd5b600060208284031215612da057600080fd5b8151801515811461128257600080fd5b600060208284031215612dc257600080fd5b813562ffffff8116811461128257600080fd5b600060208284031215612de757600080fd5b5035919050565b600060208284031215612e0057600080fd5b5051919050565b600080600060608486031215612e1c57600080fd5b8351925060208401519150604084015190509250925092565b60008251612e47818460208701612f49565b9190910192915050565b6020815260008251806020840152612e70816040850160208701612f49565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60008219821115612eb557612eb5612f75565b500190565b600082612ef0577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612f2d57612f2d612f75565b500290565b600082821015612f4457612f44612f75565b500390565b60005b83811015612f64578181015183820152602001612f4c565b838111156127a75750506000910152565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fdfea26469706673582212202c86b54cea867ae71653e1a0b4e948d0d86ef0ab52e0c856e29cee6c1ac8b11a64736f6c63430008070033000000000000000000000000bcd7254a1d759efa08ec7c3291b2e85c5dcc12ce000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102415760003560e01c80638456cb5911610145578063b8984c86116100bd578063ea09c2a11161008c578063f7b0055311610071578063f7b00553146104d8578063f7c618c1146104e0578063fca3f55b1461050757600080fd5b8063ea09c2a1146104bc578063f2fde38b146104c557600080fd5b8063b8984c8614610452578063d7f8e43f1461045a578063d84e9ebb14610482578063db200bfa146104a957600080fd5b80639a59514111610114578063b10aa43a116100f9578063b10aa43a1461042e578063b3e7860814610436578063b6b55f251461043f57600080fd5b80639a59514114610408578063ab5e32af1461041b57600080fd5b80638456cb59146103d1578063853828b6146103d95780638b2aa597146103e15780638da5cb5b146103ea57600080fd5b80632e1a7d4d116101d85780635c975abb116101a7578063715018a61161018c578063715018a61461037b578063735de9f7146103835780637f085fd1146103aa57600080fd5b80635c975abb146103505780636de26e381461037357600080fd5b80632e1a7d4d146102e057806336db9fb2146102f35780633a98ef391461033f5780633f4ba83a1461034857600080fd5b8063130180de11610214578063130180de1461029b57806314b74d9a146102ae5780631959a002146102b757806328f4dbb6146102d757600080fd5b8063056f7a0f1461024657806305d26905146102505780630a738779146102635780631064ac151461027e575b600080fd5b61024e61050f565b005b61024e61025e366004612dd5565b6106ea565b61026b6107a7565b6040519081526020015b60405180910390f35b60025461028b9060ff1681565b6040519015158152602001610275565b61024e6102a9366004612dd5565b6108db565b61026b60045481565b61026b6102c5366004612d58565b60086020526000908152604090205481565b61026b60065481565b61024e6102ee366004612dd5565b610a23565b61031a7f000000000000000000000000f4d2888d29d722226fafa5d9b24f9164c092421e81565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610275565b61026b60075481565b61024e610b4f565b60005474010000000000000000000000000000000000000000900460ff1661028b565b61026b610c5e565b61024e610d59565b61031a7f000000000000000000000000e592427a0aece92de3edee1f18e0157c0586156481565b61031a7f000000000000000000000000bcd7254a1d759efa08ec7c3291b2e85c5dcc12ce81565b61024e610de4565b61024e610ef2565b61026b61196481565b60005473ffffffffffffffffffffffffffffffffffffffff1661031a565b61024e610416366004612db0565b610ff3565b61026b610429366004612d58565b61116f565b61024e611289565b61026b60035481565b61024e61044d366004612dd5565b61135d565b61024e6117f9565b60025461046e90610100900462ffffff1681565b60405162ffffff9091168152602001610275565b61026b7f0000000000000000000000000000000000000000000000000de0b6b3a764000081565b61024e6104b7366004612dd5565b611985565b61026b60055481565b61024e6104d3366004612d58565b611a3b565b61024e611b68565b61031a7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b61024e611c3f565b60026001541415610581576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b600260015560005473ffffffffffffffffffffffffffffffffffffffff163314610607576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b600754610670576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f486172766573743a204e6f2073686172650000000000000000000000000000006044820152606401610578565b6004544314156106dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f486172766573743a20416c726561647920646f6e6500000000000000000000006044820152606401610578565b6106e4611d7a565b60018055565b60005473ffffffffffffffffffffffffffffffffffffffff16331461076b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b60058190556040518181527fbb7d853f3ca3c528bd0d8658c87586e2aa72e909bf52350a2febebc3d86e6e92906020015b60405180910390a150565b6040517f1959a002000000000000000000000000000000000000000000000000000000008152306004820152600090819073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000bcd7254a1d759efa08ec7c3291b2e85c5dcc12ce1690631959a0029060240160606040518083038186803b15801561083157600080fd5b505afa158015610845573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108699190612e07565b505090506007546000146108b3576007546108a47f0000000000000000000000000000000000000000000000000de0b6b3a764000083612ef5565b6108ae9190612eba565b6108d5565b7f0000000000000000000000000000000000000000000000000de0b6b3a76400005b91505090565b60005473ffffffffffffffffffffffffffffffffffffffff16331461095c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b6119648111156109ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4f776e65723a204d7573742062652062656c6f77204d4158494d554d5f48415260448201527f564553545f4255464645525f424c4f434b5300000000000000000000000000006064820152608401610578565b60038190556040518181527f6d7e6751f19ef9993001812d2c797cbadcd5d28801195fc8865e1f89210388789060200161079c565b60026001541415610a90576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610578565b60026001558015801590610ab35750336000908152600860205260409020548111155b610b3f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f57697468647261773a2053686172657320657175616c20746f2030206f72206c60448201527f6172676572207468616e207573657220736861726573000000000000000000006064820152608401610578565b610b488161206e565b5060018055565b60005473ffffffffffffffffffffffffffffffffffffffff163314610bd0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b60005474010000000000000000000000000000000000000000900460ff16610c54576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610578565b610c5c612471565b565b6040517fab5e32af000000000000000000000000000000000000000000000000000000008152306004820152600090819073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000bcd7254a1d759efa08ec7c3291b2e85c5dcc12ce169063ab5e32af9060240160206040518083038186803b158015610ce857600080fd5b505afa158015610cfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d209190612dee565b90506007546000146108b3576007546108a47f0000000000000000000000000000000000000000000000000de0b6b3a764000083612ef5565b60005473ffffffffffffffffffffffffffffffffffffffff163314610dda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b610c5c600061256a565b60005473ffffffffffffffffffffffffffffffffffffffff163314610e65576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b60005474010000000000000000000000000000000000000000900460ff1615610eea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610578565b610c5c6125df565b60026001541415610f5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610578565b600260015533600090815260086020526040902054610fda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f57697468647261773a2053686172657320657175616c20746f203000000000006044820152606401610578565b336000908152600860205260409020546106e49061206e565b60005473ffffffffffffffffffffffffffffffffffffffff163314611074576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b8062ffffff16612710148061108f57508062ffffff16610bb8145b806110a057508062ffffff166101f4145b611106576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f4f776e65723a2046656520696e76616c696400000000000000000000000000006044820152606401610578565b600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ff1661010062ffffff8416908102919091179091556040519081527f6ad74f3d67c0aaacc1d39a227db4945469415b7fbe576e134a5d6d5dbf0d889a9060200161079c565b6040517fab5e32af000000000000000000000000000000000000000000000000000000008152306004820152600090819073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000bcd7254a1d759efa08ec7c3291b2e85c5dcc12ce169063ab5e32af9060240160206040518083038186803b1580156111f957600080fd5b505afa15801561120d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112319190612dee565b905060075460001461127f5760075473ffffffffffffffffffffffffffffffffffffffff84166000908152600860205260409020546112709083612ef5565b61127a9190612eba565b611282565b60005b9392505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461130a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040517fac2c97b84646af77f8f38b20c67f88e77b613bb18dcff8dada6d85fc46bbb68590600090a1565b600260015414156113ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610578565b600260015560005474010000000000000000000000000000000000000000900460ff1615611454576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610578565b7f0000000000000000000000000000000000000000000000000de0b6b3a7640000811015611504576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f4465706f7369743a20416d6f756e74206d757374206265203e3d2031204c4f4f60448201527f4b530000000000000000000000000000000000000000000000000000000000006064820152608401610578565b6003546004546115149190612ea2565b43118015611524575060025460ff165b8015611531575060075415155b1561153e5761153e611d7a565b61158073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000f4d2888d29d722226fafa5d9b24f9164c092421e163330846126cb565b6040517fab5e32af0000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000bcd7254a1d759efa08ec7c3291b2e85c5dcc12ce73ffffffffffffffffffffffffffffffffffffffff169063ab5e32af9060240160206040518083038186803b15801561160857600080fd5b505afa15801561161c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116409190612dee565b9050600060075460001461166c57816007548461165d9190612ef5565b6116679190612eba565b61166e565b825b9050806116d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4465706f7369743a204661696c000000000000000000000000000000000000006044820152606401610578565b33600090815260086020526040812080548392906116f6908490612ea2565b92505081905550806007600082825461170f9190612ea2565b90915550506040517f9a40832100000000000000000000000000000000000000000000000000000000815260048101849052600060248201527f000000000000000000000000bcd7254a1d759efa08ec7c3291b2e85c5dcc12ce73ffffffffffffffffffffffffffffffffffffffff1690639a40832190604401600060405180830381600087803b1580156117a357600080fd5b505af11580156117b7573d6000803e3d6000fd5b50506040518581523392507fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c915060200160405180910390a250506001805550565b60005473ffffffffffffffffffffffffffffffffffffffff16331461187a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b6040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000bcd7254a1d759efa08ec7c3291b2e85c5dcc12ce811660048301527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60248301527f000000000000000000000000f4d2888d29d722226fafa5d9b24f9164c092421e169063095ea7b3906044015b602060405180830381600087803b15801561194a57600080fd5b505af115801561195e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119829190612d8e565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314611a06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b60068190556040518181527f0c5f835c1112970802d2e3848cc0541d14975686d176cfc3439b7ac0a9ee28d09060200161079c565b60005473ffffffffffffffffffffffffffffffffffffffff163314611abc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b73ffffffffffffffffffffffffffffffffffffffff8116611b5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610578565b6119828161256a565b60005473ffffffffffffffffffffffffffffffffffffffff163314611be9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040517fd1051920bdffd26b2c190ffd77161a6611db762e9d0b4c2b87681f6a45af75ec90600090a1565b60005473ffffffffffffffffffffffffffffffffffffffff163314611cc0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610578565b6040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564811660048301527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60248301527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2169063095ea7b390604401611930565b7f000000000000000000000000bcd7254a1d759efa08ec7c3291b2e85c5dcc12ce73ffffffffffffffffffffffffffffffffffffffff16634641257d6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611de257600080fd5b505af1925050508015611df3575060015b506040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b158015611e7c57600080fd5b505afa158015611e90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eb49190612dee565b90506006548110612067576000611eca826127ad565b90508015612065576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000f4d2888d29d722226fafa5d9b24f9164c092421e73ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b158015611f5a57600080fd5b505afa158015611f6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f929190612dee565b90507f0000000000000000000000000000000000000000000000000de0b6b3a76400008110612063576040517f9a40832100000000000000000000000000000000000000000000000000000000815260048101829052600060248201527f000000000000000000000000bcd7254a1d759efa08ec7c3291b2e85c5dcc12ce73ffffffffffffffffffffffffffffffffffffffff1690639a40832190604401600060405180830381600087803b15801561204a57600080fd5b505af115801561205e573d6000803e3d6000fd5b505050505b505b505b5043600455565b60035460045461207e9190612ea2565b4311801561208e575060025460ff165b1561209b5761209b611d7a565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000f4d2888d29d722226fafa5d9b24f9164c092421e73ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b15801561212357600080fd5b505afa158015612137573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215b9190612dee565b6040517f1959a00200000000000000000000000000000000000000000000000000000000815230600482015290915060009073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000bcd7254a1d759efa08ec7c3291b2e85c5dcc12ce1690631959a0029060240160606040518083038186803b1580156121e657600080fd5b505afa1580156121fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061221e9190612e07565b50509050600060075484836122339190612ef5565b61223d9190612eba565b33600090815260086020526040812080549293508692909190612261908490612f32565b92505081905550836007600082825461227a9190612f32565b90915550506040517f38d0743600000000000000000000000000000000000000000000000000000000815260048101829052600060248201527f000000000000000000000000bcd7254a1d759efa08ec7c3291b2e85c5dcc12ce73ffffffffffffffffffffffffffffffffffffffff16906338d0743690604401600060405180830381600087803b15801561230e57600080fd5b505af1158015612322573d6000803e3d6000fd5b50506040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000925085915073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000f4d2888d29d722226fafa5d9b24f9164c092421e16906370a082319060240160206040518083038186803b1580156123b057600080fd5b505afa1580156123c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123e89190612dee565b6123f29190612f32565b905061243573ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000f4d2888d29d722226fafa5d9b24f9164c092421e163383612a07565b60405181815233907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a94243649060200160405180910390a25050505050565b60005474010000000000000000000000000000000000000000900460ff166124f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610578565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60005474010000000000000000000000000000000000000000900460ff1615612664576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610578565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586125403390565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526127a79085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612a62565b50505050565b600080600554600014156127c25760006127e1565b6005546127d784670de0b6b3a7640000612ef5565b6127e19190612eba565b60408051610100808201835273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2811683527f000000000000000000000000f4d2888d29d722226fafa5d9b24f9164c092421e81166020840190815260025462ffffff93900483168486019081523060608601908152426080870190815260a087018c815260c088018a8152600060e08a0190815299517f414bf38900000000000000000000000000000000000000000000000000000000815289518816600482015295518716602487015293519096166044850152905184166064840152516084830152925160a4820152915160c48301529251831660e4820152929350917f000000000000000000000000e592427a0aece92de3edee1f18e0157c058615649091169063414bf3899061010401602060405180830381600087803b15801561293e57600080fd5b505af192505050801561298c575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261298991810190612dee565b60015b6129c3576040517faae67a130b4659edc2a47c783b84fd0693bf47710bfcf2ab37958b563676274190600090a15060009392505050565b60408051868152602081018390527fb69d773dde0af0af79dc63e6051ba81c5d8f46dfbd0c6f32e5537e97c2abf155910160405180910390a1506001949350505050565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052612a5d9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401612725565b505050565b6000612ac4826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612b6e9092919063ffffffff16565b805190915015612a5d5780806020019051810190612ae29190612d8e565b612a5d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610578565b6060612b7d8484600085612b85565b949350505050565b606082471015612c17576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610578565b843b612c7f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610578565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612ca89190612e35565b60006040518083038185875af1925050503d8060008114612ce5576040519150601f19603f3d011682016040523d82523d6000602084013e612cea565b606091505b5091509150612cfa828286612d05565b979650505050505050565b60608315612d14575081611282565b825115612d245782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105789190612e51565b600060208284031215612d6a57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461128257600080fd5b600060208284031215612da057600080fd5b8151801515811461128257600080fd5b600060208284031215612dc257600080fd5b813562ffffff8116811461128257600080fd5b600060208284031215612de757600080fd5b5035919050565b600060208284031215612e0057600080fd5b5051919050565b600080600060608486031215612e1c57600080fd5b8351925060208401519150604084015190509250925092565b60008251612e47818460208701612f49565b9190910192915050565b6020815260008251806020840152612e70816040850160208701612f49565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60008219821115612eb557612eb5612f75565b500190565b600082612ef0577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612f2d57612f2d612f75565b500290565b600082821015612f4457612f44612f75565b500390565b60005b83811015612f64578181015183820152602001612f4c565b838111156127a75750506000910152565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fdfea26469706673582212202c86b54cea867ae71653e1a0b4e948d0d86ef0ab52e0c856e29cee6c1ac8b11a64736f6c63430008070033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000bcd7254a1d759efa08ec7c3291b2e85c5dcc12ce000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564
-----Decoded View---------------
Arg [0] : _feeSharingSystem (address): 0xBcD7254A1D759EFA08eC7c3291B2E85c5dCC12ce
Arg [1] : _uniswapRouter (address): 0xE592427A0AEce92De3Edee1F18E0157C05861564
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000bcd7254a1d759efa08ec7c3291b2e85c5dcc12ce
Arg [1] : 000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $3,273.04 | 0.1305 | $427.06 |
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.