Source Code
Latest 22 from a total of 22 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Retrieve ETH | 23470789 | 154 days ago | IN | 0 ETH | 0.00011486 | ||||
| Deploy Token | 23344739 | 172 days ago | IN | 0.01 ETH | 0.00155781 | ||||
| Deploy Token | 23337808 | 173 days ago | IN | 0.01 ETH | 0.00162417 | ||||
| Deploy Token | 23337646 | 173 days ago | IN | 0.01 ETH | 0.00133993 | ||||
| Deploy Token | 22928109 | 230 days ago | IN | 0.01 ETH | 0.01422497 | ||||
| Deploy Token | 22927983 | 230 days ago | IN | 0.01 ETH | 0.01282965 | ||||
| Deploy Token | 22835984 | 243 days ago | IN | 0.01 ETH | 0.00255694 | ||||
| Predict Token Ad... | 22809394 | 247 days ago | IN | 0 ETH | 0.00001423 | ||||
| Predict Token Ad... | 22760087 | 254 days ago | IN | 0 ETH | 0.0000394 | ||||
| Predict Token Ad... | 22669198 | 266 days ago | IN | 0 ETH | 0.00009768 | ||||
| Deploy Token | 22627209 | 272 days ago | IN | 0.01 ETH | 0.00713767 | ||||
| Retrieve ETH | 22625933 | 272 days ago | IN | 0 ETH | 0.00014852 | ||||
| Deploy Token | 22625752 | 273 days ago | IN | 0.01 ETH | 0.02644882 | ||||
| Deploy Token | 22619594 | 273 days ago | IN | 0.01 ETH | 0.02866949 | ||||
| Retrieve ETH | 22619323 | 273 days ago | IN | 0 ETH | 0.00016504 | ||||
| Deploy Token | 22598048 | 276 days ago | IN | 0.01 ETH | 0.01152463 | ||||
| Deploy Token | 22597612 | 276 days ago | IN | 0.01 ETH | 0.0113246 | ||||
| Retrieve ETH | 22562144 | 281 days ago | IN | 0 ETH | 0.00003423 | ||||
| Deploy Token | 22561867 | 281 days ago | IN | 0.01 ETH | 0.00549825 | ||||
| Collect Fees | 22552178 | 283 days ago | IN | 0 ETH | 0.00025908 | ||||
| Retrieve ETH | 22552155 | 283 days ago | IN | 0 ETH | 0.00004202 | ||||
| Deploy Token | 22551973 | 283 days ago | IN | 0.0102 ETH | 0.00346645 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| Transfer | 23470789 | 154 days ago | 0.0686 ETH | ||||
| 0x60806040 | 23344739 | 172 days ago | Contract Creation | 0 ETH | |||
| Transfer | 23344739 | 172 days ago | 0.0002 ETH | ||||
| 0x60806040 | 23337808 | 173 days ago | Contract Creation | 0 ETH | |||
| Transfer | 23337808 | 173 days ago | 0.0002 ETH | ||||
| 0x60806040 | 23337646 | 173 days ago | Contract Creation | 0 ETH | |||
| Transfer | 23337646 | 173 days ago | 0.0002 ETH | ||||
| 0x60806040 | 22928109 | 230 days ago | Contract Creation | 0 ETH | |||
| Transfer | 22928109 | 230 days ago | 0.0002 ETH | ||||
| 0x60806040 | 22927983 | 230 days ago | Contract Creation | 0 ETH | |||
| Transfer | 22927983 | 230 days ago | 0.0002 ETH | ||||
| 0x60806040 | 22835984 | 243 days ago | Contract Creation | 0 ETH | |||
| Transfer | 22835984 | 243 days ago | 0.0002 ETH | ||||
| 0x60806040 | 22627209 | 272 days ago | Contract Creation | 0 ETH | |||
| Transfer | 22627209 | 272 days ago | 0.0002 ETH | ||||
| Transfer | 22625933 | 272 days ago | 0.0196 ETH | ||||
| 0x60806040 | 22625752 | 273 days ago | Contract Creation | 0 ETH | |||
| Transfer | 22625752 | 273 days ago | 0.0002 ETH | ||||
| 0x60806040 | 22619594 | 273 days ago | Contract Creation | 0 ETH | |||
| Transfer | 22619594 | 273 days ago | 0.0002 ETH | ||||
| Transfer | 22619323 | 273 days ago | 0.0196 ETH | ||||
| 0x60806040 | 22598048 | 276 days ago | Contract Creation | 0 ETH | |||
| Transfer | 22598048 | 276 days ago | 0.0002 ETH | ||||
| 0x60806040 | 22597612 | 276 days ago | Contract Creation | 0 ETH | |||
| Transfer | 22597612 | 276 days ago | 0.0002 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
KOAToLockerV5
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "./NFTAutoLockerV5.sol";
import "./libraries/TickMath.sol";
import {Token} from "./token.sol";
import "./Interface.sol";
// GoPlus Locker Interface
interface IUniV3LPLocker {
struct FeeStruct {
string name;
uint256 lpFee;
uint256 collectFee;
uint256 lockFee;
address lockFeeToken;
}
function lock(
address nftManager_,
uint256 nftId_,
address owner_,
address collector_,
uint256 endTime_,
string memory feeName_
) external payable returns (uint256 lockId);
function getFee(string memory name_) external view returns (FeeStruct memory);
function isSupportedFeeName(string memory name_) external view returns(bool);
}
/**
* @title KING OF APES
* @dev BBB
*
* _ _______ _ _ _____ ____ ______ _____ ______ _____
*| |/ /_ _| \ | |/ ____| / __ \| ____| /\ | __ \| ____|/ ____|
*| ' / | | | \| | | __ | | | | |__ / \ | |__) | |__ | (___
*| < | | | . ` | | |_ | | | | | __| / /\ \ | ___/| __| \___ \
*| . \ _| |_| |\ | |__| | | |__| | | / ____ \| | | |____ ____) |
*|_|\_\_____|_| \_|\_____| \____/|_| /_/ \_\_| |______|_____/
*
*
*/
contract KOAToLockerV5 is Ownable, Pausable {
// Deployment parameters struct to avoid stack too deep
struct DeploymentParams {
string name;
string symbol;
uint256 supply;
int24 initialTick;
uint24 fee;
address feeRecipient;
address recipient;
uint256 recipientAmount;
}
// NFTAutoLockerV5 contract address
address payable public nftLocker;
// GoPlus Locker contract address
address public goPlusLocker;
// State variables that were in KOAToWallet
address public taxCollector;
address public weth;
IUniswapV3Factory public uniswapV3Factory;
INonfungiblePositionManager public positionManager;
address public swapRouter;
// Define the required recipient address (where fees go)
address public constant REQUIRED_RECIPIENT = 0xc5C216E6E60ccE2d189Bcce5f6ebFFDE1e8ce926;
// Fee constants
uint256 public constant MINIMUM_DEPLOYMENT_FEE = 0.01 ether; // 0.01 ETH minimum
uint256 public constant PROTOCOL_FEE = 0.0002 ether; // 0.0002 ETH protocol fee
// Debug events
event DebugStep(string step);
event DebugValues(string name, uint256 value);
event DebugAddress(string name, address addr);
event DebugIntValues(string name, int256 value);
event SaltGeneration(uint256 attempts, bytes32 salt);
// Retrieve function events
event ETHRetrieved(address recipient, uint256 amount);
event ERC20Retrieved(address tokenAddress, address recipient, uint256 amount);
// Fee events
event DeploymentFeeCollected(uint256 totalFee, uint256 protocolFee, uint256 remainingForSwap);
event ProtocolFeeTransferred(address recipient, uint256 amount);
// Pause events
event ContractPaused(address indexed by);
event ContractUnpaused(address indexed by);
// Event for token deployment with locker
event TokenCreatedWithLocker(
address tokenAddress,
uint256 lpNftId,
address deployer,
string name,
string symbol,
uint256 supply,
address recipient,
uint256 recipientAmount,
address lockerAddress,
address feeRecipient
);
// GoPlus locking events
event NFTLockedInGoPlus(uint256 nftId, uint256 goPlusLockId, uint256 endTime);
event GoPlusLockerUpdated(address oldLocker, address newLocker);
/**
* @dev Constructor that includes all necessary parameters
* @param taxCollector_ Address that receives the tax
* @param weth_ WETH address
* @param uniswapV3Factory_ Uniswap V3 factory address
* @param positionManager_ Uniswap V3 position manager address
* @param swapRouter_ Uniswap V3 swap router address
* @param nftLockerV5_ Existing NFTAutoLockerV5 contract address
* @param goPlusLocker_ GoPlus locker contract address
*/
constructor(
address taxCollector_,
address weth_,
address uniswapV3Factory_,
address positionManager_,
address swapRouter_,
address payable nftLockerV5_,
address goPlusLocker_
) {
_transferOwnership(msg.sender);
taxCollector = taxCollector_;
weth = weth_;
uniswapV3Factory = IUniswapV3Factory(uniswapV3Factory_);
positionManager = INonfungiblePositionManager(positionManager_);
swapRouter = swapRouter_;
// Use the existing NFTAutoLockerV5 contract
require(nftLockerV5_ != address(0), "NFTAutoLockerV5 address cannot be zero");
nftLocker = nftLockerV5_;
// Set GoPlus locker
require(goPlusLocker_ != address(0), "GoPlus locker address cannot be zero");
goPlusLocker = goPlusLocker_;
// Automatically authorize this contract in the NFTAutoLockerV5
try NFTAutoLockerV5(nftLocker).setAuthorizedCaller(address(this), true) {
// Authorization successful
} catch {
// Authorization failed - this might happen if we're not the owner
// Contract will still deploy but setFeeRecipient calls will fail until manual authorization
}
}
/**
* @notice Creates a new token, deploys liquidity, and sends the NFT to the autolocker contract
* Also sets the fee recipient for 50/50 split
* @dev Requires minimum deployment fee of 0.01 ETH (no first buy anymore)
*/
function deployToken(
string calldata _name,
string calldata _symbol,
uint256 _supply,
int24 _initialTick,
uint24 _fee,
address _feeRecipient, // Address that will receive 50% of LP fees
address _recipient,
uint256 _recipientAmount
) external payable whenNotPaused returns (address tokenAddress, uint256 tokenId) {
DeploymentParams memory params = DeploymentParams({
name: _name,
symbol: _symbol,
supply: _supply,
initialTick: _initialTick,
fee: _fee,
feeRecipient: _feeRecipient,
recipient: _recipient,
recipientAmount: _recipientAmount
});
return _deployTokenInternal(params);
}
/**
* @dev Internal deployment function using struct to avoid stack too deep
*/
function _deployTokenInternal(DeploymentParams memory params) internal returns (address tokenAddress, uint256 tokenId) {
// Validate inputs and handle fees - returns LP amount
uint256 lpAmount = _validateAndHandleFees(params.recipient, params.recipientAmount, params.supply, params.fee, params.initialTick);
// Deploy token
tokenAddress = _deployToken(params.name, params.symbol, params.supply, params.recipient, params.recipientAmount);
// Create pool and position
tokenId = _createPoolAndPosition(tokenAddress, params.initialTick, params.fee, lpAmount);
// Handle NFT and fee recipient
_handleNFTTransfer(tokenId, params.feeRecipient);
emit TokenCreatedWithLocker(
tokenAddress,
tokenId,
msg.sender,
params.name,
params.symbol,
params.supply,
params.recipient,
params.recipientAmount,
nftLocker,
params.feeRecipient
);
}
/**
* @dev Validate inputs and handle fee transfers
*/
function _validateAndHandleFees(
address _recipient,
uint256 _recipientAmount,
uint256 _supply,
uint24 _fee,
int24 _initialTick
) internal returns (uint256 lpAmount) {
emit DebugStep("Starting deployToken with NFTAutoLockerV5");
require(msg.value >= MINIMUM_DEPLOYMENT_FEE, "Deployment fee must be at least 0.01 ETH");
require(_recipient == REQUIRED_RECIPIENT, "Recipient must be the required address");
require(_recipientAmount <= _supply, "Recipient amount exceeds supply");
int24 tickSpacing = uniswapV3Factory.feeAmountTickSpacing(_fee);
require(tickSpacing != 0 && _initialTick % tickSpacing == 0, "Invalid tick or tick spacing");
lpAmount = _supply - _recipientAmount;
// Handle protocol fee
(bool success, ) = _recipient.call{value: PROTOCOL_FEE}("");
require(success, "Protocol fee transfer failed");
emit DeploymentFeeCollected(msg.value, PROTOCOL_FEE, msg.value - PROTOCOL_FEE);
emit DebugStep("Validation and fee handling complete");
}
/**
* @dev Deploy the token contract
*/
function _deployToken(
string memory _name,
string memory _symbol,
uint256 _supply,
address _recipient,
uint256 _recipientAmount
) internal returns (address tokenAddress) {
(bytes32 create2Salt, ) = findValidSalt(_name, _symbol, _supply);
bytes memory bytecode = abi.encodePacked(
type(Token).creationCode,
abi.encode(_name, _symbol, _supply, address(this))
);
assembly {
tokenAddress := create2(0, add(bytecode, 32), mload(bytecode), create2Salt)
}
require(tokenAddress != address(0), "Token deployment failed");
// Transfer tokens to recipient if needed
if (_recipientAmount > 0) {
require(IToken(tokenAddress).transfer(_recipient, _recipientAmount), "Token transfer failed");
}
emit DebugAddress("Token deployed at", tokenAddress);
}
/**
* @dev Create pool and liquidity position
*/
function _createPoolAndPosition(
address tokenAddress,
int24 _initialTick,
uint24 _fee,
uint256 lpAmount
) internal returns (uint256 tokenId) {
uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(_initialTick);
// Create and initialize pool
address pool = uniswapV3Factory.createPool(tokenAddress, weth, _fee);
IUniswapV3Pool(pool).initialize(sqrtPriceX96);
// Create position
int24 tickSpacing = uniswapV3Factory.feeAmountTickSpacing(_fee);
INonfungiblePositionManager.MintParams memory params = INonfungiblePositionManager.MintParams(
tokenAddress,
weth,
_fee,
_initialTick,
maxUsableTick(tickSpacing),
lpAmount,
0,
0,
0,
address(this),
block.timestamp
);
require(IToken(tokenAddress).approve(address(positionManager), lpAmount), "Token approval failed");
(tokenId, , , ) = positionManager.mint(params);
emit DebugStep("Pool and position created");
}
/**
* @dev Handle NFT transfer and fee recipient setup
*/
function _handleNFTTransfer(uint256 tokenId, address _feeRecipient) internal {
require(_feeRecipient != address(0), "Fee recipient cannot be zero address");
// Validate fee recipient can receive ETH
if (_feeRecipient.code.length > 0) {
(bool canReceiveETH, ) = _feeRecipient.call{value: 0}("");
require(canReceiveETH, "Fee recipient contract cannot receive ETH");
}
NFTAutoLockerV5(nftLocker).setFeeRecipient(tokenId, _feeRecipient);
positionManager.safeTransferFrom(address(this), nftLocker, tokenId);
emit DebugStep("NFT transferred to NFTAutoLockerV5");
}
/**
* @notice Lock an NFT into the GoPlus locker contract
* @param nftId The NFT ID to lock
* @param owner_ The owner of the lock
* @param collector_ The address that can collect fees
* @param lockDurationDays Number of days to lock for
* @param feeName_ The fee name to use (e.g., "DEFAULT", "LVP", "LLP")
* @dev The NFT must be owned by this contract or the caller must approve this contract
*/
function lockNFTInGoPlus(
uint256 nftId,
address owner_,
address collector_,
uint256 lockDurationDays,
string memory feeName_
) external payable returns (uint256 goPlusLockId) {
require(owner_ != address(0), "Owner cannot be zero address");
require(collector_ != address(0), "Collector cannot be zero address");
require(lockDurationDays > 0, "Lock duration must be greater than 0");
IUniV3LPLocker goPlusContract = IUniV3LPLocker(goPlusLocker);
// Check if the fee name is supported
require(goPlusContract.isSupportedFeeName(feeName_), "Fee name not supported");
// Get fee information
IUniV3LPLocker.FeeStruct memory feeInfo = goPlusContract.getFee(feeName_);
// Calculate end time
uint256 endTime = block.timestamp + (lockDurationDays * 1 days);
// Check if we need to pay a lock fee
if (feeInfo.lockFee > 0 && feeInfo.lockFeeToken == address(0)) {
require(msg.value >= feeInfo.lockFee, "Insufficient ETH for lock fee");
}
// Transfer NFT to this contract if not already owned
if (IERC721(address(positionManager)).ownerOf(nftId) != address(this)) {
positionManager.safeTransferFrom(msg.sender, address(this), nftId);
}
// Approve GoPlus locker to take the NFT
IERC721(address(positionManager)).approve(goPlusLocker, nftId);
// Lock the NFT in GoPlus
goPlusLockId = goPlusContract.lock{value: msg.value}(
address(positionManager),
nftId,
owner_,
collector_,
endTime,
feeName_
);
emit NFTLockedInGoPlus(nftId, goPlusLockId, endTime);
return goPlusLockId;
}
/**
* @notice Update the GoPlus locker contract address
* @param newGoPlusLocker The new GoPlus locker contract address
* @dev Can only be called by the owner
*/
function setGoPlusLocker(address newGoPlusLocker) external onlyOwner {
require(newGoPlusLocker != address(0), "GoPlus locker cannot be zero address");
address oldLocker = goPlusLocker;
goPlusLocker = newGoPlusLocker;
emit GoPlusLockerUpdated(oldLocker, newGoPlusLocker);
}
/**
* @notice Get the current GoPlus locker address
* @return The address of the GoPlus locker contract
*/
function getGoPlusLocker() external view returns (address) {
return goPlusLocker;
}
/**
* @notice Check if a fee name is supported by GoPlus locker
* @param feeName The fee name to check
* @return True if supported, false otherwise
*/
function isGoPlusFeeNameSupported(string memory feeName) external view returns (bool) {
return IUniV3LPLocker(goPlusLocker).isSupportedFeeName(feeName);
}
/**
* @notice Get fee information from GoPlus locker
* @param feeName The fee name to query
* @return The fee structure
*/
function getGoPlusFeeInfo(string memory feeName) external view returns (IUniV3LPLocker.FeeStruct memory) {
return IUniV3LPLocker(goPlusLocker).getFee(feeName);
}
/**
* @notice Pause the contract to prevent new deployments
* @dev Can only be called by the owner
*/
function pause() external onlyOwner {
_pause();
emit ContractPaused(msg.sender);
}
/**
* @notice Unpause the contract to allow new deployments
* @dev Can only be called by the owner
*/
function unpause() external onlyOwner {
_unpause();
emit ContractUnpaused(msg.sender);
}
/**
* @notice Check if the contract is currently paused
* @return True if paused, false otherwise
*/
function isPaused() external view returns (bool) {
return paused();
}
/**
* @notice Get the current fee structure
* @return minimumFee The minimum deployment fee required
* @return protocolFee The protocol fee amount
* @return feeRecipient The address that receives the protocol fee
*/
function getFeeInfo() external pure returns (uint256 minimumFee, uint256 protocolFee, address feeRecipient) {
return (MINIMUM_DEPLOYMENT_FEE, PROTOCOL_FEE, REQUIRED_RECIPIENT);
}
/**
* @dev Returns the maximum usable tick based on the tick spacing
*/
function maxUsableTick(int24 tickSpacing) internal pure returns (int24) {
return TickMath.MAX_TICK - (TickMath.MAX_TICK % tickSpacing);
}
/**
* @dev Optimized salt generation algorithm to avoid stack overflow
*/
function findValidSalt(
string memory _name,
string memory _symbol,
uint256 _supply
) internal returns (bytes32 validSalt, address predictedAddress) {
bytes32 bytecodeHash = keccak256(abi.encodePacked(
type(Token).creationCode,
abi.encode(_name, _symbol, _supply, address(this))
));
// Try simple sequential salts first
for (uint16 i = 1; i <= 5000; i++) {
bytes32 create2Salt = keccak256(abi.encode(msg.sender, bytes32(uint256(i))));
address tokenAddress = _computeAddress(create2Salt, bytecodeHash);
if (uint160(tokenAddress) < uint160(weth)) {
emit SaltGeneration(i, bytes32(uint256(i)));
return (create2Salt, tokenAddress);
}
}
// Try block-based variations
for (uint16 i = 0; i < 300; i++) {
bytes32 create2Salt = keccak256(abi.encode(msg.sender, keccak256(abi.encode(block.timestamp, block.number, i))));
address tokenAddress = _computeAddress(create2Salt, bytecodeHash);
if (uint160(tokenAddress) < uint160(weth)) {
emit SaltGeneration(10000 + i, keccak256(abi.encode(block.timestamp, block.number, i)));
return (create2Salt, tokenAddress);
}
}
// Last resort - timestamp variations
for (uint16 i = 0; i < 1000; i++) {
bytes32 create2Salt = keccak256(abi.encode(msg.sender, keccak256(abi.encode(block.timestamp, i))));
address tokenAddress = _computeAddress(create2Salt, bytecodeHash);
if (uint160(tokenAddress) < uint160(weth)) {
emit SaltGeneration(20000 + i, keccak256(abi.encode(block.timestamp, i)));
return (create2Salt, tokenAddress);
}
}
revert("Could not find valid salt - try different token name");
}
/**
* @dev Helper function to compute CREATE2 address
*/
function _computeAddress(bytes32 salt, bytes32 bytecodeHash) private view returns (address) {
return address(uint160(uint256(keccak256(
abi.encodePacked(bytes1(0xff), address(this), salt, bytecodeHash)
))));
}
/**
* @notice Gets the NFTAutoLockerV5 contract address
* @return The address of the NFTAutoLockerV5 contract
*/
function getNFTLockerAddress() external view returns (address) {
return nftLocker;
}
/**
* @notice Gets lock information for a specific NFT
* @param nftId The NFT ID to query
* @return The lock ID in the V5 locker
*/
function getNFTLockInfo(uint256 nftId) external view returns (uint256) {
return NFTAutoLockerV5(nftLocker).nftToLockId(nftId);
}
/**
* @notice Gets all locked NFT IDs
* @return Array of all locked NFT IDs
*/
function getAllLockedNFTs() external view returns (uint256[] memory) {
return NFTAutoLockerV5(nftLocker).getAllLockedNFTs();
}
/**
* @notice Collect fees from an NFT with automatic 50/50 splitting
* @param nftId The NFT ID for which to collect fees
*/
function collectFees(uint256 nftId) external {
NFTAutoLockerV5(nftLocker).collectFees(nftId);
}
/**
* @notice Batch collect fees from multiple NFTs with automatic 50/50 splitting
* @param nftIds Array of NFT IDs for which to collect fees
*/
function batchCollectFees(uint256[] calldata nftIds) external {
NFTAutoLockerV5(nftLocker).batchCollectFees(nftIds);
}
/**
* @notice Enable or disable the 50/50 fee splitting feature
* @param enabled Whether fee splitting should be enabled
* @dev Can only be called by the owner
*/
function toggleFeeSplitting(bool enabled) external onlyOwner {
NFTAutoLockerV5(nftLocker).toggleFeeSplitting(enabled);
}
/**
* @notice Withdraw ETH from the NFTAutoLockerV5 contract
* @param to Address to send ETH to
* @param amount Amount of ETH to withdraw
* @dev Can only be called by the owner
*/
function withdrawLockerETH(address to, uint256 amount) external onlyOwner {
NFTAutoLockerV5(nftLocker).withdrawETH(to, amount);
}
/**
* @notice Retrieve accidental ETH sent to the contract
* @param recipient Address to send the ETH to
* @param amount Amount of ETH to retrieve
*/
function retrieveETH(address recipient, uint256 amount) external onlyOwner {
require(recipient != address(0), "Cannot withdraw to zero address");
require(amount <= address(this).balance, "Insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "ETH transfer failed");
emit ETHRetrieved(recipient, amount);
}
/**
* @notice Retrieve ERC20 tokens from the contract
* @param tokenAddress Address of the token to retrieve
* @param recipient Address to send the tokens to
* @param amount Amount of tokens to retrieve
*/
function retrieveERC20(address tokenAddress, address recipient, uint256 amount) external onlyOwner {
require(recipient != address(0), "Cannot withdraw to zero address");
IToken token = IToken(tokenAddress);
require(amount <= token.balanceOf(address(this)), "Insufficient balance");
require(token.transfer(recipient, amount), "Token transfer failed");
emit ERC20Retrieved(tokenAddress, recipient, amount);
}
/**
* @notice Predict a token address before deployment
* This is a helper function to determine what address a token will have
*/
function predictTokenAddress(string calldata name, string calldata symbol, uint256 supply) public returns (address) {
bytes32 bytecodeHash = keccak256(abi.encodePacked(
type(Token).creationCode,
abi.encode(name, symbol, supply, address(this))
));
// Try simple sequential salts for prediction
for (uint16 i = 1; i <= 100; i++) {
bytes32 create2Salt = keccak256(abi.encode(msg.sender, bytes32(uint256(i))));
address tokenAddress = _computeAddress(create2Salt, bytecodeHash);
if (uint160(tokenAddress) < uint160(weth)) {
emit SaltGeneration(i, bytes32(uint256(i)));
return tokenAddress;
}
}
// Return approximation with fixed salt
bytes32 fixedSalt = keccak256(abi.encode(msg.sender, bytes32(uint256(1))));
return _computeAddress(fixedSalt, bytecodeHash);
}
/**
* @notice Allow the contract to receive ETH
*/
receive() external payable {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(address from, address to, uint256 amount) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
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`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
// Swap Router parameters struct
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
// Interfaces for Uniswap V3 components
interface IUniswapV3Pool {
function initialize(uint160 sqrtPriceX96) external;
}
interface IUniswapV3Factory {
function createPool(
address tokenA,
address tokenB,
uint24 fee
) external returns (address pool);
function getPool(
address tokenA,
address tokenB,
uint24 fee
) external view returns (address pool);
function feeAmountTickSpacing(uint24 fee) external view returns (int24);
}
interface ISwapRouter {
function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
}
// Interface for the Position Manager
interface INonfungiblePositionManager {
struct MintParams {
address token0;
address token1;
uint24 fee;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
address recipient;
uint256 deadline;
}
struct CollectParams {
uint256 tokenId;
address recipient;
uint128 amount0Max;
uint128 amount1Max;
}
function mint(MintParams calldata params)
external
payable
returns (
uint256 tokenId,
uint128 liquidity,
uint256 amount0,
uint256 amount1
);
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
function factory() external view returns (address);
function collect(CollectParams calldata params)
external
payable
returns (uint256 amount0, uint256 amount1);
function positions(uint256 tokenId)
external
view
returns (
uint96 nonce,
address operator,
address token0,
address token1,
uint24 fee,
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
uint128 tokensOwed0,
uint128 tokensOwed1
);
}
// Interface for the Liquidity Locker
interface IMultiPositionLiquidityLocker {
function initializePosition(
uint256 tokenId,
address owner,
uint64 unlockTime,
uint16 feeCut
) external;
}
// Interface for KOA Token
interface IToken {
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
/// @title Math library for computing sqrt price for ticks of size 1.0001, i.e., sqrt(1.0001^tick) as fixed point Q64.96 numbers
library TickMath {
/// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128
int24 internal constant MIN_TICK = -887272;
/// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128
int24 internal constant MAX_TICK = 887272;
/// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
uint160 internal constant MIN_SQRT_RATIO = 4295128739;
/// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;
/// @notice Calculates sqrt(1.0001^tick) * 2^96
/// @dev Throws if |tick| > max tick
/// @param tick The input tick for the calculation
/// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)
/// at the given tick
function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {
uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));
require(absTick <= uint256(int256(MAX_TICK)), 'TickMath: 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 Q128.96.
// we then downcast because we know the result always fits within 160 bits due to our tick input constraint
// we round up in the division so getTickAtSqrtRatio of the output price is always consistent
sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));
}
/// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio
/// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may
/// return.
/// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96
/// @return tick The greatest tick for which the ratio is less than or equal to the input ratio
function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) {
// second inequality must be < because the price can never reach the price at the max tick
require(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, 'TickMath: SQRT_RATIO_OUT_OF_BOUNDS');
uint256 ratio = uint256(sqrtPriceX96) << 32;
uint256 r = ratio;
uint256 msb = 0;
assembly {
let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(5, gt(r, 0xFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(4, gt(r, 0xFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(3, gt(r, 0xFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(2, gt(r, 0xF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(1, gt(r, 0x3))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := gt(r, 0x1)
msb := or(msb, f)
}
if (msb >= 128) r = ratio >> (msb - 127);
else r = ratio << (127 - msb);
int256 log_2 = (int256(msb) - 128) << 64;
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(63, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(62, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(61, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(60, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(59, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(58, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(57, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(56, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(55, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(54, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(53, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(52, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(51, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(50, f))
}
int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number
int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128);
int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128);
tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./Interface.sol"; // Added import for INonfungiblePositionManager
/**
* @title KING OF APES
* @dev BBB
*
* _ _______ _ _ _____ ____ ______ _____ ______ _____
*| |/ /_ _| \ | |/ ____| / __ \| ____| /\ | __ \| ____|/ ____|
*| ' / | | | \| | | __ | | | | |__ / \ | |__) | |__ | (___
*| < | | | . ` | | |_ | | | | | __| / /\ \ | ___/| __| \___ \
*| . \ _| |_| |\ | |__| | | |__| | | / ____ \| | | |____ ____) |
*|_|\_\_____|_| \_|\_____| \____/|_| /_/ \_\_| |______|_____/
*
*
*/
contract NFTAutoLockerV5 is Ownable, IERC721Receiver, ReentrancyGuard {
// Uniswap V3 position manager interface
IERC721 public positionManager;
// Position manager interface for getting position tokens
INonfungiblePositionManager public positionManagerExtended;
// GoPlus locker interface
address public goPlusLocker;
// Mapping from NFT ID to GoPlus lock ID
mapping(uint256 => uint256) public nftToLockId;
// Array of all locked NFT IDs
uint256[] public lockedNftIds;
// Fee splitting features
bool public feeSplittingEnabled = true; // Default enabled
// Mapping from NFT ID to fee recipient address (gets 50% of fees)
mapping(uint256 => address) public nftFeeRecipients;
// Protocol fee address - where fees are sent (treasury)
address public protocolFeeAddress = 0xc5C216E6E60ccE2d189Bcce5f6ebFFDE1e8ce926;
// Authorization mapping for contracts that can set fee recipients
mapping(address => bool) public authorizedCallers;
// Events
event NFTReceived(address operator, address from, uint256 tokenId, bytes data);
event NFTLocked(uint256 tokenId, uint256 lockId, uint256 unlockTime);
event FeesCollected(uint256 nftId, uint256 lockId, uint256 totalCollected);
event FeeSplittingToggled(bool enabled);
event FeesSplit(uint256 indexed nftId, address indexed owner, address indexed feeRecipient, uint256 ownerAmount, uint256 recipientAmount);
event TokenFeesSplit(uint256 indexed nftId, address token, address indexed owner, address indexed feeRecipient, uint256 ownerAmount, uint256 recipientAmount);
event AuthorizedCallerUpdated(address indexed caller, bool authorized);
/**
* @dev Initialize the contract with the position manager and GoPlus locker addresses
*/
constructor(address _positionManager, address _goPlusLocker) Ownable() {
require(_positionManager != address(0), "Position manager cannot be zero address");
require(_goPlusLocker != address(0), "GoPlus locker cannot be zero address");
positionManager = IERC721(_positionManager);
positionManagerExtended = INonfungiblePositionManager(_positionManager);
goPlusLocker = _goPlusLocker;
}
/**
* @dev Implements IERC721Receiver to receive NFTs
* This function is called when an NFT is transferred to this contract
* After receiving the NFT, it automatically locks it in GoPlus
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external override returns (bytes4) {
// Only accept NFTs from the position manager
require(msg.sender == address(positionManager), "Only accepts Uniswap V3 NFTs");
emit NFTReceived(operator, from, tokenId, data);
// Lock the NFT in GoPlus
_lockNFT(tokenId);
return this.onERC721Received.selector;
}
/**
* @notice Authorize or deauthorize a contract to set fee recipients
* @dev Can only be called by the owner
* @param caller The address to authorize/deauthorize
* @param authorized Whether the address should be authorized
*/
function setAuthorizedCaller(address caller, bool authorized) external onlyOwner {
require(caller != address(0), "Cannot authorize zero address");
authorizedCallers[caller] = authorized;
emit AuthorizedCallerUpdated(caller, authorized);
}
/**
* @notice Store fee recipient address for a specific NFT
* @dev Called by authorized contracts when creating a token and locking liquidity
* @param nftId The NFT ID to associate with the fee recipient
* @param feeRecipient The address to receive part of the fees
*/
function setFeeRecipient(uint256 nftId, address feeRecipient) external {
require(
(nftToLockId[nftId] == 0 && authorizedCallers[msg.sender]) ||
owner() == msg.sender,
"Not authorized to set fee recipient"
);
nftFeeRecipients[nftId] = feeRecipient;
}
/**
* @notice Enable or disable fee splitting
* @dev Can only be called by the owner
* @param enabled Whether fee splitting should be enabled
*/
function toggleFeeSplitting(bool enabled) external onlyOwner {
feeSplittingEnabled = enabled;
emit FeeSplittingToggled(enabled);
}
/**
* @notice Update the protocol fee address
* @dev Can only be called by the owner
* @param _protocolFeeAddress The new address to receive protocol fees
*/
function setProtocolFeeAddress(address _protocolFeeAddress) external onlyOwner {
require(_protocolFeeAddress != address(0), "Cannot set zero address");
protocolFeeAddress = _protocolFeeAddress;
}
/**
* @dev Internal function to lock the NFT in GoPlus
* @param tokenId The NFT ID to lock
*/
function _lockNFT(uint256 tokenId) internal {
// Approve the GoPlus locker to transfer this NFT
positionManager.approve(goPlusLocker, tokenId);
// Calculate unlock time: current time + 365 days
uint256 unlockTime = block.timestamp + 365 days;
// Prepare the lock call parameters
// Lock using the LVP fee structure
bytes memory lockData = abi.encodeWithSignature(
"lock(address,uint256,address,address,uint256,string)",
address(positionManager),
tokenId,
address(this), // owner
address(this), // collector (fees will go to this contract for splitting)
unlockTime,
"LVP" // Fee name - LVP: LP Fee 0.64%, Collect Fee 0.8%
);
// Call the GoPlus locker
(bool success, bytes memory returnData) = goPlusLocker.call(lockData);
require(success, "Failed to lock NFT in GoPlus");
// Parse lock ID from the return data
uint256 lockId = abi.decode(returnData, (uint256));
// Store the mapping between NFT ID and lock ID
nftToLockId[tokenId] = lockId;
lockedNftIds.push(tokenId);
emit NFTLocked(tokenId, lockId, unlockTime);
}
/**
* @dev Allows the owner to lock an NFT manually if needed
* @param tokenId The NFT ID to lock
* Requires that the NFT is already in this contract
*/
function lockNFT(uint256 tokenId) external onlyOwner {
require(positionManager.ownerOf(tokenId) == address(this), "NFT not owned by this contract");
require(nftToLockId[tokenId] == 0, "NFT already locked");
_lockNFT(tokenId);
}
/**
* @dev Collect both ETH and token fees from the GoPlus locker for a specific NFT
* @param nftId The NFT ID for which to collect fees
* @notice This function handles both ETH and token fees with intelligent distribution
*/
function collectFees(uint256 nftId) external nonReentrant {
uint256 lockId = nftToLockId[nftId];
require(lockId != 0, "NFT not locked");
// Get token addresses from the position
(address token0, address token1) = _getPositionTokens(nftId);
// Get balances before collection
uint256 ethBefore = address(this).balance;
uint256 token0Before = IERC20(token0).balanceOf(address(this));
uint256 token1Before = IERC20(token1).balanceOf(address(this));
// Call the GoPlus locker to collect fees
bytes memory collectData = abi.encodeWithSignature(
"collect(uint256,address,uint128,uint128)",
lockId,
address(this), // Recipient is this contract for splitting
type(uint128).max, // Max amount token0
type(uint128).max // Max amount token1
);
(bool success, ) = goPlusLocker.call(collectData);
require(success, "Failed to collect fees");
// Calculate collected amounts
uint256 ethCollected = address(this).balance - ethBefore;
uint256 token0Collected = IERC20(token0).balanceOf(address(this)) - token0Before;
uint256 token1Collected = IERC20(token1).balanceOf(address(this)) - token1Before;
// Emit collection events
emit FeesCollected(nftId, lockId, ethCollected + token0Collected + token1Collected);
// Split fees if anything was collected and splitting is enabled
if (feeSplittingEnabled) {
// Handle ETH if any was collected
if (ethCollected > 0) {
_splitEthFees(nftId, ethCollected);
}
// Handle token0 if any was collected
if (token0Collected > 0) {
_splitTokenFees(nftId, token0, token0Collected);
}
// Handle token1 if any was collected
if (token1Collected > 0) {
_splitTokenFees(nftId, token1, token1Collected);
}
}
}
/**
* @dev Batch collect fees from multiple NFTs
* @param nftIds Array of NFT IDs for which to collect fees
*/
function batchCollectFees(uint256[] calldata nftIds) external nonReentrant {
for (uint256 i = 0; i < nftIds.length; i++) {
uint256 nftId = nftIds[i];
uint256 lockId = nftToLockId[nftId];
if (lockId != 0) {
// Get token addresses
(address token0, address token1) = _getPositionTokens(nftId);
// Get balances before collection
uint256 ethBefore = address(this).balance;
uint256 token0Before = IERC20(token0).balanceOf(address(this));
uint256 token1Before = IERC20(token1).balanceOf(address(this));
// Use the correct collect function signature
bytes memory collectData = abi.encodeWithSignature(
"collect(uint256,address,uint128,uint128)",
lockId,
address(this), // Recipient is this contract for splitting
type(uint128).max, // Max amount token0
type(uint128).max // Max amount token1
);
// Call the GoPlus locker (ignore failures)
(bool success, ) = goPlusLocker.call(collectData);
if (success) {
// Calculate collected amounts
uint256 ethCollected = address(this).balance - ethBefore;
uint256 token0Collected = IERC20(token0).balanceOf(address(this)) - token0Before;
uint256 token1Collected = IERC20(token1).balanceOf(address(this)) - token1Before;
// Emit collection event
emit FeesCollected(nftId, lockId, ethCollected + token0Collected + token1Collected);
// Split fees if anything was collected and splitting is enabled
if (feeSplittingEnabled) {
// Handle ETH if any was collected
if (ethCollected > 0) {
_splitEthFees(nftId, ethCollected);
}
// Handle token0 if any was collected
if (token0Collected > 0) {
_splitTokenFees(nftId, token0, token0Collected);
}
// Handle token1 if any was collected
if (token1Collected > 0) {
_splitTokenFees(nftId, token1, token1Collected);
}
}
}
}
}
}
/**
* @dev Internal function to split ETH fees between owner and fee recipient
* @param nftId The NFT ID for which fees were collected
* @param amount The amount of ETH to split
*/
function _splitEthFees(uint256 nftId, uint256 amount) internal {
address feeRecipient = nftFeeRecipients[nftId];
// If no fee recipient is set, send all fees to the protocol address
if (feeRecipient == address(0)) {
// Send all fees to the protocol address
(bool success,) = protocolFeeAddress.call{value: amount}("");
require(success, "ETH transfer to protocol failed");
emit FeesSplit(nftId, protocolFeeAddress, address(0), amount, 0);
return;
}
// Split 50/50
uint256 halfAmount = amount / 2;
uint256 recipientAmount = amount - halfAmount; // To handle odd amounts correctly
// Send half to the fee recipient
(bool recipientSuccess,) = feeRecipient.call{value: recipientAmount}("");
// Send the other half directly to the protocol address
(bool protocolSuccess,) = protocolFeeAddress.call{value: halfAmount}("");
require(protocolSuccess, "ETH transfer to protocol failed");
// Emit event
emit FeesSplit(nftId, protocolFeeAddress, feeRecipient, halfAmount, recipientAmount);
// If transfer to fee recipient failed, send their portion to the protocol address
if (!recipientSuccess) {
(bool fallbackSuccess,) = protocolFeeAddress.call{value: recipientAmount}("");
require(fallbackSuccess, "ETH fallback transfer failed");
// Re-emit event to log the failed recipient transfer and fallback to protocol
emit FeesSplit(
nftId,
protocolFeeAddress,
protocolFeeAddress,
halfAmount + recipientAmount,
0
);
}
}
/**
* @dev Internal function to split token fees between owner and fee recipient
* @param nftId The NFT ID for which fees were collected
* @param token The token address
* @param amount The amount of tokens to split
*/
function _splitTokenFees(uint256 nftId, address token, uint256 amount) internal {
address feeRecipient = nftFeeRecipients[nftId];
// If no fee recipient is set, send all fees to the protocol address
if (feeRecipient == address(0)) {
// Send all tokens to the protocol address
bool success = IERC20(token).transfer(protocolFeeAddress, amount);
require(success, "Token transfer to protocol failed");
emit TokenFeesSplit(nftId, token, protocolFeeAddress, address(0), amount, 0);
return;
}
// Split 50/50
uint256 halfAmount = amount / 2;
uint256 recipientAmount = amount - halfAmount; // To handle odd amounts correctly
// Send half to the fee recipient
bool recipientSuccess = IERC20(token).transfer(feeRecipient, recipientAmount);
// Send the other half directly to the protocol address
bool protocolSuccess = IERC20(token).transfer(protocolFeeAddress, halfAmount);
require(protocolSuccess, "Token transfer to protocol failed");
// Emit event
emit TokenFeesSplit(nftId, token, protocolFeeAddress, feeRecipient, halfAmount, recipientAmount);
// If transfer to fee recipient failed, send their portion to the protocol address
if (!recipientSuccess) {
bool fallbackSuccess = IERC20(token).transfer(protocolFeeAddress, recipientAmount);
require(fallbackSuccess, "Token fallback transfer failed");
// Re-emit event for the fallback transfer
emit TokenFeesSplit(
nftId,
token,
protocolFeeAddress,
protocolFeeAddress,
halfAmount + recipientAmount,
0
);
}
}
/**
* @dev Helper function to get position tokens
* @param nftId The NFT ID to get token addresses for
* @return token0 The first token in the pair
* @return token1 The second token in the pair
*/
function _getPositionTokens(uint256 nftId) internal view returns (address token0, address token1) {
// Get the positions data and correctly extract token0 and token1
(
, // uint96 nonce
, // address operator
token0,
token1,
, // uint24 fee
, // int24 tickLower
, // int24 tickUpper
, // uint128 liquidity
, // uint256 feeGrowthInside0LastX128
, // uint256 feeGrowthInside1LastX128
, // uint128 tokensOwed0
// uint128 tokensOwed1
) = positionManagerExtended.positions(nftId);
}
/**
* @dev Public helper function to get position tokens
* @param nftId The NFT ID to get token addresses for
* @return token0 The first token in the pair
* @return token1 The second token in the pair
*/
function getPositionTokens(uint256 nftId) external view returns (address token0, address token1) {
return _getPositionTokens(nftId);
}
/**
* @dev Get all locked NFT IDs
* @return Array of locked NFT IDs
*/
function getAllLockedNFTs() external view returns (uint256[] memory) {
return lockedNftIds;
}
/**
* @dev Allows the owner to withdraw any ETH from the contract
* @param to Address to send ETH to
* @param amount Amount of ETH to withdraw
*/
function withdrawETH(address to, uint256 amount) external onlyOwner {
require(to != address(0), "Cannot withdraw to zero address");
require(amount <= address(this).balance, "Insufficient balance");
(bool success, ) = to.call{value: amount}("");
require(success, "ETH transfer failed");
}
/**
* @dev Allows the owner to withdraw any tokens from the contract
* @param token The token address to withdraw
* @param to Address to send tokens to
* @param amount Amount of tokens to withdraw
*/
function withdrawTokens(address token, address to, uint256 amount) external onlyOwner {
require(to != address(0), "Cannot withdraw to zero address");
require(amount <= IERC20(token).balanceOf(address(this)), "Insufficient balance");
bool success = IERC20(token).transfer(to, amount);
require(success, "Token transfer failed");
}
/**
* @dev Allow the contract to receive ETH
*/
receive() external payable {}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
/**
* @title KING OF APES
* @dev BBB
*
* _ _______ _ _ _____ ____ ______ _____ ______ _____
*| |/ /_ _| \ | |/ ____| / __ \| ____| /\ | __ \| ____|/ ____|
*| ' / | | | \| | | __ | | | | |__ / \ | |__) | |__ | (___
*| < | | | . ` | | |_ | | | | | __| / /\ \ | ___/| __| \___ \
*| . \ _| |_| |\ | |__| | | |__| | | / ____ \| | | |____ ____) |
*|_|\_\_____|_| \_|\_____| \____/|_| /_/ \_\_| |______|_____/
*
*
*/
contract Token is ERC20 {
constructor(
string memory name_,
string memory symbol_,
uint256 maxSupply_,
address recipient_
) ERC20(name_, symbol_) {
_mint(recipient_, maxSupply_);
}
function decimals() public view virtual override returns (uint8) {
return 18;
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"viaIR": true,
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"taxCollector_","type":"address"},{"internalType":"address","name":"weth_","type":"address"},{"internalType":"address","name":"uniswapV3Factory_","type":"address"},{"internalType":"address","name":"positionManager_","type":"address"},{"internalType":"address","name":"swapRouter_","type":"address"},{"internalType":"address payable","name":"nftLockerV5_","type":"address"},{"internalType":"address","name":"goPlusLocker_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"}],"name":"ContractPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"}],"name":"ContractUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"DebugAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"int256","name":"value","type":"int256"}],"name":"DebugIntValues","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"step","type":"string"}],"name":"DebugStep","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"DebugValues","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"totalFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"protocolFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"remainingForSwap","type":"uint256"}],"name":"DeploymentFeeCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ERC20Retrieved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ETHRetrieved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldLocker","type":"address"},{"indexed":false,"internalType":"address","name":"newLocker","type":"address"}],"name":"GoPlusLockerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"nftId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"goPlusLockId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"}],"name":"NFTLockedInGoPlus","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ProtocolFeeTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"attempts","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"SaltGeneration","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"lpNftId","type":"uint256"},{"indexed":false,"internalType":"address","name":"deployer","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"supply","type":"uint256"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"recipientAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"lockerAddress","type":"address"},{"indexed":false,"internalType":"address","name":"feeRecipient","type":"address"}],"name":"TokenCreatedWithLocker","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"MINIMUM_DEPLOYMENT_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROTOCOL_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REQUIRED_RECIPIENT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"nftIds","type":"uint256[]"}],"name":"batchCollectFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"collectFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_supply","type":"uint256"},{"internalType":"int24","name":"_initialTick","type":"int24"},{"internalType":"uint24","name":"_fee","type":"uint24"},{"internalType":"address","name":"_feeRecipient","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_recipientAmount","type":"uint256"}],"name":"deployToken","outputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getAllLockedNFTs","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFeeInfo","outputs":[{"internalType":"uint256","name":"minimumFee","type":"uint256"},{"internalType":"uint256","name":"protocolFee","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"string","name":"feeName","type":"string"}],"name":"getGoPlusFeeInfo","outputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"lpFee","type":"uint256"},{"internalType":"uint256","name":"collectFee","type":"uint256"},{"internalType":"uint256","name":"lockFee","type":"uint256"},{"internalType":"address","name":"lockFeeToken","type":"address"}],"internalType":"struct IUniV3LPLocker.FeeStruct","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGoPlusLocker","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"getNFTLockInfo","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNFTLockerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"goPlusLocker","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"feeName","type":"string"}],"name":"isGoPlusFeeNameSupported","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftId","type":"uint256"},{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"collector_","type":"address"},{"internalType":"uint256","name":"lockDurationDays","type":"uint256"},{"internalType":"string","name":"feeName_","type":"string"}],"name":"lockNFTInGoPlus","outputs":[{"internalType":"uint256","name":"goPlusLockId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"nftLocker","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"positionManager","outputs":[{"internalType":"contract INonfungiblePositionManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"supply","type":"uint256"}],"name":"predictTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"retrieveERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"retrieveETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newGoPlusLocker","type":"address"}],"name":"setGoPlusLocker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"taxCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"toggleFeeSplitting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniswapV3Factory","outputs":[{"internalType":"contract IUniswapV3Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawLockerETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
608080604052346102465760009060e0816146ff8038038091610022828561024b565b8339810103126102425761003581610284565b61004160208301610284565b61004d60408401610284565b61005960608501610284565b9061006660808601610284565b60a08601516001600160a01b038116969194919087900361023e5760c061008d9101610284565b9461009733610298565b875460ff60a01b191688556100ab33610298565b600380546001600160a01b03199081166001600160a01b039384161790915560048054821693831693909317909255600580548316938216939093179092556006805482169383169390931790925560078054909216921691909117905581156101ea57600180546001600160a01b031916831790556001600160a01b031690811561019957600280546001600160a01b0319169092179091558190803b1561019657819060446040518094819363454bbd2960e01b8352306004840152600160248401525af1610186575b60405161441f90816102e08239f35b816101909161024b565b38610177565b50fd5b60405162461bcd60e51b8152602060048201526024808201527f476f506c7573206c6f636b657220616464726573732063616e6e6f74206265206044820152637a65726f60e01b6064820152608490fd5b60405162461bcd60e51b815260206004820152602660248201527f4e46544175746f4c6f636b6572563520616464726573732063616e6e6f74206260448201526565207a65726f60d01b6064820152608490fd5b8780fd5b5080fd5b600080fd5b601f909101601f19168101906001600160401b0382119082101761026e57604052565b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b038216820361024657565b600080546001600160a01b039283166001600160a01b03198216811783559216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a356fe6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c806202eab71461022a578062a04feb146102255780630150b5db14610220578063058e58341461021b5780630b4501fd1461021657806317508637146101f85780632f9c02b61461021157806334dea1691461020c5780633a5642f4146102075780633f4ba83a146102025780633fc8cef3146101fd578063477f6e42146101f85780634e9c8927146101e45780635b549182146101f35780635c975abb146101c6578063715018a6146101ee5780637192c566146101e95780637919dd34146101e4578063791b98bc146101df578063803bfb0a146101da5780638456cb59146101d55780638da5cb5b146101d0578063b17acdcd146101cb578063b187bd26146101c6578063b5989102146101c1578063bea1dcf8146101bc578063c31c9c07146101b7578063d55ac27f146101b2578063d63f4594146101ad578063dbd96fa3146101a8578063eab1f410146101a3578063f2fde38b1461019e578063f45fc718146101995763f55d77280361000e576115da565b611531565b611457565b6113e4565b6112cd565b611168565b611146565b61111d565b6110f4565b610cf5565b610968565b610c99565b610c70565b610be8565b610b6c565b610b39565b610916565b610a7b565b61098e565b61093f565b610526565b6108ed565b61082b565b61079a565b610704565b61054f565b610505565b6104d6565b6103ce565b6102b4565b61023f565b600091031261023a57565b600080fd5b3461023a57600036600319011261023a576060604051662386f26fc10000815265b5e620f48000602082015273c5c216e6e60cce2d189bcce5f6ebffde1e8ce9266040820152f35b6001600160a01b0381160361023a57565b60a435906102a582610287565b565b60c435906102a582610287565b3461023a57604036600319011261023a576004356102d181610287565b6024356102dc6121b4565b6102f06001600160a01b0383161515611635565b6102fc47821115611681565b600080808084865af161030d6116c4565b501561035957604080516001600160a01b03909316835260208301919091527fc8509a63402c5fc92474eaf55ef1d99608b69605f3e4a4a29dfafff277f9e9d79190819081015b0390a1005b60405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152606490fd5b602060408183019282815284518094520192019060005b8181106103b85750505090565b82518452602093840193909201916001016103ab565b3461023a57600036600319011261023a57600154604051630150b5db60e01b815290600090829060049082906001600160a01b03165afa9081156104d157600091610426575b604051806104228482610394565b0390f35b3d8083833e610435818361062b565b8101906020818303126104c9578051906001600160401b0382116104cd570181601f820112156104c9578051926001600160401b0384116104c4578360051b9160405194610486602085018761062b565b85526020808601938201019384116104c057602001915b8383106104b05750505050610422610414565b825181526020928301920161049d565b5080fd5b6105de565b8280fd5b8380fd5b6116f4565b3461023a57600036600319011261023a57602060405173c5c216e6e60cce2d189bcce5f6ebffde1e8ce9268152f35b3461023a57600036600319011261023a57602060405165b5e620f480008152f35b3461023a57600036600319011261023a576001546040516001600160a01b039091168152602090f35b3461023a57600060403660031901126105db5760043561056e81610287565b8160243561057a6121b4565b6001546001600160a01b0316803b156104c957604051634782f77960e01b81526001600160a01b0394909416600485015260248401919091528290604490829084905af180156104d15782906105cd5780f35b6105d69161062b565b388180f35b80fd5b634e487b7160e01b600052604160045260246000fd5b60a081019081106001600160401b038211176104c457604052565b61010081019081106001600160401b038211176104c457604052565b90601f801991011681019081106001600160401b038211176104c457604052565b604051906102a56101608361062b565b906102a5604051928361062b565b6001600160401b0381116104c457601f01601f191660200190565b9291926106918261066a565b9161069f604051938461062b565b82948184528183011161023a578281602093846000960137010152565b9080601f8301121561023a578160206106d793359101610685565b90565b602060031982011261023a57600435906001600160401b03821161023a576106d7916004016106bc565b3461023a576107426020610717366106da565b60018060a01b0360025416604051808095819462beb0b560e51b835286600484018181520190610a0a565b03915afa80156104d1576104229160009161076b575b5060405190151581529081906020820190565b61078d915060203d602011610793575b610785818361062b565b810190611700565b38610758565b503d61077b565b3461023a57602036600319011261023a5760015460405163232633a360e11b8152600480359082015290602090829060249082906001600160a01b03165afa80156104d157610422916000916107fc575b506040519081529081906020820190565b61081e915060203d602011610824575b610816818361062b565b810190611726565b386107eb565b503d61080c565b3461023a57600036600319011261023a576108446121b4565b60005460ff8160a01c16156108b15760ff60a01b19166000556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa90602090a1337f5b65b0c1363b3003db9bcc5e1fd8805a6d6bf5bf6dc9d3431ee4494cd7d11766600080a2005b60405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606490fd5b3461023a57600036600319011261023a576004546040516001600160a01b039091168152602090f35b3461023a57600036600319011261023a576002546040516001600160a01b039091168152602090f35b3461023a57600036600319011261023a576005546040516001600160a01b039091168152602090f35b3461023a57600036600319011261023a57602060ff60005460a01c166040519015158152f35b3461023a57600036600319011261023a576109a76121b4565b600080546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b60005b8381106109fa5750506000910152565b81810151838201526020016109ea565b90602091610a23815180928185528580860191016109e7565b601f01601f1916010190565b6020815260a0610a4a835182602085015260c0840190610a0a565b926020810151604084015260408101516060840152606081015160808401526080600180841b039101511691015290565b3461023a57610af36000610a8e366106da565b816080604051610a9d816105f4565b606081528260208201528260408201528260608201520152610ad8610acc610acc60025460018060a01b031690565b6001600160a01b031690565b6040518080958194631da3ddcd60e31b835260048301611715565b03915afa80156104d15761042291600091610b16575b5060405191829182610a2f565b610b3391503d806000833e610b2b818361062b565b810190611740565b38610b09565b3461023a57600036600319011261023a576006546040516001600160a01b039091168152602090f35b8015150361023a57565b3461023a57602036600319011261023a57600435610b8981610b62565b610b916121b4565b6001546001600160a01b031690813b1561023a5760009160248392604051948593849263401dfd8560e11b8452151560048401525af180156104d157610bd357005b80610be260006100199361062b565b8061022f565b3461023a57600036600319011261023a57610c016121b4565b610c0961224e565b6000805460ff60a01b1916600160a01b1790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602090a1337f81990fd9a5c552b8e3677917d8a03c07678f0d2cb68f88b634aca2022e9bd19f600080a2005b3461023a57600036600319011261023a576000546040516001600160a01b039091168152602090f35b3461023a57600060203660031901126105db576001548190600435906001600160a01b0316803b15610cf15760248392604051948593849263b17acdcd60e01b845260048401525af180156104d15782906105cd5780f35b5050fd5b60a036600319011261023a57600435602435610d1081610287565b60443591610d1d83610287565b606435916084356001600160401b03811161023a57610d409036906004016106bc565b90610d556001600160a01b03821615156117fd565b610d696001600160a01b0386161515611849565b610d74841515611894565b600254610d8b90610acc906001600160a01b031681565b60405162beb0b560e51b815260208180610da88760048301611715565b0381855afa80156104d157610dc5916000916110d5575b506118ec565b604051631da3ddcd60e31b81529460008680610de48760048301611715565b0381855afa9586156104d1576000966110b0575b50610e05610e0b91611947565b42611d34565b946060810151908115159081611092575b50611080575b50600654610e38906001600160a01b0316610acc565b610e4a6001600160a01b038216610acc565b6040516331a9108f60e11b81526004810187905290602090829060249082905afa9081156104d157600091611051575b50306001600160a01b0390911603610ffb575b50600654610ea790610acc9081906001600160a01b031681565b6002546001600160a01b03169390803b1561023a5760405163095ea7b360e01b81526001600160a01b03959095166004860152602485018690526000908590604490829084905af19081156104d1576020948692610fe6575b50600654610f3990610f1a906001600160a01b0316610acc565b91886040519a8b97889687966387d8de3d60e01b885260048801611da2565b039134905af19182156104d15761042293600093610f9f575b5060408051928352602083018490528201527f551698bdc559ecd28afa921d1e208573aaa3115abf7710efcb3dc7bda5e017fb9080606081015b0390a16040519081529081906020820190565b610f8c935091610fde7f551698bdc559ecd28afa921d1e208573aaa3115abf7710efcb3dc7bda5e017fb9360203d60201161082457610816818361062b565b935091610f52565b80610be26000610ff59361062b565b38610f00565b803b1561023a57604051632142170760e11b815233600482015230602482015260448101869052906000908290606490829084905af180156104d15715610e8d5780610be2600061104b9361062b565b38610e8d565b611073915060203d602011611079575b61106b818361062b565b810190611d8d565b38610e7a565b503d611061565b61108c90341015611d41565b38610e22565b608001516110a991506001600160a01b0316610acc565b1538610e1c565b610e0b9196506110cd610e05913d806000833e610b2b818361062b565b969150610df8565b6110ee915060203d60201161079357610785818361062b565b38610dbf565b3461023a57600036600319011261023a576003546040516001600160a01b039091168152602090f35b3461023a57600036600319011261023a576007546040516001600160a01b039091168152602090f35b3461023a57600036600319011261023a576020604051662386f26fc100008152f35b3461023a57606036600319011261023a5760043561118581610287565b60243561119181610287565b6044359161119d6121b4565b6111b16001600160a01b0383161515611635565b6040516370a0823160e01b81523060048201526001600160a01b0382169390602081602481885afa80156104d1576111f4916000916112ae575b50821115611681565b60405163a9059cbb60e01b81526001600160a01b03841660048201526024810182905293602090859060449082906000905af19081156104d157611265610354927ffe8481f63faf91d08f7565991454ae923fc935d8fcb9a3c8334dcb54c7ade0369660009161128f575b50611de3565b604080516001600160a01b0394851681529490931660208501529183019190915281906060820190565b6112a8915060203d60201161079357610785818361062b565b3861125f565b6112c7915060203d60201161082457610816818361062b565b386111eb565b3461023a57602036600319011261023a576004356112ea81610287565b6112f26121b4565b6001600160a01b0381161561136657600280546001600160a01b038381166001600160a01b03198316179092557f8977e98559e29c9185e31021f81f42c435d8fdf093856040aac30d90543a5682929116604080516001600160a01b03928316815292909116602083015281908101610354565b60405162461bcd60e51b8152602060048201526024808201527f476f506c7573206c6f636b65722063616e6e6f74206265207a65726f206164646044820152637265737360e01b6064820152608490fd5b9181601f8401121561023a578235916001600160401b03831161023a576020838186019501011161023a57565b3461023a57606036600319011261023a576004356001600160401b03811161023a576114149036906004016113b7565b90602435906001600160401b03821161023a5760209261143b6114459336906004016113b7565b9160443593611eb4565b6040516001600160a01b039091168152f35b3461023a57602036600319011261023a5760043561147481610287565b61147c6121b4565b6001600160a01b038116156114d257600080546001600160a01b039283166001600160a01b03198216811783559216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3005b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b8060020b0361023a57565b61010036600319011261023a576004356001600160401b03811161023a5761155d9036906004016113b7565b906024356001600160401b03811161023a5761157d9036906004016113b7565b929060443560643561158e81611526565b6084359162ffffff8316830361023a576115bd966115aa610298565b946115b36102a7565b9660e43598611fec565b604080516001600160a01b03939093168352602083019190915290f35b3461023a57602036600319011261023a576004356001600160401b03811161023a573660238201121561023a5780600401356001600160401b03811161023a573660248260051b8401011161023a5760246100199201612139565b1561163c57565b60405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f7420776974686472617720746f207a65726f2061646472657373006044820152606490fd5b1561168857565b60405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606490fd5b3d156116ef573d906116d58261066a565b916116e3604051938461062b565b82523d6000602084013e565b606090565b6040513d6000823e3d90fd5b9081602091031261023a57516106d781610b62565b9060206106d7928181520190610a0a565b9081602091031261023a575190565b51906102a582610287565b60208183031261023a578051906001600160401b03821161023a570160a08183031261023a5760405191611773836105f4565b81516001600160401b03811161023a5782019181601f8401121561023a5782519161179d8361066a565b906117ab604051928361062b565b8382526020848601011161023a576117cf6080936117f595602080850191016109e7565b845260208101516020850152604081015160408501526060810151606085015201611735565b608082015290565b1561180457565b60405162461bcd60e51b815260206004820152601c60248201527f4f776e65722063616e6e6f74206265207a65726f2061646472657373000000006044820152606490fd5b1561185057565b606460405162461bcd60e51b815260206004820152602060248201527f436f6c6c6563746f722063616e6e6f74206265207a65726f20616464726573736044820152fd5b1561189b57565b60405162461bcd60e51b8152602060048201526024808201527f4c6f636b206475726174696f6e206d75737420626520677265617465722074686044820152630616e20360e41b6064820152608490fd5b156118f357565b60405162461bcd60e51b8152602060048201526016602482015275119959481b985b59481b9bdd081cdd5c1c1bdc9d195960521b6044820152606490fd5b634e487b7160e01b600052601160045260246000fd5b906201518082029180830462015180149015171561196157565b611931565b906ffff97272373d413259a46990580e213a8202918083046ffff97272373d413259a46990580e213a149015171561196157565b906ffff2e50f5f656932ef12357cf3c7fdcc8202918083046ffff2e50f5f656932ef12357cf3c7fdcc149015171561196157565b906fffe5caca7e10e4e61c3624eaa0941cd08202918083046fffe5caca7e10e4e61c3624eaa0941cd0149015171561196157565b906fffcb9843d60f6159c9db58835c9266448202918083046fffcb9843d60f6159c9db58835c926644149015171561196157565b906fff973b41fa98c081472e6896dfb254c08202918083046fff973b41fa98c081472e6896dfb254c0149015171561196157565b906fff2ea16466c96a3843ec78b326b528618202918083046fff2ea16466c96a3843ec78b326b52861149015171561196157565b906ffe5dee046a99a2a811c461f1969c30538202918083046ffe5dee046a99a2a811c461f1969c3053149015171561196157565b906ffcbe86c7900a88aedcffc83b479aa3a48202918083046ffcbe86c7900a88aedcffc83b479aa3a4149015171561196157565b906ff987a7253ac413176f2b074cf7815e548202918083046ff987a7253ac413176f2b074cf7815e54149015171561196157565b906ff3392b0822b70005940c7a398e4b70f38202918083046ff3392b0822b70005940c7a398e4b70f3149015171561196157565b906fe7159475a2c29b7443b29c7fa6e889d98202918083046fe7159475a2c29b7443b29c7fa6e889d9149015171561196157565b906fd097f3bdfd2022b8845ad8f792aa58258202918083046fd097f3bdfd2022b8845ad8f792aa5825149015171561196157565b906fa9f746462d870fdf8a65dc1f90e061e58202918083046fa9f746462d870fdf8a65dc1f90e061e5149015171561196157565b906f70d869a156d2a1b890bb3df62baf32f78202918083046f70d869a156d2a1b890bb3df62baf32f7149015171561196157565b906f31be135f97d08fd981231505542fcfa68202918083046f31be135f97d08fd981231505542fcfa6149015171561196157565b906f09aa508b5b7a84e1c677de54f3e99bc98202918083046f09aa508b5b7a84e1c677de54f3e99bc9149015171561196157565b906e5d6af8dedb81196699c329225ee6048202918083046e5d6af8dedb81196699c329225ee604149015171561196157565b906d2216e584f5fa1ea926041bedfe988202918083046d2216e584f5fa1ea926041bedfe98149015171561196157565b906b048a170391f7dc42444e8fa28202918083046b048a170391f7dc42444e8fa2149015171561196157565b9190820180921161196157565b15611d4857565b60405162461bcd60e51b815260206004820152601d60248201527f496e73756666696369656e742045544820666f72206c6f636b206665650000006044820152606490fd5b9081602091031261023a57516106d781610287565b6001600160a01b0391821681526020810192909252918216604082015291166060820152608081019190915260c060a082018190526106d792910190610a0a565b15611dea57565b60405162461bcd60e51b8152602060048201526015602482015274151bdad95b881d1c985b9cd9995c8819985a5b1959605a1b6044820152606490fd5b908060209392818452848401376000828201840152601f01601f1916010190565b949695929093611e66606095611e7494608089526080890191611e27565b918683036020880152611e27565b60408401959095526001600160a01b0316910152565b90611e9d602092828151948592016109e7565b0190565b61ffff1661ffff81146119615760010190565b611f1a9291611ef2611f0092611ef29697610d3c98611ed560208b0161065c565b99808b5261366e60208c0139604051968795309460208801611e48565b03601f19810183528261062b565b604051928391611f14602084018097611e8a565b90611e8a565b519020600454600190611f3790610acc906001600160a01b031681565b905b61ffff811660648111611fc257604080513360208201908152918101839052611f73918691611f6b8160608101611ef2565b51902061220c565b906001600160a01b0382168411611f94575050611f8f90611ea1565b611f39565b6040805161ffff94909416845260208401919091529093506000805160206143ca833981519152925090a190565b50506040805133602082019081526001928201929092526106d7939250611f6b8160608101611ef2565b999895949796929099611ffd61224e565b6040519a61200a8c61060f565b369061201592610685565b8a52369061202292610685565b602089019081526040890183815260029790970b60608a0181815262ffffff9590951660808b018181526001600160a01b0394851660a08d019081529890941660c08c0181815260e08d01898152979a90999098949796909594612087949392612514565b89518551875189516001600160a01b0316908751926120a5946127d5565b975160020b915162ffffff166120bb928961297d565b81519098906001600160a01b03166120d3908a612e42565b519251935194516001600160a01b031691516001546001600160a01b031691516001600160a01b0316926040519687963396612111978d8c8b612295565b037fe066edb1db52f98a38d68a78bc2ca9bab37ef397ba8fd5929a2b4ecb672ab4c091a19190565b6001546001600160a01b031691823b1561023a57604051631eabaee560e31b81526020600482015260248101829052926001600160fb1b03821161023a578360006044828296819660051b80918484013781010301925af180156104d15761219e5750565b806121ab6000809361062b565b80031261023a57565b6000546001600160a01b031633036121c857565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b60405191602083019160ff60f81b83523060601b6021850152603584015260558301526055825261223e60758361062b565b905190206001600160a01b031690565b60ff60005460a01c1661225d57565b60405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606490fd5b98959a9996936122e6936101209996936122d89360018060a01b03168c5260208c015260018060a01b031660408b015261014060608b01526101408a0190610a0a565b9088820360808a0152610a0a565b60a08701989098526001600160a01b0390811660c087015260e086019190915290811661010085015216910152565b1561231c57565b60405162461bcd60e51b815260206004820152602860248201527f4465706c6f796d656e7420666565206d757374206265206174206c65617374206044820152670605c6062408aa8960c31b6064820152608490fd5b1561237957565b60405162461bcd60e51b815260206004820152602660248201527f526563697069656e74206d75737420626520746865207265717569726564206160448201526564647265737360d01b6064820152608490fd5b156123d457565b60405162461bcd60e51b815260206004820152601f60248201527f526563697069656e7420616d6f756e74206578636565647320737570706c79006044820152606490fd5b9081602091031261023a57516106d781611526565b634e487b7160e01b600052601260045260246000fd5b9060020b9081156124565760020b0790565b61242e565b1561246257565b60405162461bcd60e51b815260206004820152601c60248201527f496e76616c6964207469636b206f72207469636b2073706163696e67000000006044820152606490fd5b65b5e620f47fff1981019190821161196157565b9190820391821161196157565b156124cf57565b60405162461bcd60e51b815260206004820152601c60248201527f50726f746f636f6c20666565207472616e73666572206661696c6564000000006044820152606490fd5b949392916020612605936000805160206143aa8339815191526040518061257f8160809060208152602960208201527f5374617274696e67206465706c6f79546f6b656e2077697468204e46544175746040820152686f4c6f636b6572563560b81b60608201520190565b0390a1612595662386f26fc10000341015612315565b6125bd6001600160a01b03891673c5c216e6e60cce2d189bcce5f6ebffde1e8ce92614612372565b6125c9838511156123cd565b6005546125de906001600160a01b0316610acc565b60405180809781946322afcccb60e01b83526004830191909162ffffff6020820193169052565b03915afa9283156104d15765b5e620f4800061264d6000959486959461264861265e99889788978891612730575b508060020b15159182612713575b505061245b565b6124bb565b975af16126586116c4565b506124c8565b7f1fe20b63cae31fc9f78c0bef12d650e5d82cbb98b7c1d17096830cfff47c6bf86126af61268b346124a7565b6040805134815265b5e620f480006020820152908101919091529081906060820190565b0390a16000805160206143aa8339815191526040518061270e8160809060208152602460208201527f56616c69646174696f6e20616e64206665652068616e646c696e6720636f6d706040820152636c65746560e01b60608201520190565b0390a1565b61272892509061272291612444565b60020b90565b153880612641565b612752915060203d602011612758575b61274a818361062b565b810190612419565b38612633565b503d612740565b9294939060609261277b611e7492608087526080870190610a0a565b908582036020870152610a0a565b1561279057565b60405162461bcd60e51b815260206004820152601760248201527f546f6b656e206465706c6f796d656e74206661696c65640000000000000000006044820152606490fd5b9091612822611ef29196959496611f006127f0828787612ff6565b5095611ef2610d3c966128056020890161065c565b9780895261366e60208a013960405194859330926020860161275f565b51906000f5926001600160a01b0384169161283e831515612789565b806128ac575b50506040805181815260119181019190915270151bdad95b8819195c1b1bde595908185d607a1b60608201526001600160a01b03841660208201527fb3f7d6c63a62ab0e6ae5263ef1deb9c5a64f4689288c380db949c116314a55409150806080810161270e565b60405163a9059cbb60e01b81526001600160a01b03929092166004830152602482015290602090829060449082906000905af180156104d1576128f69160009161128f5750611de3565b388080612844565b1561290557565b60405162461bcd60e51b8152602060048201526015602482015274151bdad95b88185c1c1c9bdd985b0819985a5b1959605a1b6044820152606490fd5b919082608091031261023a5781519160208101516fffffffffffffffffffffffffffffffff8116810361023a57916060604083015192015190565b926129878261335d565b6005546129f59060209086906129a5906001600160a01b0316610acc565b6004546001600160a01b031660405163a167129560e01b81526001600160a01b03808c166004830152909116602482015262ffffff90921660448301529092839190829060009082906064820190565b03925af19081156104d157600091612d6d575b506001600160a01b0316803b1561023a5760405163f637731d60e01b81526001600160a01b039290921660048301526000908290602490829084905af180156104d157612d58575b50600554612a66906001600160a01b0316610acc565b6040516322afcccb60e01b815262ffffff851660048201529290602090849060249082905afa9283156104d157612b90946020948793612b1893600092612d33575b50612b04612b0e9293612af8612ace612ac860045460018060a01b031690565b96613642565b95612ae9612ada61064c565b6001600160a01b03909e168e52565b6001600160a01b03168c8b0152565b62ffffff1660408b0152565b60020b6060890152565b60020b6080870152565b60a08501829052600060c0860181905260e086018190526101008601523061012086015242610140860152600654612b58906001600160a01b0316610acc565b60405163095ea7b360e01b81526001600160a01b03909116600482015260248101929092529092839190829060009082906044820190565b03926001600160a01b03165af180156104d157600092612bbd612c7e926080948691612d14575b506128fe565b600654612bd2906001600160a01b0316610acc565b60408051634418b22b60e11b815283516001600160a01b0390811660048301526020850151811660248301529184015162ffffff1660448201526060840151600290810b60648301526080850151900b608482015260a084015160a482015260c084015160c482015260e084015160e482015261010084015161010482015261012084015190911661012482015261014090920151610144830152909384928391908290610164820190565b03925af19081156104d157600091612ce2575b50906000805160206143aa8339815191526040518061270e8160609060208152601960208201527f506f6f6c20616e6420706f736974696f6e20637265617465640000000000000060408201520190565b612d04915060803d608011612d0d575b612cfc818361062b565b810190612942565b50505038612c91565b503d612cf2565b612d2d915060203d60201161079357610785818361062b565b38612bb7565b612b0e9250612d51612b0491893d8b116127585761274a818361062b565b9250612aa8565b80610be26000612d679361062b565b38612a50565b612d86915060203d6020116110795761106b818361062b565b38612a08565b15612d9357565b60405162461bcd60e51b8152602060048201526024808201527f46656520726563697069656e742063616e6e6f74206265207a65726f206164646044820152637265737360e01b6064820152608490fd5b15612deb57565b60405162461bcd60e51b815260206004820152602960248201527f46656520726563697069656e7420636f6e74726163742063616e6e6f742072656044820152680c6cad2ecca408aa8960bb1b6064820152608490fd5b90612e576001600160a01b0382161515612d8c565b803b612faf575b600154612e7590610acc906001600160a01b031681565b803b1561023a57604051633dc4139960e11b8152600481018490526001600160a01b039290921660248301526000908290604490829084905af180156104d157612f9a575b50600654612ed0906001600160a01b0316610acc565b6001549091906001600160a01b031690823b1561023a57604051632142170760e11b81523060048201526001600160a01b039290921660248301526044820152906000908290606490829084905af180156104d157612f85575b506000805160206143aa8339815191526040518061270e8160809060208152602260208201527f4e4654207472616e7366657272656420746f204e46544175746f4c6f636b6572604082015261563560f01b60608201520190565b80610be26000612f949361062b565b38612f2a565b80610be26000612fa99361062b565b38612eba565b612fc9600080808080865af1612fc36116c4565b50612de4565b612e5e565b61ffff16612710019061ffff821161196157565b61ffff16614e20019061ffff821161196157565b9161301590611f00611ef293611ef2610d3c966128056020890161065c565b5190206004546001929061303390610acc906001600160a01b031681565b925b61ffff811661138881116130c8576040805133602082019081529181018390526130628160608101611ef2565b51902061306f858261220c565b916001600160a01b03831687116130915750505061308c90611ea1565b613035565b6040805161ffff909516855260208501919091529195509293506000805160206143ca8339815191529190819081015b0390a19190565b505091909160005b61012c61ffff82161061322b575060005b6103e861ffff8216106131505760405162461bcd60e51b815260206004820152603460248201527f436f756c64206e6f742066696e642076616c69642073616c74202d2074727920604482015273646966666572656e7420746f6b656e206e616d6560601b6064820152608490fd5b60408051426020820190815261ffff8416928201929092526131758160608101611ef2565b51902060408051336020820190815291810192909252906131998160608101611ef2565b5190206131a6858261220c565b906001600160a01b03821685116131c557505060010161ffff166130e1565b9293509350806131e36000805160206143ca83398151915292612fe2565b9060405161320b81611ef26020820194428690929161ffff6020916040840195845216910152565b5190206040805161ffff90931683526020830191909152819081016130c1565b604080514260208201908152439282019290925261ffff831660608201526132568160808101611ef2565b519020604080513360208201908152918101929092529061327a8160608101611ef2565b519020613287858261220c565b906001600160a01b03821685116132a657505060010161ffff166130d0565b9293509350806132c46000805160206143ca83398151915292612fce565b9060405161320b81611ef2602082019443428791604091949361ffff9160608501968552602085015216910152565b600160ff1b81146119615760000390565b1561330b57565b60405162461bcd60e51b815260206004820152601b60248201527f5469636b4d6174683a205449434b5f4f55545f4f465f52414e474500000000006044820152606490fd5b8015612456576000190490565b610acc6106d79160020b6000811260001461363c5761337b816132f3565b905b61338c620d89e8831115613304565b600182161561362a576001600160881b036ffffcb933bd6fad37aa2d162d1a5940015b169160028116613617575b60048116613604575b600881166135f1575b601081166135de575b602081166135cb575b604081166135b8575b608081166135a5575b6101008116613592575b610200811661357f575b610400811661356c575b6108008116613559575b6110008116613546575b6120008116613533575b6140008116613520575b618000811661350d575b6201000081166134fa575b6202000081166134e7575b6204000081166134ce575b62080000166134b1575b6000126134a3575b61348a6134808260201c90565b9163ffffffff1690565b61349a5760ff60005b1690611d34565b60ff6001613493565b6134ac90613350565b613473565b906134c66134c0600092611d08565b60801c90565b91905061346b565b916134df6134c06208000092611cd8565b929050613461565b916134c06134f491611ca6565b91613456565b916134c061350791611c72565b9161344b565b916134c061351a91611c3e565b91613440565b916134c061352d91611c0a565b91613436565b916134c061354091611bd6565b9161342c565b916134c061355391611ba2565b91613422565b916134c061356691611b6e565b91613418565b916134c061357991611b3a565b9161340e565b916134c061358c91611b06565b91613404565b916134c061359f91611ad2565b916133fa565b916134c06135b291611a9e565b916133f0565b916134c06135c591611a6a565b916133e7565b916134c06135d891611a36565b916133de565b916134c06135eb91611a02565b916133d5565b916134c06135fe916119ce565b916133cc565b916134c06136119161199a565b916133c3565b916134c061362491611966565b916133ba565b6001600160881b03600160801b6133af565b8061337d565b60020b801561245657620d89e80760020b620d89e803627fffff8113627fffff19821217611961579056fe6080604052346103fa57610d3c80380380610019816103ff565b9283398101906080818303126103fa5780516001600160401b0381116103fa5782610045918301610424565b602082015190926001600160401b0382116103fa57610065918301610424565b604082015160609092015190916001600160a01b038216918290036103fa5783516001600160401b03811161030357600354600181811c911680156103f0575b60208210146102e357601f811161038b575b50602094601f821160011461032457948192939495600092610319575b50508160011b916000199060031b1c1916176003555b82516001600160401b03811161030357600454600181811c911680156102f9575b60208210146102e357601f811161027e575b506020601f8211600114610217578192939460009261020c575b50508160011b916000199060031b1c1916176004555b81156101c757600254908082018092116101b15760207fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9160009360025584845283825260408420818154019055604051908152a36040516108ac90816104908239f35b634e487b7160e01b600052601160045260246000fd5b60405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606490fd5b015190503880610137565b601f198216906004600052806000209160005b8181106102665750958360019596971061024d575b505050811b0160045561014d565b015160001960f88460031b161c1916905538808061023f565b9192602060018192868b01518155019401920161022a565b60046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c810191602084106102d9575b601f0160051c01905b8181106102cd575061011d565b600081556001016102c0565b90915081906102b7565b634e487b7160e01b600052602260045260246000fd5b90607f169061010b565b634e487b7160e01b600052604160045260246000fd5b0151905038806100d4565b601f198216956003600052806000209160005b8881106103735750836001959697981061035a575b505050811b016003556100ea565b015160001960f88460031b161c1916905538808061034c565b91926020600181928685015181550194019201610337565b60036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c810191602084106103e6575b601f0160051c01905b8181106103da57506100b7565b600081556001016103cd565b90915081906103c4565b90607f16906100a5565b600080fd5b6040519190601f01601f191682016001600160401b0381118382101761030357604052565b81601f820112156103fa578051906001600160401b03821161030357610453601f8301601f19166020016103ff565b92828452602083830101116103fa5760005b82811061047a57505060206000918301015290565b8060208092840101518282870101520161046556fe608080604052600436101561001357600080fd5b60003560e01c90816306fdde03146104a757508063095ea7b31461048157806318160ddd1461046357806323b872dd146103a5578063313ce56714610389578063395093511461032157806370a08231146102e757806395d89b41146101c6578063a457c2d71461011f578063a9059cbb146100ee5763dd62ed3e1461009857600080fd5b346100e95760403660031901126100e9576100b16105c3565b6100b96105d9565b6001600160a01b039182166000908152600160209081526040808320949093168252928352819020549051908152f35b600080fd5b346100e95760403660031901126100e95761011461010a6105c3565b60243590336106f7565b602060405160018152f35b346100e95760403660031901126100e9576101386105c3565b60243590336000526001602052604060002060018060a01b0382166000526020526040600020549180831061017357610114920390336105ef565b60405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608490fd5b346100e95760003660031901126100e95760405160006004548060011c906001811680156102dd575b6020831081146102c9578285529081156102ad5750600114610256575b50819003601f01601f191681019067ffffffffffffffff8211818310176102405761023c8291826040528261057a565b0390f35b634e487b7160e01b600052604160045260246000fd5b905060046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b6000905b8282106102975750602091508201018261020c565b6001816020925483858801015201910190610282565b90506020925060ff191682840152151560051b8201018261020c565b634e487b7160e01b84526022600452602484fd5b91607f16916101ef565b346100e95760203660031901126100e9576001600160a01b036103086105c3565b1660005260006020526020604060002054604051908152f35b346100e95760403660031901126100e95761033a6105c3565b336000526001602052604060002060018060a01b03821660005260205260406000205460243581018091116103735761011491336105ef565b634e487b7160e01b600052601160045260246000fd5b346100e95760003660031901126100e957602060405160128152f35b346100e95760603660031901126100e9576103be6105c3565b6103c66105d9565b6001600160a01b0382166000908152600160208181526040808420338552909152909120549260443592918401610402575b61011493506106f7565b82841061041e5761041983610114950333836105ef565b6103f8565b60405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606490fd5b346100e95760003660031901126100e9576020600254604051908152f35b346100e95760403660031901126100e95761011461049d6105c3565b60243590336105ef565b346100e95760003660031901126100e95760006003548060011c90600181168015610570575b6020831081146102c9578285529081156102ad57506001146105195750819003601f01601f191681019067ffffffffffffffff8211818310176102405761023c8291826040528261057a565b905060036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b6000905b82821061055a5750602091508201018261020c565b6001816020925483858801015201910190610545565b91607f16916104cd565b91909160208152825180602083015260005b8181106105ad575060409293506000838284010152601f8019910116010190565b806020809287010151604082860101520161058c565b600435906001600160a01b03821682036100e957565b602435906001600160a01b03821682036100e957565b6001600160a01b03169081156106a6576001600160a01b03169182156106565760207f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925918360005260018252604060002085600052825280604060002055604051908152a3565b60405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608490fd5b60405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608490fd5b6001600160a01b0316908115610823576001600160a01b03169182156107d25781600052600060205260406000205481811061077e57817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9260209285600052600084520360406000205584600052600082526040600020818154019055604051908152a3565b60405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608490fd5b60405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608490fd5b60405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608490fdfea264697066735822122074ff4234c658f74e187510519776b8ea4e39b5c6743b1caeebf48be4c2f0270464736f6c634300081a003394ebca8d29d278a0288a52a710c11e928307b6f2e15fbaf4508cc4ceb3d21f8b2d85e5bc21a27644fa43503d10d34b03fef575277be4ae9f6da8f6f484ab0652a2646970667358221220fc89f062f0f16d35043a568f1cacb772d61a3999b149b553636a8c30706af53264736f6c634300081a0033000000000000000000000000c5c216e6e60cce2d189bcce5f6ebffde1e8ce926000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f984000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe88000000000000000000000000e592427a0aece92de3edee1f18e0157c058615640000000000000000000000000fa69466d99880fb6db58775343bd214f58c98b000000000000000000000000025c9c4b56e820e0dea438b145284f02d9ca9bd52
Deployed Bytecode
0x6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c806202eab71461022a578062a04feb146102255780630150b5db14610220578063058e58341461021b5780630b4501fd1461021657806317508637146101f85780632f9c02b61461021157806334dea1691461020c5780633a5642f4146102075780633f4ba83a146102025780633fc8cef3146101fd578063477f6e42146101f85780634e9c8927146101e45780635b549182146101f35780635c975abb146101c6578063715018a6146101ee5780637192c566146101e95780637919dd34146101e4578063791b98bc146101df578063803bfb0a146101da5780638456cb59146101d55780638da5cb5b146101d0578063b17acdcd146101cb578063b187bd26146101c6578063b5989102146101c1578063bea1dcf8146101bc578063c31c9c07146101b7578063d55ac27f146101b2578063d63f4594146101ad578063dbd96fa3146101a8578063eab1f410146101a3578063f2fde38b1461019e578063f45fc718146101995763f55d77280361000e576115da565b611531565b611457565b6113e4565b6112cd565b611168565b611146565b61111d565b6110f4565b610cf5565b610968565b610c99565b610c70565b610be8565b610b6c565b610b39565b610916565b610a7b565b61098e565b61093f565b610526565b6108ed565b61082b565b61079a565b610704565b61054f565b610505565b6104d6565b6103ce565b6102b4565b61023f565b600091031261023a57565b600080fd5b3461023a57600036600319011261023a576060604051662386f26fc10000815265b5e620f48000602082015273c5c216e6e60cce2d189bcce5f6ebffde1e8ce9266040820152f35b6001600160a01b0381160361023a57565b60a435906102a582610287565b565b60c435906102a582610287565b3461023a57604036600319011261023a576004356102d181610287565b6024356102dc6121b4565b6102f06001600160a01b0383161515611635565b6102fc47821115611681565b600080808084865af161030d6116c4565b501561035957604080516001600160a01b03909316835260208301919091527fc8509a63402c5fc92474eaf55ef1d99608b69605f3e4a4a29dfafff277f9e9d79190819081015b0390a1005b60405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152606490fd5b602060408183019282815284518094520192019060005b8181106103b85750505090565b82518452602093840193909201916001016103ab565b3461023a57600036600319011261023a57600154604051630150b5db60e01b815290600090829060049082906001600160a01b03165afa9081156104d157600091610426575b604051806104228482610394565b0390f35b3d8083833e610435818361062b565b8101906020818303126104c9578051906001600160401b0382116104cd570181601f820112156104c9578051926001600160401b0384116104c4578360051b9160405194610486602085018761062b565b85526020808601938201019384116104c057602001915b8383106104b05750505050610422610414565b825181526020928301920161049d565b5080fd5b6105de565b8280fd5b8380fd5b6116f4565b3461023a57600036600319011261023a57602060405173c5c216e6e60cce2d189bcce5f6ebffde1e8ce9268152f35b3461023a57600036600319011261023a57602060405165b5e620f480008152f35b3461023a57600036600319011261023a576001546040516001600160a01b039091168152602090f35b3461023a57600060403660031901126105db5760043561056e81610287565b8160243561057a6121b4565b6001546001600160a01b0316803b156104c957604051634782f77960e01b81526001600160a01b0394909416600485015260248401919091528290604490829084905af180156104d15782906105cd5780f35b6105d69161062b565b388180f35b80fd5b634e487b7160e01b600052604160045260246000fd5b60a081019081106001600160401b038211176104c457604052565b61010081019081106001600160401b038211176104c457604052565b90601f801991011681019081106001600160401b038211176104c457604052565b604051906102a56101608361062b565b906102a5604051928361062b565b6001600160401b0381116104c457601f01601f191660200190565b9291926106918261066a565b9161069f604051938461062b565b82948184528183011161023a578281602093846000960137010152565b9080601f8301121561023a578160206106d793359101610685565b90565b602060031982011261023a57600435906001600160401b03821161023a576106d7916004016106bc565b3461023a576107426020610717366106da565b60018060a01b0360025416604051808095819462beb0b560e51b835286600484018181520190610a0a565b03915afa80156104d1576104229160009161076b575b5060405190151581529081906020820190565b61078d915060203d602011610793575b610785818361062b565b810190611700565b38610758565b503d61077b565b3461023a57602036600319011261023a5760015460405163232633a360e11b8152600480359082015290602090829060249082906001600160a01b03165afa80156104d157610422916000916107fc575b506040519081529081906020820190565b61081e915060203d602011610824575b610816818361062b565b810190611726565b386107eb565b503d61080c565b3461023a57600036600319011261023a576108446121b4565b60005460ff8160a01c16156108b15760ff60a01b19166000556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa90602090a1337f5b65b0c1363b3003db9bcc5e1fd8805a6d6bf5bf6dc9d3431ee4494cd7d11766600080a2005b60405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606490fd5b3461023a57600036600319011261023a576004546040516001600160a01b039091168152602090f35b3461023a57600036600319011261023a576002546040516001600160a01b039091168152602090f35b3461023a57600036600319011261023a576005546040516001600160a01b039091168152602090f35b3461023a57600036600319011261023a57602060ff60005460a01c166040519015158152f35b3461023a57600036600319011261023a576109a76121b4565b600080546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b60005b8381106109fa5750506000910152565b81810151838201526020016109ea565b90602091610a23815180928185528580860191016109e7565b601f01601f1916010190565b6020815260a0610a4a835182602085015260c0840190610a0a565b926020810151604084015260408101516060840152606081015160808401526080600180841b039101511691015290565b3461023a57610af36000610a8e366106da565b816080604051610a9d816105f4565b606081528260208201528260408201528260608201520152610ad8610acc610acc60025460018060a01b031690565b6001600160a01b031690565b6040518080958194631da3ddcd60e31b835260048301611715565b03915afa80156104d15761042291600091610b16575b5060405191829182610a2f565b610b3391503d806000833e610b2b818361062b565b810190611740565b38610b09565b3461023a57600036600319011261023a576006546040516001600160a01b039091168152602090f35b8015150361023a57565b3461023a57602036600319011261023a57600435610b8981610b62565b610b916121b4565b6001546001600160a01b031690813b1561023a5760009160248392604051948593849263401dfd8560e11b8452151560048401525af180156104d157610bd357005b80610be260006100199361062b565b8061022f565b3461023a57600036600319011261023a57610c016121b4565b610c0961224e565b6000805460ff60a01b1916600160a01b1790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602090a1337f81990fd9a5c552b8e3677917d8a03c07678f0d2cb68f88b634aca2022e9bd19f600080a2005b3461023a57600036600319011261023a576000546040516001600160a01b039091168152602090f35b3461023a57600060203660031901126105db576001548190600435906001600160a01b0316803b15610cf15760248392604051948593849263b17acdcd60e01b845260048401525af180156104d15782906105cd5780f35b5050fd5b60a036600319011261023a57600435602435610d1081610287565b60443591610d1d83610287565b606435916084356001600160401b03811161023a57610d409036906004016106bc565b90610d556001600160a01b03821615156117fd565b610d696001600160a01b0386161515611849565b610d74841515611894565b600254610d8b90610acc906001600160a01b031681565b60405162beb0b560e51b815260208180610da88760048301611715565b0381855afa80156104d157610dc5916000916110d5575b506118ec565b604051631da3ddcd60e31b81529460008680610de48760048301611715565b0381855afa9586156104d1576000966110b0575b50610e05610e0b91611947565b42611d34565b946060810151908115159081611092575b50611080575b50600654610e38906001600160a01b0316610acc565b610e4a6001600160a01b038216610acc565b6040516331a9108f60e11b81526004810187905290602090829060249082905afa9081156104d157600091611051575b50306001600160a01b0390911603610ffb575b50600654610ea790610acc9081906001600160a01b031681565b6002546001600160a01b03169390803b1561023a5760405163095ea7b360e01b81526001600160a01b03959095166004860152602485018690526000908590604490829084905af19081156104d1576020948692610fe6575b50600654610f3990610f1a906001600160a01b0316610acc565b91886040519a8b97889687966387d8de3d60e01b885260048801611da2565b039134905af19182156104d15761042293600093610f9f575b5060408051928352602083018490528201527f551698bdc559ecd28afa921d1e208573aaa3115abf7710efcb3dc7bda5e017fb9080606081015b0390a16040519081529081906020820190565b610f8c935091610fde7f551698bdc559ecd28afa921d1e208573aaa3115abf7710efcb3dc7bda5e017fb9360203d60201161082457610816818361062b565b935091610f52565b80610be26000610ff59361062b565b38610f00565b803b1561023a57604051632142170760e11b815233600482015230602482015260448101869052906000908290606490829084905af180156104d15715610e8d5780610be2600061104b9361062b565b38610e8d565b611073915060203d602011611079575b61106b818361062b565b810190611d8d565b38610e7a565b503d611061565b61108c90341015611d41565b38610e22565b608001516110a991506001600160a01b0316610acc565b1538610e1c565b610e0b9196506110cd610e05913d806000833e610b2b818361062b565b969150610df8565b6110ee915060203d60201161079357610785818361062b565b38610dbf565b3461023a57600036600319011261023a576003546040516001600160a01b039091168152602090f35b3461023a57600036600319011261023a576007546040516001600160a01b039091168152602090f35b3461023a57600036600319011261023a576020604051662386f26fc100008152f35b3461023a57606036600319011261023a5760043561118581610287565b60243561119181610287565b6044359161119d6121b4565b6111b16001600160a01b0383161515611635565b6040516370a0823160e01b81523060048201526001600160a01b0382169390602081602481885afa80156104d1576111f4916000916112ae575b50821115611681565b60405163a9059cbb60e01b81526001600160a01b03841660048201526024810182905293602090859060449082906000905af19081156104d157611265610354927ffe8481f63faf91d08f7565991454ae923fc935d8fcb9a3c8334dcb54c7ade0369660009161128f575b50611de3565b604080516001600160a01b0394851681529490931660208501529183019190915281906060820190565b6112a8915060203d60201161079357610785818361062b565b3861125f565b6112c7915060203d60201161082457610816818361062b565b386111eb565b3461023a57602036600319011261023a576004356112ea81610287565b6112f26121b4565b6001600160a01b0381161561136657600280546001600160a01b038381166001600160a01b03198316179092557f8977e98559e29c9185e31021f81f42c435d8fdf093856040aac30d90543a5682929116604080516001600160a01b03928316815292909116602083015281908101610354565b60405162461bcd60e51b8152602060048201526024808201527f476f506c7573206c6f636b65722063616e6e6f74206265207a65726f206164646044820152637265737360e01b6064820152608490fd5b9181601f8401121561023a578235916001600160401b03831161023a576020838186019501011161023a57565b3461023a57606036600319011261023a576004356001600160401b03811161023a576114149036906004016113b7565b90602435906001600160401b03821161023a5760209261143b6114459336906004016113b7565b9160443593611eb4565b6040516001600160a01b039091168152f35b3461023a57602036600319011261023a5760043561147481610287565b61147c6121b4565b6001600160a01b038116156114d257600080546001600160a01b039283166001600160a01b03198216811783559216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3005b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b8060020b0361023a57565b61010036600319011261023a576004356001600160401b03811161023a5761155d9036906004016113b7565b906024356001600160401b03811161023a5761157d9036906004016113b7565b929060443560643561158e81611526565b6084359162ffffff8316830361023a576115bd966115aa610298565b946115b36102a7565b9660e43598611fec565b604080516001600160a01b03939093168352602083019190915290f35b3461023a57602036600319011261023a576004356001600160401b03811161023a573660238201121561023a5780600401356001600160401b03811161023a573660248260051b8401011161023a5760246100199201612139565b1561163c57565b60405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f7420776974686472617720746f207a65726f2061646472657373006044820152606490fd5b1561168857565b60405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606490fd5b3d156116ef573d906116d58261066a565b916116e3604051938461062b565b82523d6000602084013e565b606090565b6040513d6000823e3d90fd5b9081602091031261023a57516106d781610b62565b9060206106d7928181520190610a0a565b9081602091031261023a575190565b51906102a582610287565b60208183031261023a578051906001600160401b03821161023a570160a08183031261023a5760405191611773836105f4565b81516001600160401b03811161023a5782019181601f8401121561023a5782519161179d8361066a565b906117ab604051928361062b565b8382526020848601011161023a576117cf6080936117f595602080850191016109e7565b845260208101516020850152604081015160408501526060810151606085015201611735565b608082015290565b1561180457565b60405162461bcd60e51b815260206004820152601c60248201527f4f776e65722063616e6e6f74206265207a65726f2061646472657373000000006044820152606490fd5b1561185057565b606460405162461bcd60e51b815260206004820152602060248201527f436f6c6c6563746f722063616e6e6f74206265207a65726f20616464726573736044820152fd5b1561189b57565b60405162461bcd60e51b8152602060048201526024808201527f4c6f636b206475726174696f6e206d75737420626520677265617465722074686044820152630616e20360e41b6064820152608490fd5b156118f357565b60405162461bcd60e51b8152602060048201526016602482015275119959481b985b59481b9bdd081cdd5c1c1bdc9d195960521b6044820152606490fd5b634e487b7160e01b600052601160045260246000fd5b906201518082029180830462015180149015171561196157565b611931565b906ffff97272373d413259a46990580e213a8202918083046ffff97272373d413259a46990580e213a149015171561196157565b906ffff2e50f5f656932ef12357cf3c7fdcc8202918083046ffff2e50f5f656932ef12357cf3c7fdcc149015171561196157565b906fffe5caca7e10e4e61c3624eaa0941cd08202918083046fffe5caca7e10e4e61c3624eaa0941cd0149015171561196157565b906fffcb9843d60f6159c9db58835c9266448202918083046fffcb9843d60f6159c9db58835c926644149015171561196157565b906fff973b41fa98c081472e6896dfb254c08202918083046fff973b41fa98c081472e6896dfb254c0149015171561196157565b906fff2ea16466c96a3843ec78b326b528618202918083046fff2ea16466c96a3843ec78b326b52861149015171561196157565b906ffe5dee046a99a2a811c461f1969c30538202918083046ffe5dee046a99a2a811c461f1969c3053149015171561196157565b906ffcbe86c7900a88aedcffc83b479aa3a48202918083046ffcbe86c7900a88aedcffc83b479aa3a4149015171561196157565b906ff987a7253ac413176f2b074cf7815e548202918083046ff987a7253ac413176f2b074cf7815e54149015171561196157565b906ff3392b0822b70005940c7a398e4b70f38202918083046ff3392b0822b70005940c7a398e4b70f3149015171561196157565b906fe7159475a2c29b7443b29c7fa6e889d98202918083046fe7159475a2c29b7443b29c7fa6e889d9149015171561196157565b906fd097f3bdfd2022b8845ad8f792aa58258202918083046fd097f3bdfd2022b8845ad8f792aa5825149015171561196157565b906fa9f746462d870fdf8a65dc1f90e061e58202918083046fa9f746462d870fdf8a65dc1f90e061e5149015171561196157565b906f70d869a156d2a1b890bb3df62baf32f78202918083046f70d869a156d2a1b890bb3df62baf32f7149015171561196157565b906f31be135f97d08fd981231505542fcfa68202918083046f31be135f97d08fd981231505542fcfa6149015171561196157565b906f09aa508b5b7a84e1c677de54f3e99bc98202918083046f09aa508b5b7a84e1c677de54f3e99bc9149015171561196157565b906e5d6af8dedb81196699c329225ee6048202918083046e5d6af8dedb81196699c329225ee604149015171561196157565b906d2216e584f5fa1ea926041bedfe988202918083046d2216e584f5fa1ea926041bedfe98149015171561196157565b906b048a170391f7dc42444e8fa28202918083046b048a170391f7dc42444e8fa2149015171561196157565b9190820180921161196157565b15611d4857565b60405162461bcd60e51b815260206004820152601d60248201527f496e73756666696369656e742045544820666f72206c6f636b206665650000006044820152606490fd5b9081602091031261023a57516106d781610287565b6001600160a01b0391821681526020810192909252918216604082015291166060820152608081019190915260c060a082018190526106d792910190610a0a565b15611dea57565b60405162461bcd60e51b8152602060048201526015602482015274151bdad95b881d1c985b9cd9995c8819985a5b1959605a1b6044820152606490fd5b908060209392818452848401376000828201840152601f01601f1916010190565b949695929093611e66606095611e7494608089526080890191611e27565b918683036020880152611e27565b60408401959095526001600160a01b0316910152565b90611e9d602092828151948592016109e7565b0190565b61ffff1661ffff81146119615760010190565b611f1a9291611ef2611f0092611ef29697610d3c98611ed560208b0161065c565b99808b5261366e60208c0139604051968795309460208801611e48565b03601f19810183528261062b565b604051928391611f14602084018097611e8a565b90611e8a565b519020600454600190611f3790610acc906001600160a01b031681565b905b61ffff811660648111611fc257604080513360208201908152918101839052611f73918691611f6b8160608101611ef2565b51902061220c565b906001600160a01b0382168411611f94575050611f8f90611ea1565b611f39565b6040805161ffff94909416845260208401919091529093506000805160206143ca833981519152925090a190565b50506040805133602082019081526001928201929092526106d7939250611f6b8160608101611ef2565b999895949796929099611ffd61224e565b6040519a61200a8c61060f565b369061201592610685565b8a52369061202292610685565b602089019081526040890183815260029790970b60608a0181815262ffffff9590951660808b018181526001600160a01b0394851660a08d019081529890941660c08c0181815260e08d01898152979a90999098949796909594612087949392612514565b89518551875189516001600160a01b0316908751926120a5946127d5565b975160020b915162ffffff166120bb928961297d565b81519098906001600160a01b03166120d3908a612e42565b519251935194516001600160a01b031691516001546001600160a01b031691516001600160a01b0316926040519687963396612111978d8c8b612295565b037fe066edb1db52f98a38d68a78bc2ca9bab37ef397ba8fd5929a2b4ecb672ab4c091a19190565b6001546001600160a01b031691823b1561023a57604051631eabaee560e31b81526020600482015260248101829052926001600160fb1b03821161023a578360006044828296819660051b80918484013781010301925af180156104d15761219e5750565b806121ab6000809361062b565b80031261023a57565b6000546001600160a01b031633036121c857565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b60405191602083019160ff60f81b83523060601b6021850152603584015260558301526055825261223e60758361062b565b905190206001600160a01b031690565b60ff60005460a01c1661225d57565b60405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606490fd5b98959a9996936122e6936101209996936122d89360018060a01b03168c5260208c015260018060a01b031660408b015261014060608b01526101408a0190610a0a565b9088820360808a0152610a0a565b60a08701989098526001600160a01b0390811660c087015260e086019190915290811661010085015216910152565b1561231c57565b60405162461bcd60e51b815260206004820152602860248201527f4465706c6f796d656e7420666565206d757374206265206174206c65617374206044820152670605c6062408aa8960c31b6064820152608490fd5b1561237957565b60405162461bcd60e51b815260206004820152602660248201527f526563697069656e74206d75737420626520746865207265717569726564206160448201526564647265737360d01b6064820152608490fd5b156123d457565b60405162461bcd60e51b815260206004820152601f60248201527f526563697069656e7420616d6f756e74206578636565647320737570706c79006044820152606490fd5b9081602091031261023a57516106d781611526565b634e487b7160e01b600052601260045260246000fd5b9060020b9081156124565760020b0790565b61242e565b1561246257565b60405162461bcd60e51b815260206004820152601c60248201527f496e76616c6964207469636b206f72207469636b2073706163696e67000000006044820152606490fd5b65b5e620f47fff1981019190821161196157565b9190820391821161196157565b156124cf57565b60405162461bcd60e51b815260206004820152601c60248201527f50726f746f636f6c20666565207472616e73666572206661696c6564000000006044820152606490fd5b949392916020612605936000805160206143aa8339815191526040518061257f8160809060208152602960208201527f5374617274696e67206465706c6f79546f6b656e2077697468204e46544175746040820152686f4c6f636b6572563560b81b60608201520190565b0390a1612595662386f26fc10000341015612315565b6125bd6001600160a01b03891673c5c216e6e60cce2d189bcce5f6ebffde1e8ce92614612372565b6125c9838511156123cd565b6005546125de906001600160a01b0316610acc565b60405180809781946322afcccb60e01b83526004830191909162ffffff6020820193169052565b03915afa9283156104d15765b5e620f4800061264d6000959486959461264861265e99889788978891612730575b508060020b15159182612713575b505061245b565b6124bb565b975af16126586116c4565b506124c8565b7f1fe20b63cae31fc9f78c0bef12d650e5d82cbb98b7c1d17096830cfff47c6bf86126af61268b346124a7565b6040805134815265b5e620f480006020820152908101919091529081906060820190565b0390a16000805160206143aa8339815191526040518061270e8160809060208152602460208201527f56616c69646174696f6e20616e64206665652068616e646c696e6720636f6d706040820152636c65746560e01b60608201520190565b0390a1565b61272892509061272291612444565b60020b90565b153880612641565b612752915060203d602011612758575b61274a818361062b565b810190612419565b38612633565b503d612740565b9294939060609261277b611e7492608087526080870190610a0a565b908582036020870152610a0a565b1561279057565b60405162461bcd60e51b815260206004820152601760248201527f546f6b656e206465706c6f796d656e74206661696c65640000000000000000006044820152606490fd5b9091612822611ef29196959496611f006127f0828787612ff6565b5095611ef2610d3c966128056020890161065c565b9780895261366e60208a013960405194859330926020860161275f565b51906000f5926001600160a01b0384169161283e831515612789565b806128ac575b50506040805181815260119181019190915270151bdad95b8819195c1b1bde595908185d607a1b60608201526001600160a01b03841660208201527fb3f7d6c63a62ab0e6ae5263ef1deb9c5a64f4689288c380db949c116314a55409150806080810161270e565b60405163a9059cbb60e01b81526001600160a01b03929092166004830152602482015290602090829060449082906000905af180156104d1576128f69160009161128f5750611de3565b388080612844565b1561290557565b60405162461bcd60e51b8152602060048201526015602482015274151bdad95b88185c1c1c9bdd985b0819985a5b1959605a1b6044820152606490fd5b919082608091031261023a5781519160208101516fffffffffffffffffffffffffffffffff8116810361023a57916060604083015192015190565b926129878261335d565b6005546129f59060209086906129a5906001600160a01b0316610acc565b6004546001600160a01b031660405163a167129560e01b81526001600160a01b03808c166004830152909116602482015262ffffff90921660448301529092839190829060009082906064820190565b03925af19081156104d157600091612d6d575b506001600160a01b0316803b1561023a5760405163f637731d60e01b81526001600160a01b039290921660048301526000908290602490829084905af180156104d157612d58575b50600554612a66906001600160a01b0316610acc565b6040516322afcccb60e01b815262ffffff851660048201529290602090849060249082905afa9283156104d157612b90946020948793612b1893600092612d33575b50612b04612b0e9293612af8612ace612ac860045460018060a01b031690565b96613642565b95612ae9612ada61064c565b6001600160a01b03909e168e52565b6001600160a01b03168c8b0152565b62ffffff1660408b0152565b60020b6060890152565b60020b6080870152565b60a08501829052600060c0860181905260e086018190526101008601523061012086015242610140860152600654612b58906001600160a01b0316610acc565b60405163095ea7b360e01b81526001600160a01b03909116600482015260248101929092529092839190829060009082906044820190565b03926001600160a01b03165af180156104d157600092612bbd612c7e926080948691612d14575b506128fe565b600654612bd2906001600160a01b0316610acc565b60408051634418b22b60e11b815283516001600160a01b0390811660048301526020850151811660248301529184015162ffffff1660448201526060840151600290810b60648301526080850151900b608482015260a084015160a482015260c084015160c482015260e084015160e482015261010084015161010482015261012084015190911661012482015261014090920151610144830152909384928391908290610164820190565b03925af19081156104d157600091612ce2575b50906000805160206143aa8339815191526040518061270e8160609060208152601960208201527f506f6f6c20616e6420706f736974696f6e20637265617465640000000000000060408201520190565b612d04915060803d608011612d0d575b612cfc818361062b565b810190612942565b50505038612c91565b503d612cf2565b612d2d915060203d60201161079357610785818361062b565b38612bb7565b612b0e9250612d51612b0491893d8b116127585761274a818361062b565b9250612aa8565b80610be26000612d679361062b565b38612a50565b612d86915060203d6020116110795761106b818361062b565b38612a08565b15612d9357565b60405162461bcd60e51b8152602060048201526024808201527f46656520726563697069656e742063616e6e6f74206265207a65726f206164646044820152637265737360e01b6064820152608490fd5b15612deb57565b60405162461bcd60e51b815260206004820152602960248201527f46656520726563697069656e7420636f6e74726163742063616e6e6f742072656044820152680c6cad2ecca408aa8960bb1b6064820152608490fd5b90612e576001600160a01b0382161515612d8c565b803b612faf575b600154612e7590610acc906001600160a01b031681565b803b1561023a57604051633dc4139960e11b8152600481018490526001600160a01b039290921660248301526000908290604490829084905af180156104d157612f9a575b50600654612ed0906001600160a01b0316610acc565b6001549091906001600160a01b031690823b1561023a57604051632142170760e11b81523060048201526001600160a01b039290921660248301526044820152906000908290606490829084905af180156104d157612f85575b506000805160206143aa8339815191526040518061270e8160809060208152602260208201527f4e4654207472616e7366657272656420746f204e46544175746f4c6f636b6572604082015261563560f01b60608201520190565b80610be26000612f949361062b565b38612f2a565b80610be26000612fa99361062b565b38612eba565b612fc9600080808080865af1612fc36116c4565b50612de4565b612e5e565b61ffff16612710019061ffff821161196157565b61ffff16614e20019061ffff821161196157565b9161301590611f00611ef293611ef2610d3c966128056020890161065c565b5190206004546001929061303390610acc906001600160a01b031681565b925b61ffff811661138881116130c8576040805133602082019081529181018390526130628160608101611ef2565b51902061306f858261220c565b916001600160a01b03831687116130915750505061308c90611ea1565b613035565b6040805161ffff909516855260208501919091529195509293506000805160206143ca8339815191529190819081015b0390a19190565b505091909160005b61012c61ffff82161061322b575060005b6103e861ffff8216106131505760405162461bcd60e51b815260206004820152603460248201527f436f756c64206e6f742066696e642076616c69642073616c74202d2074727920604482015273646966666572656e7420746f6b656e206e616d6560601b6064820152608490fd5b60408051426020820190815261ffff8416928201929092526131758160608101611ef2565b51902060408051336020820190815291810192909252906131998160608101611ef2565b5190206131a6858261220c565b906001600160a01b03821685116131c557505060010161ffff166130e1565b9293509350806131e36000805160206143ca83398151915292612fe2565b9060405161320b81611ef26020820194428690929161ffff6020916040840195845216910152565b5190206040805161ffff90931683526020830191909152819081016130c1565b604080514260208201908152439282019290925261ffff831660608201526132568160808101611ef2565b519020604080513360208201908152918101929092529061327a8160608101611ef2565b519020613287858261220c565b906001600160a01b03821685116132a657505060010161ffff166130d0565b9293509350806132c46000805160206143ca83398151915292612fce565b9060405161320b81611ef2602082019443428791604091949361ffff9160608501968552602085015216910152565b600160ff1b81146119615760000390565b1561330b57565b60405162461bcd60e51b815260206004820152601b60248201527f5469636b4d6174683a205449434b5f4f55545f4f465f52414e474500000000006044820152606490fd5b8015612456576000190490565b610acc6106d79160020b6000811260001461363c5761337b816132f3565b905b61338c620d89e8831115613304565b600182161561362a576001600160881b036ffffcb933bd6fad37aa2d162d1a5940015b169160028116613617575b60048116613604575b600881166135f1575b601081166135de575b602081166135cb575b604081166135b8575b608081166135a5575b6101008116613592575b610200811661357f575b610400811661356c575b6108008116613559575b6110008116613546575b6120008116613533575b6140008116613520575b618000811661350d575b6201000081166134fa575b6202000081166134e7575b6204000081166134ce575b62080000166134b1575b6000126134a3575b61348a6134808260201c90565b9163ffffffff1690565b61349a5760ff60005b1690611d34565b60ff6001613493565b6134ac90613350565b613473565b906134c66134c0600092611d08565b60801c90565b91905061346b565b916134df6134c06208000092611cd8565b929050613461565b916134c06134f491611ca6565b91613456565b916134c061350791611c72565b9161344b565b916134c061351a91611c3e565b91613440565b916134c061352d91611c0a565b91613436565b916134c061354091611bd6565b9161342c565b916134c061355391611ba2565b91613422565b916134c061356691611b6e565b91613418565b916134c061357991611b3a565b9161340e565b916134c061358c91611b06565b91613404565b916134c061359f91611ad2565b916133fa565b916134c06135b291611a9e565b916133f0565b916134c06135c591611a6a565b916133e7565b916134c06135d891611a36565b916133de565b916134c06135eb91611a02565b916133d5565b916134c06135fe916119ce565b916133cc565b916134c06136119161199a565b916133c3565b916134c061362491611966565b916133ba565b6001600160881b03600160801b6133af565b8061337d565b60020b801561245657620d89e80760020b620d89e803627fffff8113627fffff19821217611961579056fe6080604052346103fa57610d3c80380380610019816103ff565b9283398101906080818303126103fa5780516001600160401b0381116103fa5782610045918301610424565b602082015190926001600160401b0382116103fa57610065918301610424565b604082015160609092015190916001600160a01b038216918290036103fa5783516001600160401b03811161030357600354600181811c911680156103f0575b60208210146102e357601f811161038b575b50602094601f821160011461032457948192939495600092610319575b50508160011b916000199060031b1c1916176003555b82516001600160401b03811161030357600454600181811c911680156102f9575b60208210146102e357601f811161027e575b506020601f8211600114610217578192939460009261020c575b50508160011b916000199060031b1c1916176004555b81156101c757600254908082018092116101b15760207fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9160009360025584845283825260408420818154019055604051908152a36040516108ac90816104908239f35b634e487b7160e01b600052601160045260246000fd5b60405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606490fd5b015190503880610137565b601f198216906004600052806000209160005b8181106102665750958360019596971061024d575b505050811b0160045561014d565b015160001960f88460031b161c1916905538808061023f565b9192602060018192868b01518155019401920161022a565b60046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c810191602084106102d9575b601f0160051c01905b8181106102cd575061011d565b600081556001016102c0565b90915081906102b7565b634e487b7160e01b600052602260045260246000fd5b90607f169061010b565b634e487b7160e01b600052604160045260246000fd5b0151905038806100d4565b601f198216956003600052806000209160005b8881106103735750836001959697981061035a575b505050811b016003556100ea565b015160001960f88460031b161c1916905538808061034c565b91926020600181928685015181550194019201610337565b60036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c810191602084106103e6575b601f0160051c01905b8181106103da57506100b7565b600081556001016103cd565b90915081906103c4565b90607f16906100a5565b600080fd5b6040519190601f01601f191682016001600160401b0381118382101761030357604052565b81601f820112156103fa578051906001600160401b03821161030357610453601f8301601f19166020016103ff565b92828452602083830101116103fa5760005b82811061047a57505060206000918301015290565b8060208092840101518282870101520161046556fe608080604052600436101561001357600080fd5b60003560e01c90816306fdde03146104a757508063095ea7b31461048157806318160ddd1461046357806323b872dd146103a5578063313ce56714610389578063395093511461032157806370a08231146102e757806395d89b41146101c6578063a457c2d71461011f578063a9059cbb146100ee5763dd62ed3e1461009857600080fd5b346100e95760403660031901126100e9576100b16105c3565b6100b96105d9565b6001600160a01b039182166000908152600160209081526040808320949093168252928352819020549051908152f35b600080fd5b346100e95760403660031901126100e95761011461010a6105c3565b60243590336106f7565b602060405160018152f35b346100e95760403660031901126100e9576101386105c3565b60243590336000526001602052604060002060018060a01b0382166000526020526040600020549180831061017357610114920390336105ef565b60405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608490fd5b346100e95760003660031901126100e95760405160006004548060011c906001811680156102dd575b6020831081146102c9578285529081156102ad5750600114610256575b50819003601f01601f191681019067ffffffffffffffff8211818310176102405761023c8291826040528261057a565b0390f35b634e487b7160e01b600052604160045260246000fd5b905060046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b6000905b8282106102975750602091508201018261020c565b6001816020925483858801015201910190610282565b90506020925060ff191682840152151560051b8201018261020c565b634e487b7160e01b84526022600452602484fd5b91607f16916101ef565b346100e95760203660031901126100e9576001600160a01b036103086105c3565b1660005260006020526020604060002054604051908152f35b346100e95760403660031901126100e95761033a6105c3565b336000526001602052604060002060018060a01b03821660005260205260406000205460243581018091116103735761011491336105ef565b634e487b7160e01b600052601160045260246000fd5b346100e95760003660031901126100e957602060405160128152f35b346100e95760603660031901126100e9576103be6105c3565b6103c66105d9565b6001600160a01b0382166000908152600160208181526040808420338552909152909120549260443592918401610402575b61011493506106f7565b82841061041e5761041983610114950333836105ef565b6103f8565b60405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606490fd5b346100e95760003660031901126100e9576020600254604051908152f35b346100e95760403660031901126100e95761011461049d6105c3565b60243590336105ef565b346100e95760003660031901126100e95760006003548060011c90600181168015610570575b6020831081146102c9578285529081156102ad57506001146105195750819003601f01601f191681019067ffffffffffffffff8211818310176102405761023c8291826040528261057a565b905060036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b6000905b82821061055a5750602091508201018261020c565b6001816020925483858801015201910190610545565b91607f16916104cd565b91909160208152825180602083015260005b8181106105ad575060409293506000838284010152601f8019910116010190565b806020809287010151604082860101520161058c565b600435906001600160a01b03821682036100e957565b602435906001600160a01b03821682036100e957565b6001600160a01b03169081156106a6576001600160a01b03169182156106565760207f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925918360005260018252604060002085600052825280604060002055604051908152a3565b60405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608490fd5b60405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608490fd5b6001600160a01b0316908115610823576001600160a01b03169182156107d25781600052600060205260406000205481811061077e57817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9260209285600052600084520360406000205584600052600082526040600020818154019055604051908152a3565b60405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608490fd5b60405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608490fd5b60405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608490fdfea264697066735822122074ff4234c658f74e187510519776b8ea4e39b5c6743b1caeebf48be4c2f0270464736f6c634300081a003394ebca8d29d278a0288a52a710c11e928307b6f2e15fbaf4508cc4ceb3d21f8b2d85e5bc21a27644fa43503d10d34b03fef575277be4ae9f6da8f6f484ab0652a2646970667358221220fc89f062f0f16d35043a568f1cacb772d61a3999b149b553636a8c30706af53264736f6c634300081a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c5c216e6e60cce2d189bcce5f6ebffde1e8ce926000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f984000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe88000000000000000000000000e592427a0aece92de3edee1f18e0157c058615640000000000000000000000000fa69466d99880fb6db58775343bd214f58c98b000000000000000000000000025c9c4b56e820e0dea438b145284f02d9ca9bd52
-----Decoded View---------------
Arg [0] : taxCollector_ (address): 0xc5C216E6E60ccE2d189Bcce5f6ebFFDE1e8ce926
Arg [1] : weth_ (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [2] : uniswapV3Factory_ (address): 0x1F98431c8aD98523631AE4a59f267346ea31F984
Arg [3] : positionManager_ (address): 0xC36442b4a4522E871399CD717aBDD847Ab11FE88
Arg [4] : swapRouter_ (address): 0xE592427A0AEce92De3Edee1F18E0157C05861564
Arg [5] : nftLockerV5_ (address): 0x0fa69466d99880fb6dB58775343BD214f58c98b0
Arg [6] : goPlusLocker_ (address): 0x25c9C4B56E820e0DEA438b145284F02D9Ca9Bd52
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 000000000000000000000000c5c216e6e60cce2d189bcce5f6ebffde1e8ce926
Arg [1] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [2] : 0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f984
Arg [3] : 000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe88
Arg [4] : 000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564
Arg [5] : 0000000000000000000000000fa69466d99880fb6db58775343bd214f58c98b0
Arg [6] : 00000000000000000000000025c9c4b56e820e0dea438b145284f02d9ca9bd52
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.