Source Code
Overview
ETH Balance
0 ETH
Token Holdings
More Info
ContractCreator
Multichain Info
N/A
Latest 19 from a total of 19 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
Amount
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Stake Uniswap V3... | 31415309 | 77 days ago | IN | 0 ETH | 0.00000049 | ||||
| Set Reward Param... | 31414331 | 77 days ago | IN | 0 ETH | 0.00000007 | ||||
| Set Reward Param... | 31414321 | 77 days ago | IN | 0 ETH | 0.00000011 | ||||
| Add Reward Token | 31414303 | 77 days ago | IN | 0 ETH | 0.00000013 | ||||
| Decrease Liquidi... | 31414250 | 77 days ago | IN | 0 ETH | 0.0000004 | ||||
| Increase Liquidi... | 31414234 | 77 days ago | IN | 0 ETH | 0.00000045 | ||||
| Increase Liquidi... | 31413650 | 77 days ago | IN | 0 ETH | 0.00000035 | ||||
| Increase Liquidi... | 31413628 | 77 days ago | IN | 0 ETH | 0.00000055 | ||||
| Stake Uniswap V3... | 31413605 | 77 days ago | IN | 0 ETH | 0.00000042 | ||||
| Stake Uniswap V3... | 31183344 | 83 days ago | IN | 0 ETH | 0.00000057 | ||||
| Set Reward Param... | 31093990 | 85 days ago | IN | 0 ETH | 0.00000009 | ||||
| Set Reward Param... | 31057445 | 86 days ago | IN | 0 ETH | 0.00000009 | ||||
| Decrease Liquidi... | 30570240 | 97 days ago | IN | 0 ETH | 0.00000076 | ||||
| Decrease Liquidi... | 30570128 | 97 days ago | IN | 0 ETH | 0.00000056 | ||||
| Decrease Liquidi... | 30570103 | 97 days ago | IN | 0 ETH | 0.00000042 | ||||
| Stake Uniswap V3... | 30570079 | 97 days ago | IN | 0 ETH | 0.00000046 | ||||
| Stake Uniswap V3... | 30540994 | 98 days ago | IN | 0 ETH | 0.00000058 | ||||
| Setup Add Tokens | 30489063 | 99 days ago | IN | 0 ETH | 0.00000071 | ||||
| Set POW_Contract | 30489062 | 99 days ago | IN | 0 ETH | 0.0000001 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | Amount | ||
|---|---|---|---|---|---|---|
| 33635593 | 26 days ago | 0.00012188 ETH | ||||
| 33635593 | 26 days ago | 0.00012188 ETH | ||||
| 33633840 | 26 days ago | 0.00012188 ETH | ||||
| 33633840 | 26 days ago | 0.00012188 ETH | ||||
| 33002091 | 41 days ago | 0.00007609 ETH | ||||
| 33002091 | 41 days ago | 0.00007609 ETH | ||||
| 32905136 | 43 days ago | 0.00007251 ETH | ||||
| 32905136 | 43 days ago | 0.00007251 ETH | ||||
| 32808464 | 45 days ago | 0.0000163 ETH | ||||
| 32808464 | 45 days ago | 0.0000163 ETH | ||||
| 32779104 | 46 days ago | 0.00001454 ETH | ||||
| 32779104 | 46 days ago | 0.00001454 ETH | ||||
| 32750991 | 46 days ago | 0.00001186 ETH | ||||
| 32750991 | 46 days ago | 0.00001186 ETH | ||||
| 32726710 | 47 days ago | 0.00001238 ETH | ||||
| 32726710 | 47 days ago | 0.00001238 ETH | ||||
| 32700187 | 48 days ago | 0.0000028 ETH | ||||
| 32700187 | 48 days ago | 0.0000028 ETH | ||||
| 32693352 | 48 days ago | 0.00000279 ETH | ||||
| 32693352 | 48 days ago | 0.00000279 ETH | ||||
| 32686426 | 48 days ago | 0.00000265 ETH | ||||
| 32686426 | 48 days ago | 0.00000265 ETH | ||||
| 32679730 | 48 days ago | 0.00000261 ETH | ||||
| 32679730 | 48 days ago | 0.00000261 ETH | ||||
| 32673050 | 48 days ago | 0.00000062 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
B0x_LP_Rewards
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
//Might want to make Ownables' owner our cold storage address
/* MUST UPDATE ADDRSES WETH FOR EACH CHAIN */
/* MUST UPDATE ADDRSES WETH FOR EACH CHAIN */
/* MUST UPDATE ADDRSES WETH FOR EACH CHAIN */
/* MUST UPDATE ADDRSES WETH FOR EACH CHAIN */
//address public addressWETH = (0xfff9976782d46cc05630d1f6ebab18b2324d6b14);
/* REMOVE maxTime and the if statement
if(startTime>maxTime){
startTime = maxTime;
}
We dont need it for actual launch.ab
uint maxTime=0; //Helps us have easier launch
function addRewardToken(IERC20 token) external onlyOwner {
require(!isRewardToken[token], "Token already added");
rewardTokens_Map.push(token);
isRewardToken[token] = true;
RewardData storage rd = rewardData[token];
rd.rewardPerTokenStored = rewardPerToken(token);
rd.rewardRate = 0;
rd.lastUpdateTime = 0;
uint startTime = (_PoW_Contract.startTime());
if(startTime>maxTime){
startTime = maxTime;
}
change to mainnet address
/// @notice Address of USDC token on the current chain
address immutable public addressUSDC = address(0x036CbD53842c5426634e7929541eC2318f3dCF7e);
change to mainnet address
change to mainnet address
/// @notice Uniswap V4 state view contract for reading pool data
IStateView public immutable stateView = IStateView(0x571291b572ed32ce6751a2Cb2486EbEe8DEfB9B4);
change to mainnet address
change to mainnet address
/// @notice Permit2 contract address for token approvals
address public immutable permit2 = address(0x000000000022D473030F116dDEE9F6B43aC78BA3);
change to mainnet address
uniswapv4PositionManager = IPositionManager(0x4B2C77d209D3405F41a037Ec6c77F7F5b8e2ca80);
change to mainnet address
change to mainnet address
*/
// B ZERO X Token - B0x Token Uniswap v4 Staking Contract for 0xBTC/B0x
//
// Website: https://bzerox.com/
// Github: https://github.com/B0x-Token/
// Discord: https://discord.gg/K89uF2C8vJ
// Twitter: https://x.com/B0x_Token/
//
//
// Distrubtion of B ZERO X Tokens - B0x Token is as follows:
//
// B0x Token is distributed to users by using Proof of work and is considered a Version 2 & Layer 2 of 0xBitcoin. Our contract allows all 0xBitcoin to be converted to B0x Tokens.
// Computers solve a complicated problem to gain tokens!
// 100% of 0xBitcoin accepted for B0x Tokens
// 100% Of the Token is distributed to the users! No dev fee!
// Token Mining will take place on Base Blockchain, while having the token reside on Mainnet Ethereum.
//
// Symbol: B0x
// Decimals: 18
//
// Total supply: 31,165,100.000000000000000000
// =
// 10,835,900 0xBitcoin Tokens able to transfered to B0x Tokens.
// +
// 10,164,100 Mined over 100+ years using Bitcoins Distrubtion halvings every ~4 years. Uses Proof-oF-Work to distribute the tokens. Public Miner is available see https://bzerox.com/
// +
// 10,164,100 sent to Liquidity Providers of the 0xBTC/B0x liquidity pool. Distributes 1 token to the Staking contract for every 1 token minted by Proof-of-Work miners
//
//
// No dev cut, or advantage taken at launch. Public miner available at launch. 100% of the token is given away fairly over 100+ years using Bitcoins model!
//
// Mint 2016 answers per challenge in this cost savings Bitcoin!! Less failed transactions as the challenge only changes every 2016 answers instead of every answer.
//
// Credits: 0xBitcoin
//
// File: @openzeppelin/contracts/ownership/Ownable.sol
pragma solidity ^0.8.14;
/// @title Ownable
/// @notice Contract module which provides a basic access control mechanism
/// @dev Provides ownership functionality where there is an account (an owner) that can be granted exclusive access to specific functions
contract Ownable {
/// @notice The current owner of the contract
address public owner;
/// @notice Emitted when ownership is transferred from one address to another
/// @param previousOwner The address of the previous owner
/// @param newOwner The address of the new owner
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/// @notice Sets the deployer as the initial owner of the contract
constructor() {
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
/// @notice Modifier that restricts function access to only the contract owner
modifier onlyOwner() {
require(msg.sender == owner, "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.
*/
/// @notice Renounces ownership of the contract, leaving it without an owner
/// @dev This will disable all onlyOwner functions permanently
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(owner, address(0));
owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
/// @notice Transfers ownership of the contract to a new account
/// @param newOwner The address of the new owner
function transferOwnership(address newOwner) public onlyOwner {
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
*/
/// @notice Internal function to transfer ownership with validation
/// @param newOwner The address of the new owner
/// @dev Validates that newOwner is not the zero address before transferring
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
library SafeMath2 {
function divRound(uint256 x, uint256 y) internal pure returns (uint256) {
require(y != 0);
uint256 r = x / y;
if (x % y != 0) {
r = r + 1;
}
return r;
}
}
interface IB0x_Mining_Proof_of_Work {
// Function to get the startTime value
function startTime() external view returns (uint);
}
interface IWETH {
// Main deposit function - converts ETH to WETH
function deposit() external payable;
}
/**
* @title Uniswap V4 Swap Contract with ETH Support
* @notice Implementation for swapping with Uniswap V4 pools with native ETH support
*/
/**
* @title IPermit2
* @dev Interface for the Permit2 contract which handles token approvals with signatures
*/
interface IPermit2 {
/**
* @notice Approves the spender to use up to amount of the owner's token until the expiration timestamp
* @param token The token address to approve
* @param spender The address to approve for spending
* @param amount The amount of tokens approved as a uint160
* @param expiration The timestamp at which the approval expires (uint48)
*/
function approve(
address token,
address spender,
uint160 amount,
uint48 expiration
) external;
}
/// @title IStateView
/// @notice Interface for viewing pool state information in Uniswap V4
/// @dev Provides read-only access to pool liquidity and state data
interface IStateView {
/// @notice Type alias for pool identifier as bytes32
type PoolId is bytes32;
/// @notice Gets the current liquidity amount for a specific pool
/// @param poolId The unique identifier of the pool
/// @return liquidity The current liquidity amount in the pool
function getLiquidity(bytes32 poolId) external view returns (uint128 liquidity);
/**
* @notice Retrieves the Slot0 data for a specific pool
* @param poolId The unique identifier of the pool
* @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value
* @return tick The current tick of the pool
* @return protocolFee The current protocol fee setting of the pool
* @return lpFee The current LP fee setting of the pool
*/
function getSlot0(bytes32 poolId)
external
view
returns (uint160 sqrtPriceX96, int24 tick, uint24 protocolFee, uint24 lpFee);
}
// Define the Currency type as a wrapped address
type Currency is address;
// Minimal interface for Hooks
interface IHooks2 {
function currentFee() external view returns (uint24);
function beforeInitialize(address sender, PoolKey calldata key, uint160 sqrtPriceX96, bytes calldata hookData) external returns (bytes4);
function afterInitialize(address sender, PoolKey calldata key, uint160 sqrtPriceX96, int24 tick, bytes calldata hookData) external returns (bytes4);
}
// Minimal representation of Uniswap V4 PoolKey
struct PoolKey {
Currency currency0;
Currency currency1;
uint24 fee;
int24 tickSpacing;
IHooks2 hooks;
}
/// @title IPositionManager
/// @notice Interface for managing Uniswap V4 liquidity positions
/// @dev Provides functionality for position management, liquidity modifications, and NFT operations
interface IPositionManager {
/// @notice Returns the owner of a specific position NFT
/// @param id The token ID of the position NFT
/// @return owner The address that owns the position NFT
function ownerOf(uint256 id) external view returns (address owner);
/// @notice Approves another address to transfer a specific position NFT
/// @param to The address to approve for transfer
/// @param tokenId The token ID of the position NFT to approve
function approve(address to, uint256 tokenId) external;
/// @notice Gets the current liquidity amount for a specific position
/// @param tokenId The token ID of the position NFT
/// @return liquidity The current liquidity amount in the position
function getPositionLiquidity(uint256 tokenId) external view returns (uint128 liquidity);
/// @notice Gets the pool key and position information for a specific position
/// @param tokenId The token ID of the position NFT
/// @return poolKey The pool key structure containing pool parameters
/// @return info Additional position information
function getPoolAndPositionInfo(uint256 tokenId) external view returns (PoolKey memory poolKey, uint info);
/// @notice Returns the next token ID that will be minted
/// @return uint256 The next available token ID
function nextTokenId() external view returns (uint256);
/**
* @notice Modifies liquidities based on encoded actions in unlockData
* @param unlockData Encoded data containing the actions to be executed
* @param deadline Timestamp after which the transaction will revert
* @dev Function is payable and includes isNotLocked and checkDeadline modifiers
*/
/// @notice Modifies liquidity positions based on encoded action data
/// @param unlockData Encoded bytes containing the actions and parameters to execute
/// @param deadline Timestamp after which the transaction will revert
/// @dev This is the main function for creating, modifying, and managing positions
function modifyLiquidities(
bytes calldata unlockData,
uint256 deadline
) external payable;
/// @notice Safely transfers a position NFT from one address to another
/// @param from The current owner of the position NFT
/// @param to The address to transfer the position NFT to
/// @param tokenId The token ID of the position NFT to transfer
/// @dev Includes safety checks to ensure the recipient can handle NFTs
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
}
//Recieve NFTs
/// @title IERC721Receiver
/// @notice Interface for contracts that can receive ERC721 tokens via safe transfers
/// @dev Implementation of this interface allows a contract to receive NFTs through safeTransferFrom
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
/// @notice Handles the receipt of an NFT
/// @param operator The address which initiated the transfer (may be the owner or approved address)
/// @param from The address which previously owned the token
/// @param tokenId The NFT identifier which is being transferred
/// @param data Additional data with no specified format, sent in call to `to`
/// @return bytes4 Must return `IERC721Receiver.onERC721Received.selector` to accept the transfer
/// @dev This function is called whenever an ERC721 token is transferred to this contract via safeTransferFrom
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
interface IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
/// @title StakedTokenWrapper
/// @notice Base contract for managing staked token balances and total supply
/// @dev Provides internal staking and withdrawal functionality with balance tracking
contract StakedTokenWrapper {
/// @notice Total amount of tokens currently staked across all users
uint256 public totalSupply;
/// @notice Mapping of user addresses to their staked token balances
mapping(address => uint256) private _balances;
/// @notice Emitted when a user stakes tokens
/// @param user The address of the user who staked tokens
/// @param amount The amount of tokens staked
event Staked(address indexed user, uint256 amount);
/// @notice Emitted when a user withdraws staked tokens
/// @param user The address of the user who withdrew tokens
/// @param amount The amount of tokens withdrawn
event Withdrawn(address indexed user, uint256 amount);
/// @notice Returns the staked token balance of a specific account
/// @param account The address to query the balance for
/// @return uint256 The staked token balance of the account
function balanceOf(address account) public view returns (uint256) {
return _balances[account];
}
/// @notice Error message for failed staked token transfers
string constant _transferErrorMessage = "staked token transfer failed";
/// @notice Internal function to stake tokens for a specific address
/// @param forWhom The address to stake tokens for
/// @param amount The amount of tokens to stake
/// @dev Updates total supply and user balance, emits Staked event
function stakeFor(address forWhom, uint128 amount) internal virtual {
unchecked {
totalSupply += amount;
_balances[forWhom] += amount;
}
emit Staked(forWhom, amount);
}
/// @notice Internal function to withdraw staked tokens for the caller
/// @param amount The amount of tokens to withdraw
/// @dev Requires sufficient balance, updates total supply and user balance, emits Withdrawn event
function withdraw(uint128 amount) internal virtual {
require(amount <= _balances[msg.sender], "withdraw: balance is lower");
unchecked {
_balances[msg.sender] -= amount;
totalSupply = totalSupply-amount;
}
emit Withdrawn(msg.sender, amount);
}
}
/// @title B0x_LP_Rewards
/// @notice Liquidity provider rewards contract for Uniswap V4 positions with multi-token rewards
/// @dev Extends StakedTokenWrapper and Ownable to provide staking functionality for LP NFTs
contract B0x_LP_Rewards is StakedTokenWrapper, Ownable {
/// @notice Main token contract interface for B0x Token on Base
IERC20 public immutable MainTokenAddress;
/// @notice Address of the 0xBTC token (must be updated for each chain)
address immutable public zeroXBTC = address(0);
/// @notice Address of WETH token on the current chain
address immutable public addressWETH = address(0x4200000000000000000000000000000000000006);
/// @notice Address of USDC token on the current chain
address immutable public addressUSDC = address(0x036CbD53842c5426634e7929541eC2318f3dCF7e);
/* MUST UPDATE addressWETH & zeroxBTC FOR EACH CHAIN */
/* MUST UPDATE ADDRSES WETH & zeroxBTC FOR EACH CHAIN */
/* MUST UPDATE ADDRSES WETH FOR EACH CHAIN */
/* MUST UPDATE ADDRSES WETH FOR EACH CHAIN */
/* MUST UPDATE ADDRSES WETH FOR EACH CHAIN */
/// @notice Array of all reward tokens supported by this contract
IERC20 [] public rewardTokens_Map;
/// @notice Mapping to check if a token is already added as a reward token
mapping(IERC20 => bool) public isRewardToken;
/// @notice Duration of reward distribution period in seconds
uint64 public duration_of_rewards = 60*5; //60*60*24*45; //60 sec * 60 min * 24 hours * 45 days
using SafeMath2 for uint256;
/// @notice Structure containing reward distribution data for each token
/// @dev Tracks reward rates, timing, and cumulative rewards
struct RewardData {
uint256 rewardRate;
uint256 periodFinish;
uint256 lastUpdateTime;
uint256 rewardPerTokenStored;
uint256 totalRewarded;
}
/// @notice Structure containing user-specific reward tracking data
/// @dev Tracks user's reward calculations and pending rewards
struct UserRewards {
uint256 userRewardPerTokenPaid;
uint256 rewards;
}
/// @notice Mapping from token address to its reward distribution data
mapping(IERC20 => RewardData) public rewardData;
/// @notice Mapping from user address to token address to user's reward data
mapping(address => mapping(IERC20 => UserRewards)) public userRewards;
/// @notice Structure to store details of a staked liquidity position
/// @dev Contains NFT ID, liquidity amount, staking status and timing
struct StakedPosition {
uint256 tokenId; // The NFT token ID
uint128 liquidity; // The liquidity amount
bool isStaked; // Whether the position is currently staked
uint timeStakedAt;
address ownerOfPosition;
}
/// @notice Emitted when rewards are added for a specific token
/// @param token The reward token address
/// @param reward The amount of rewards added
event RewardAdded(IERC20 indexed token, uint256 reward);
/// @notice Emitted when a reward token is removed from the system
/// @param token The reward token address that was removed
event RewardTokenRemoved(IERC20 indexed token);
/// @notice Emitted when a user claims rewards
/// @param user The address of the user claiming rewards
/// @param token The reward token address
/// @param reward The amount of rewards claimed
event RewardPaid(address indexed user, IERC20 indexed token, uint256 reward);
/// @notice Emitted when a reward transfer fails
/// @param user The address of the user
/// @param rewardToken The reward token that failed to transfer
/// @param amount The amount that failed to transfer
event RewardTransferFailed(address indexed user, IERC20 indexed rewardToken, uint256 amount);
/// @notice Emitted when liquidity is increased for a position
/// @param holderOfNFT The address of the NFT holder
/// @param tokenID The NFT token ID
/// @param amountOfLiqIncreased The amount of liquidity added
event increaseLiquidity(address holderOfNFT, uint tokenID, uint amountOfLiqIncreased);
/// @notice Emitted when liquidity is decreased for a position
/// @param holderOfNFT The address of the NFT holder
/// @param tokenID The NFT token ID
/// @param amountOfLiqDecreased The amount of liquidity removed
event decreaseLiquidity(address holderOfNFT, uint tokenID, uint amountOfLiqDecreased);
/// @notice Mapping from user address to sequential ID to staked position data
mapping(address => mapping(uint256 => StakedPosition)) public userPositions;
/// @notice Mapping from user address to their total number of positions
mapping(address => uint256) public userPositionCount;
/// @notice Mapping from NFT token ID to sequential ID for efficient lookups
mapping(uint256 => uint256) public tokenIdToSequentialId;
/// @notice Mapping to track if an NFT is currently staked
mapping(uint256 => bool) public isNFTStaked;
/// @notice Mapping to track which user owns which NFT
mapping(uint256 => address) public nftOwner;
/// @notice Uniswap V4 state view contract for reading pool data
IStateView public immutable stateView = IStateView(0x571291b572ed32ce6751a2Cb2486EbEe8DEfB9B4);
/// @notice Permit2 contract address for token approvals
address public immutable permit2 = address(0x000000000022D473030F116dDEE9F6B43aC78BA3);
/// @notice Uniswap V4 position manager contract interface
IPositionManager public immutable uniswapv4PositionManager; // INonfungiblePositionManager (0xC364...)
/// @notice Maximum tick value for full range positions
int24 public MAX_TICK = 887220;
/// @notice Minimum tick value for full range positions
int24 public MIN_TICK = -887220;
/// @notice Proof of Work contract interface for B0x Token
IB0x_Mining_Proof_of_Work public _PoW_Contract;
/// @notice Hook contract interface for Uniswap V4
IHooks2 public immutable HookContract;
/// @notice Address of token0 in the pair (lower address)
address token0;
/// @notice Address of token1 in the pair (higher address)
address token1;
/// @notice Address of the important hook contract for the pool
address public HookAddress_Important;
/// @notice Timestamp to allow only setting Proof of Work first 120 days. Backup case.
uint stopNow = block.timestamp;
/// @notice Bool to represent if we have set the Proof Of Work Contract, to prevent it being set again. Backup case.
bool setOnce = false;
/// @notice Constructor to initialize the rewards contract
/// @param _MainTokenAddress Address of the main token contract for B0x Token on base
/// @param _zeroXBTC Address of the 0xBitconi token on base
/// @param _HookAddress Address of the Uniswap V4 hook contract
/// @dev Sets up token ordering and initializes contract interfaces
constructor(address _MainTokenAddress, address _zeroXBTC, address _HookAddress)
{
zeroXBTC = _zeroXBTC;
HookAddress_Important = _HookAddress;
HookContract = IHooks2(_HookAddress);
MainTokenAddress = IERC20(_MainTokenAddress);
uniswapv4PositionManager = IPositionManager(0x4B2C77d209D3405F41a037Ec6c77F7F5b8e2ca80);
token0 = address(zeroXBTC) < address(MainTokenAddress) ? address(zeroXBTC) : address(MainTokenAddress);
token1 = address(zeroXBTC) < address(MainTokenAddress) ? address(MainTokenAddress) : address(zeroXBTC);
//adjust owner here if u need be but let this run for the sake of setting Z up
}
function setupAddTokens() public onlyOwner
{
addRewardToken(IERC20(addressUSDC));
addRewardToken(IERC20(MainTokenAddress));
addRewardToken(IERC20(zeroXBTC));
addRewardToken(IERC20(addressWETH));
}
/// @notice Sets the Proof of Work contract address (can only be set once)
/// @param pow Address of the Proof of Work contract
/// @return bool Returns true if successfully set
/// @dev Can only be called by owner within first 120 days and only once
function setPOW_Contract(address pow)public onlyOwner returns (bool)
{
require(setOnce == false, " Set once true");
setOnce = true;
require(stopNow + 24*60*60*120 > block.timestamp, "Only avail first 120 days");
if(address(_PoW_Contract) == address(0)){
_PoW_Contract = IB0x_Mining_Proof_of_Work(pow);
}
}
/// @notice Handles receipt of ERC721 tokens (NFTs)
/// @return bytes4 The selector confirming successful receipt
/// @dev Required to receive NFTs via safeTransferFrom
function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) {
return IERC721Receiver.onERC721Received.selector;
}
/// @notice Adds a new reward token to the system
/// @param token The ERC20 token to add as a reward token
/// @dev Non-owners must pay USDC fee based on number of existing reward tokens
function addRewardToken(IERC20 token) public
{
if(owner != msg.sender){
uint multipler = rewardTokens_Map.length / 20;
multipler = multipler + 1;
uint usdcDecimals = IERC20(addressUSDC).decimals();
require(
IERC20(addressUSDC).transferFrom(msg.sender, address(this), multipler * 20 * 10**(usdcDecimals)),
"USDC transfer failed"
);
}
require(!isRewardToken[token], "Token already added");
rewardTokens_Map.push(token);
isRewardToken[token] = true;
RewardData storage rd = rewardData[token];
rd.rewardPerTokenStored = rewardPerToken(token);
rd.rewardRate = 0;
rd.lastUpdateTime = 0;
uint startTime = (_PoW_Contract.startTime());
rd.periodFinish = startTime + 1*24*60*60;
}
/// @notice Removes a reward token from the system
/// @param token The ERC20 token to remove
/// @dev Can only be called by the contract owner
function removeRewardToken(IERC20 token) public onlyOwner
{
removeRewardTokenInternal(token);
}
/// @notice Internal function to remove a reward token from the system
/// @param token The ERC20 token to remove from rewards
/// @dev Prevents removal of core tokens (WETH, 0xBTC, B0x, USDC) and cleans up data structures
function removeRewardTokenInternal(IERC20 token) internal
{
require(isRewardToken[token], "Token not in reward list");
require(address(token) != addressWETH, "not allowed to remove WETH");
require(address(token) != zeroXBTC, "not allowed to remove 0xBTC");
require(address(token) != address(MainTokenAddress), "not allowed to remove B0x token");
require(address(token) != addressUSDC, "not allowed to remove usdc token");
// Remove from rewardTokens array
for (uint i = 0; i < rewardTokens_Map.length; i++) {
if (rewardTokens_Map[i] == token) {
// Swap with last element and pop (more gas efficient)
rewardTokens_Map[i] = rewardTokens_Map[rewardTokens_Map.length - 1];
rewardTokens_Map.pop();
break;
}
}
// Update mapping
isRewardToken[token] = false;
// Clear reward data (optional - you might want to keep historical data)
delete rewardData[token];
emit RewardTokenRemoved(token);
}
/// @notice Modifier to update reward calculations before function execution
/// @param account The user account to update rewards for
/// @param token The reward token to update calculations for
/// @dev Updates reward per token stored and user's earned rewards before function execution
modifier updateReward(address account, IERC20 token)
{
RewardData storage rd = rewardData[token];
uint256 _rewardPerTokenStored = rewardPerToken(token);
rd.lastUpdateTime = lastTimeRewardApplicable(token);
rd.rewardPerTokenStored = _rewardPerTokenStored;
userRewards[account][token].rewards = earned(account, token);
userRewards[account][token].userRewardPerTokenPaid = _rewardPerTokenStored;
_;
}
/// @notice Returns the last time rewards are applicable for a token
/// @param token The reward token to check
/// @return uint256 The timestamp of last applicable reward time
/// @dev Returns current block timestamp or period finish time, whichever is earlier
function lastTimeRewardApplicable(IERC20 token) public view returns (uint256)
{
RewardData storage rd = rewardData[token];
uint256 blockTimestamp = uint256(block.timestamp);
return blockTimestamp < rd.periodFinish ? blockTimestamp : rd.periodFinish;
}
/// @notice Calculates the current reward per token for a specific reward token
/// @param token The reward token to calculate rewards per token for
/// @return uint256 The current reward per token amount
/// @dev Uses high precision math to prevent overflow and ensure accurate calculations
function rewardPerToken(IERC20 token) public view returns (uint256)
{
RewardData storage rd = rewardData[token];
uint256 totalStakedSupply = totalSupply;
if (totalStakedSupply == 0) {
return rd.rewardPerTokenStored;
}
// unchecked {
// uint256 rewardDuration = lastTimeRewardApplicable(token) - rd.lastUpdateTime;
// return uint256(rd.rewardPerTokenStored + rewardDuration * rd.rewardRate * 1e18 / totalStakedSupply);
// }
uint256 rewardDuration = lastTimeRewardApplicable(token) - rd.lastUpdateTime;
uint returnAmt = mulDiv(
rewardDuration * 1e9, // 1e9 leaves alot of space
rd.rewardRate * 1e9,
totalStakedSupply
) + rd.rewardPerTokenStored;
return returnAmt;
}
/// @notice Calculates the total earned rewards for an account for a specific token
/// @param account The address of the account to calculate rewards for
/// @param token The reward token to calculate earnings for
/// @return uint256 The total amount of rewards earned by the account
/// @dev Uses high precision math to calculate rewards based on staked balance and reward rate difference
function earned(address account, IERC20 token) public view returns (uint256)
{
return mulDiv(
balanceOf(account),
rewardPerToken(token) - userRewards[account][token].userRewardPerTokenPaid,
1e18
) + userRewards[account][token].rewards;
}
/// @notice Collects accumulated fees from a Uniswap V4 NFT position to this contract
/// @param tokenID The ID of the NFT position to collect fees from
/// @return bool Returns true if fee collection is successful
/// @dev Calls internal getUnsiwapv4Fees function with this contract as recipient
function collectFeesForNFT(uint tokenID)public returns (bool)
{
getUnsiwapv4Fees(tokenID, address(this));
return true;
}
/// @notice Internal function to collect fees from a Uniswap V4 position
/// @param tokenId The ID of the NFT position to collect fees from
/// @param FeeForWho The address to receive the collected fees
/// @return bool Returns true if fee collection is successful
/// @dev Uses decrease liquidity with 0 amount to collect fees, then takes the pair
function getUnsiwapv4Fees(uint tokenId, address FeeForWho) internal returns (bool)
{
Currency currency0 = Currency.wrap(address(token0)); // tokenAddress1 = 0 for native ETH
Currency currency1 = Currency.wrap(address(token1));
bytes memory actions = abi.encodePacked(uint8(0x01), uint8(0x11));
bytes[] memory params = new bytes[](2);
params[0] = abi.encode(tokenId, 0, 0, 0, bytes(""));
params[1] = abi.encode(currency0, currency1, FeeForWho);
uint256 deadline = block.timestamp + 160;
uniswapv4PositionManager.modifyLiquidities{value: 0}(
abi.encode(actions, params),
deadline
);
return true;
}
/// @notice Stakes a Uniswap V4 NFT position for the caller
/// @param tokenId The ID of the NFT position to stake
/// @dev Transfers NFT to contract and delegates to stakeFORUniswapV3NFT
function stakeUniswapV3NFT(uint256 tokenId) public
{
stakeFORUniswapV3NFT(msg.sender, tokenId);
}
/// @notice Stakes a Uniswap V4 NFT position for a specific address
/// @param forWhom The address to stake the position for
/// @param tokenId The ID of the NFT position to stake
/// @dev Validates position parameters, updates rewards, manages position tracking, and collects fees
function stakeFORUniswapV3NFT(address forWhom, uint256 tokenId) public
{
address msgSender = msg.sender;
uniswapv4PositionManager.safeTransferFrom(msgSender, address(this), tokenId);
(PoolKey memory key, uint info) = uniswapv4PositionManager.getPoolAndPositionInfo(tokenId);
require(uniswapv4PositionManager.ownerOf(tokenId) == address(this),"Incorrectly staked token");
// Validate pool parameters
require(Currency.unwrap(key.currency0) == address(token0), "currency0 must be ETH");
require(Currency.unwrap(key.currency1) == address(token1), "currency1 must be main token");
require(key.tickSpacing == 60, "incorrect tick spacing");
require(key.hooks == IHooks2(address(HookAddress_Important)), "incorrect hook address");
// Extract ticks
int24 tickLower = TOtickLower(info);
int24 tickUpper = TOtickUpper(info);
// Check if NFT is full-range
(uint128 liquidity) = uniswapv4PositionManager.getPositionLiquidity(tokenId);
require(tickLower == MIN_TICK && tickUpper == MAX_TICK, "Must be full-range");
// Update rewards for all supported tokens before staking
IERC20[] memory tokens = getRewardTokens();
for (uint i = 0; i < tokens.length; i++) {
_updateReward(forWhom, tokens[i]);
}
StakedPosition memory post = StakedPosition(tokenId, liquidity, true, block.timestamp, forWhom);
// Check if this tokenId was previously owned by the same user
if (tokenIdToSequentialId[tokenId] != 0 && nftOwner[tokenId] == forWhom) {
// Reuse the same sequential ID if it's the same owner
uint sequentialId = tokenIdToSequentialId[tokenId];
userPositions[forWhom][sequentialId] = post;
}
// Check if this tokenId was previously owned by someone else
else if (tokenIdToSequentialId[tokenId] != 0 && nftOwner[tokenId] != forWhom) {
// If there was a previous owner, reset the mapping and assign new ID
delete tokenIdToSequentialId[tokenId];
uint userPosCount = userPositionCount[forWhom]+1;
userPositions[forWhom][userPosCount] = post;
tokenIdToSequentialId[tokenId] = userPosCount;
userPositionCount[forWhom] = userPosCount;
}
// First time staking this token ID
else {
uint userPosCount = userPositionCount[forWhom]+1;
userPositions[forWhom][userPosCount] = post;
tokenIdToSequentialId[tokenId] = userPosCount;
userPositionCount[forWhom] = userPosCount;
}
nftOwner[tokenId] = forWhom;
getUnsiwapv4Fees(tokenId, msgSender);
emit increaseLiquidity(forWhom, tokenId, liquidity);
// Proceed with the original staking logic
super.stakeFor(forWhom, liquidity);
}
/// @notice Gets the current timelock multiplier for a staked NFT position
/// @param TokenID The ID of the staked NFT position
/// @param ownerOfNFT The address of the NFT owner
/// @return multi The current multiplier based on staking duration
/// @dev Retrieves position data and calculates multiplier based on time staked
function CurrentMultiplierTimelock(uint TokenID, address ownerOfNFT)public view returns (uint128 multi)
{
uint sequen = tokenIdToSequentialId[TokenID];
StakedPosition memory post = userPositions[ownerOfNFT][sequen];
require(post.timeStakedAt != 0,"Not a NFT that is currently staked!");
return calc_howMuchToRemove(post.timeStakedAt);
}
/// @notice Calculates the withdrawal multiplier based on staking duration
/// @param timeStakedAt The timestamp when the position was staked
/// @return multiplier The multiplier percentage applied to withdrawals
/// @dev Uses tiered system: starts at 200%, decreases to 30% over 15 days, then further reductions
function calc_howMuchToRemove(uint timeStakedAt) public view returns (uint128 multiplier)
{
//CALCULATE HOW MUCH TO REMOVE
// Calculate the multiplier based on elapsed time
uint256 startMultiplier = 200;
uint256 endMultiplier = 30;
uint256 totalDays = 15;
// Get the current time and the start time
uint256 currentTime = block.timestamp;
// Calculate elapsed days (using seconds in a day = 86400)
uint256 elapsedDays = (currentTime - timeStakedAt) / 86400;
// Calculate the current multiplier using linear interpolation
if (elapsedDays >= totalDays) {
if(elapsedDays < totalDays * 2){
multiplier = 20;
}else if(elapsedDays < totalDays * 3){
multiplier = 15;
}else if(elapsedDays < totalDays * 4){
multiplier = 10;
}else if(elapsedDays < totalDays * 5){
multiplier = 7;
}else if(elapsedDays < totalDays * 10){
multiplier = 5;
}else{
multiplier = 1;
}
} else {
// Linear decrease from startMultiplier to endMultiplier
multiplier = uint128(startMultiplier - ((startMultiplier - endMultiplier) * elapsedDays / totalDays));
}
}
/// @notice Gets the maximum redeemable token amounts for a staked NFT position
/// @param tokenID The ID of the staked NFT position
/// @param ownerOfNFT The address of the NFT owner
/// @return amount0fees Amount of token0 that would be taken as fees
/// @return amount1fees Amount of token1 that would be taken as fees
/// @return amount0 Amount of token0 the user would receive
/// @return amount1 Amount of token1 the user would receive
/// @dev Calculates amounts for 100% withdrawal of the position
function getMaxRedeemableTokens(uint tokenID, address ownerOfNFT)public view returns (uint amount0fees, uint amount1fees, uint amount0, uint amount1){
uint128 maxPercentageToRem = 10000000000000;
(amount0fees, amount1fees,amount0,amount1) = getTokenAmountForPercentageLiquidity(tokenID, maxPercentageToRem, ownerOfNFT);
}
/// @notice Calculates token amounts for a percentage-based liquidity withdrawal
/// @param tokenID The ID of the staked NFT position
/// @param percentageToRemoveOutOf10000000000000 Percentage to withdraw (out of 10^13)
/// @param ownerOfNFT The address of the NFT owner
/// @return amount0fees Amount of token0 that would be taken as fees
/// @return amount1fees Amount of token1 that would be taken as fees
/// @return amount0 Amount of token0 the user would receive after fees
/// @return amount1 Amount of token1 the user would receive after fees
/// @dev Applies timelock multiplier penalties and calculates exact token amounts using current pool price
function getTokenAmountForPercentageLiquidity(uint tokenID, uint128 percentageToRemoveOutOf10000000000000, address ownerOfNFT)public view returns (uint amount0fees, uint amount1fees, uint amount0, uint amount1){
( uint128 liquidity ) =
uniswapv4PositionManager.getPositionLiquidity(tokenID);
uint128 multiplier = CurrentMultiplierTimelock(tokenID, ownerOfNFT);
// (liquidity*multiplier/1000* percentageToRemoveOutOf10000000000000)/10000000000000
uint128 baseAmount = uint128(
(uint256(liquidity) * uint256(percentageToRemoveOutOf10000000000000))/10000000000000
);
uint128 fees = uint128(
(uint256(baseAmount) * uint256(multiplier)).divRound(1000)
);
uint128 userGets = baseAmount - fees;
if((uint256(liquidity) * uint256(multiplier) * uint256(percentageToRemoveOutOf10000000000000)) % (10000000000000 * 1000) != 0 && userGets > 0){
userGets = userGets - 1;
}
int24 tickLower = -887220; // Your desired lower tick
int24 tickUpper = 887220; // Your desired upper tick
// Convert ticks to sqrtPriceX96 values
uint160 sqrtRatioAX96 = getSqrtRatioAtTick(tickLower);
uint160 sqrtRatioBX96 = getSqrtRatioAtTick(tickUpper);
PoolKey memory poolKey = PoolKey(Currency.wrap(token0), Currency.wrap(token1), 0x800000, 60, IHooks2(HookAddress_Important));
bytes32 idz = toId(poolKey);
(uint160 sqrtPricex96,,,) = stateView.getSlot0(idz);
amount0= getAmount0ForLiquidity(sqrtPricex96, sqrtRatioBX96,userGets );
amount1= getAmount1ForLiquidity(sqrtRatioAX96, sqrtPricex96,userGets );
amount0fees= getAmount0ForLiquidity(sqrtPricex96, sqrtRatioBX96,fees );
amount1fees= getAmount1ForLiquidity(sqrtRatioAX96, sqrtPricex96,fees );
}
function getContractTotals() public view returns (uint128 liquidityInStaking, uint128 totalPooLLiquidity,
uint total0xBTCStaked, uint totalB0xStaked) {
int24 tickLower = -887220;
int24 tickUpper = 887220;
uint160 sqrtRatioAX96 = getSqrtRatioAtTick(tickLower);
uint160 sqrtRatioBX96 = getSqrtRatioAtTick(tickUpper);
PoolKey memory poolKey = PoolKey(Currency.wrap(token0), Currency.wrap(token1), 0x800000, 60, IHooks2(HookAddress_Important));
bytes32 idz = toId(poolKey);
uint128 totalPooLLiqForEverything = stateView.getLiquidity(idz);
(uint160 sqrtPricex96,,,) = stateView.getSlot0(idz);
totalPooLLiquidity = totalPooLLiqForEverything;
liquidityInStaking = uint128(totalSupply);
// Calculate amounts based on pool's token ordering
uint amount0 = getAmount0ForLiquidity(sqrtPricex96, sqrtRatioBX96, liquidityInStaking);
uint amount1 = getAmount1ForLiquidity(sqrtRatioAX96, sqrtPricex96, liquidityInStaking);
// Now assign based on which token is which in the pool
if (token0 == address(zeroXBTC)) { // zeroXBTC is token0
total0xBTCStaked = amount0; // zeroXBTC amount
totalB0xStaked = amount1; // MainToken amount
} else { // MainToken is token0
total0xBTCStaked = amount1; // zeroXBTC amount
totalB0xStaked = amount0; // MainToken amount
}
}
/// @notice Resolution constant for price calculations (96 bits for X96 format)
uint8 internal constant RESOLUTION = 96;
/// @notice Calculates the amount of token0 for a given liquidity amount
/// @param sqrtPriceAX96 Sqrt price at the lower bound in X96 format
/// @param sqrtPriceBX96 Sqrt price at the upper bound in X96 format
/// @param liquidity Amount of liquidity to calculate token0 amount for
/// @return uint Amount of token0 corresponding to the liquidity
/// @dev Uses bit shifting and high precision math to prevent overflow in calculations
function getAmount0ForLiquidity(uint160 sqrtPriceAX96, uint160 sqrtPriceBX96, uint128 liquidity) public pure returns (uint){
if (sqrtPriceAX96 > sqrtPriceBX96) (sqrtPriceAX96, sqrtPriceBX96) = (sqrtPriceBX96, sqrtPriceAX96);
return mulDiv(
uint256(liquidity) << RESOLUTION, sqrtPriceBX96 - sqrtPriceAX96, sqrtPriceBX96
) / sqrtPriceAX96;
}
/// @notice Calculates the amount of token1 for a given liquidity amount
/// @param sqrtPriceAX96 Sqrt price at the lower bound in X96 format
/// @param sqrtPriceBX96 Sqrt price at the upper bound in X96 format
/// @param liquidity Amount of liquidity to calculate token1 amount for
/// @return amount1 Amount of token1 corresponding to the liquidity
/// @dev Uses Q96 constant for fixed-point arithmetic in token1 calculations
function getAmount1ForLiquidity(uint160 sqrtPriceAX96, uint160 sqrtPriceBX96, uint128 liquidity) public pure returns (uint256 amount1)
{
if (sqrtPriceAX96 > sqrtPriceBX96) (sqrtPriceAX96, sqrtPriceBX96) = (sqrtPriceBX96, sqrtPriceAX96);
return mulDiv(liquidity, sqrtPriceBX96 - sqrtPriceAX96, Q96);
}
/// @notice Decreases liquidity from a staked position with timelock penalties
/// @param tokenID The ID of the NFT position to decrease liquidity from
/// @param percentageToRemoveOutOf10000000000000 Percentage of liquidity to remove (out of 10^13)
/// @param minAmount0 Minimum amount of token0 to receive (slippage protection)
/// @param minAmount1 Minimum amount of token1 to receive (slippage protection)
/// @return bool Returns true if liquidity decrease is successful
/// @dev Applies timelock penalties, collects fees, updates rewards, and executes two separate withdrawals
function decreaseLiquidityOfPosition(uint tokenID, uint128 percentageToRemoveOutOf10000000000000, uint minAmount0, uint minAmount1)public returns (bool){
address msgSender = msg.sender;
uint128 getMaxPercentageToRem = 10000000000000;
if(getMaxPercentageToRem<percentageToRemoveOutOf10000000000000){
percentageToRemoveOutOf10000000000000 = getMaxPercentageToRem;
}
StakedPosition storage post = userPositions[msgSender][tokenIdToSequentialId[tokenID]];
uint Id = post.tokenId;
uint preCallLiquidity = post.liquidity;
require(tokenID == Id,"You must have control of NFT");
require(msgSender == post.ownerOfPosition, "Must own this position");
bool isStaked = post.isStaked;
require(isStaked == true,"Must have actively staked position to remove it");
getUnsiwapv4Fees(tokenID, address(this));
uint128 multiplier = CurrentMultiplierTimelock(tokenID, msgSender);
// Update rewards for all supported tokens
IERC20[] memory rewardTokens = getRewardTokens();
for (uint i = 0; i < rewardTokens.length; i++) {
_updateReward(msg.sender, rewardTokens[i]);
}
( uint128 liquidity ) =
uniswapv4PositionManager.getPositionLiquidity(tokenID);
Currency currency0 = Currency.wrap(address(token0)); // tokenAddress1 = 0 for native ETH
Currency currency1 = Currency.wrap(address(token1));
bytes[] memory params = new bytes[](2); // new bytes[](3) for ETH liquidity positions
uint128 baseAmount = uint128(
(uint256(liquidity) * uint256(percentageToRemoveOutOf10000000000000))/10000000000000
);
uint128 fees = uint128(
(uint256(baseAmount) * uint256(multiplier)) / 1000
);
uint128 userLiq = baseAmount - fees;
if(getMaxPercentageToRem == percentageToRemoveOutOf10000000000000){
uint128 difference = liquidity - fees;
userLiq = difference-1; //leave 1 liquidity always
}
uint128 totalLiqremoved = fees + userLiq;
require(liquidity>=totalLiqremoved,"invalid liquidity removal");
params[0] = abi.encode(tokenID, fees, minAmount0*multiplier/1000, minAmount1*multiplier/1000, bytes(""));
params[1] = abi.encode(currency0, currency1, address(this));
bytes memory actions = abi.encodePacked(uint8(0x01), uint8(0x11));
uint256 deadline = block.timestamp + 160;
uniswapv4PositionManager.modifyLiquidities{value: 0}(
abi.encode(actions, params),
deadline
);
bytes[] memory params2 = new bytes[](2); // new bytes[](3) for ETH liquidity positions
params2[0] = abi.encode(tokenID, userLiq, minAmount0, minAmount1, bytes(""));
params2[1] = abi.encode(currency0, currency1, msgSender);
bytes memory actions2 = abi.encodePacked(uint8(0x01), uint8(0x11));
uint256 deadline2 = block.timestamp + 160;
uniswapv4PositionManager.modifyLiquidities{value: 0}(
abi.encode(actions2, params2),
deadline2
);
uint256 afterCallLiquidity = preCallLiquidity - totalLiqremoved;
super.withdraw(totalLiqremoved);
post.liquidity = uint128(afterCallLiquidity);
emit decreaseLiquidity(msgSender, tokenID, totalLiqremoved);
return true;
}
/// @notice Increases liquidity for an existing staked position with slippage protection
/// @param forWho The address that owns the position to increase liquidity for
/// @param amount0In Amount of token0 to add to the position
/// @param amount1In Amount of token1 to add to the position
/// @param tokenID The ID of the NFT position to increase liquidity for
/// @param expectedSqrtPricex96 Expected sqrt price when transaction was initiated
/// @param slippageBps Slippage tolerance in basis points (e.g., 50 = 0.5%)
/// @return bool Returns true if liquidity increase is successful
/// @dev Validates ownership, applies slippage protection, updates rewards, resets timelock timer
function increaseLiquidityOfPosition(address forWho, uint256 amount0In, uint amount1In, uint tokenID, uint160 expectedSqrtPricex96, uint160 slippageBps) public returns (bool){
//we are going to want to pass liquidity delta when its time to really use
StakedPosition memory post = userPositions[forWho][tokenIdToSequentialId[tokenID]];
uint Id = post.tokenId;
require(tokenID == Id,"forWho must have control of NFT");
require(forWho == post.ownerOfPosition, "forWho must be ownerOfPosition");
bool isStaked = post.isStaked;
require(isStaked == true,"Must be actively staked position to increase it");
getUnsiwapv4Fees(tokenID, address(this));
// Update rewards for all supported tokens
IERC20[] memory rewardTokens = getRewardTokens();
for (uint i = 0; i < rewardTokens.length; i++) {
_updateReward(forWho, rewardTokens[i]);
}
IERC20(token0).approve(address(permit2), type(uint256).max);
IERC20(token1).approve(address(permit2), type(uint256).max);
IPermit2(permit2).approve(address(token0), address(uniswapv4PositionManager), type(uint160).max, uint48(block.timestamp)+60*60*1);
IPermit2(permit2).approve(address(token1), address(uniswapv4PositionManager), type(uint160).max, uint48(block.timestamp)+60*60*1);
IERC20(token0).approve(address(uniswapv4PositionManager), type(uint256).max);
IERC20(token1).approve(address(uniswapv4PositionManager), type(uint256).max);
// Transfer tokens from sender
IERC20(token0).transferFrom(msg.sender, address(this), amount0In);
// Transfer tokens from sender
IERC20(token1).transferFrom(msg.sender, address(this), amount1In);
PoolKey memory poolKey = PoolKey(Currency.wrap(token0), Currency.wrap(token1), 0x800000, 60, IHooks2(HookAddress_Important));
bytes32 idz = toId(poolKey);
(uint160 sqrtPricex96,,,) = stateView.getSlot0(idz);
// Get min and max acceptable sqrt prices
(uint160 minSqrtPrice, uint160 maxSqrtPrice) = getSqrtPriceRangeForSlippage(
expectedSqrtPricex96,
slippageBps
);
// Verify price hasn't moved beyond slippage tolerance
require(
sqrtPricex96 >= minSqrtPrice &&
sqrtPricex96 <= maxSqrtPrice,
"Price moved too much"
);
// Convert ticks to sqrtPriceX96 values
// Convert specific ticks to sqrtPriceX96 values
int24 tickLower = -887220; // Your desired lower tick
int24 tickUpper = 887220; // Your desired upper tick
// Convert ticks to sqrtPriceX96 values
uint160 sqrtRatioAX96 = getSqrtRatioAtTick(tickLower);
uint160 sqrtRatioBX96 = getSqrtRatioAtTick(tickUpper);
uint liquidityDelta = getLiquidityForAmounts(
sqrtPricex96,
sqrtRatioAX96,
sqrtRatioBX96,
amount0In,
amount1In
);
bytes memory actions = abi.encodePacked(uint8(0x00), uint8(0x0d));
bytes[] memory params = new bytes[](2); // new bytes[](3) for ETH liquidity positions
// Position has liquidity - use INCREASE_LIQUIDITY action
actions = abi.encodePacked(uint8(0x00), uint8(0x0d)); // INCREASE_LIQUIDITY + SETTLE_PAIR
// Use increase parameters
params[0] = abi.encode(tokenID, liquidityDelta, amount0In, amount1In, bytes(""));
Currency currency0 = Currency.wrap(token0); // tokenAddress1 = 0 for native ETH
Currency currency1 = Currency.wrap(token1);
params[1] = abi.encode(currency0, currency1); //settle pair
//For ETH see 2 tokens @ https://docs.uniswap.org/contracts/v4/quickstart/manage-liquidity/increase-liquidity
uint256 deadline = block.timestamp + 160;
uint256 valueToPass = 0;
uniswapv4PositionManager.modifyLiquidities{value: valueToPass}(
abi.encode(actions, params),
deadline
);
( uint128 liquidity ) =
uniswapv4PositionManager.getPositionLiquidity(tokenID);
//Reset timer for withdrawal if adding to NFT
StakedPosition storage test = userPositions[forWho][tokenIdToSequentialId[tokenID]];
test.timeStakedAt = block.timestamp;
uint liqDifference = liquidity - test.liquidity;
stakeFor(forWho, uint128(liqDifference));
test.liquidity = liquidity;
emit increaseLiquidity(forWho, tokenID, liqDifference);
return true;
}
/// @notice Withdraws a staked NFT position completely with timelock penalties applied
/// @param tokenId The ID of the NFT position to withdraw
/// @return bool Returns true if withdrawal is successful
/// @dev Updates rewards, applies penalties, transfers NFT back to user, and updates position tracking
function withdraw(uint tokenId) public returns (bool) {
// Update rewards for all supported tokens before staking
IERC20[] memory tokens = getRewardTokens();
for (uint i = 0; i < tokens.length; i++) {
_updateReward(msg.sender, tokens[i]);
}
uint sequen = tokenIdToSequentialId[tokenId];
StakedPosition memory post = userPositions[msg.sender][sequen];
require(msg.sender == post.ownerOfPosition, "Must own this position");
uint Id = post.tokenId;
uint128 liquidity = post.liquidity; // The liquidity amount
bool isStaked = post.isStaked;
require(isStaked == true,"Must have actively staked position to remove it");
// Store the NFT ID and its liquidity
getUnsiwapv4Fees(tokenId, address(this));
RemovePenaltyFromNFTforWithdrawl(tokenId);
StakedPosition memory post2 = StakedPosition(Id, 0, false, block.timestamp, address(0));
userPositions[msg.sender][sequen] = post2;
uniswapv4PositionManager.approve(address(this), Id);
uniswapv4PositionManager.safeTransferFrom(address(this), msg.sender, Id);
super.withdraw(liquidity);
emit decreaseLiquidity(msg.sender, tokenId, liquidity);
return true;
}
/// @notice Internal function to withdraw all liquidity from a staked position
/// @param tokenId The ID of the NFT position to withdraw completely
/// @dev Similar to withdraw() but internal - applies penalties and transfers NFT back to user
function withdrawALL(uint tokenId) internal {
uint sequen = tokenIdToSequentialId[tokenId];
StakedPosition memory post = userPositions[msg.sender][sequen];
uint Id = post.tokenId;
uint128 liquidity = post.liquidity; // The liquidity amount
bool isStaked = post.isStaked;
require(isStaked == true,"Must have actively staked position to remove it");
require(msg.sender == post.ownerOfPosition, "Must own this position");
// Store the NFT ID and its liquidity
getUnsiwapv4Fees(tokenId, address(this));
RemovePenaltyFromNFTforWithdrawl(tokenId);
StakedPosition memory post2 = StakedPosition(Id, 0, false, block.timestamp, address(0));
userPositions[msg.sender][sequen] = post2;
uniswapv4PositionManager.approve(address(this), Id);
uniswapv4PositionManager.safeTransferFrom(address(this), msg.sender, Id);
super.withdraw(liquidity);
emit decreaseLiquidity(msg.sender, tokenId, liquidity);
}
/// @notice Exits multiple staked positions and claims all rewards
/// @param startIndex The starting index in the user's position array
/// @param count The number of positions to exit from the starting index
/// @dev Claims rewards first, then withdraws all specified positions
function exit(uint256 startIndex, uint256 count) public {
if (startIndex + count > userPositionCount[msg.sender]){
count = userPositionCount[msg.sender] - startIndex;
}
getReward();
/* Get reward does it for us Update rewards for all supported tokens
IERC20[] memory rewardTokens = getRewardTokens();
for (uint i = 0; i < rewardTokens.length; i++) {
_updateReward(msg.sender, rewardTokens[i]);
}
*/
uint256[] memory iDs = this.getStakedTokenIds(msg.sender, startIndex, count);
for(uint x=0; x<iDs.length; x++){
withdrawALL(iDs[x]);
}
}
/// @notice Internal function to remove penalty liquidity from NFT during withdrawal
/// @param tokenID The ID of the NFT position to apply penalties to
/// @return bool Returns true if penalty removal is successful
/// @dev Calculates timelock penalty based on staking duration and removes penalty liquidity to contract
function RemovePenaltyFromNFTforWithdrawl(uint tokenID) internal returns (bool)
{
uint multiplier = CurrentMultiplierTimelock(tokenID, msg.sender);
// Check if NFT is full-range
( uint128 liquidity ) =
uniswapv4PositionManager.getPositionLiquidity(tokenID);
Currency currency0 = Currency.wrap(token0);
Currency currency1 = Currency.wrap(token1);
bytes[] memory params = new bytes[](2);
params[0] = abi.encode(tokenID, (liquidity*multiplier).divRound(1000), 0, 0, bytes(""));
params[1] = abi.encode(currency0, currency1, address(this));
bytes memory actions = abi.encodePacked(uint8(0x01), uint8(0x11));
uint256 deadline = block.timestamp + 160;
uint256 valueToPass = msg.value;
uniswapv4PositionManager.modifyLiquidities{value: valueToPass}(
abi.encode(actions, params),
deadline
);
return true;
}
/// @notice Gets the token IDs of staked positions for a user within a specified range
/// @param user The address of the user to query positions for
/// @param startIndex The starting index in the user's position array
/// @param count The maximum number of token IDs to return
/// @return tokenIds Array of staked NFT token IDs
/// @dev Efficient function for getting just the token IDs without additional metadata
function getStakedTokenIds(address user, uint startIndex, uint count) external view returns (uint256[] memory tokenIds) {
if (startIndex + count > userPositionCount[user]){
count = userPositionCount[user] - startIndex;
}
// First, count how many active staked positions the user has
uint256 stakedCount = 0;
for (uint256 i = startIndex; i <= userPositionCount[user]; i++) {
StakedPosition memory position = userPositions[user][i];
if (position.isStaked) {
stakedCount++;
}
if(stakedCount > count){
break;
}
}
// Initialize array with the correct size
uint256[] memory stakedTokenIds = new uint256[](stakedCount);
// Fill the array with token IDs of staked positions
uint256 index = 0;
for (uint256 i = 1; i <= userPositionCount[user]; i++) {
StakedPosition memory position = userPositions[user][i];
if (position.isStaked) {
stakedTokenIds[index] = position.tokenId;
index++;
}
}
return (stakedTokenIds);
}
/// @notice Claims all available rewards for the caller across all reward tokens
/// @dev Updates rewards and transfers all earned tokens to the caller
function getReward() public {
IERC20[] memory rewardTokens = getRewardTokens();
getRewardForTokens(rewardTokens);
}
/// @notice Claims rewards for specific reward tokens
/// @param rewardTokens Array of reward token addresses to claim rewards for
/// @dev Updates rewards, calculates earned amounts, and transfers tokens to caller
function getRewardForTokens(IERC20[] memory rewardTokens) public {
for (uint i = 0; i < rewardTokens.length; i++) {
_updateReward(msg.sender, rewardTokens[i]);
uint256 reward = earned(msg.sender, rewardTokens[i]);
if (reward > 0) {
RewardData storage rd = rewardData[rewardTokens[i]];
rd.totalRewarded = rd.totalRewarded - reward;
userRewards[msg.sender][rewardTokens[i]].rewards = 0;
rewardTokens[i].transfer(msg.sender, reward);
emit RewardPaid(msg.sender, rewardTokens[i], reward);
}
}
}
/// @notice Gets comprehensive reward statistics for all reward tokens
/// @return rewardTokenAddresses Array of reward token contract addresses
/// @return rewardsOwed Array of rewards owed to the caller for each token
/// @return tokenSymbols Array of token symbols (with fallback to "?" if not available)
/// @return tokenNames Array of token names (with fallback to "?" if not available)
/// @return tokenDecimals Array of token decimal places (with fallback to 1 if not available)
/// @return tokenRewardRates Array of current reward rates for each token
/// @return tokenPeriodEndsAt Array of timestamps when reward periods end for each token
/// @dev Provides complete reward system overview with safe fallbacks for token metadata
function getRewardOwedStats() public view returns(address[] memory rewardTokenAddresses, uint256[] memory rewardsOwed, string[] memory tokenSymbols, string[] memory tokenNames, uint8[] memory tokenDecimals, uint[] memory tokenRewardRates, uint[] memory tokenPeriodEndsAt) {
IERC20[] memory rewardTokens = getRewardTokens();
rewardTokenAddresses = new address[](rewardTokens.length);
tokenSymbols = new string[](rewardTokens.length);
tokenNames = new string[](rewardTokens.length);
tokenDecimals = new uint8[](rewardTokens.length);
tokenRewardRates = new uint[](rewardTokens.length);
tokenPeriodEndsAt = new uint[](rewardTokens.length);
for(uint x=0; x<rewardTokens.length; x++){
rewardTokenAddresses[x]=address(rewardTokens[x]);
// Handle symbol
try rewardTokens[x].symbol() returns (string memory symbol) {
tokenSymbols[x] = symbol;
} catch {
tokenSymbols[x] = "?"; // Default fallback for symbol
}
// Handle name
try rewardTokens[x].name() returns (string memory name) {
tokenNames[x] = name;
} catch {
tokenNames[x] = "?"; // Default fallback for name
}
// Handle decimals
try rewardTokens[x].decimals() returns (uint8 decimals) {
tokenDecimals[x] = decimals;
} catch {
tokenDecimals[x] = 1; // Default fallback for decimals
}
RewardData memory rd = rewardData[IERC20(rewardTokens[x])];
tokenRewardRates[x]= rd.rewardRate;
tokenPeriodEndsAt[x]= rd.periodFinish;
}
rewardsOwed = getRewardForTokensOwed(rewardTokens);
}
/// @notice Calculates the amount of rewards owed to the caller for specific reward tokens
/// @param rewardTokens Array of reward token addresses to calculate owed rewards for
/// @return rewardsOwed Array of reward amounts owed to the caller for each token
/// @dev View function that calculates earned rewards without updating state
function getRewardForTokensOwed(IERC20[] memory rewardTokens) public view returns (uint[] memory rewardsOwed){
rewardsOwed = new uint[](rewardTokens.length);
for (uint i = 0; i < rewardTokens.length; i++) {
uint256 reward = earned(msg.sender, rewardTokens[i]);
rewardsOwed[i] = reward;
}
}
/// @notice Number of USDC distribution periods that have occurred
uint public periodsDistributedUSDC;
/// @notice Sets reward distribution parameters for a specific token
/// @param token The reward token to set parameters for
/// @dev Calculates reward rates, handles special USDC tiered distribution, validates token transfers
function setRewardParams(IERC20 token) public {
uint64 duration = duration_of_rewards;
unchecked {
RewardData storage rd = rewardData[token];
rd.rewardPerTokenStored = rewardPerToken(token);
uint256 blockTimestamp = uint256(block.timestamp);
uint256 maxRewardSupply = token.balanceOf(address(this)) - rd.totalRewarded;
require(maxRewardSupply > 0, "Reward must be positive");
uint totalReward = ( maxRewardSupply * 4 ) / 10;// 4/10ths every distribution phase
if(address(token) == addressUSDC){
uint256 periodsElapsed = periodsDistributedUSDC;
uint256 periodRate;
if(periodsElapsed < 8) {
periodRate = 125; // 10% / 8 periods = 1.25% per period
} else if(periodsElapsed < 16) {
periodRate = 125; // 10% / 8 periods = 1.25% per period
} else if(periodsElapsed < 24) {
periodRate = 250; // 20% / 8 periods = 2.5% per period
} else if(periodsElapsed < 32) {
periodRate = 250; // 20% / 8 periods = 2.5% per period
}else if(periodsElapsed < 40) {
periodRate = 375; // 30% / 8 periods = 3.75% per period
} else {
periodRate = 375; // 30% / 8 periods = 3.75% per period
}
// Use original total supply as base (store this in constructor)
totalReward = (maxRewardSupply * periodRate) / 10000; // basis points
periodsDistributedUSDC++;
}
uint rewardBefore = IERC20(token).balanceOf(address(this));
// Test token transferability with the actual amount we plan to use
try token.transfer(address(this), totalReward) {
} catch {
removeRewardTokenInternal(token);
return;
}
uint rewardAfter = IERC20(token).balanceOf(address(this));
maxRewardSupply = rewardAfter;
totalReward = totalReward - (rewardBefore - rewardAfter);
if(rd.periodFinish > block.timestamp){
revert("No good PeriodFinish must be behind block.timestamp");
}else{
totalReward = totalReward / duration;
}
require(totalReward <= maxRewardSupply, "not enough tokens");
require(totalReward < 1e38, "Reward rate too high");
rd.rewardRate = totalReward;
rd.totalRewarded = (totalReward*duration) + rd.totalRewarded;
rd.lastUpdateTime = blockTimestamp;
rd.periodFinish = blockTimestamp + duration;
emit RewardAdded(token, (totalReward*duration));
}
}
/// @notice Gets all reward tokens currently supported by the contract
/// @return IERC20[] Array of all reward token contracts
/// @dev Returns the complete list of reward tokens from the mapping
function getRewardTokens() public view returns (IERC20[] memory) {
return rewardTokens_Map;
// This would need to track which tokens have active rewards
// Implementation depends on how you want to track active reward tokens
// Could maintain an array or use events to track
//revert("Not implemented - need to track active reward tokens");
}
/// @notice Internal function to update reward calculations for a user and token
/// @param account The user address to update rewards for
/// @param token The reward token to update calculations for
/// @dev Updates reward per token stored and user's earned rewards without using modifier
function _updateReward(address account, IERC20 token) internal {
RewardData storage rd = rewardData[token];
uint256 _rewardPerTokenStored = rewardPerToken(token);
rd.lastUpdateTime = lastTimeRewardApplicable(token);
rd.rewardPerTokenStored = _rewardPerTokenStored;
userRewards[account][token].rewards = earned(account, token);
userRewards[account][token].userRewardPerTokenPaid = _rewardPerTokenStored;
}
/// @notice Converts all ETH held by the contract to WETH
/// @dev Deposits the entire ETH balance into the WETH contract
function convertETHtoWETH()public {
// Get the ETH balance of this contract
uint256 ethBalance = address(this).balance;
// Deposit all ETH into WETH
IWETH(addressWETH).deposit{value: ethBalance}();
}
/// @notice Generates a unique pool ID from pool key parameters
/// @param poolKey The pool key structure containing currency pairs, fee, tick spacing, and hooks
/// @return poolId The unique bytes32 identifier for the pool
/// @dev Uses keccak256 hash of the entire poolKey struct (5 slots * 32 bytes = 0xa0)
function toId(PoolKey memory poolKey) internal pure returns (bytes32 poolId) {
assembly ("memory-safe") {
// 0xa0 represents the total size of the poolKey struct (5 slots of 32 bytes)
poolId := keccak256(poolKey, 0xa0)
}
}
/// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
/// @param a The multiplicand
/// @param b The multiplier
/// @param denominator The divisor
/// @return result The 256-bit result
/// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
function mulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = a * b
// Compute the product mod 2**256 and mod 2**256 - 1
// then use the Chinese Remainder Theorem to reconstruct
// the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2**256 + prod0
uint256 prod0 = a * b; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly ("memory-safe") {
let mm := mulmod(a, b, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Make sure the result is less than 2**256.
// Also prevents denominator == 0
require(denominator > prod1);
// Handle non-overflow cases, 256 by 256 division
if (prod1 == 0) {
assembly ("memory-safe") {
result := div(prod0, denominator)
}
return result;
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0]
// Compute remainder using mulmod
uint256 remainder;
assembly ("memory-safe") {
remainder := mulmod(a, b, denominator)
}
// Subtract 256 bit number from 512 bit number
assembly ("memory-safe") {
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator
// Compute largest power of two divisor of denominator.
// Always >= 1.
uint256 twos = (0 - denominator) & denominator;
// Divide denominator by power of two
assembly ("memory-safe") {
denominator := div(denominator, twos)
}
// Divide [prod1 prod0] by the factors of two
assembly ("memory-safe") {
prod0 := div(prod0, twos)
}
// Shift in bits from prod1 into prod0. For this we need
// to flip `twos` such that it is 2**256 / twos.
// If twos is zero, then it becomes one
assembly ("memory-safe") {
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
// Invert denominator mod 2**256
// Now that denominator is an odd number, it has an inverse
// modulo 2**256 such that denominator * inv = 1 mod 2**256.
// Compute the inverse by starting with a seed that is correct
// correct for four bits. That is, denominator * inv = 1 mod 2**4
uint256 inv = (3 * denominator) ^ 2;
// Now use Newton-Raphson iteration to improve the precision.
// Thanks to Hensel's lifting lemma, this also works in modular
// arithmetic, doubling the correct bits in each step.
inv *= 2 - denominator * inv; // inverse mod 2**8
inv *= 2 - denominator * inv; // inverse mod 2**16
inv *= 2 - denominator * inv; // inverse mod 2**32
inv *= 2 - denominator * inv; // inverse mod 2**64
inv *= 2 - denominator * inv; // inverse mod 2**128
inv *= 2 - denominator * inv; // inverse mod 2**256
// Because the division is now exact we can divide by multiplying
// with the modular inverse of denominator. This will give us the
// correct result modulo 2**256. Since the preconditions guarantee
// that the outcome is less than 2**256, this is the final result.
// We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inv;
return result;
}
}
/// @notice Q96 constant for fixed-point arithmetic (2^96)
uint256 constant Q96 = 0x1000000000000000000000000;
/// @notice Converts a tick value to its corresponding sqrt price in X96 format
/// @param tick The tick value to convert (must be within valid range)
/// @return uint160 The sqrt price in X96 format
/// @dev Uses bit manipulation and precomputed constants for efficient tick-to-price conversion
function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160) {
uint MAX_TICKz = 887220;
uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));
require(absTick <= uint256(int256(MAX_TICKz)), "TICK_OUT_OF_RANGE");
uint256 ratio = absTick & 0x1 != 0
? 0xfffcb933bd6fad37aa2d162d1a594001
: 0x100000000000000000000000000000000;
if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;
if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;
if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;
if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;
if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;
if (tick > 0) ratio = type(uint256).max / ratio;
// This divides by 1<<32 rounding up to go from a Q128.128 to a Q96.64
uint256 sqrtPriceX96 = uint256((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));
return uint160(sqrtPriceX96);
}
/// @notice Calculates liquidity for a given amount of token0
/// @param sqrtRatioAX96 Sqrt price at the lower tick boundary in X96 format
/// @param sqrtRatioBX96 Sqrt price at the upper tick boundary in X96 format
/// @param amount0 Amount of token0 to provide
/// @return liquidity The calculated liquidity amount
/// @dev Helper function for token0-based liquidity calculations
function getLiquidityForAmount0(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint256 amount0) internal pure returns (uint128 liquidity)
{
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
uint256 intermediate = mulDiv(sqrtRatioAX96, sqrtRatioBX96, Q96);
return uint128(mulDiv(amount0, intermediate, sqrtRatioBX96 - sqrtRatioAX96));
}
/// @notice Calculates liquidity for a given amount of token1
/// @param sqrtRatioAX96 Sqrt price at the lower tick boundary in X96 format
/// @param sqrtRatioBX96 Sqrt price at the upper tick boundary in X96 format
/// @param amount1 Amount of token1 to provide
/// @return liquidity The calculated liquidity amount
/// @dev Helper function for token1-based liquidity calculations
function getLiquidityForAmount1(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint256 amount1) internal pure returns (uint128 liquidity)
{
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
return uint128(mulDiv(amount1, Q96, sqrtRatioBX96 - sqrtRatioAX96));
}
/// @notice Calculates the liquidity amount for given token amounts and price range
/// @param sqrtPriceX96 Current sqrt price in X96 format
/// @param sqrtPriceAX96 Sqrt price at the lower tick boundary in X96 format
/// @param sqrtPriceBX96 Sqrt price at the upper tick boundary in X96 format
/// @param amount0 Amount of token0 available
/// @param amount1 Amount of token1 available
/// @return liquidity The calculated liquidity amount (minimum of token0 and token1 constraints)
/// @dev Main function for calculating liquidity based on current price position and token amounts
function getLiquidityForAmounts(uint160 sqrtPriceX96, uint160 sqrtPriceAX96, uint160 sqrtPriceBX96, uint256 amount0, uint256 amount1) public pure returns (uint128 liquidity)
{
require(sqrtPriceAX96 < sqrtPriceBX96, "PRICE_ORDER");
if (sqrtPriceX96 <= sqrtPriceAX96) {
liquidity = getLiquidityForAmount0(sqrtPriceAX96, sqrtPriceBX96, amount0);
} else if (sqrtPriceX96 >= sqrtPriceBX96) {
liquidity = getLiquidityForAmount1(sqrtPriceAX96, sqrtPriceBX96, amount1);
} else {
uint128 liquidity0 = getLiquidityForAmount0(sqrtPriceX96, sqrtPriceBX96, amount0);
uint128 liquidity1 = getLiquidityForAmount1(sqrtPriceAX96, sqrtPriceX96, amount1);
liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1;
}
}
/// @notice Calculates the price ratio from sqrtPriceX96 with specified decimal precision
/// @param sqrtPriceX96 The sqrt price in X96 format from Uniswap V4
/// @param decimals Number of decimal places for the returned price ratio
/// @return priceRatio The price ratio scaled by 10^decimals
/// @dev Clean implementation using MulDiv for overflow-safe calculations
function getPriceRatioWithDecimals(uint160 sqrtPriceX96, uint8 decimals) public pure returns (uint256 priceRatio) {
if (sqrtPriceX96 == 0) return 0;
uint256 sqrtPrice = uint256(sqrtPriceX96);
uint256 multiplier = 10 ** decimals;
// Calculate price = (sqrtPriceX96^2 * 10^decimals) / 2^192
// Using MulDiv for safe high-precision arithmetic
// First: sqrtPrice^2
uint256 priceX192 = sqrtPrice * sqrtPrice; // This is safe with your corrected values
// Second: MulDiv(priceX192, multiplier, 2^192)
uint256 Q192 = 1 << 192;
priceRatio = mulDiv(priceX192, multiplier, Q192);
return priceRatio;
}
/// @notice Gets the current price ratio and token information for the main token pair
/// @return ratio Price ratio scaled to 18 decimals
/// @return token0z Address of token0 (lower address)
/// @return token1z Address of token1 (higher address)
/// @return token0decimals Decimal places of token0
/// @return token1decimals Decimal places of token1
/// @dev Uses the contract's main token pair and hook address
function getPriceRatio() public view returns (uint ratio, address token0z, address token1z, uint8 token0decimals, uint8 token1decimals) {
PoolKey memory poolKey = PoolKey(Currency.wrap(token0), Currency.wrap(token1), 0x800000, 60, IHooks2(HookAddress_Important));
bytes32 idz = toId(poolKey);
(uint160 sqrtPricex96,,,) = stateView.getSlot0(idz);
uint priceRatiox18decimals2 = getPriceRatioWithDecimals(sqrtPricex96, 18);
token0decimals = IERC20(token0).decimals();
token1decimals = IERC20(token1).decimals();
token0z=token0;
token1z=token1;
return (priceRatiox18decimals2, token0, token1, token0decimals, token1decimals);
}
/// @notice Converts basis points slippage to sqrt price bounds for slippage protection
/// @param expectedSqrtPricex96 The expected sqrt price when transaction was initiated
/// @param slippageBps Slippage tolerance in basis points (e.g., 50 = 0.5%)
/// @return minSqrtPrice Minimum acceptable sqrt price
/// @return maxSqrtPrice Maximum acceptable sqrt price
/// @dev Uses square root approximation for efficient slippage calculation
function getSqrtPriceRangeForSlippage(
uint160 expectedSqrtPricex96,
uint slippageBps // in basis points (e.g., 50 = 0.5%)
) internal pure returns (uint160 minSqrtPrice, uint160 maxSqrtPrice) {
// For slippage of s basis points (s/10000 as a decimal):
// Price change factor is (1 ± s/10000)
// SqrtPrice change factor is √(1 ± s/10000)
// For small values of s, √(1 + s/10000) ≈ 1 + (s/10000)/2 = 1 + s/20000
// Calculate the adjustment factor (s/20000 in our fixed-point representation)
uint adjustmentFactor = slippageBps / 2; // Divide by 2 for the sqrt approximation
// Calculate the minimum and maximum sqrt prices (multiply by 10000 for fixed-point division)
minSqrtPrice = uint160((uint256(expectedSqrtPricex96) * (10000 - adjustmentFactor)) / 10000);
maxSqrtPrice = uint160((uint256(expectedSqrtPricex96) * (10000 + adjustmentFactor)) / 10000);
return (minSqrtPrice, maxSqrtPrice);
}
/// @notice Gets the current sqrt price for the main token pair
/// @return sqrtPricex96 The current sqrt price in X96 format
/// @dev Retrieves current price from the pool state for the main token pair
function getExpectedSqrtPricex96()public view returns (uint160 sqrtPricex96){
PoolKey memory poolKey = PoolKey(Currency.wrap(address(token0)), Currency.wrap(address(token1)), 0x800000, 60, IHooks2(HookAddress_Important));
bytes32 idz = toId(poolKey);
(sqrtPricex96,,,) = stateView.getSlot0(idz);
}
/// @notice Bit offset for extracting tick lower value from packed info
uint8 internal constant TICK_LOWER_OFFSET = 8;
/// @notice Bit offset for extracting tick upper value from packed info
uint8 internal constant TICK_UPPER_OFFSET = 32;
/// @notice Extracts the lower tick value from packed position info
/// @param info The packed position information containing tick data
/// @return _tickLower The lower tick boundary of the position
/// @dev Uses assembly to extract and sign-extend the tick value from packed data
function TOtickLower(uint info) public pure returns (int24 _tickLower) {
assembly ("memory-safe") {
_tickLower := signextend(2, shr(TICK_LOWER_OFFSET, info))
}
}
/// @notice Extracts the upper tick value from packed position info
/// @param info The packed position information containing tick data
/// @return _tickUpper The upper tick boundary of the position
/// @dev Uses assembly to extract and sign-extend the tick value from packed data
function TOtickUpper(uint info) public pure returns (int24 _tickUpper) {
assembly ("memory-safe") {
_tickUpper := signextend(2, shr(TICK_UPPER_OFFSET, info))
}
}
/// @notice Fallback function to handle unexpected function calls
/// @dev Accepts ether but performs no operations
fallback() external payable {
// Optional: handle unexpected data
}
/// @notice Receive function to accept plain ether transfers
/// @dev Allows the contract to receive ETH without data
receive() external payable {
}
}
/*
*
* MIT License
* ===========
*
* Copyright (c) 2025 B0x Token (B0x)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/{
"optimizer": {
"enabled": true,
"runs": 200
},
"viaIR": true,
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract ABI
API[{"inputs":[{"internalType":"address","name":"_MainTokenAddress","type":"address"},{"internalType":"address","name":"_zeroXBTC","type":"address"},{"internalType":"address","name":"_HookAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"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":true,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"RewardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"RewardPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC20","name":"token","type":"address"}],"name":"RewardTokenRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"contract IERC20","name":"rewardToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardTransferFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"holderOfNFT","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfLiqDecreased","type":"uint256"}],"name":"decreaseLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"holderOfNFT","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfLiqIncreased","type":"uint256"}],"name":"increaseLiquidity","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"uint256","name":"TokenID","type":"uint256"},{"internalType":"address","name":"ownerOfNFT","type":"address"}],"name":"CurrentMultiplierTimelock","outputs":[{"internalType":"uint128","name":"multi","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"HookAddress_Important","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"HookContract","outputs":[{"internalType":"contract IHooks2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_TICK","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_TICK","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MainTokenAddress","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"info","type":"uint256"}],"name":"TOtickLower","outputs":[{"internalType":"int24","name":"_tickLower","type":"int24"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"info","type":"uint256"}],"name":"TOtickUpper","outputs":[{"internalType":"int24","name":"_tickUpper","type":"int24"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"_PoW_Contract","outputs":[{"internalType":"contract IB0x_Mining_Proof_of_Work","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"addRewardToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"addressUSDC","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"addressWETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timeStakedAt","type":"uint256"}],"name":"calc_howMuchToRemove","outputs":[{"internalType":"uint128","name":"multiplier","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"collectFeesForNFT","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"convertETHtoWETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"},{"internalType":"uint128","name":"percentageToRemoveOutOf10000000000000","type":"uint128"},{"internalType":"uint256","name":"minAmount0","type":"uint256"},{"internalType":"uint256","name":"minAmount1","type":"uint256"}],"name":"decreaseLiquidityOfPosition","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"duration_of_rewards","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"earned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"exit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint160","name":"sqrtPriceAX96","type":"uint160"},{"internalType":"uint160","name":"sqrtPriceBX96","type":"uint160"},{"internalType":"uint128","name":"liquidity","type":"uint128"}],"name":"getAmount0ForLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint160","name":"sqrtPriceAX96","type":"uint160"},{"internalType":"uint160","name":"sqrtPriceBX96","type":"uint160"},{"internalType":"uint128","name":"liquidity","type":"uint128"}],"name":"getAmount1ForLiquidity","outputs":[{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getContractTotals","outputs":[{"internalType":"uint128","name":"liquidityInStaking","type":"uint128"},{"internalType":"uint128","name":"totalPooLLiquidity","type":"uint128"},{"internalType":"uint256","name":"total0xBTCStaked","type":"uint256"},{"internalType":"uint256","name":"totalB0xStaked","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExpectedSqrtPricex96","outputs":[{"internalType":"uint160","name":"sqrtPricex96","type":"uint160"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint160","name":"sqrtPriceX96","type":"uint160"},{"internalType":"uint160","name":"sqrtPriceAX96","type":"uint160"},{"internalType":"uint160","name":"sqrtPriceBX96","type":"uint160"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"getLiquidityForAmounts","outputs":[{"internalType":"uint128","name":"liquidity","type":"uint128"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"},{"internalType":"address","name":"ownerOfNFT","type":"address"}],"name":"getMaxRedeemableTokens","outputs":[{"internalType":"uint256","name":"amount0fees","type":"uint256"},{"internalType":"uint256","name":"amount1fees","type":"uint256"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPriceRatio","outputs":[{"internalType":"uint256","name":"ratio","type":"uint256"},{"internalType":"address","name":"token0z","type":"address"},{"internalType":"address","name":"token1z","type":"address"},{"internalType":"uint8","name":"token0decimals","type":"uint8"},{"internalType":"uint8","name":"token1decimals","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint160","name":"sqrtPriceX96","type":"uint160"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"getPriceRatioWithDecimals","outputs":[{"internalType":"uint256","name":"priceRatio","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"rewardTokens","type":"address[]"}],"name":"getRewardForTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"rewardTokens","type":"address[]"}],"name":"getRewardForTokensOwed","outputs":[{"internalType":"uint256[]","name":"rewardsOwed","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardOwedStats","outputs":[{"internalType":"address[]","name":"rewardTokenAddresses","type":"address[]"},{"internalType":"uint256[]","name":"rewardsOwed","type":"uint256[]"},{"internalType":"string[]","name":"tokenSymbols","type":"string[]"},{"internalType":"string[]","name":"tokenNames","type":"string[]"},{"internalType":"uint8[]","name":"tokenDecimals","type":"uint8[]"},{"internalType":"uint256[]","name":"tokenRewardRates","type":"uint256[]"},{"internalType":"uint256[]","name":"tokenPeriodEndsAt","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardTokens","outputs":[{"internalType":"contract IERC20[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"getStakedTokenIds","outputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"},{"internalType":"uint128","name":"percentageToRemoveOutOf10000000000000","type":"uint128"},{"internalType":"address","name":"ownerOfNFT","type":"address"}],"name":"getTokenAmountForPercentageLiquidity","outputs":[{"internalType":"uint256","name":"amount0fees","type":"uint256"},{"internalType":"uint256","name":"amount1fees","type":"uint256"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"forWho","type":"address"},{"internalType":"uint256","name":"amount0In","type":"uint256"},{"internalType":"uint256","name":"amount1In","type":"uint256"},{"internalType":"uint256","name":"tokenID","type":"uint256"},{"internalType":"uint160","name":"expectedSqrtPricex96","type":"uint160"},{"internalType":"uint160","name":"slippageBps","type":"uint160"}],"name":"increaseLiquidityOfPosition","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"isNFTStaked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"name":"isRewardToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"lastTimeRewardApplicable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"nftOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"periodsDistributedUSDC","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"permit2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"removeRewardToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"name":"rewardData","outputs":[{"internalType":"uint256","name":"rewardRate","type":"uint256"},{"internalType":"uint256","name":"periodFinish","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTime","type":"uint256"},{"internalType":"uint256","name":"rewardPerTokenStored","type":"uint256"},{"internalType":"uint256","name":"totalRewarded","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"rewardPerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardTokens_Map","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pow","type":"address"}],"name":"setPOW_Contract","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"setRewardParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setupAddTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"forWhom","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"stakeFORUniswapV3NFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"stakeUniswapV3NFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stateView","outputs":[{"internalType":"contract IStateView","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenIdToSequentialId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniswapv4PositionManager","outputs":[{"internalType":"contract IPositionManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userPositionCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userPositions","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"bool","name":"isStaked","type":"bool"},{"internalType":"uint256","name":"timeStakedAt","type":"uint256"},{"internalType":"address","name":"ownerOfPosition","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"contract IERC20","name":"","type":"address"}],"name":"userRewards","outputs":[{"internalType":"uint256","name":"userRewardPerTokenPaid","type":"uint256"},{"internalType":"uint256","name":"rewards","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"zeroXBTC","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
610180346102e257601f61618938819003918201601f19168301916001600160401b038311848410176102e7578084926060946040528339810103126102e257610048816102fd565b6100606040610059602085016102fd565b93016102fd565b600280546001600160a01b0319908116331790915573420000000000000000000000000000000000000660c05273036cbd53842c5426634e7929541ec2318f3dcf7e60e052600580546001600160401b03191661012c17905573571291b572ed32ce6751a2cb2486ebee8defb9b4610100526e22d473030f116ddee9f6b43ac78ba361012052600d805465ffffffffffff191665f2764c0d89b4179055426011556012805460ff1916905560a0849052601080549091166001600160a01b03928316908117909155610160529081166080819052734b2c77d209d3405f41a037ec6c77f7f5b8e2ca8061014052911681811080156102dc57815b600e80546001600160a01b0319166001600160a01b0392909216919091179055156102d557505b600f80546001600160a01b0319166001600160a01b0392909216919091179055604051615e77908161031282396080518181816119bf01528181611fbf0152615a30015260a0518181816106c301528181611fe801528181612fd70152615a00015260c05181818161067e0152818161201a0152818161219a01526159d0015260e051818181611c6901528181611f8d01528181613b3c01528181614f3a0152615a60015261010051818181610b9301528181611e29015281816124d0015281816125d801528181612aee0152612f3201526101205181818161086401526135bf01526101405181818161090a0152818161126201528181611459015281816114ae015281816115c20152818161161801528181611b7401528181611cd6015281816122ae01528181612da9015281816131260152818161442b01528181615668015261572e01526101605181611bb90152f35b9050610181565b8261015a565b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036102e25756fe6080806040526004361015610011575b005b60003560e01c9081630918eb14146135ee5750806312261ee7146135a957806314d0d8de14613587578063150b7a021461351657806315131d7a146134f857806318160ddd146134da5780631c03e6cc146134b9578063211dc32d1461348d57806329e24cb7146134595780632af9cc411461309c5780632d99153814612eae5780632e1a7d4d14612c085780633d18b91214612bec5780633d509c9714612bb65780634819543914612b8357806348e5d9f814612b1d5780634c4a3c2514612ad85780634d9937f6146126fc57806354b2a7691461255e578063556afceb146125385780635684aef01461245557806359ae8f7e1461243f5780635e1b4d99146123b65780635ee29240146122685780636098fd4a1461221b578063638634ee146121f85780636645e413146121865780636882a888146121655780636a2cac65146121405780636ac69a8e1461210c5780636fd495d0146120df57806370a08231146120a5578063715018a6146120475780637497962014611f62578063857f400b14611c9857806389c54f4f14611c535780638b19d82214611c115780638da5cb5b14611be857806399da213d14611ba35780639c85dca214611b5e578063a0c8bed114611b32578063a1634b1414611b0e578063a980356a14611aaf578063aaea77b314611a87578063ab7c303114611a5e578063ac8bb71d14611a2d578063b5fd73f8146119ee578063c15ed8ff146119a9578063c35fd9bc1461197c578063c4f59f9b14611915578063c8de06de146117eb578063ce0235cb146117c8578063d7e80e6c14611156578063d8162cdf1461070f578063e6c0fe3d146106f2578063e6fa0168146106ad578063ea9834fe14610668578063ec81937e1461063f578063f122977714610614578063f24bfd451461041f578063f2fde38b14610352578063f58e7b3314610331578063f7ea16ac146103135763fd731837146102da57005b3461030e57602036600319011261030e57600435600052600c602052602060018060a01b0360406000205416604051908152f35b600080fd5b3461030e57600036600319011261030e576020601354604051908152f35b3461030e57602036600319011261030e5761000f61034d613624565b614ebc565b3461030e57602036600319011261030e5761036b613624565b6002546001600160a01b03811691610384338414613ee3565b6001600160a01b03169182156103cb5782907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a36001600160a01b03191617600255005b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b3461030e57606036600319011261030e57610438613624565b6044356024356104488282613963565b9260018060a01b031692836000526009602052604060002054106105f4575b6000905b83600052600960205260406000205481116105055783600052600860205260406000208160005260205260406000206040516104a681613767565b8154815260018201546001600160801b0381166020830152608090811c60ff16151560408301819052600284015460608401526003909301546001600160a01b03169101526105e4575b8282116105055761050090614ead565b61046b565b506105109150613fe4565b60009060015b83600052600960205260406000205481116105ca5783600052600860205260406000208160005260205260406000206040519061055282613767565b805491828152608060ff60018401546001600160801b0381166020850152821c1615159283604084015260028101546060840152600360018060a01b03910154169101526105aa575b506105a590614ead565b610516565b836105c3916105bd6105a5949686613d7a565b52614ead565b929061059b565b604051602080825281906105e090820185613692565b0390f35b906105ee90614ead565b906104f0565b905081600052600960205261060e81604060002054613894565b90610467565b3461030e57602036600319011261030e576020610637610632613624565b614e1d565b604051908152f35b3461030e57602036600319011261030e5761065c3060043561556c565b50602060405160018152f35b3461030e57600036600319011261030e576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461030e57600036600319011261030e576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461030e57602036600319011261030e5761000f60043533614429565b3461030e5760c036600319011261030e57610728613624565b60643590602435906044356084356001600160a01b0381169081900361030e5760a435946001600160a01b038616860361030e5760018060a01b03841691826000526008602052604060002082600052600a602052604060002054600052602052604060002060405161079a81613767565b815480825260018301546001600160801b0381166020840152608090811c60ff16151560408401908152600285015460608501526003909401546001600160a01b03169201918252840361111157516001600160a01b031684036110cc576001905115150361106f5761080d308361556c565b50610816614cc8565b9660005b8851811015610849576001906108436001600160a01b0361083b838d613d7a565b5116896154f6565b0161081a565b50600e5460405163095ea7b360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301819052600019602484015289959490938b93919260209183916044918391600091165af18015610ee157611052575b50600f5460405163095ea7b360e01b815260048101859052600019602482015290602090829060449082906000906001600160a01b03165af18015610ee157611035575b50600e546001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116949165ffffffffffff4216911661094182614e00565b90833b1561030e576040516387517c4560e01b81526001600160a01b0391821660048201528782166024820152604481019190915265ffffffffffff91909116606482015260008160848183875af18015610ee157611024575b50600f546001600160a01b0316906109b290614e00565b823b1561030e576040516387517c4560e01b81526001600160a01b0392831660048201528683166024820152604481019290925265ffffffffffff166064820152906000908290608490829084905af18015610ee157611013575b50600e5460405163095ea7b360e01b815260048101859052600019602482015290602090829060449082906000906001600160a01b03165af18015610ee157610ff6575b50600f5460405163095ea7b360e01b815260048101859052600019602482015290602090829060449082906000906001600160a01b03165af18015610ee157610fd9575b50600e546040516323b872dd60e01b81523360048201523060248201526044810184905290602090829060649082906000906001600160a01b03165af18015610ee157610fbc575b50600f546040516323b872dd60e01b8152336004820152306024820152604481018a905290602090829060649082906000906001600160a01b03165af18015610ee157610f8f575b50600e54600f546010546040516001600160a01b039283169793831694939260a09216610b5182613767565b858252886020830152628000006040830152603c60608301526080820152209160405192633205590760e21b8452600484015260808360248160018060a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa928315610ee157600093610f5b575b5060011c60016001609f1b031690612710828103908111610efe576001600160a01b039061271090610bf690846138c1565b041691612710018061271011610efe576001600160a01b039161271091610c1c916138c1565b041660018060a01b038316918210159182610f50575b505015610f14578883640100ad139c73ff53611968f1e5ca45cfca7918447e7f5776f6d490610c6094614335565b60405160006020820152600d60f81b6021820152600281526001600160801b03919091169490610c9290602290613799565b6060908760405194610ca48487613799565b60028652610cb9601f19850160208801613f92565b60405160006020820152600d60f81b60218201526002815297610cdd60228a613799565b60209c8d9260405192610cf08585613799565b60008452604051958695860152604085015286840152608083015260a0820160a0905260c08201610d20916136e9565b03601f1981018252610d329082613799565b610d3b85613d5d565b52610d4584613d5d565b50604051928a840152604083015260408252610d619082613799565b610d6a82613d6a565b52610d7481613d6a565b504260a00192834211610efe57610da490610d966040519384928b8401614d71565b03601f198101835282613799565b813b1561030e5760405163dd46508f60e01b81529260009184918291610dce919060048401614de4565b038183855af1908115610ee1576024928792610eed575b5060405192838092631efeed3360e01b82528760048301525afa8015610ee157600080516020615e2283398151915294610ea692600092610eb2575b5060005260088652604060002084600052600a8752604060002054600052865260016040600020426002820155016001600160801b0380610e658184541685614315565b1692610e718487615dc5565b166001600160801b031982541617905560405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a160405160018152f35b610ed3919250873d8911610eda575b610ecb8183613799565b810190613d8e565b9087610e21565b503d610ec1565b6040513d6000823e3d90fd5b6000610ef891613799565b87610de5565b634e487b7160e01b600052601160045260246000fd5b60405162461bcd60e51b81526020600482015260146024820152730a0e4d2c6ca40dadeeccac840e8dede40daeac6d60631b6044820152606490fd5b111590508a80610c32565b610f7e91935060803d608011610f88575b610f768183613799565b810190613dcb565b505050918b610bc4565b503d610f6c565b610fb09060203d602011610fb5575b610fa88183613799565b810190613989565b610b25565b503d610f9e565b610fd49060203d602011610fb557610fa88183613799565b610add565b610ff19060203d602011610fb557610fa88183613799565b610a95565b61100e9060203d602011610fb557610fa88183613799565b610a51565b600061101e91613799565b88610a0d565b600061102f91613799565b8a61099b565b61104d9060203d602011610fb557610fa88183613799565b6108fc565b61106a9060203d602011610fb557610fa88183613799565b6108b8565b60405162461bcd60e51b815260206004820152602f60248201527f4d757374206265206163746976656c79207374616b656420706f736974696f6e60448201526e081d1bc81a5b98dc99585cd9481a5d608a1b6064820152608490fd5b60405162461bcd60e51b815260206004820152601e60248201527f666f7257686f206d757374206265206f776e65724f66506f736974696f6e00006044820152606490fd5b60405162461bcd60e51b815260206004820152601f60248201527f666f7257686f206d757374206861766520636f6e74726f6c206f66204e4654006044820152606490fd5b3461030e57608036600319011261030e5761116f61367c565b6001600160801b0381166509184e72a000106117bb575b3360005260086020526040600020600435600052600a602052604060002054600052602052604060002080549160018201549260043503611776576111d860018060a01b036003840154163314613e0f565b6111ec600160ff8560801c16151514613e54565b6111f83060043561556c565b50611205336004356140a4565b9061120e614cc8565b9360005b85518110156112415760019061123b6001600160a01b03611233838a613d7a565b5116336154f6565b01611212565b50604051631efeed3360e01b815260048035908201529084906020836024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa928315610ee157600093611755575b50600e54600f546040516001600160a01b03918216966060939192909116906112c48484613799565b600283526112d9601f19850160208501613f92565b6001600160801b031696876001600160801b038816906112f8916138c1565b6509184e72a00090046001600160801b0316966001600160801b038a1661131f90896138c1565b6103e890046001600160801b0316978861133891614315565b986509184e72a0001461173b575b6001600160801b03808a16890111610efe576001600160801b0380808b168a01169116106116f657866113c66103e861139a6001600160801b038261138f8f83166044356138c1565b049d166064356138c1565b04610d9660209c8d92604051916113b18584613799565b60008352604051968795600435908701614d1c565b6113cf84613d5d565b526113d983613d5d565b506040516113ef81610d963085878f8501614d4e565b6113f884613d6a565b5261140283613d6a565b50604051600160f81b8a8201908152601160f81b60018201529091906114369083906002015b03601f198101845283613799565b60a0420193844211610efe578a611428611457926040519586938401614d71565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163b1561030e576000846114a993604051948592839263dd46508f60e01b845260048401614de4565b0381837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af1918215610ee157611563926116e5575b5061150a604051956114fa8188613799565b60028752601f19018b8701613f92565b8861153c8b610d9660405161151f8382613799565b600081526040519485936064359160443591600435908701614d1c565b61154586613d5d565b5261154f85613d5d565b50610d9660405193849233918d8501614d4e565b61156c83613d6a565b5261157682613d6a565b50604051600160f81b888201908152601160f81b60018201529092906115a990849060020103601f198101855284613799565b6115c0600093610d966040519384928c8401614d71565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163b156116e15760405163dd46508f60e01b81529291829184918291611613919060048401614de4565b0381837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af180156116d4576001600160801b0380611698610ea6968299967f1d15074a35b5a1181cbb682ad77c37e0fd0d3ae2aecb0fe1338bf14b93da7d169b99966001966116c4575b50508280808b168901169116613894565b6116a582891687016158ff565b1616861982840154161791015560405193849316016004353384613eb8565b6116cd91613799565b8c80611687565b50604051903d90823e3d90fd5b8280fd5b60006116f091613799565b8a6114e8565b60405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206c69717569646974792072656d6f76616c000000000000006044820152606490fd5b975061174f61174a888a614315565b6142f6565b97611346565b61176f91935060203d602011610eda57610ecb8183613799565b918561129b565b60405162461bcd60e51b815260206004820152601c60248201527f596f75206d757374206861766520636f6e74726f6c206f66204e4654000000006044820152606490fd5b506509184e72a000611186565b3461030e57602036600319011261030e57602060405160043560081c60020b8152f35b3461030e57602036600319011261030e57611804613624565b61181960018060a01b03600254163314613ee3565b60125460ff81166118df5760ff1916600117601255601154629e34008101908110610efe5742101561189a57600d5490603082901c6001600160a01b031615611868575b602060405160008152f35b6601000000000000600160d01b031990911660309190911b6601000000000000600160d01b031617600d55808061185d565b60405162461bcd60e51b815260206004820152601960248201527f4f6e6c7920617661696c206669727374203132302064617973000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152600e60248201526d20536574206f6e6365207472756560901b6044820152606490fd5b3461030e57600036600319011261030e5761192e614cc8565b60405180916020820160208352815180915260206040840192019060005b81811061195a575050500390f35b82516001600160a01b031684528594506020938401939092019160010161194c565b3461030e576105e0611995611990366137d3565b614c83565b604051918291602083526020830190613692565b3461030e57600036600319011261030e576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461030e57602036600319011261030e576001600160a01b03611a0f613624565b166000526004602052602060ff604060002054166040519015158152f35b3461030e57602036600319011261030e57600435600052600b602052602060ff604060002054166040519015158152f35b3461030e57600036600319011261030e576010546040516001600160a01b039091168152602090f35b3461030e57600036600319011261030e57602067ffffffffffffffff60055416604051908152f35b3461030e57604036600319011261030e57611ac8613624565b611ad061363a565b9060018060a01b0316600052600760205260406000209060018060a01b03166000526020526040806000206001815491015482519182526020820152f35b3461030e57600036600319011261030e576020600d5460181c60020b604051908152f35b3461030e57602036600319011261030e57600435600052600a6020526020604060002054604051908152f35b3461030e57600036600319011261030e576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461030e57600036600319011261030e576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461030e57600036600319011261030e576002546040516001600160a01b039091168152602090f35b3461030e57602036600319011261030e5760043560035481101561030e57611c3a602091613863565b905460405160039290921b1c6001600160a01b03168152f35b3461030e57600036600319011261030e576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461030e57604036600319011261030e57600435611cb461363a565b604051631efeed3360e01b8152600481018390526000929091906020836024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa928315611f57578493611f27575b506001600160801b0391611d21916140a4565b9116916509184e72a000808402848104821485151715611f13576001600160801b038083611d789304169416611d726001600160801b03611d6a611d6584896138c1565b615d02565b168096614315565b956138c1565b818102918183041490151715611eff57662386f26fc100009006151580611eed575b611edd575b640100ad139c5b9173ff53611968f1e5ca45cfca7918447e7f5776f6d4600e54600f5460105460405193959360a09390926001600160a01b03928316929081169116611dea84613767565b83526020830152628000006040830152603c606083015260808201522060405190633205590760e21b8252600482015260808160248160018060a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa918215611ed157916105e0949391611e8b9391611eaf575b50611e8582611e7e611e768a8886614c0f565b99848a613d1a565b9583614c0f565b95613d1a565b93604051948594859094939260609260808301968352602083015260408201520152565b611ec8915060803d608011610f8857610f768183613799565b50505087611e63565b604051903d90823e3d90fd5b91611ee7906142f6565b91611d9f565b506001600160801b0383161515611d9a565b634e487b7160e01b82526011600452602482fd5b634e487b7160e01b83526011600452602483fd5b611d2191935091611f4e6001600160801b039360203d602011610eda57610ecb8183613799565b93915091611d0e565b6040513d86823e3d90fd5b3461030e57600036600319011261030e57611f8860018060a01b03600254163314613ee3565b611fba7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166139a1565b611fe37f00000000000000000000000000000000000000000000000000000000000000006139a1565b6120157f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166139a1565b61000f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166139a1565b3461030e57600036600319011261030e5760025460006001600160a01b038216612072338214613ee3565b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a36001600160a01b031916600255005b3461030e57602036600319011261030e576001600160a01b036120c6613624565b1660005260016020526020604060002054604051908152f35b3461030e57600036600319011261030e57600d5460405160309190911c6001600160a01b03168152602090f35b3461030e57606036600319011261030e57602061063761212a613624565b61213261363a565b61213a613666565b91614c0f565b3461030e57604036600319011261030e5761000f61215c613624565b60243590614429565b3461030e57600036600319011261030e576020600d5460020b604051908152f35b3461030e57600036600319011261030e57477f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561030e57600090600460405180948193630d0e30db60e41b83525af18015610ee1576121ed57005b600061000f91613799565b3461030e57602036600319011261030e576020610637612216613624565b6143ed565b3461030e5760a036600319011261030e576020612257612239613624565b61224161363a565b9061224a613650565b6084359260643592614335565b6001600160801b0360405191168152f35b3461030e57606036600319011261030e5760043561228461367c565b9061228d613650565b604051631efeed3360e01b81526004810183905291600091906020846024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9384156123ab57839461236c575b506001600160801b0380612305662386f26fc1000094612355946140a4565b951695166123506001600160801b03806509184e72a000612326858b6138c1565b0416961661234a6001600160801b03612342611d65848b6138c1565b168098614315565b976138c1565b6138c1565b06151580611eed57611edd57640100ad139c611da6565b6123559194506001600160801b03612305662386f26fc100009461239f839460203d602011610eda57610ecb8183613799565b979450945050506122e6565b6040513d85823e3d90fd5b3461030e57604036600319011261030e576001600160a01b036123d7613624565b166000526008602052604060002060243560005260205260a0604060002080549060018101549060ff6002820154916003600180881b0391015416926040519485526001600160801b038116602086015260801c161515604084015260608301526080820152f35b3461030e5761000f612450366137d3565b614187565b3461030e57600036600319011261030e57600e54600f5460105460405160a09390926001600160a01b0392831692908116911661249184613767565b83526020830152628000006040830152603c606083015260808201522060405190633205590760e21b8252600482015260808160248160018060a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa8015610ee157602091600091612516575b506040516001600160a01b039091168152f35b61252f915060803d608011610f8857610f768183613799565b50505082612503565b3461030e57604036600319011261030e57602061225761255661363a565b6004356140a4565b3461030e57600036600319011261030e57600e54600f546010546040516001600160a01b039283169383169260a0921661259782613767565b838252846020830152628000006040830152603c606083015260808201522060405190633205590760e21b8252600482015260808160248160018060a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa8015610ee157612612916000916126da575b50613f2e565b60405163313ce56760e01b81529091602082600481845afa918215610ee1576000926126b9575b5060405163313ce56760e01b815291602083600481885afa908115610ee15760a09560ff94600093612688575b5084929360405196875260208701526040860152166060840152166080820152f35b8593506126ac9060203d6020116126b2575b6126a48183613799565b810190613970565b92612666565b503d61269a565b6126d391925060203d6020116126b2576126a48183613799565b9084612639565b6126f3915060803d608011610f8857610f768183613799565b5050508461260c565b3461030e57600036600319011261030e57612715614cc8565b8051612739612723826137bb565b916127316040519384613799565b8083526137bb565b602082019190601f19013683376127508351613faf565b9061275b8451613faf565b84519061278061276a836137bb565b926127786040519485613799565b8084526137bb565b602083019490601f19013686376127978751613fe4565b936127a28851613fe4565b9560005b89518110156129e7576001906001600160a01b036127c4828d613d7a565b51166127d08286613d7a565b52600460008c6127e684868060a01b0392613d7a565b5116604051928380926395d89b4160e01b82525afa600091816129cc575b506129b15750612812614085565b61281c8287613d7a565b526128278186613d7a565b505b600460008c61283e84868060a01b0392613d7a565b5116604051928380926306fdde0360e01b82525afa6000918161298e575b50612973575061286a614085565b6128748288613d7a565b5261287f8187613d7a565b505b600460208c61289684868060a01b0392613d7a565b51166040519283809263313ce56760e01b82525afa60009181612953575b5061293e5750816128c58289613d7a565b525b818060a01b036128d7828d613d7a565b5116600052600660205260406000206040516128f281613767565b815490818152608060048685015494602084019586526002810154604085015260038101546060850152015491015261292b838b613d7a565b5251612937828b613d7a565b52016127a6565b60ff61294a838a613d7a565b911690526128c7565b61296c91925060203d81116126b2576126a48183613799565b908d6128b4565b61297d8288613d7a565b526129888187613d7a565b50612881565b6129aa91923d8091833e6129a28183613799565b810190614016565b908d61285c565b6129bb8287613d7a565b526129c68186613d7a565b50612829565b6129e091923d8091833e6129a28183613799565b908d612804565b50949392919096976129f890614c83565b9760405198899860e08a019060e08b52518091526101008a01929060005b818110612ab657505050612a5892612a3c83612a4a938c602081819a9803910152613692565b908a820360408c015261370e565b9088820360608a015261370e565b918683036080880152519182815201929060005b818110612a9a5750505081612a8c91856105e095940360a0870152613692565b9083820360c0850152613692565b825160ff16855287965060209485019490920191600101612a6c565b82516001600160a01b031685528c9b5060209485019490920191600101612a16565b3461030e57600036600319011261030e576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461030e57602036600319011261030e576001600160a01b03612b3e613624565b16600052600660205260a06040600020805490600181015490600281015460046003830154920154926040519485526020850152604084015260608301526080820152f35b3461030e57604036600319011261030e57612b9c613624565b6024359060ff8216820361030e5760209161063791613f5e565b3461030e57602036600319011261030e5761000f612bd2613624565b612be760018060a01b03600254163314613ee3565b6159ae565b3461030e57600036600319011261030e5761000f612450614cc8565b3461030e57602036600319011261030e57600435612c24614cc8565b9060005b8251811015612c4f57600190612c496001600160a01b036112338387613d7a565b01612c28565b5080600052600a60205260406000205433600052600860205260406000208160005260205260406000209160405191612c8783613767565b83548352612cea60016001600160801b038187015495612cdc60208201988389168a5260ff604084019960801c1615158952600281015460608401526003858060a01b03910154168060808401523314613e0f565b519651169451151514613e54565b612cf4308361556c565b50612cfe8261570b565b50600360405191612d0e83613767565b85835260006020808501828152604080870184815242606089019081526080808a0187815233885260088752848820988852979095529190942096518755905160018701805494516001600160881b03199095166001600160801b03929092169190911793151590921b60ff60801b1692909217905551600284015551910180546001600160a01b0319166001600160a01b039283161790557f000000000000000000000000000000000000000000000000000000000000000016803b1561030e5760405163095ea7b360e01b81523060048201526024810185905260008160448183865af18015610ee157612e9d575b50803b1561030e57604051632142170760e11b815230600482015233602482015260448101949094526000908490606490829084905af1928315610ee1577f1d15074a35b5a1181cbb682ad77c37e0fd0d3ae2aecb0fe1338bf14b93da7d1693612e8c575b50612e6e826158ff565b612e7e6040519283923384613eb8565b0390a1602060405160018152f35b6000612e9791613799565b83612e64565b6000612ea891613799565b84612dff565b3461030e57600036600319011261030e576000640100ad139c73ff53611968f1e5ca45cfca7918447e7f5776f6d4600e54600f5460105460405193946001600160a01b0393841694909360a093919281169116612f0a83613767565b8583526020830152628000006040830152603c60608301526080820152209260018060a01b037f0000000000000000000000000000000000000000000000000000000000000000166040519463fa6793d560e01b8652806004870152602086602481855afa95861561309157879661306d575b50608090602460405180948193633205590760e21b835260048301525afa9081156130625791612fd49187612fce9796959460809992613037575b506001600160801b039054169687809383614c0f565b93613d1a565b917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603613028576001600160801b039091925b60405194855216602084015260408301526060820152f35b916001600160801b0390613010565b6001600160801b03919250613058908a3d8c11610f8857610f768183613799565b5050509190612fb8565b6040513d88823e3d90fd5b608091965061308a9060203d602011610eda57610ecb8183613799565b9590612f7d565b6040513d89823e3d90fd5b3461030e57604036600319011261030e5761310f60006024356004356130c28282613963565b338452600960205260408420541061343b575b6130e0612450614cc8565b60405163f24bfd4560e01b81523360048201526024810191909152604481019190915291829081906064820190565b0381305afa908115610ee1576000916133a4575b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169060005b815181101561000f576131658183613d7a565b519081600052600a6020526040600020549133600052600860205260406000208360005260205260406000206040519361319e85613767565b6132048254958681526131f360018086015495608060ff6001600160801b03891698896020880152821c16151591826040870152600281015460608701526003848060a01b0391015416940193845214613e54565b516001600160a01b03163314613e0f565b61320e308461556c565b506132188361570b565b5060036040519161322883613767565b86835260006020808501828152604080870184815242606089019081526080808a0187815233885260088752848820988852979095529190942096518755905160018701805494516001600160881b03199095166001600160801b03929092169190911793151590921b60ff60801b1692909217905551600284015551910180546001600160a01b0319166001600160a01b0392909216919091179055853b1561030e5760405163095ea7b360e01b815230600482015260248101859052600081604481838b5af18015610ee157613393575b50853b1561030e57604051632142170760e11b81523060048201523360248201526044810194909452600084606481838a5af1918215610ee1576001947f1d15074a35b5a1181cbb682ad77c37e0fd0d3ae2aecb0fe1338bf14b93da7d1693613382575b50613369826158ff565b6133796040519283923384613eb8565b0390a101613152565b600061338d91613799565b8761335f565b600061339e91613799565b866132fb565b3d8083833e6133b38183613799565b8101906020818303126116e15780519067ffffffffffffffff8211613437570181601f820112156116e1578051906133ea826137bb565b936133f86040519586613799565b82855260208086019360051b8301019384116134345750602001905b8282106134245750505081613123565b8151815260209182019101613414565b80fd5b8380fd5b90503382526009602052613453816040842054613894565b906130d5565b3461030e57606036600319011261030e576020610637613477613624565b61347f61363a565b613487613666565b91613d1a565b3461030e57604036600319011261030e5760206106376134ab613624565b6134b361363a565b90613c76565b3461030e57602036600319011261030e5761000f6134d5613624565b6139a1565b3461030e57600036600319011261030e576020600054604051908152f35b3461030e57602036600319011261030e5760206122576004356138d4565b3461030e57608036600319011261030e5761352f613624565b5061353861363a565b5060643567ffffffffffffffff811161030e573660238201121561030e57806004013567ffffffffffffffff811161030e573691016024011161030e57604051630a85bd0160e11b8152602090f35b3461030e57602036600319011261030e576020604051600435821c60020b8152f35b3461030e57600036600319011261030e576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461030e57602036600319011261030e576020906001600160a01b03613612613624565b16600052600982526040600020548152f35b600435906001600160a01b038216820361030e57565b602435906001600160a01b038216820361030e57565b604435906001600160a01b038216820361030e57565b604435906001600160801b038216820361030e57565b602435906001600160801b038216820361030e57565b906020808351928381520192019060005b8181106136b05750505090565b82518452602093840193909201916001016136a3565b60005b8381106136d95750506000910152565b81810151838201526020016136c9565b90602091613702815180928185528580860191016136c6565b601f01601f1916010190565b9080602083519182815201916020808360051b8301019401926000915b83831061373a57505050505090565b9091929394602080613758600193601f1986820301875289516136e9565b9701930193019193929061372b565b60a0810190811067ffffffffffffffff82111761378357604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff82111761378357604052565b67ffffffffffffffff81116137835760051b60200190565b602060031982011261030e576004359067ffffffffffffffff821161030e578060238301121561030e5781600401359061380c826137bb565b9261381a6040519485613799565b8284526024602085019360051b82010191821161030e57602401915b8183106138435750505090565b82356001600160a01b038116810361030e57815260209283019201613836565b60035481101561387e57600360005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b91908203918211610efe57565b81156138ab570490565b634e487b7160e01b600052601260045260246000fd5b81810292918115918404141715610efe57565b6138e2620151809142613894565b04600f811061393a57601e8110156138fb57506014905b565b602d81101561390a5750600f90565b603c8110156139195750600a90565b604b8110156139285750600790565b6096111561393557600590565b600190565b8060aa029060aa820403610efe57600f900460c80360c88111610efe576001600160801b031690565b91908201809211610efe57565b9081602091031261030e575160ff8116810361030e5790565b9081602091031261030e5751801515810361030e5790565b6002546001600160a01b03163303613b1c575b6001600160a01b03811660008181526004602052604090205490919060ff16613ae157600354916801000000000000000083101561378357613a2682613a0285600160049701600355613863565b81546001600160a01b0393841660039290921b91821b9390911b1916919091179055565b80600052826020526040600020600160ff198254161790556000526006602052613a54604060002091614e1d565b600382015560008082556002820155600d546040516378e9792560e01b815292602091849190829060301c6001600160a01b03165afa918215610ee157600092613aad575b50620151808201809211610efe5760010155565b90916020823d602011613ad9575b81613ac860209383613799565b810103126134345750519038613a99565b3d9150613abb565b60405162461bcd60e51b8152602060048201526013602482015272151bdad95b88185b1c9958591e481859191959606a1b6044820152606490fd5b60146003540460018101809111610efe5760405163313ce56760e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169190602081600481865afa8015610ee15760ff91600091613c57575b501690601481029080820460141490151715610efe57604d8211610efe57600092613bb4613be492602094600a0a906138c1565b6040516323b872dd60e01b8152336004820152306024820152604481019190915293849283919082906064820190565b03925af1908115610ee157600091613c38575b506139b45760405162461bcd60e51b81526020600482015260146024820152731554d110c81d1c985b9cd9995c8819985a5b195960621b6044820152606490fd5b613c51915060203d602011610fb557610fa88183613799565b38613bf7565b613c70915060203d6020116126b2576126a48183613799565b38613b80565b6001600160a01b0316600081815260016020526040902054613cfe9290613cd290613ccc613ca384614e1d565b856000526007602052604060002060018060a01b03861660005260205260406000205490613894565b906152d6565b91600052600760205260406000209060018060a01b031660005260205260016040600020015490613963565b90565b6001600160a01b039182169082160391908211610efe57565b613cfe92916001600160801b03916001600160a01b0380831690821611613d57575b6001600160a01b0391613d4f9190613d01565b169116615352565b90613d3c565b80511561387e5760200190565b80516001101561387e5760400190565b805182101561387e5760209160051b010190565b9081602091031261030e57516001600160801b038116810361030e5790565b51908160020b820361030e57565b519062ffffff8216820361030e57565b919082608091031261030e5781516001600160a01b038116810361030e5791613df660208201613dad565b91613cfe6060613e0860408501613dbb565b9301613dbb565b15613e1657565b60405162461bcd60e51b815260206004820152601660248201527526bab9ba1037bbb7103a3434b9903837b9b4ba34b7b760511b6044820152606490fd5b15613e5b57565b60405162461bcd60e51b815260206004820152602f60248201527f4d7573742068617665206163746976656c79207374616b656420706f7369746960448201526e1bdb881d1bc81c995b5bdd99481a5d608a1b6064820152608490fd5b6001600160a01b03909116815260208101919091526001600160801b03909116604082015260600190565b15613eea57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b6001600160a01b03168015613f5857670de0b6b3a7640000613f53613cfe92806138c1565b61539c565b50600090565b6001600160a01b0316908115613f8b5760ff1690604d8211610efe57613f53613cfe92600a0a91806138c1565b5050600090565b60005b828110613fa157505050565b606082820152602001613f95565b906138f9613fbc836137bb565b613fc96040519182613799565b83815260208194613fdc601f19916137bb565b019101613f92565b90613fee826137bb565b613ffb6040519182613799565b828152809261400c601f19916137bb565b0190602036910137565b60208183031261030e5780519067ffffffffffffffff821161030e570181601f8201121561030e57805167ffffffffffffffff81116137835760405192614067601f8301601f191660200185613799565b8184526020828401011161030e57613cfe91602080850191016136c6565b60405190614094604083613799565b60018252603f60f81b6020830152565b600052600a6020526040600020549060018060a01b0316600052600860205260406000209060005260205260406000206040516140e081613767565b8154815260018201546001600160801b0381166020830152608090811c60ff16151560408301526002830154606083018181526003909401546001600160a01b031691909201521561413657613cfe90516138d4565b60405162461bcd60e51b815260206004820152602360248201527f4e6f742061204e465420746861742069732063757272656e746c79207374616b60448201526265642160e81b6064820152608490fd5b9060005b82518110156142f1576141a96001600160a01b036112338386613d7a565b6141c66001600160a01b036141be8386613d7a565b511633613c76565b90816141d7575b600191500161418b565b6001600160a01b036141e98286613d7a565b511660005260066020526004604060002001614206838254613894565b905533600090815260076020526040808220600191906001600160a01b0361422e868a613d7a565b511660a084901b849003168452602052822001556001600160a01b036142548286613d7a565b5160405163a9059cbb60e01b815233600482015260248101859052939160209185916044918391600091165af1928315610ee1576001936142d5575b50828060a01b036142a18387613d7a565b5116906040519081527f540798df468d7b23d11f156fdb954cb19ad414d150722a7b6d55ba369dea792e60203392a36141cd565b6142ec9060203d8111610fb557610fa88183613799565b614290565b509050565b6001600160801b03600019911601906001600160801b038211610efe57565b906001600160801b03809116911603906001600160801b038211610efe57565b9093906001600160a01b03838116908616818110156143ba576001600160a01b03831690811161436c5750505050613cfe92615d25565b9294919210614380575050613cfe92615d82565b61438f90614395949383615d25565b93615d82565b6001600160801b0381166001600160801b038316106000146143b5575090565b905090565b60405162461bcd60e51b815260206004820152600b60248201526a282924a1a2afa7a92222a960a91b6044820152606490fd5b6001600160a01b031660009081526006602052604090206001015442811115613cfe57504290565b51906001600160a01b038216820361030e57565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031692833b1561030e57604051632142170760e11b8152336004820152306024820152604481018490526000908181606481838a5af18015614c0457614bf4575b5090604051637ba03aad60e01b815284600482015260c081602481895afa9081156123ab5783908492614b52575b506040516331a9108f60e11b8152600481018790526020816024818b5afa908115614b47578591614b09575b50306001600160a01b0390911603614ac4578051600e546001600160a01b03918216911603614a87576020810151600f546001600160a01b03918216911603614a4257603c606082015160020b03614a0457608001516010546001600160a01b039182169116036149c657602060249660405197888092631efeed3360e01b82528960048301525afa9586156123ab5783966149a5575b50600d54908160181c60020b8160081c60020b149182614990575b505015614956576145ad614cc8565b94825b86518110156145df576001906145d96001600160a01b036145d1838b613d7a565b5116876154f6565b016145b0565b5092919450926040516145f181613767565b81815260208101956001600160801b038516875260408201916001835260608101428152608082019060018060a01b03871694858352868552600a6020526040852054151580614938575b1561472157868552600a602090815260408087205488885260088352818820908852909152808620945185559a51600185018054925160ff60801b90151560801b166001600160801b039092166001600160881b03199093169290921717905551600283015551600390910180546001600160a01b039092166001600160a01b031990921691909117905594956138f995600080516020615e22833981519152938693909290915b838152600c6020522080546001600160a01b0319169091179055614708338261556c565b506147196040519283928684613eb8565b0390a1615dc5565b9399868b52600a60205260408b2054151580614919575b1561483c57868b52600a6020528a6040812055858b52600960205260408b20549460018601809611614828579360036040948d94600080516020615e228339815191529a98946138f99e9f988b8f9c9a526008602052888820878952602052888820955186556001600160801b038060018801935116166001600160801b031983541617825551151581549060ff60801b9060801b169060ff60801b191617905551600284015560018060a01b0390511691019060018060a01b03166bffffffffffffffffffffffff60a01b825416179055848252600a60205280838320558382526009602052828220556146e4565b634e487b7160e01b8c52601160045260248cfd5b858b52600960205260408b20549460018601809611614828579360036040948d94600080516020615e228339815191529a98946138f99e9f988b8f9c9a526008602052888820878952602052888820955186556001600160801b038060018801935116166001600160801b031983541617825551151581549060ff60801b9060801b169060ff60801b191617905551600284015560018060a01b0390511691019060018060a01b03166bffffffffffffffffffffffff60a01b825416179055848252600a60205280838320558382526009602052828220556146e4565b50868b52600c60205260408b20546001600160a01b0316861415614738565b50868552600c60205260408520546001600160a01b0316861461463c565b60405162461bcd60e51b81526020600482015260126024820152714d7573742062652066756c6c2d72616e676560701b6044820152606490fd5b90915060020b9060201c60020b14388061459e565b6149bf91965060203d602011610eda57610ecb8183613799565b9438614583565b60405162461bcd60e51b8152602060048201526016602482015275696e636f727265637420686f6f6b206164647265737360501b6044820152606490fd5b60405162461bcd60e51b8152602060048201526016602482015275696e636f7272656374207469636b2073706163696e6760501b6044820152606490fd5b60405162461bcd60e51b815260206004820152601c60248201527f63757272656e637931206d757374206265206d61696e20746f6b656e000000006044820152606490fd5b60405162461bcd60e51b81526020600482015260156024820152740c6eae4e4cadcc6f26040daeae6e840c4ca408aa89605b1b6044820152606490fd5b60405162461bcd60e51b815260206004820152601860248201527f496e636f72726563746c79207374616b656420746f6b656e00000000000000006044820152606490fd5b90506020813d602011614b3f575b81614b2460209383613799565b81010312614b3b57614b3590614415565b386144ec565b8480fd5b3d9150614b17565b6040513d87823e3d90fd5b9150508060c03d60c011614bed575b614b6b8183613799565b81010360c081126134375760a0136116e15760405190614b8a82613767565b614b9381614415565b8252614ba160208201614415565b6020830152614bb260408201613dbb565b6040830152614bc360608201613dad565b606083015260808101516001600160a01b0381168103614b3b57608083015260a0015190386144c0565b503d614b61565b81614bfe91613799565b38614492565b6040513d84823e3d90fd5b613cfe929091614c6c91906001600160a01b0380821690851611614c7d575b6001600160a01b03614c408583613d01565b6001600160a01b039092169291169060601b6fffffffffffffffffffffffffffffffff60601b16615473565b6001600160a01b03909116906138a1565b92614c2e565b90614c8e8251613fe4565b9160005b8151811015614cc457600190614cb36001600160a01b036141be8386613d7a565b614cbd8287613d7a565b5201614c92565b5050565b604051906003548083528260208101600360005260206000209260005b818110614cfa5750506138f992500383613799565b84546001600160a01b0316835260019485019487945060209093019201614ce5565b91926001600160801b0360a094613cfe97969385521660208401526040830152606082015281608082015201906136e9565b6001600160a01b0391821681529181166020830152909116604082015260600190565b90614d84906040835260408301906136e9565b906020818303910152815180825260208201916020808360051b8301019401926000915b838310614db757505050505090565b9091929394602080614dd5600193601f1986820301875289516136e9565b97019301930191939290614da8565b929190614dfb6020916040865260408601906136e9565b930152565b65ffffffffffff610e109116019065ffffffffffff8211610efe57565b6001600160a01b03811660009081526006602052604081209054918215614ea357614e4a614e55916143ed565b600283015490613894565b633b9aca00810290808204633b9aca001490151715610efe57815490633b9aca00820291808304633b9aca001490151715610efe57613cfe93600392614e9a92615473565b91015490613963565b5060039150015490565b6000198114610efe5760010190565b6005546001600160a01b038216600081815260066020526040902090929167ffffffffffffffff16614eed83614e1d565b60038301556040516370a0823160e01b815230600482015290602082602481885afa918215610ee1576000926152a2575b5060048301908154808403931461525d57600a600284901b04927f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031687146151e8575b506040516370a0823160e01b8152306004820152906020826024818a5afa918215610ee1576000926151b4575b5060405163a9059cbb60e01b81523060048201526024810185905260208160448160008c5af19081615197575b50614fd75750505050506138f991506159ae565b6040516370a0823160e01b815230600482015294955091929091906020856024818a5afa948515610ee157600095615163575b5060018601924284541160001461507c5760405162461bcd60e51b815260206004820152603360248201527f4e6f20676f6f6420506572696f6446696e697368206d757374206265206265686044820152720696e6420626c6f636b2e74696d657374616d7606c1b6064820152608490fd5b61508b918684920390036138a1565b93841161512a576f4b3b4ca85a86c47a098a2240000000008410156150ee578481856020967fac24935fd910bc682b5ccb1a07b718cadf8cf2f6d1404c4f3ddc3662dae40e299855029380548501905560024291015542019055604051908152a2565b60405162461bcd60e51b81526020600482015260146024820152730a4caeec2e4c840e4c2e8ca40e8dede40d0d2ced60631b6044820152606490fd5b60405162461bcd60e51b81526020600482015260116024820152706e6f7420656e6f75676820746f6b656e7360781b6044820152606490fd5b90946020823d60201161518f575b8161517e60209383613799565b81010312613434575051933861500a565b3d9150615171565b6151af9060203d602011610fb557610fa88183613799565b614fc3565b9091506020813d6020116151e0575b816151d060209383613799565b8101031261030e57519038614f96565b3d91506151c3565b92506001612710601354946008861060001461520f57607d905b0204930160135538614f69565b601086101561522057607d90615202565b60188610156152315760fa90615202565b60208610156152425760fa90615202565b60288610156152545761017790615202565b61017790615202565b60405162461bcd60e51b815260206004820152601760248201527f526577617264206d75737420626520706f7369746976650000000000000000006044820152606490fd5b90916020823d6020116152ce575b816152bd60209383613799565b810103126134345750519038614f1e565b3d91506152b0565b8082029060001983820990828083109203918083039283670de0b6b3a7640000111561030e5714615341577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066993670de0b6b3a7640000910990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b818102919060001982820991838084109303928084039384600160601b111561030e571461539357600160601b910990828211900360a01b910360601c1790565b50505060601c90565b818102919060001982820991838084109303928084039384600160c01b111561030e57146153dd57600160c01b910990828211900360401b910360c01c1790565b50505060c01c90565b90606082901b90600019600160601b84099282808510940393808503948584111561030e571461546c578190600160601b9009818060000316809204600281600302188082026002030280820260020302808202600203028082026002030280820260020302809102600203029360018380600003040190848311900302920304170290565b5091500490565b91818302916000198185099383808610950394808603958685111561030e57146154ee5790829109818060000316809204600281600302188082026002030280820260020302808202600203028082026002030280820260020302809102600203029360018380600003040190848311900302920304170290565b505091500490565b6001600160a01b0382166000908152600660205260409020600392919061551c83614e1d565b938491615528856143ed565b600282015501556155398282613c76565b6001600160a01b039182166000908152600760209081526040808320959094168252939093529120600181019190915555565b600e54600f54604051600160f81b6020820152601160f81b60218201526002815260009490926001600160a01b039092169161564391610d96906155b1602287613799565b604051966155c0606089613799565b600288526155d2604060208a01613f92565b615617604051916155e4602084613799565b8a8352610d9660405193849260208401528c60408401528c60608401528c608084015260a08084015260c08301906136e9565b61562088613d5d565b5261562a87613d5d565b506040519485936001600160a01b031660208501614d4e565b61564c83613d6a565b5261565682613d6a565b5060a04201918242116156f7576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169290916156a6918391610d969160208401614d71565b813b15613437579183916156d1938360405180968195829463dd46508f60e01b845260048401614de4565b03925af18015614c04576156e7575b5050600190565b816156f191613799565b386156e0565b634e487b7160e01b84526011600452602484fd5b61571533826140a4565b604051631efeed3360e01b8152600481018390526000927f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691602081602481865afa908115614b475785916158e0575b5061582d60018060a01b03600e5416916157c2611d6560018060a01b03600f5416926001600160801b03806040519a6157a860608d613799565b60028c526157ba604060208e01613f92565b1691166138c1565b615806602095610d966040516157d88982613799565b8b81526040519485938a85015260408401528b60608401528b608084015260a08084015260c08301906136e9565b61580f87613d5d565b5261581986613d5d565b50610d966040519384923091878501614d4e565b61583684613d6a565b5261584083613d6a565b50604051600160f81b828201908152601160f81b600182015290919061586a908390600201611428565b60a04201938442116158cc5790610d9661588b926040519485938401614d71565b813b15613437579183916158b59360405180958194829363dd46508f60e01b845260048401614de4565b039134905af18015614c04576156e7575050600190565b634e487b7160e01b86526011600452602486fd5b6158f9915060203d602011610eda57610ecb8183613799565b3861576e565b3360005260016020526001600160801b03604060002054911690811161596957336000526001602052604060002081815403905580600054036000556040519081527f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d560203392a2565b60405162461bcd60e51b815260206004820152601a60248201527f77697468647261773a2062616c616e6365206973206c6f7765720000000000006044820152606490fd5b6001600160a01b031660008181526004602052604090205460ff1615615cbd577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168114615c78577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168114615c33577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168114615bee577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168114615baa5760005b6003549081811015615ba35782615aa782613863565b905460039190911b1c6001600160a01b031614615ac8576001915001615a91565b6000198201918211610efe57613a02615ae3615afb93613863565b905460039190911b1c6001600160a01b031691613863565b6003548015615b8d5760001901615b1181613863565b81546001600160a01b03600392831b1b1916909155555b806000526004602052604060002060ff198154169055806000526006602052600060046040822082815582600182015582600282015582600382015501557f66257bcef574219c04f7c05f7a1c78d599da10491294c92a5805c48b4cdf5009600080a2565b634e487b7160e01b600052603160045260246000fd5b5050615b28565b606460405162461bcd60e51b815260206004820152602060248201527f6e6f7420616c6c6f77656420746f2072656d6f7665207573646320746f6b656e6044820152fd5b60405162461bcd60e51b815260206004820152601f60248201527f6e6f7420616c6c6f77656420746f2072656d6f76652042307820746f6b656e006044820152606490fd5b60405162461bcd60e51b815260206004820152601b60248201527f6e6f7420616c6c6f77656420746f2072656d6f766520307842544300000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601a60248201527f6e6f7420616c6c6f77656420746f2072656d6f766520574554480000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601860248201527f546f6b656e206e6f7420696e20726577617264206c69737400000000000000006044820152606490fd5b6103e881046103e8819206615d15575090565b905060018101809111610efe5790565b6001600160801b0392615d78929091906001600160a01b0380821690831611615d7c575b615d71615d626001600160a01b03838116908516615352565b926001600160a01b0392613d01565b1691615473565b1690565b90615d49565b6001600160801b0392615d789290916001600160a01b0380831690821611615dbf575b6001600160a01b0391615db89190613d01565b16906153e6565b90615da5565b9060206001600160801b037f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d921692836000540160005560018060a01b03169283600052600182526040600020818154019055604051908152a256feaf0991cd0b594b80a926fbe48091f3ca4909caad5725ed872618837c38f2a838a2646970667358221220913537cfc0fac672c37868b9207a834a6cb961c0c7b1aa6772ae8798063bd02664736f6c634300081c0033000000000000000000000000b379a851ac41bcdf0c2564b88916b10e5a08daae0000000000000000000000004b20b6e9b678b111dcc365ead92b3277b178fb74000000000000000000000000794b1409ef4b40a90ec8af62eaf4c8bf275e5000
Deployed Bytecode
0x6080806040526004361015610011575b005b60003560e01c9081630918eb14146135ee5750806312261ee7146135a957806314d0d8de14613587578063150b7a021461351657806315131d7a146134f857806318160ddd146134da5780631c03e6cc146134b9578063211dc32d1461348d57806329e24cb7146134595780632af9cc411461309c5780632d99153814612eae5780632e1a7d4d14612c085780633d18b91214612bec5780633d509c9714612bb65780634819543914612b8357806348e5d9f814612b1d5780634c4a3c2514612ad85780634d9937f6146126fc57806354b2a7691461255e578063556afceb146125385780635684aef01461245557806359ae8f7e1461243f5780635e1b4d99146123b65780635ee29240146122685780636098fd4a1461221b578063638634ee146121f85780636645e413146121865780636882a888146121655780636a2cac65146121405780636ac69a8e1461210c5780636fd495d0146120df57806370a08231146120a5578063715018a6146120475780637497962014611f62578063857f400b14611c9857806389c54f4f14611c535780638b19d82214611c115780638da5cb5b14611be857806399da213d14611ba35780639c85dca214611b5e578063a0c8bed114611b32578063a1634b1414611b0e578063a980356a14611aaf578063aaea77b314611a87578063ab7c303114611a5e578063ac8bb71d14611a2d578063b5fd73f8146119ee578063c15ed8ff146119a9578063c35fd9bc1461197c578063c4f59f9b14611915578063c8de06de146117eb578063ce0235cb146117c8578063d7e80e6c14611156578063d8162cdf1461070f578063e6c0fe3d146106f2578063e6fa0168146106ad578063ea9834fe14610668578063ec81937e1461063f578063f122977714610614578063f24bfd451461041f578063f2fde38b14610352578063f58e7b3314610331578063f7ea16ac146103135763fd731837146102da57005b3461030e57602036600319011261030e57600435600052600c602052602060018060a01b0360406000205416604051908152f35b600080fd5b3461030e57600036600319011261030e576020601354604051908152f35b3461030e57602036600319011261030e5761000f61034d613624565b614ebc565b3461030e57602036600319011261030e5761036b613624565b6002546001600160a01b03811691610384338414613ee3565b6001600160a01b03169182156103cb5782907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a36001600160a01b03191617600255005b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b3461030e57606036600319011261030e57610438613624565b6044356024356104488282613963565b9260018060a01b031692836000526009602052604060002054106105f4575b6000905b83600052600960205260406000205481116105055783600052600860205260406000208160005260205260406000206040516104a681613767565b8154815260018201546001600160801b0381166020830152608090811c60ff16151560408301819052600284015460608401526003909301546001600160a01b03169101526105e4575b8282116105055761050090614ead565b61046b565b506105109150613fe4565b60009060015b83600052600960205260406000205481116105ca5783600052600860205260406000208160005260205260406000206040519061055282613767565b805491828152608060ff60018401546001600160801b0381166020850152821c1615159283604084015260028101546060840152600360018060a01b03910154169101526105aa575b506105a590614ead565b610516565b836105c3916105bd6105a5949686613d7a565b52614ead565b929061059b565b604051602080825281906105e090820185613692565b0390f35b906105ee90614ead565b906104f0565b905081600052600960205261060e81604060002054613894565b90610467565b3461030e57602036600319011261030e576020610637610632613624565b614e1d565b604051908152f35b3461030e57602036600319011261030e5761065c3060043561556c565b50602060405160018152f35b3461030e57600036600319011261030e576040517f00000000000000000000000042000000000000000000000000000000000000066001600160a01b03168152602090f35b3461030e57600036600319011261030e576040517f0000000000000000000000004b20b6e9b678b111dcc365ead92b3277b178fb746001600160a01b03168152602090f35b3461030e57602036600319011261030e5761000f60043533614429565b3461030e5760c036600319011261030e57610728613624565b60643590602435906044356084356001600160a01b0381169081900361030e5760a435946001600160a01b038616860361030e5760018060a01b03841691826000526008602052604060002082600052600a602052604060002054600052602052604060002060405161079a81613767565b815480825260018301546001600160801b0381166020840152608090811c60ff16151560408401908152600285015460608501526003909401546001600160a01b03169201918252840361111157516001600160a01b031684036110cc576001905115150361106f5761080d308361556c565b50610816614cc8565b9660005b8851811015610849576001906108436001600160a01b0361083b838d613d7a565b5116896154f6565b0161081a565b50600e5460405163095ea7b360e01b81526001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3811660048301819052600019602484015289959490938b93919260209183916044918391600091165af18015610ee157611052575b50600f5460405163095ea7b360e01b815260048101859052600019602482015290602090829060449082906000906001600160a01b03165af18015610ee157611035575b50600e546001600160a01b037f0000000000000000000000004b2c77d209d3405f41a037ec6c77f7f5b8e2ca808116949165ffffffffffff4216911661094182614e00565b90833b1561030e576040516387517c4560e01b81526001600160a01b0391821660048201528782166024820152604481019190915265ffffffffffff91909116606482015260008160848183875af18015610ee157611024575b50600f546001600160a01b0316906109b290614e00565b823b1561030e576040516387517c4560e01b81526001600160a01b0392831660048201528683166024820152604481019290925265ffffffffffff166064820152906000908290608490829084905af18015610ee157611013575b50600e5460405163095ea7b360e01b815260048101859052600019602482015290602090829060449082906000906001600160a01b03165af18015610ee157610ff6575b50600f5460405163095ea7b360e01b815260048101859052600019602482015290602090829060449082906000906001600160a01b03165af18015610ee157610fd9575b50600e546040516323b872dd60e01b81523360048201523060248201526044810184905290602090829060649082906000906001600160a01b03165af18015610ee157610fbc575b50600f546040516323b872dd60e01b8152336004820152306024820152604481018a905290602090829060649082906000906001600160a01b03165af18015610ee157610f8f575b50600e54600f546010546040516001600160a01b039283169793831694939260a09216610b5182613767565b858252886020830152628000006040830152603c60608301526080820152209160405192633205590760e21b8452600484015260808360248160018060a01b037f000000000000000000000000571291b572ed32ce6751a2cb2486ebee8defb9b4165afa928315610ee157600093610f5b575b5060011c60016001609f1b031690612710828103908111610efe576001600160a01b039061271090610bf690846138c1565b041691612710018061271011610efe576001600160a01b039161271091610c1c916138c1565b041660018060a01b038316918210159182610f50575b505015610f14578883640100ad139c73ff53611968f1e5ca45cfca7918447e7f5776f6d490610c6094614335565b60405160006020820152600d60f81b6021820152600281526001600160801b03919091169490610c9290602290613799565b6060908760405194610ca48487613799565b60028652610cb9601f19850160208801613f92565b60405160006020820152600d60f81b60218201526002815297610cdd60228a613799565b60209c8d9260405192610cf08585613799565b60008452604051958695860152604085015286840152608083015260a0820160a0905260c08201610d20916136e9565b03601f1981018252610d329082613799565b610d3b85613d5d565b52610d4584613d5d565b50604051928a840152604083015260408252610d619082613799565b610d6a82613d6a565b52610d7481613d6a565b504260a00192834211610efe57610da490610d966040519384928b8401614d71565b03601f198101835282613799565b813b1561030e5760405163dd46508f60e01b81529260009184918291610dce919060048401614de4565b038183855af1908115610ee1576024928792610eed575b5060405192838092631efeed3360e01b82528760048301525afa8015610ee157600080516020615e2283398151915294610ea692600092610eb2575b5060005260088652604060002084600052600a8752604060002054600052865260016040600020426002820155016001600160801b0380610e658184541685614315565b1692610e718487615dc5565b166001600160801b031982541617905560405193849384604091949392606082019560018060a01b0316825260208201520152565b0390a160405160018152f35b610ed3919250873d8911610eda575b610ecb8183613799565b810190613d8e565b9087610e21565b503d610ec1565b6040513d6000823e3d90fd5b6000610ef891613799565b87610de5565b634e487b7160e01b600052601160045260246000fd5b60405162461bcd60e51b81526020600482015260146024820152730a0e4d2c6ca40dadeeccac840e8dede40daeac6d60631b6044820152606490fd5b111590508a80610c32565b610f7e91935060803d608011610f88575b610f768183613799565b810190613dcb565b505050918b610bc4565b503d610f6c565b610fb09060203d602011610fb5575b610fa88183613799565b810190613989565b610b25565b503d610f9e565b610fd49060203d602011610fb557610fa88183613799565b610add565b610ff19060203d602011610fb557610fa88183613799565b610a95565b61100e9060203d602011610fb557610fa88183613799565b610a51565b600061101e91613799565b88610a0d565b600061102f91613799565b8a61099b565b61104d9060203d602011610fb557610fa88183613799565b6108fc565b61106a9060203d602011610fb557610fa88183613799565b6108b8565b60405162461bcd60e51b815260206004820152602f60248201527f4d757374206265206163746976656c79207374616b656420706f736974696f6e60448201526e081d1bc81a5b98dc99585cd9481a5d608a1b6064820152608490fd5b60405162461bcd60e51b815260206004820152601e60248201527f666f7257686f206d757374206265206f776e65724f66506f736974696f6e00006044820152606490fd5b60405162461bcd60e51b815260206004820152601f60248201527f666f7257686f206d757374206861766520636f6e74726f6c206f66204e4654006044820152606490fd5b3461030e57608036600319011261030e5761116f61367c565b6001600160801b0381166509184e72a000106117bb575b3360005260086020526040600020600435600052600a602052604060002054600052602052604060002080549160018201549260043503611776576111d860018060a01b036003840154163314613e0f565b6111ec600160ff8560801c16151514613e54565b6111f83060043561556c565b50611205336004356140a4565b9061120e614cc8565b9360005b85518110156112415760019061123b6001600160a01b03611233838a613d7a565b5116336154f6565b01611212565b50604051631efeed3360e01b815260048035908201529084906020836024817f0000000000000000000000004b2c77d209d3405f41a037ec6c77f7f5b8e2ca806001600160a01b03165afa928315610ee157600093611755575b50600e54600f546040516001600160a01b03918216966060939192909116906112c48484613799565b600283526112d9601f19850160208501613f92565b6001600160801b031696876001600160801b038816906112f8916138c1565b6509184e72a00090046001600160801b0316966001600160801b038a1661131f90896138c1565b6103e890046001600160801b0316978861133891614315565b986509184e72a0001461173b575b6001600160801b03808a16890111610efe576001600160801b0380808b168a01169116106116f657866113c66103e861139a6001600160801b038261138f8f83166044356138c1565b049d166064356138c1565b04610d9660209c8d92604051916113b18584613799565b60008352604051968795600435908701614d1c565b6113cf84613d5d565b526113d983613d5d565b506040516113ef81610d963085878f8501614d4e565b6113f884613d6a565b5261140283613d6a565b50604051600160f81b8a8201908152601160f81b60018201529091906114369083906002015b03601f198101845283613799565b60a0420193844211610efe578a611428611457926040519586938401614d71565b7f0000000000000000000000004b2c77d209d3405f41a037ec6c77f7f5b8e2ca806001600160a01b03163b1561030e576000846114a993604051948592839263dd46508f60e01b845260048401614de4565b0381837f0000000000000000000000004b2c77d209d3405f41a037ec6c77f7f5b8e2ca806001600160a01b03165af1918215610ee157611563926116e5575b5061150a604051956114fa8188613799565b60028752601f19018b8701613f92565b8861153c8b610d9660405161151f8382613799565b600081526040519485936064359160443591600435908701614d1c565b61154586613d5d565b5261154f85613d5d565b50610d9660405193849233918d8501614d4e565b61156c83613d6a565b5261157682613d6a565b50604051600160f81b888201908152601160f81b60018201529092906115a990849060020103601f198101855284613799565b6115c0600093610d966040519384928c8401614d71565b7f0000000000000000000000004b2c77d209d3405f41a037ec6c77f7f5b8e2ca806001600160a01b03163b156116e15760405163dd46508f60e01b81529291829184918291611613919060048401614de4565b0381837f0000000000000000000000004b2c77d209d3405f41a037ec6c77f7f5b8e2ca806001600160a01b03165af180156116d4576001600160801b0380611698610ea6968299967f1d15074a35b5a1181cbb682ad77c37e0fd0d3ae2aecb0fe1338bf14b93da7d169b99966001966116c4575b50508280808b168901169116613894565b6116a582891687016158ff565b1616861982840154161791015560405193849316016004353384613eb8565b6116cd91613799565b8c80611687565b50604051903d90823e3d90fd5b8280fd5b60006116f091613799565b8a6114e8565b60405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206c69717569646974792072656d6f76616c000000000000006044820152606490fd5b975061174f61174a888a614315565b6142f6565b97611346565b61176f91935060203d602011610eda57610ecb8183613799565b918561129b565b60405162461bcd60e51b815260206004820152601c60248201527f596f75206d757374206861766520636f6e74726f6c206f66204e4654000000006044820152606490fd5b506509184e72a000611186565b3461030e57602036600319011261030e57602060405160043560081c60020b8152f35b3461030e57602036600319011261030e57611804613624565b61181960018060a01b03600254163314613ee3565b60125460ff81166118df5760ff1916600117601255601154629e34008101908110610efe5742101561189a57600d5490603082901c6001600160a01b031615611868575b602060405160008152f35b6601000000000000600160d01b031990911660309190911b6601000000000000600160d01b031617600d55808061185d565b60405162461bcd60e51b815260206004820152601960248201527f4f6e6c7920617661696c206669727374203132302064617973000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152600e60248201526d20536574206f6e6365207472756560901b6044820152606490fd5b3461030e57600036600319011261030e5761192e614cc8565b60405180916020820160208352815180915260206040840192019060005b81811061195a575050500390f35b82516001600160a01b031684528594506020938401939092019160010161194c565b3461030e576105e0611995611990366137d3565b614c83565b604051918291602083526020830190613692565b3461030e57600036600319011261030e576040517f000000000000000000000000b379a851ac41bcdf0c2564b88916b10e5a08daae6001600160a01b03168152602090f35b3461030e57602036600319011261030e576001600160a01b03611a0f613624565b166000526004602052602060ff604060002054166040519015158152f35b3461030e57602036600319011261030e57600435600052600b602052602060ff604060002054166040519015158152f35b3461030e57600036600319011261030e576010546040516001600160a01b039091168152602090f35b3461030e57600036600319011261030e57602067ffffffffffffffff60055416604051908152f35b3461030e57604036600319011261030e57611ac8613624565b611ad061363a565b9060018060a01b0316600052600760205260406000209060018060a01b03166000526020526040806000206001815491015482519182526020820152f35b3461030e57600036600319011261030e576020600d5460181c60020b604051908152f35b3461030e57602036600319011261030e57600435600052600a6020526020604060002054604051908152f35b3461030e57600036600319011261030e576040517f0000000000000000000000004b2c77d209d3405f41a037ec6c77f7f5b8e2ca806001600160a01b03168152602090f35b3461030e57600036600319011261030e576040517f000000000000000000000000794b1409ef4b40a90ec8af62eaf4c8bf275e50006001600160a01b03168152602090f35b3461030e57600036600319011261030e576002546040516001600160a01b039091168152602090f35b3461030e57602036600319011261030e5760043560035481101561030e57611c3a602091613863565b905460405160039290921b1c6001600160a01b03168152f35b3461030e57600036600319011261030e576040517f000000000000000000000000036cbd53842c5426634e7929541ec2318f3dcf7e6001600160a01b03168152602090f35b3461030e57604036600319011261030e57600435611cb461363a565b604051631efeed3360e01b8152600481018390526000929091906020836024817f0000000000000000000000004b2c77d209d3405f41a037ec6c77f7f5b8e2ca806001600160a01b03165afa928315611f57578493611f27575b506001600160801b0391611d21916140a4565b9116916509184e72a000808402848104821485151715611f13576001600160801b038083611d789304169416611d726001600160801b03611d6a611d6584896138c1565b615d02565b168096614315565b956138c1565b818102918183041490151715611eff57662386f26fc100009006151580611eed575b611edd575b640100ad139c5b9173ff53611968f1e5ca45cfca7918447e7f5776f6d4600e54600f5460105460405193959360a09390926001600160a01b03928316929081169116611dea84613767565b83526020830152628000006040830152603c606083015260808201522060405190633205590760e21b8252600482015260808160248160018060a01b037f000000000000000000000000571291b572ed32ce6751a2cb2486ebee8defb9b4165afa918215611ed157916105e0949391611e8b9391611eaf575b50611e8582611e7e611e768a8886614c0f565b99848a613d1a565b9583614c0f565b95613d1a565b93604051948594859094939260609260808301968352602083015260408201520152565b611ec8915060803d608011610f8857610f768183613799565b50505087611e63565b604051903d90823e3d90fd5b91611ee7906142f6565b91611d9f565b506001600160801b0383161515611d9a565b634e487b7160e01b82526011600452602482fd5b634e487b7160e01b83526011600452602483fd5b611d2191935091611f4e6001600160801b039360203d602011610eda57610ecb8183613799565b93915091611d0e565b6040513d86823e3d90fd5b3461030e57600036600319011261030e57611f8860018060a01b03600254163314613ee3565b611fba7f000000000000000000000000036cbd53842c5426634e7929541ec2318f3dcf7e6001600160a01b03166139a1565b611fe37f000000000000000000000000b379a851ac41bcdf0c2564b88916b10e5a08daae6139a1565b6120157f0000000000000000000000004b20b6e9b678b111dcc365ead92b3277b178fb746001600160a01b03166139a1565b61000f7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b03166139a1565b3461030e57600036600319011261030e5760025460006001600160a01b038216612072338214613ee3565b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a36001600160a01b031916600255005b3461030e57602036600319011261030e576001600160a01b036120c6613624565b1660005260016020526020604060002054604051908152f35b3461030e57600036600319011261030e57600d5460405160309190911c6001600160a01b03168152602090f35b3461030e57606036600319011261030e57602061063761212a613624565b61213261363a565b61213a613666565b91614c0f565b3461030e57604036600319011261030e5761000f61215c613624565b60243590614429565b3461030e57600036600319011261030e576020600d5460020b604051908152f35b3461030e57600036600319011261030e57477f00000000000000000000000042000000000000000000000000000000000000066001600160a01b0316803b1561030e57600090600460405180948193630d0e30db60e41b83525af18015610ee1576121ed57005b600061000f91613799565b3461030e57602036600319011261030e576020610637612216613624565b6143ed565b3461030e5760a036600319011261030e576020612257612239613624565b61224161363a565b9061224a613650565b6084359260643592614335565b6001600160801b0360405191168152f35b3461030e57606036600319011261030e5760043561228461367c565b9061228d613650565b604051631efeed3360e01b81526004810183905291600091906020846024817f0000000000000000000000004b2c77d209d3405f41a037ec6c77f7f5b8e2ca806001600160a01b03165afa9384156123ab57839461236c575b506001600160801b0380612305662386f26fc1000094612355946140a4565b951695166123506001600160801b03806509184e72a000612326858b6138c1565b0416961661234a6001600160801b03612342611d65848b6138c1565b168098614315565b976138c1565b6138c1565b06151580611eed57611edd57640100ad139c611da6565b6123559194506001600160801b03612305662386f26fc100009461239f839460203d602011610eda57610ecb8183613799565b979450945050506122e6565b6040513d85823e3d90fd5b3461030e57604036600319011261030e576001600160a01b036123d7613624565b166000526008602052604060002060243560005260205260a0604060002080549060018101549060ff6002820154916003600180881b0391015416926040519485526001600160801b038116602086015260801c161515604084015260608301526080820152f35b3461030e5761000f612450366137d3565b614187565b3461030e57600036600319011261030e57600e54600f5460105460405160a09390926001600160a01b0392831692908116911661249184613767565b83526020830152628000006040830152603c606083015260808201522060405190633205590760e21b8252600482015260808160248160018060a01b037f000000000000000000000000571291b572ed32ce6751a2cb2486ebee8defb9b4165afa8015610ee157602091600091612516575b506040516001600160a01b039091168152f35b61252f915060803d608011610f8857610f768183613799565b50505082612503565b3461030e57604036600319011261030e57602061225761255661363a565b6004356140a4565b3461030e57600036600319011261030e57600e54600f546010546040516001600160a01b039283169383169260a0921661259782613767565b838252846020830152628000006040830152603c606083015260808201522060405190633205590760e21b8252600482015260808160248160018060a01b037f000000000000000000000000571291b572ed32ce6751a2cb2486ebee8defb9b4165afa8015610ee157612612916000916126da575b50613f2e565b60405163313ce56760e01b81529091602082600481845afa918215610ee1576000926126b9575b5060405163313ce56760e01b815291602083600481885afa908115610ee15760a09560ff94600093612688575b5084929360405196875260208701526040860152166060840152166080820152f35b8593506126ac9060203d6020116126b2575b6126a48183613799565b810190613970565b92612666565b503d61269a565b6126d391925060203d6020116126b2576126a48183613799565b9084612639565b6126f3915060803d608011610f8857610f768183613799565b5050508461260c565b3461030e57600036600319011261030e57612715614cc8565b8051612739612723826137bb565b916127316040519384613799565b8083526137bb565b602082019190601f19013683376127508351613faf565b9061275b8451613faf565b84519061278061276a836137bb565b926127786040519485613799565b8084526137bb565b602083019490601f19013686376127978751613fe4565b936127a28851613fe4565b9560005b89518110156129e7576001906001600160a01b036127c4828d613d7a565b51166127d08286613d7a565b52600460008c6127e684868060a01b0392613d7a565b5116604051928380926395d89b4160e01b82525afa600091816129cc575b506129b15750612812614085565b61281c8287613d7a565b526128278186613d7a565b505b600460008c61283e84868060a01b0392613d7a565b5116604051928380926306fdde0360e01b82525afa6000918161298e575b50612973575061286a614085565b6128748288613d7a565b5261287f8187613d7a565b505b600460208c61289684868060a01b0392613d7a565b51166040519283809263313ce56760e01b82525afa60009181612953575b5061293e5750816128c58289613d7a565b525b818060a01b036128d7828d613d7a565b5116600052600660205260406000206040516128f281613767565b815490818152608060048685015494602084019586526002810154604085015260038101546060850152015491015261292b838b613d7a565b5251612937828b613d7a565b52016127a6565b60ff61294a838a613d7a565b911690526128c7565b61296c91925060203d81116126b2576126a48183613799565b908d6128b4565b61297d8288613d7a565b526129888187613d7a565b50612881565b6129aa91923d8091833e6129a28183613799565b810190614016565b908d61285c565b6129bb8287613d7a565b526129c68186613d7a565b50612829565b6129e091923d8091833e6129a28183613799565b908d612804565b50949392919096976129f890614c83565b9760405198899860e08a019060e08b52518091526101008a01929060005b818110612ab657505050612a5892612a3c83612a4a938c602081819a9803910152613692565b908a820360408c015261370e565b9088820360608a015261370e565b918683036080880152519182815201929060005b818110612a9a5750505081612a8c91856105e095940360a0870152613692565b9083820360c0850152613692565b825160ff16855287965060209485019490920191600101612a6c565b82516001600160a01b031685528c9b5060209485019490920191600101612a16565b3461030e57600036600319011261030e576040517f000000000000000000000000571291b572ed32ce6751a2cb2486ebee8defb9b46001600160a01b03168152602090f35b3461030e57602036600319011261030e576001600160a01b03612b3e613624565b16600052600660205260a06040600020805490600181015490600281015460046003830154920154926040519485526020850152604084015260608301526080820152f35b3461030e57604036600319011261030e57612b9c613624565b6024359060ff8216820361030e5760209161063791613f5e565b3461030e57602036600319011261030e5761000f612bd2613624565b612be760018060a01b03600254163314613ee3565b6159ae565b3461030e57600036600319011261030e5761000f612450614cc8565b3461030e57602036600319011261030e57600435612c24614cc8565b9060005b8251811015612c4f57600190612c496001600160a01b036112338387613d7a565b01612c28565b5080600052600a60205260406000205433600052600860205260406000208160005260205260406000209160405191612c8783613767565b83548352612cea60016001600160801b038187015495612cdc60208201988389168a5260ff604084019960801c1615158952600281015460608401526003858060a01b03910154168060808401523314613e0f565b519651169451151514613e54565b612cf4308361556c565b50612cfe8261570b565b50600360405191612d0e83613767565b85835260006020808501828152604080870184815242606089019081526080808a0187815233885260088752848820988852979095529190942096518755905160018701805494516001600160881b03199095166001600160801b03929092169190911793151590921b60ff60801b1692909217905551600284015551910180546001600160a01b0319166001600160a01b039283161790557f0000000000000000000000004b2c77d209d3405f41a037ec6c77f7f5b8e2ca8016803b1561030e5760405163095ea7b360e01b81523060048201526024810185905260008160448183865af18015610ee157612e9d575b50803b1561030e57604051632142170760e11b815230600482015233602482015260448101949094526000908490606490829084905af1928315610ee1577f1d15074a35b5a1181cbb682ad77c37e0fd0d3ae2aecb0fe1338bf14b93da7d1693612e8c575b50612e6e826158ff565b612e7e6040519283923384613eb8565b0390a1602060405160018152f35b6000612e9791613799565b83612e64565b6000612ea891613799565b84612dff565b3461030e57600036600319011261030e576000640100ad139c73ff53611968f1e5ca45cfca7918447e7f5776f6d4600e54600f5460105460405193946001600160a01b0393841694909360a093919281169116612f0a83613767565b8583526020830152628000006040830152603c60608301526080820152209260018060a01b037f000000000000000000000000571291b572ed32ce6751a2cb2486ebee8defb9b4166040519463fa6793d560e01b8652806004870152602086602481855afa95861561309157879661306d575b50608090602460405180948193633205590760e21b835260048301525afa9081156130625791612fd49187612fce9796959460809992613037575b506001600160801b039054169687809383614c0f565b93613d1a565b917f0000000000000000000000004b20b6e9b678b111dcc365ead92b3277b178fb746001600160a01b031603613028576001600160801b039091925b60405194855216602084015260408301526060820152f35b916001600160801b0390613010565b6001600160801b03919250613058908a3d8c11610f8857610f768183613799565b5050509190612fb8565b6040513d88823e3d90fd5b608091965061308a9060203d602011610eda57610ecb8183613799565b9590612f7d565b6040513d89823e3d90fd5b3461030e57604036600319011261030e5761310f60006024356004356130c28282613963565b338452600960205260408420541061343b575b6130e0612450614cc8565b60405163f24bfd4560e01b81523360048201526024810191909152604481019190915291829081906064820190565b0381305afa908115610ee1576000916133a4575b507f0000000000000000000000004b2c77d209d3405f41a037ec6c77f7f5b8e2ca806001600160a01b03169060005b815181101561000f576131658183613d7a565b519081600052600a6020526040600020549133600052600860205260406000208360005260205260406000206040519361319e85613767565b6132048254958681526131f360018086015495608060ff6001600160801b03891698896020880152821c16151591826040870152600281015460608701526003848060a01b0391015416940193845214613e54565b516001600160a01b03163314613e0f565b61320e308461556c565b506132188361570b565b5060036040519161322883613767565b86835260006020808501828152604080870184815242606089019081526080808a0187815233885260088752848820988852979095529190942096518755905160018701805494516001600160881b03199095166001600160801b03929092169190911793151590921b60ff60801b1692909217905551600284015551910180546001600160a01b0319166001600160a01b0392909216919091179055853b1561030e5760405163095ea7b360e01b815230600482015260248101859052600081604481838b5af18015610ee157613393575b50853b1561030e57604051632142170760e11b81523060048201523360248201526044810194909452600084606481838a5af1918215610ee1576001947f1d15074a35b5a1181cbb682ad77c37e0fd0d3ae2aecb0fe1338bf14b93da7d1693613382575b50613369826158ff565b6133796040519283923384613eb8565b0390a101613152565b600061338d91613799565b8761335f565b600061339e91613799565b866132fb565b3d8083833e6133b38183613799565b8101906020818303126116e15780519067ffffffffffffffff8211613437570181601f820112156116e1578051906133ea826137bb565b936133f86040519586613799565b82855260208086019360051b8301019384116134345750602001905b8282106134245750505081613123565b8151815260209182019101613414565b80fd5b8380fd5b90503382526009602052613453816040842054613894565b906130d5565b3461030e57606036600319011261030e576020610637613477613624565b61347f61363a565b613487613666565b91613d1a565b3461030e57604036600319011261030e5760206106376134ab613624565b6134b361363a565b90613c76565b3461030e57602036600319011261030e5761000f6134d5613624565b6139a1565b3461030e57600036600319011261030e576020600054604051908152f35b3461030e57602036600319011261030e5760206122576004356138d4565b3461030e57608036600319011261030e5761352f613624565b5061353861363a565b5060643567ffffffffffffffff811161030e573660238201121561030e57806004013567ffffffffffffffff811161030e573691016024011161030e57604051630a85bd0160e11b8152602090f35b3461030e57602036600319011261030e576020604051600435821c60020b8152f35b3461030e57600036600319011261030e576040517f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba36001600160a01b03168152602090f35b3461030e57602036600319011261030e576020906001600160a01b03613612613624565b16600052600982526040600020548152f35b600435906001600160a01b038216820361030e57565b602435906001600160a01b038216820361030e57565b604435906001600160a01b038216820361030e57565b604435906001600160801b038216820361030e57565b602435906001600160801b038216820361030e57565b906020808351928381520192019060005b8181106136b05750505090565b82518452602093840193909201916001016136a3565b60005b8381106136d95750506000910152565b81810151838201526020016136c9565b90602091613702815180928185528580860191016136c6565b601f01601f1916010190565b9080602083519182815201916020808360051b8301019401926000915b83831061373a57505050505090565b9091929394602080613758600193601f1986820301875289516136e9565b9701930193019193929061372b565b60a0810190811067ffffffffffffffff82111761378357604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff82111761378357604052565b67ffffffffffffffff81116137835760051b60200190565b602060031982011261030e576004359067ffffffffffffffff821161030e578060238301121561030e5781600401359061380c826137bb565b9261381a6040519485613799565b8284526024602085019360051b82010191821161030e57602401915b8183106138435750505090565b82356001600160a01b038116810361030e57815260209283019201613836565b60035481101561387e57600360005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b91908203918211610efe57565b81156138ab570490565b634e487b7160e01b600052601260045260246000fd5b81810292918115918404141715610efe57565b6138e2620151809142613894565b04600f811061393a57601e8110156138fb57506014905b565b602d81101561390a5750600f90565b603c8110156139195750600a90565b604b8110156139285750600790565b6096111561393557600590565b600190565b8060aa029060aa820403610efe57600f900460c80360c88111610efe576001600160801b031690565b91908201809211610efe57565b9081602091031261030e575160ff8116810361030e5790565b9081602091031261030e5751801515810361030e5790565b6002546001600160a01b03163303613b1c575b6001600160a01b03811660008181526004602052604090205490919060ff16613ae157600354916801000000000000000083101561378357613a2682613a0285600160049701600355613863565b81546001600160a01b0393841660039290921b91821b9390911b1916919091179055565b80600052826020526040600020600160ff198254161790556000526006602052613a54604060002091614e1d565b600382015560008082556002820155600d546040516378e9792560e01b815292602091849190829060301c6001600160a01b03165afa918215610ee157600092613aad575b50620151808201809211610efe5760010155565b90916020823d602011613ad9575b81613ac860209383613799565b810103126134345750519038613a99565b3d9150613abb565b60405162461bcd60e51b8152602060048201526013602482015272151bdad95b88185b1c9958591e481859191959606a1b6044820152606490fd5b60146003540460018101809111610efe5760405163313ce56760e01b81527f000000000000000000000000036cbd53842c5426634e7929541ec2318f3dcf7e6001600160a01b03169190602081600481865afa8015610ee15760ff91600091613c57575b501690601481029080820460141490151715610efe57604d8211610efe57600092613bb4613be492602094600a0a906138c1565b6040516323b872dd60e01b8152336004820152306024820152604481019190915293849283919082906064820190565b03925af1908115610ee157600091613c38575b506139b45760405162461bcd60e51b81526020600482015260146024820152731554d110c81d1c985b9cd9995c8819985a5b195960621b6044820152606490fd5b613c51915060203d602011610fb557610fa88183613799565b38613bf7565b613c70915060203d6020116126b2576126a48183613799565b38613b80565b6001600160a01b0316600081815260016020526040902054613cfe9290613cd290613ccc613ca384614e1d565b856000526007602052604060002060018060a01b03861660005260205260406000205490613894565b906152d6565b91600052600760205260406000209060018060a01b031660005260205260016040600020015490613963565b90565b6001600160a01b039182169082160391908211610efe57565b613cfe92916001600160801b03916001600160a01b0380831690821611613d57575b6001600160a01b0391613d4f9190613d01565b169116615352565b90613d3c565b80511561387e5760200190565b80516001101561387e5760400190565b805182101561387e5760209160051b010190565b9081602091031261030e57516001600160801b038116810361030e5790565b51908160020b820361030e57565b519062ffffff8216820361030e57565b919082608091031261030e5781516001600160a01b038116810361030e5791613df660208201613dad565b91613cfe6060613e0860408501613dbb565b9301613dbb565b15613e1657565b60405162461bcd60e51b815260206004820152601660248201527526bab9ba1037bbb7103a3434b9903837b9b4ba34b7b760511b6044820152606490fd5b15613e5b57565b60405162461bcd60e51b815260206004820152602f60248201527f4d7573742068617665206163746976656c79207374616b656420706f7369746960448201526e1bdb881d1bc81c995b5bdd99481a5d608a1b6064820152608490fd5b6001600160a01b03909116815260208101919091526001600160801b03909116604082015260600190565b15613eea57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b6001600160a01b03168015613f5857670de0b6b3a7640000613f53613cfe92806138c1565b61539c565b50600090565b6001600160a01b0316908115613f8b5760ff1690604d8211610efe57613f53613cfe92600a0a91806138c1565b5050600090565b60005b828110613fa157505050565b606082820152602001613f95565b906138f9613fbc836137bb565b613fc96040519182613799565b83815260208194613fdc601f19916137bb565b019101613f92565b90613fee826137bb565b613ffb6040519182613799565b828152809261400c601f19916137bb565b0190602036910137565b60208183031261030e5780519067ffffffffffffffff821161030e570181601f8201121561030e57805167ffffffffffffffff81116137835760405192614067601f8301601f191660200185613799565b8184526020828401011161030e57613cfe91602080850191016136c6565b60405190614094604083613799565b60018252603f60f81b6020830152565b600052600a6020526040600020549060018060a01b0316600052600860205260406000209060005260205260406000206040516140e081613767565b8154815260018201546001600160801b0381166020830152608090811c60ff16151560408301526002830154606083018181526003909401546001600160a01b031691909201521561413657613cfe90516138d4565b60405162461bcd60e51b815260206004820152602360248201527f4e6f742061204e465420746861742069732063757272656e746c79207374616b60448201526265642160e81b6064820152608490fd5b9060005b82518110156142f1576141a96001600160a01b036112338386613d7a565b6141c66001600160a01b036141be8386613d7a565b511633613c76565b90816141d7575b600191500161418b565b6001600160a01b036141e98286613d7a565b511660005260066020526004604060002001614206838254613894565b905533600090815260076020526040808220600191906001600160a01b0361422e868a613d7a565b511660a084901b849003168452602052822001556001600160a01b036142548286613d7a565b5160405163a9059cbb60e01b815233600482015260248101859052939160209185916044918391600091165af1928315610ee1576001936142d5575b50828060a01b036142a18387613d7a565b5116906040519081527f540798df468d7b23d11f156fdb954cb19ad414d150722a7b6d55ba369dea792e60203392a36141cd565b6142ec9060203d8111610fb557610fa88183613799565b614290565b509050565b6001600160801b03600019911601906001600160801b038211610efe57565b906001600160801b03809116911603906001600160801b038211610efe57565b9093906001600160a01b03838116908616818110156143ba576001600160a01b03831690811161436c5750505050613cfe92615d25565b9294919210614380575050613cfe92615d82565b61438f90614395949383615d25565b93615d82565b6001600160801b0381166001600160801b038316106000146143b5575090565b905090565b60405162461bcd60e51b815260206004820152600b60248201526a282924a1a2afa7a92222a960a91b6044820152606490fd5b6001600160a01b031660009081526006602052604090206001015442811115613cfe57504290565b51906001600160a01b038216820361030e57565b7f0000000000000000000000004b2c77d209d3405f41a037ec6c77f7f5b8e2ca806001600160a01b031692833b1561030e57604051632142170760e11b8152336004820152306024820152604481018490526000908181606481838a5af18015614c0457614bf4575b5090604051637ba03aad60e01b815284600482015260c081602481895afa9081156123ab5783908492614b52575b506040516331a9108f60e11b8152600481018790526020816024818b5afa908115614b47578591614b09575b50306001600160a01b0390911603614ac4578051600e546001600160a01b03918216911603614a87576020810151600f546001600160a01b03918216911603614a4257603c606082015160020b03614a0457608001516010546001600160a01b039182169116036149c657602060249660405197888092631efeed3360e01b82528960048301525afa9586156123ab5783966149a5575b50600d54908160181c60020b8160081c60020b149182614990575b505015614956576145ad614cc8565b94825b86518110156145df576001906145d96001600160a01b036145d1838b613d7a565b5116876154f6565b016145b0565b5092919450926040516145f181613767565b81815260208101956001600160801b038516875260408201916001835260608101428152608082019060018060a01b03871694858352868552600a6020526040852054151580614938575b1561472157868552600a602090815260408087205488885260088352818820908852909152808620945185559a51600185018054925160ff60801b90151560801b166001600160801b039092166001600160881b03199093169290921717905551600283015551600390910180546001600160a01b039092166001600160a01b031990921691909117905594956138f995600080516020615e22833981519152938693909290915b838152600c6020522080546001600160a01b0319169091179055614708338261556c565b506147196040519283928684613eb8565b0390a1615dc5565b9399868b52600a60205260408b2054151580614919575b1561483c57868b52600a6020528a6040812055858b52600960205260408b20549460018601809611614828579360036040948d94600080516020615e228339815191529a98946138f99e9f988b8f9c9a526008602052888820878952602052888820955186556001600160801b038060018801935116166001600160801b031983541617825551151581549060ff60801b9060801b169060ff60801b191617905551600284015560018060a01b0390511691019060018060a01b03166bffffffffffffffffffffffff60a01b825416179055848252600a60205280838320558382526009602052828220556146e4565b634e487b7160e01b8c52601160045260248cfd5b858b52600960205260408b20549460018601809611614828579360036040948d94600080516020615e228339815191529a98946138f99e9f988b8f9c9a526008602052888820878952602052888820955186556001600160801b038060018801935116166001600160801b031983541617825551151581549060ff60801b9060801b169060ff60801b191617905551600284015560018060a01b0390511691019060018060a01b03166bffffffffffffffffffffffff60a01b825416179055848252600a60205280838320558382526009602052828220556146e4565b50868b52600c60205260408b20546001600160a01b0316861415614738565b50868552600c60205260408520546001600160a01b0316861461463c565b60405162461bcd60e51b81526020600482015260126024820152714d7573742062652066756c6c2d72616e676560701b6044820152606490fd5b90915060020b9060201c60020b14388061459e565b6149bf91965060203d602011610eda57610ecb8183613799565b9438614583565b60405162461bcd60e51b8152602060048201526016602482015275696e636f727265637420686f6f6b206164647265737360501b6044820152606490fd5b60405162461bcd60e51b8152602060048201526016602482015275696e636f7272656374207469636b2073706163696e6760501b6044820152606490fd5b60405162461bcd60e51b815260206004820152601c60248201527f63757272656e637931206d757374206265206d61696e20746f6b656e000000006044820152606490fd5b60405162461bcd60e51b81526020600482015260156024820152740c6eae4e4cadcc6f26040daeae6e840c4ca408aa89605b1b6044820152606490fd5b60405162461bcd60e51b815260206004820152601860248201527f496e636f72726563746c79207374616b656420746f6b656e00000000000000006044820152606490fd5b90506020813d602011614b3f575b81614b2460209383613799565b81010312614b3b57614b3590614415565b386144ec565b8480fd5b3d9150614b17565b6040513d87823e3d90fd5b9150508060c03d60c011614bed575b614b6b8183613799565b81010360c081126134375760a0136116e15760405190614b8a82613767565b614b9381614415565b8252614ba160208201614415565b6020830152614bb260408201613dbb565b6040830152614bc360608201613dad565b606083015260808101516001600160a01b0381168103614b3b57608083015260a0015190386144c0565b503d614b61565b81614bfe91613799565b38614492565b6040513d84823e3d90fd5b613cfe929091614c6c91906001600160a01b0380821690851611614c7d575b6001600160a01b03614c408583613d01565b6001600160a01b039092169291169060601b6fffffffffffffffffffffffffffffffff60601b16615473565b6001600160a01b03909116906138a1565b92614c2e565b90614c8e8251613fe4565b9160005b8151811015614cc457600190614cb36001600160a01b036141be8386613d7a565b614cbd8287613d7a565b5201614c92565b5050565b604051906003548083528260208101600360005260206000209260005b818110614cfa5750506138f992500383613799565b84546001600160a01b0316835260019485019487945060209093019201614ce5565b91926001600160801b0360a094613cfe97969385521660208401526040830152606082015281608082015201906136e9565b6001600160a01b0391821681529181166020830152909116604082015260600190565b90614d84906040835260408301906136e9565b906020818303910152815180825260208201916020808360051b8301019401926000915b838310614db757505050505090565b9091929394602080614dd5600193601f1986820301875289516136e9565b97019301930191939290614da8565b929190614dfb6020916040865260408601906136e9565b930152565b65ffffffffffff610e109116019065ffffffffffff8211610efe57565b6001600160a01b03811660009081526006602052604081209054918215614ea357614e4a614e55916143ed565b600283015490613894565b633b9aca00810290808204633b9aca001490151715610efe57815490633b9aca00820291808304633b9aca001490151715610efe57613cfe93600392614e9a92615473565b91015490613963565b5060039150015490565b6000198114610efe5760010190565b6005546001600160a01b038216600081815260066020526040902090929167ffffffffffffffff16614eed83614e1d565b60038301556040516370a0823160e01b815230600482015290602082602481885afa918215610ee1576000926152a2575b5060048301908154808403931461525d57600a600284901b04927f000000000000000000000000036cbd53842c5426634e7929541ec2318f3dcf7e6001600160a01b031687146151e8575b506040516370a0823160e01b8152306004820152906020826024818a5afa918215610ee1576000926151b4575b5060405163a9059cbb60e01b81523060048201526024810185905260208160448160008c5af19081615197575b50614fd75750505050506138f991506159ae565b6040516370a0823160e01b815230600482015294955091929091906020856024818a5afa948515610ee157600095615163575b5060018601924284541160001461507c5760405162461bcd60e51b815260206004820152603360248201527f4e6f20676f6f6420506572696f6446696e697368206d757374206265206265686044820152720696e6420626c6f636b2e74696d657374616d7606c1b6064820152608490fd5b61508b918684920390036138a1565b93841161512a576f4b3b4ca85a86c47a098a2240000000008410156150ee578481856020967fac24935fd910bc682b5ccb1a07b718cadf8cf2f6d1404c4f3ddc3662dae40e299855029380548501905560024291015542019055604051908152a2565b60405162461bcd60e51b81526020600482015260146024820152730a4caeec2e4c840e4c2e8ca40e8dede40d0d2ced60631b6044820152606490fd5b60405162461bcd60e51b81526020600482015260116024820152706e6f7420656e6f75676820746f6b656e7360781b6044820152606490fd5b90946020823d60201161518f575b8161517e60209383613799565b81010312613434575051933861500a565b3d9150615171565b6151af9060203d602011610fb557610fa88183613799565b614fc3565b9091506020813d6020116151e0575b816151d060209383613799565b8101031261030e57519038614f96565b3d91506151c3565b92506001612710601354946008861060001461520f57607d905b0204930160135538614f69565b601086101561522057607d90615202565b60188610156152315760fa90615202565b60208610156152425760fa90615202565b60288610156152545761017790615202565b61017790615202565b60405162461bcd60e51b815260206004820152601760248201527f526577617264206d75737420626520706f7369746976650000000000000000006044820152606490fd5b90916020823d6020116152ce575b816152bd60209383613799565b810103126134345750519038614f1e565b3d91506152b0565b8082029060001983820990828083109203918083039283670de0b6b3a7640000111561030e5714615341577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066993670de0b6b3a7640000910990828211900360ee1b910360121c170290565b5050670de0b6b3a764000091500490565b818102919060001982820991838084109303928084039384600160601b111561030e571461539357600160601b910990828211900360a01b910360601c1790565b50505060601c90565b818102919060001982820991838084109303928084039384600160c01b111561030e57146153dd57600160c01b910990828211900360401b910360c01c1790565b50505060c01c90565b90606082901b90600019600160601b84099282808510940393808503948584111561030e571461546c578190600160601b9009818060000316809204600281600302188082026002030280820260020302808202600203028082026002030280820260020302809102600203029360018380600003040190848311900302920304170290565b5091500490565b91818302916000198185099383808610950394808603958685111561030e57146154ee5790829109818060000316809204600281600302188082026002030280820260020302808202600203028082026002030280820260020302809102600203029360018380600003040190848311900302920304170290565b505091500490565b6001600160a01b0382166000908152600660205260409020600392919061551c83614e1d565b938491615528856143ed565b600282015501556155398282613c76565b6001600160a01b039182166000908152600760209081526040808320959094168252939093529120600181019190915555565b600e54600f54604051600160f81b6020820152601160f81b60218201526002815260009490926001600160a01b039092169161564391610d96906155b1602287613799565b604051966155c0606089613799565b600288526155d2604060208a01613f92565b615617604051916155e4602084613799565b8a8352610d9660405193849260208401528c60408401528c60608401528c608084015260a08084015260c08301906136e9565b61562088613d5d565b5261562a87613d5d565b506040519485936001600160a01b031660208501614d4e565b61564c83613d6a565b5261565682613d6a565b5060a04201918242116156f7576040517f0000000000000000000000004b2c77d209d3405f41a037ec6c77f7f5b8e2ca806001600160a01b03169290916156a6918391610d969160208401614d71565b813b15613437579183916156d1938360405180968195829463dd46508f60e01b845260048401614de4565b03925af18015614c04576156e7575b5050600190565b816156f191613799565b386156e0565b634e487b7160e01b84526011600452602484fd5b61571533826140a4565b604051631efeed3360e01b8152600481018390526000927f0000000000000000000000004b2c77d209d3405f41a037ec6c77f7f5b8e2ca806001600160a01b031691602081602481865afa908115614b475785916158e0575b5061582d60018060a01b03600e5416916157c2611d6560018060a01b03600f5416926001600160801b03806040519a6157a860608d613799565b60028c526157ba604060208e01613f92565b1691166138c1565b615806602095610d966040516157d88982613799565b8b81526040519485938a85015260408401528b60608401528b608084015260a08084015260c08301906136e9565b61580f87613d5d565b5261581986613d5d565b50610d966040519384923091878501614d4e565b61583684613d6a565b5261584083613d6a565b50604051600160f81b828201908152601160f81b600182015290919061586a908390600201611428565b60a04201938442116158cc5790610d9661588b926040519485938401614d71565b813b15613437579183916158b59360405180958194829363dd46508f60e01b845260048401614de4565b039134905af18015614c04576156e7575050600190565b634e487b7160e01b86526011600452602486fd5b6158f9915060203d602011610eda57610ecb8183613799565b3861576e565b3360005260016020526001600160801b03604060002054911690811161596957336000526001602052604060002081815403905580600054036000556040519081527f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d560203392a2565b60405162461bcd60e51b815260206004820152601a60248201527f77697468647261773a2062616c616e6365206973206c6f7765720000000000006044820152606490fd5b6001600160a01b031660008181526004602052604090205460ff1615615cbd577f00000000000000000000000042000000000000000000000000000000000000066001600160a01b03168114615c78577f0000000000000000000000004b20b6e9b678b111dcc365ead92b3277b178fb746001600160a01b03168114615c33577f000000000000000000000000b379a851ac41bcdf0c2564b88916b10e5a08daae6001600160a01b03168114615bee577f000000000000000000000000036cbd53842c5426634e7929541ec2318f3dcf7e6001600160a01b03168114615baa5760005b6003549081811015615ba35782615aa782613863565b905460039190911b1c6001600160a01b031614615ac8576001915001615a91565b6000198201918211610efe57613a02615ae3615afb93613863565b905460039190911b1c6001600160a01b031691613863565b6003548015615b8d5760001901615b1181613863565b81546001600160a01b03600392831b1b1916909155555b806000526004602052604060002060ff198154169055806000526006602052600060046040822082815582600182015582600282015582600382015501557f66257bcef574219c04f7c05f7a1c78d599da10491294c92a5805c48b4cdf5009600080a2565b634e487b7160e01b600052603160045260246000fd5b5050615b28565b606460405162461bcd60e51b815260206004820152602060248201527f6e6f7420616c6c6f77656420746f2072656d6f7665207573646320746f6b656e6044820152fd5b60405162461bcd60e51b815260206004820152601f60248201527f6e6f7420616c6c6f77656420746f2072656d6f76652042307820746f6b656e006044820152606490fd5b60405162461bcd60e51b815260206004820152601b60248201527f6e6f7420616c6c6f77656420746f2072656d6f766520307842544300000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601a60248201527f6e6f7420616c6c6f77656420746f2072656d6f766520574554480000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601860248201527f546f6b656e206e6f7420696e20726577617264206c69737400000000000000006044820152606490fd5b6103e881046103e8819206615d15575090565b905060018101809111610efe5790565b6001600160801b0392615d78929091906001600160a01b0380821690831611615d7c575b615d71615d626001600160a01b03838116908516615352565b926001600160a01b0392613d01565b1691615473565b1690565b90615d49565b6001600160801b0392615d789290916001600160a01b0380831690821611615dbf575b6001600160a01b0391615db89190613d01565b16906153e6565b90615da5565b9060206001600160801b037f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d921692836000540160005560018060a01b03169283600052600182526040600020818154019055604051908152a256feaf0991cd0b594b80a926fbe48091f3ca4909caad5725ed872618837c38f2a838a2646970667358221220913537cfc0fac672c37868b9207a834a6cb961c0c7b1aa6772ae8798063bd02664736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000b379a851ac41bcdf0c2564b88916b10e5a08daae0000000000000000000000004b20b6e9b678b111dcc365ead92b3277b178fb74000000000000000000000000794b1409ef4b40a90ec8af62eaf4c8bf275e5000
-----Decoded View---------------
Arg [0] : _MainTokenAddress (address): 0xb379A851AC41bcDF0c2564b88916B10E5A08daAe
Arg [1] : _zeroXBTC (address): 0x4b20b6e9b678b111Dcc365EaD92b3277B178FB74
Arg [2] : _HookAddress (address): 0x794B1409ef4b40a90eC8AF62EaF4c8bf275e5000
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000b379a851ac41bcdf0c2564b88916b10e5a08daae
Arg [1] : 0000000000000000000000004b20b6e9b678b111dcc365ead92b3277b178fb74
Arg [2] : 000000000000000000000000794b1409ef4b40a90ec8af62eaf4c8bf275e5000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ 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.