Overview
ETH Balance
ETH Value
$0.00Latest 25 from a total of 1,833 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Rebalance For | 17138788 | 1 hr ago | IN | 0 ETH | 0.00000302 | ||||
| Harvest For | 17134893 | 2 hrs ago | IN | 0 ETH | 0.00000264 | ||||
| Rebalance For | 17128408 | 4 hrs ago | IN | 0 ETH | 0.00000268 | ||||
| Rebalance For | 17122769 | 5 hrs ago | IN | 0 ETH | 0.00000266 | ||||
| Rebalance For | 17120609 | 6 hrs ago | IN | 0 ETH | 0.00000307 | ||||
| Rebalance For | 17119168 | 6 hrs ago | IN | 0 ETH | 0.00000273 | ||||
| Rebalance For | 17109510 | 9 hrs ago | IN | 0 ETH | 0.00000296 | ||||
| Rebalance For | 17109391 | 9 hrs ago | IN | 0 ETH | 0.00000288 | ||||
| Rebalance For | 17108789 | 9 hrs ago | IN | 0 ETH | 0.00000307 | ||||
| Rebalance For | 17078430 | 18 hrs ago | IN | 0 ETH | 0.00000314 | ||||
| Rebalance For | 17075909 | 18 hrs ago | IN | 0 ETH | 0.0000027 | ||||
| Rebalance For | 17068650 | 20 hrs ago | IN | 0 ETH | 0.00000266 | ||||
| Rebalance For | 17068169 | 20 hrs ago | IN | 0 ETH | 0.00000272 | ||||
| Rebalance For | 17065888 | 21 hrs ago | IN | 0 ETH | 0.00000316 | ||||
| Rebalance For | 17064389 | 21 hrs ago | IN | 0 ETH | 0.00000316 | ||||
| Rebalance For | 17036429 | 29 hrs ago | IN | 0 ETH | 0.00000281 | ||||
| Rebalance For | 17033430 | 30 hrs ago | IN | 0 ETH | 0.00000289 | ||||
| Rebalance For | 17032418 | 30 hrs ago | IN | 0 ETH | 0.00000288 | ||||
| Rebalance For | 17032108 | 30 hrs ago | IN | 0 ETH | 0.00000259 | ||||
| Rebalance For | 17031994 | 30 hrs ago | IN | 0 ETH | 0.00000265 | ||||
| Rebalance For | 17031389 | 31 hrs ago | IN | 0 ETH | 0.00000262 | ||||
| Rebalance For | 17031152 | 31 hrs ago | IN | 0 ETH | 0.00000266 | ||||
| Rebalance For | 17028941 | 31 hrs ago | IN | 0 ETH | 0.00000263 | ||||
| Rebalance For | 17028932 | 31 hrs ago | IN | 0 ETH | 0.00000259 | ||||
| Rebalance For | 17028763 | 31 hrs ago | IN | 0 ETH | 0.0000029 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | ||||
|---|---|---|---|---|---|---|---|
| 17138788 | 1 hr ago | 0 ETH | |||||
| 17138788 | 1 hr ago | 0 ETH | |||||
| 17138788 | 1 hr ago | 0 ETH | |||||
| 17138788 | 1 hr ago | 0 ETH | |||||
| 17134893 | 2 hrs ago | 0 ETH | |||||
| 17134893 | 2 hrs ago | 0 ETH | |||||
| 17134893 | 2 hrs ago | 0 ETH | |||||
| 17134893 | 2 hrs ago | 0 ETH | |||||
| 17128408 | 4 hrs ago | 0 ETH | |||||
| 17128408 | 4 hrs ago | 0 ETH | |||||
| 17128408 | 4 hrs ago | 0 ETH | |||||
| 17128408 | 4 hrs ago | 0 ETH | |||||
| 17122769 | 5 hrs ago | 0 ETH | |||||
| 17122769 | 5 hrs ago | 0 ETH | |||||
| 17122769 | 5 hrs ago | 0 ETH | |||||
| 17122769 | 5 hrs ago | 0 ETH | |||||
| 17120609 | 6 hrs ago | 0 ETH | |||||
| 17120609 | 6 hrs ago | 0 ETH | |||||
| 17120609 | 6 hrs ago | 0 ETH | |||||
| 17120609 | 6 hrs ago | 0 ETH | |||||
| 17119168 | 6 hrs ago | 0 ETH | |||||
| 17119168 | 6 hrs ago | 0 ETH | |||||
| 17119168 | 6 hrs ago | 0 ETH | |||||
| 17119168 | 6 hrs ago | 0 ETH | |||||
| 17109510 | 9 hrs ago | 0 ETH |
Cross-Chain Transactions
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { Admin } from "contracts/base/Admin.sol";
import { NonDelegateMulticall } from "contracts/base/NonDelegateMulticall.sol";
import { Sickle } from "contracts/Sickle.sol";
import { SickleRegistry } from "contracts/SickleRegistry.sol";
import { IAutomation } from "contracts/interfaces/IAutomation.sol";
import { INftAutomation } from "contracts/interfaces/INftAutomation.sol";
import {
NftRebalance,
NftPosition,
NftHarvest,
NftWithdraw,
NftCompound
} from "contracts/structs/NftFarmStrategyStructs.sol";
import {
Farm,
HarvestParams,
WithdrawParams,
CompoundParams
} from "contracts/structs/FarmStrategyStructs.sol";
import { AutomationPermissions } from
"contracts/libraries/AutomationPermissions.sol";
// @title Automation contract for protocol farming and NFT strategies
// @notice Allows protocol-approved automators, or user-approved automators via
// AutomatorPermissionsRegistry, to perform automated actions (compound,
// harvest,
// exit, rebalance) on behalf of Sickle users. For non-NFT positions, users can
// set automation preferences per position in PositionSettingsRegistry. For NFT
// positions, automation preferences are set per NFT in NftSettingsRegistry.
// AutomatorPermissionsRegistry enables Sickle owners to grant automation rights
// to specific addresses, overriding the global automator if desired.
// @dev Intended for use by off-chain automation bots with appropriate
// permissions. Protocol admin manages the global automator, while users can
// configure their own automator permissions and automation settings.
contract Automation is Admin, NonDelegateMulticall {
error InvalidInputLength();
error NotApprovedAutomator();
error InvalidAutomator();
error ApprovedAutomatorNotSet(address approvedAutomator);
error ApprovedAutomatorAlreadySet(address approvedAutomator);
error MalformedPermissions();
event HarvestedFor(
Sickle indexed sickle,
address indexed stakingContract,
uint256 indexed poolIndex,
address automator
);
event CompoundedFor(
Sickle indexed sickle,
address indexed claimStakingContract,
uint256 claimPoolIndex,
address indexed depositStakingContract,
uint256 depositPoolIndex,
address automator
);
event ExitedFor(
Sickle indexed sickle,
address indexed stakingContract,
uint256 indexed poolIndex,
address automator
);
event NftHarvestedFor(
Sickle indexed sickle,
address indexed nftAddress,
uint256 indexed tokenId,
address automator
);
event NftCompoundedFor(
Sickle indexed sickle,
address indexed nftAddress,
uint256 indexed tokenId,
address automator
);
event NftExitedFor(
Sickle indexed sickle,
address indexed nftAddress,
uint256 indexed tokenId,
address automator
);
event NftRebalancedFor(
Sickle indexed sickle,
address indexed nftAddress,
uint256 indexed tokenId,
address automator
);
event ApprovedAutomatorSet(address approvedAutomator);
event ApprovedAutomatorPermissionsSet(
address approvedAutomator, uint256 permissions
);
event ApprovedAutomatorRevoked(address approvedAutomator);
event CustomAutomatorSet(
Sickle indexed sickle, address indexed automator, uint256 permissions
);
address[] public approvedAutomators;
mapping(address => bool) public isApprovedAutomator;
mapping(address => uint256) public globalAutomatorPermissions;
mapping(Sickle => mapping(address => uint256)) public
customAutomatorPermissions;
mapping(Sickle => uint256) public customAutomatorCount;
constructor(
SickleRegistry registry,
address admin
) Admin(admin) NonDelegateMulticall(registry) { }
modifier validatePermissions(
uint256 permissions
) {
if (permissions > AutomationPermissions.ALL) {
revert MalformedPermissions();
}
_;
}
function setCustomAutomatorForSickle(
Sickle sickle,
address automator,
uint256 permissions
) external onlyAdmin validatePermissions(permissions) {
uint256 prevPermissions = customAutomatorPermissions[sickle][automator];
if (prevPermissions == 0 && permissions != 0) {
customAutomatorCount[sickle] += 1;
} else if (prevPermissions != 0 && permissions == 0) {
customAutomatorCount[sickle] -= 1;
}
customAutomatorPermissions[sickle][automator] = permissions;
emit CustomAutomatorSet(sickle, automator, permissions);
}
/// Public functions
function approvedAutomatorsLength() external view returns (uint256) {
return approvedAutomators.length;
}
// Admin functions
/// @notice Update approved automator address.
/// @dev Controls which external address is allowed to
/// compound farming positions for Sickles. This is expected to be the EOA
/// of an automation bot.
/// @custom:access Restricted to protocol admin.
function setApprovedAutomator(
address payable approvedAutomator
) external onlyAdmin {
_setApprovedAutomator(approvedAutomator, AutomationPermissions.ALL);
}
/// @notice Update approved automator with permissions bitmap.
/// If not already in the global allowlist, adds it.
function setApprovedAutomatorWithPermissions(
address payable approvedAutomator,
uint256 permissions
) external onlyAdmin validatePermissions(permissions) {
if (!isApprovedAutomator[approvedAutomator]) {
_setApprovedAutomator(approvedAutomator, permissions);
} else {
globalAutomatorPermissions[approvedAutomator] = permissions;
emit ApprovedAutomatorPermissionsSet(approvedAutomator, permissions);
}
}
function revokeApprovedAutomator(
address approvedAutomator
) external onlyAdmin {
if (!isApprovedAutomator[approvedAutomator]) {
revert ApprovedAutomatorNotSet(approvedAutomator);
}
for (uint256 i; i < approvedAutomators.length; i++) {
if (approvedAutomators[i] == approvedAutomator) {
approvedAutomators[i] =
approvedAutomators[approvedAutomators.length - 1];
approvedAutomators.pop();
break;
}
}
isApprovedAutomator[approvedAutomator] = false;
delete globalAutomatorPermissions[approvedAutomator];
emit ApprovedAutomatorPermissionsSet(approvedAutomator, 0);
emit ApprovedAutomatorRevoked(approvedAutomator);
}
// Automator functions
function compoundFor(
IAutomation[] memory strategies,
Sickle[] memory sickles,
CompoundParams[] memory params,
address[][] memory sweepTokens
) external {
uint256 strategiesLength = strategies.length;
if (
strategiesLength != sickles.length
|| strategiesLength != params.length
|| strategiesLength != sweepTokens.length
) {
revert InvalidInputLength();
}
_requireAuthorizedFor(sickles, AutomationPermissions.FARM_COMPOUND);
address[] memory targets = new address[](strategiesLength);
bytes[] memory data = new bytes[](strategiesLength);
for (uint256 i; i < strategiesLength;) {
Sickle sickle = sickles[i];
CompoundParams memory param = params[i];
targets[i] = address(strategies[i]);
data[i] = abi.encodeCall(
IAutomation.compoundFor, (sickle, param, sweepTokens[i])
);
emit CompoundedFor(
sickle,
param.claimFarm.stakingContract,
param.claimFarm.poolIndex,
param.depositFarm.stakingContract,
param.depositFarm.poolIndex,
msg.sender
);
unchecked {
++i;
}
}
this.multicall(targets, data);
}
function harvestFor(
IAutomation[] memory strategies,
Sickle[] memory sickles,
Farm[] memory farms,
HarvestParams[] memory params,
address[][] memory sweepTokens
) external {
uint256 strategiesLength = strategies.length;
if (
strategiesLength != sickles.length
|| strategiesLength != farms.length
|| strategiesLength != params.length
|| strategiesLength != sweepTokens.length
) {
revert InvalidInputLength();
}
_requireAuthorizedFor(sickles, AutomationPermissions.FARM_HARVEST);
address[] memory targets = new address[](strategiesLength);
bytes[] memory data = new bytes[](strategiesLength);
for (uint256 i; i < strategiesLength;) {
Sickle sickle = sickles[i];
Farm memory farm = farms[i];
HarvestParams memory param = params[i];
targets[i] = address(strategies[i]);
data[i] = abi.encodeCall(
IAutomation.harvestFor, (sickle, farm, param, sweepTokens[i])
);
emit HarvestedFor(
sickle, farm.stakingContract, farm.poolIndex, msg.sender
);
unchecked {
++i;
}
}
this.multicall(targets, data);
}
function exitFor(
IAutomation[] memory strategies,
Sickle[] memory sickles,
Farm[] memory farms,
HarvestParams[] memory harvestParams,
address[][] memory harvestSweepTokens,
WithdrawParams[] memory withdrawParams,
address[][] memory withdrawSweepTokens
) external {
uint256 strategiesLength = strategies.length;
if (
strategiesLength != sickles.length
|| strategiesLength != farms.length
|| strategiesLength != harvestParams.length
|| strategiesLength != withdrawParams.length
|| strategiesLength != harvestSweepTokens.length
|| strategiesLength != withdrawSweepTokens.length
) {
revert InvalidInputLength();
}
_requireAuthorizedFor(sickles, AutomationPermissions.FARM_EXIT);
address[] memory targets = new address[](strategiesLength);
bytes[] memory data = new bytes[](strategiesLength);
for (uint256 i; i < strategiesLength;) {
targets[i] = address(strategies[i]);
data[i] = abi.encodeCall(
IAutomation.exitFor,
(
sickles[i],
farms[i],
harvestParams[i],
harvestSweepTokens[i],
withdrawParams[i],
withdrawSweepTokens[i]
)
);
emit ExitedFor(
sickles[i],
farms[i].stakingContract,
farms[i].poolIndex,
msg.sender
);
unchecked {
++i;
}
}
this.multicall(targets, data);
}
// NFT Automator functions
// Validation is done in the NftAutomation contract
function harvestFor(
INftAutomation[] memory strategies,
Sickle[] memory sickles,
NftPosition[] memory positions,
NftHarvest[] memory params
) external {
uint256 strategiesLength = strategies.length;
if (
strategiesLength != sickles.length
|| strategiesLength != positions.length
|| strategiesLength != params.length
) {
revert InvalidInputLength();
}
_requireAuthorizedFor(sickles, AutomationPermissions.NFT_HARVEST);
address[] memory targets = new address[](strategiesLength);
bytes[] memory data = new bytes[](strategiesLength);
for (uint256 i; i < strategiesLength;) {
Sickle sickle = sickles[i];
NftPosition memory position = positions[i];
targets[i] = address(strategies[i]);
data[i] = abi.encodeCall(
INftAutomation.harvestFor, (sickle, position, params[i])
);
emit NftHarvestedFor(
sickle, address(position.nft), position.tokenId, msg.sender
);
unchecked {
++i;
}
}
this.multicall(targets, data);
}
function compoundFor(
INftAutomation[] memory strategies,
Sickle[] memory sickles,
NftPosition[] memory positions,
NftCompound[] memory params,
bool[] memory inPlace,
address[][] memory sweepTokens
) external {
uint256 strategiesLength = strategies.length;
if (
strategiesLength != sickles.length
|| strategiesLength != positions.length
|| strategiesLength != params.length
|| strategiesLength != inPlace.length
|| strategiesLength != sweepTokens.length
) {
revert InvalidInputLength();
}
_requireAuthorizedFor(sickles, AutomationPermissions.NFT_COMPOUND);
address[] memory targets = new address[](strategiesLength);
bytes[] memory data = new bytes[](strategiesLength);
for (uint256 i; i < strategiesLength;) {
Sickle sickle = sickles[i];
NftPosition memory position = positions[i];
targets[i] = address(strategies[i]);
data[i] = abi.encodeCall(
INftAutomation.compoundFor,
(sickle, position, params[i], inPlace[i], sweepTokens[i])
);
emit NftCompoundedFor(
sickle, address(position.nft), position.tokenId, msg.sender
);
unchecked {
++i;
}
}
this.multicall(targets, data);
}
function exitFor(
INftAutomation[] memory strategies,
Sickle[] memory sickles,
NftPosition[] memory positions,
NftHarvest[] memory harvestParams,
NftWithdraw[] memory withdrawParams,
address[][] memory sweepTokens
) external {
uint256 strategiesLength = strategies.length;
if (
strategiesLength != sickles.length
|| strategiesLength != positions.length
|| strategiesLength != harvestParams.length
|| strategiesLength != withdrawParams.length
|| strategiesLength != sweepTokens.length
) {
revert InvalidInputLength();
}
_requireAuthorizedFor(sickles, AutomationPermissions.NFT_EXIT);
address[] memory targets = new address[](strategiesLength);
bytes[] memory data = new bytes[](strategiesLength);
for (uint256 i; i < strategiesLength;) {
Sickle sickle = sickles[i];
NftPosition memory position = positions[i];
targets[i] = address(strategies[i]);
data[i] = abi.encodeCall(
INftAutomation.exitFor,
(
sickle,
position,
harvestParams[i],
withdrawParams[i],
sweepTokens[i]
)
);
emit NftExitedFor(
sickle, address(position.nft), position.tokenId, msg.sender
);
unchecked {
++i;
}
}
this.multicall(targets, data);
}
function rebalanceFor(
INftAutomation[] memory strategies,
Sickle[] memory sickles,
NftRebalance[] memory params,
address[][] memory sweepTokens
) external {
uint256 strategiesLength = strategies.length;
if (
strategiesLength != sickles.length
|| strategiesLength != params.length
|| strategiesLength != sweepTokens.length
) {
revert InvalidInputLength();
}
_requireAuthorizedFor(sickles, AutomationPermissions.NFT_REBALANCE);
address[] memory targets = new address[](strategiesLength);
bytes[] memory data = new bytes[](strategiesLength);
for (uint256 i; i < strategiesLength;) {
NftRebalance memory param = params[i];
Sickle sickle = sickles[i];
targets[i] = address(strategies[i]);
data[i] = abi.encodeCall(
INftAutomation.rebalanceFor, (sickle, param, sweepTokens[i])
);
emit NftRebalancedFor(
sickle,
address(param.position.nft),
param.position.tokenId,
msg.sender
);
unchecked {
++i;
}
}
this.multicall(targets, data);
}
// Internal
function _setApprovedAutomator(
address payable approvedAutomator,
uint256 permissions
) internal {
if (approvedAutomator == address(0)) revert InvalidAutomator();
if (isApprovedAutomator[approvedAutomator]) {
revert ApprovedAutomatorAlreadySet(approvedAutomator);
}
isApprovedAutomator[approvedAutomator] = true;
approvedAutomators.push(approvedAutomator);
globalAutomatorPermissions[approvedAutomator] = permissions;
emit ApprovedAutomatorSet(approvedAutomator);
emit ApprovedAutomatorPermissionsSet(approvedAutomator, permissions);
}
function _requireAuthorizedFor(
Sickle[] memory sickles,
uint256 action
) internal view {
uint256 len = sickles.length;
for (uint256 i; i < len;) {
Sickle sickle = sickles[i];
bool hasCustomAutomators = customAutomatorCount[sickle] > 0;
if (hasCustomAutomators) {
if (
(customAutomatorPermissions[sickle][msg.sender] & action)
== 0
) {
revert NotApprovedAutomator();
}
} else {
if (
!isApprovedAutomator[msg.sender]
|| (globalAutomatorPermissions[msg.sender] & action) == 0
) {
revert NotApprovedAutomator();
}
}
unchecked {
++i;
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
/// @title Admin contract
/// @author vfat.tools
/// @notice Provides an administration mechanism allowing restricted functions
abstract contract Admin {
/// ERRORS ///
/// @notice Thrown when the caller is not the admin
error NotAdminError(); //0xb5c42b3b
/// EVENTS ///
/// @notice Emitted when a new admin is set
/// @param oldAdmin Address of the old admin
/// @param newAdmin Address of the new admin
event AdminSet(address oldAdmin, address newAdmin);
/// STORAGE ///
/// @notice Address of the current admin
address public admin;
/// MODIFIERS ///
/// @dev Restricts a function to the admin
modifier onlyAdmin() {
if (msg.sender != admin) revert NotAdminError();
_;
}
/// WRITE FUNCTIONS ///
/// @param admin_ Address of the admin
constructor(
address admin_
) {
emit AdminSet(address(0), admin_);
admin = admin_;
}
/// @notice Sets a new admin
/// @param newAdmin Address of the new admin
/// @custom:access Restricted to protocol admin.
function setAdmin(
address newAdmin
) external onlyAdmin {
emit AdminSet(admin, newAdmin);
admin = newAdmin;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { SickleRegistry } from "contracts/SickleRegistry.sol";
/// @title Multicall contract
/// @author vfat.tools
/// @notice Enables calling multiple methods in a single call to the contract
abstract contract NonDelegateMulticall {
/// ERRORS ///
error MulticallParamsMismatchError(); // 0xc1e637c9
/// @notice Thrown when the target contract is not whitelisted
/// @param target Address of the non-whitelisted target
error TargetNotWhitelisted(address target); // 0x47ccabe7
/// @notice Thrown when the caller is not whitelisted
/// @param caller Address of the non-whitelisted caller
error CallerNotWhitelisted(address caller); // 0x252c8273
/// STORAGE ///
/// @notice Address of the SickleRegistry contract
/// @dev Needs to be immutable so that it's accessible for Sickle proxies
SickleRegistry public immutable registry;
/// INITIALIZATION ///
/// @param registry_ Address of the SickleRegistry contract
constructor(
SickleRegistry registry_
) {
registry = registry_;
}
/// WRITE FUNCTIONS ///
/// @notice Batch multiple calls together (calls or delegatecalls)
/// @param targets Array of targets to call
/// @param data Array of data to pass with the calls
function multicall(
address[] calldata targets,
bytes[] calldata data
) external payable {
if (targets.length != data.length) {
revert MulticallParamsMismatchError();
}
if (!registry.isWhitelistedCaller(msg.sender)) {
revert CallerNotWhitelisted(msg.sender);
}
for (uint256 i = 0; i != data.length;) {
if (targets[i] == address(0)) {
unchecked {
++i;
}
continue; // No-op
}
if (targets[i] != address(this)) {
if (!registry.isWhitelistedTarget(targets[i])) {
revert TargetNotWhitelisted(targets[i]);
}
}
(bool success, bytes memory result) = targets[i].call(data[i]);
if (!success) {
if (result.length == 0) revert();
assembly {
revert(add(32, result), mload(result))
}
}
unchecked {
++i;
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { SickleStorage } from "contracts/base/SickleStorage.sol";
import { Multicall } from "contracts/base/Multicall.sol";
import { SickleRegistry } from "contracts/SickleRegistry.sol";
/// @title Sickle contract
/// @author vfat.tools
/// @notice Sickle facilitates farming and interactions with Masterchef
/// contracts
/// @dev Base contract inheriting from all the other "manager" contracts
contract Sickle is SickleStorage, Multicall {
/// @notice Function to receive ETH
receive() external payable { }
/// @param sickleRegistry_ Address of the SickleRegistry contract
constructor(
SickleRegistry sickleRegistry_
) Multicall(sickleRegistry_) {
_disableInitializers();
}
/// @param sickleOwner_ Address of the Sickle owner
function initialize(
address sickleOwner_,
address approved_
) external initializer {
SickleStorage._initializeSickleStorage(sickleOwner_, approved_);
}
/// INTERNALS ///
function onERC721Received(
address, // operator
address, // from
uint256, // tokenId
bytes calldata // data
) external pure returns (bytes4) {
return this.onERC721Received.selector;
}
function onERC1155Received(
address, // operator
address, // from
uint256, // id
uint256, // value
bytes calldata // data
) external pure returns (bytes4) {
return this.onERC1155Received.selector;
}
function onERC1155BatchReceived(
address, // operator
address, // from
uint256[] calldata, // ids
uint256[] calldata, // values
bytes calldata // data
) external pure returns (bytes4) {
return this.onERC1155BatchReceived.selector;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { Admin } from "contracts/base/Admin.sol";
library SickleRegistryEvents {
event CollectorChanged(address newCollector);
event FeesUpdated(bytes32[] feeHashes, uint256[] feesInBP);
event ReferralCodeCreated(bytes32 indexed code, address indexed referrer);
// Multicall caller and target whitelist status changes
event CallerStatusChanged(address caller, bool isWhitelisted);
event TargetStatusChanged(address target, bool isWhitelisted);
}
/// @title SickleRegistry contract
/// @author vfat.tools
/// @notice Manages the whitelisted contracts and the collector address
contract SickleRegistry is Admin {
/// CONSTANTS ///
uint256 constant MAX_FEE = 500; // 5%
/// ERRORS ///
error ArrayLengthMismatch(); // 0xa24a13a6
error FeeAboveMaxLimit(); // 0xd6cf7b5e
error InvalidReferralCode(); // 0xe55b4629
/// STORAGE ///
/// @notice Address of the fee collector
address public collector;
/// @notice Tracks the contracts that can be called through Sickle multicall
/// @return True if the contract is a whitelisted target
mapping(address => bool) public isWhitelistedTarget;
/// @notice Tracks the contracts that can call Sickle multicall
/// @return True if the contract is a whitelisted caller
mapping(address => bool) public isWhitelistedCaller;
/// @notice Keeps track of the referrers and their associated code
mapping(bytes32 => address) public referralCodes;
/// @notice Mapping for fee hashes (hash of the strategy contract addresses
/// and the function selectors) and their associated fees
/// @return The fee in basis points to apply to the transaction amount
mapping(bytes32 => uint256) public feeRegistry;
/// WRITE FUNCTIONS ///
/// @param admin_ Address of the admin
/// @param collector_ Address of the collector
constructor(address admin_, address collector_) Admin(admin_) {
collector = collector_;
}
/// @notice Updates the whitelist status for multiple multicall targets
/// @param targets Addresses of the contracts to update
/// @param isApproved New status for the contracts
/// @custom:access Restricted to protocol admin.
function setWhitelistedTargets(
address[] calldata targets,
bool isApproved
) external onlyAdmin {
for (uint256 i; i < targets.length;) {
isWhitelistedTarget[targets[i]] = isApproved;
emit SickleRegistryEvents.TargetStatusChanged(
targets[i], isApproved
);
unchecked {
++i;
}
}
}
/// @notice Updates the fee collector address
/// @param newCollector Address of the new fee collector
/// @custom:access Restricted to protocol admin.
function updateCollector(
address newCollector
) external onlyAdmin {
collector = newCollector;
emit SickleRegistryEvents.CollectorChanged(newCollector);
}
/// @notice Update the whitelist status for multiple multicall callers
/// @param callers Addresses of the callers
/// @param isApproved New status for the caller
/// @custom:access Restricted to protocol admin.
function setWhitelistedCallers(
address[] calldata callers,
bool isApproved
) external onlyAdmin {
for (uint256 i; i < callers.length;) {
isWhitelistedCaller[callers[i]] = isApproved;
emit SickleRegistryEvents.CallerStatusChanged(
callers[i], isApproved
);
unchecked {
++i;
}
}
}
/// @notice Associates a referral code to the address of the caller
function setReferralCode(
bytes32 referralCode
) external {
if (referralCodes[referralCode] != address(0)) {
revert InvalidReferralCode();
}
referralCodes[referralCode] = msg.sender;
emit SickleRegistryEvents.ReferralCodeCreated(referralCode, msg.sender);
}
/// @notice Update the fees for multiple strategy functions
/// @param feeHashes Array of fee hashes
/// @param feesArray Array of fees to apply (in basis points)
/// @custom:access Restricted to protocol admin.
function setFees(
bytes32[] calldata feeHashes,
uint256[] calldata feesArray
) external onlyAdmin {
if (feeHashes.length != feesArray.length) {
revert ArrayLengthMismatch();
}
for (uint256 i = 0; i < feeHashes.length;) {
if (feesArray[i] <= MAX_FEE) {
feeRegistry[feeHashes[i]] = feesArray[i];
} else {
revert FeeAboveMaxLimit();
}
unchecked {
++i;
}
}
emit SickleRegistryEvents.FeesUpdated(feeHashes, feesArray);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { Sickle } from "contracts/Sickle.sol";
import {
Farm,
HarvestParams,
CompoundParams,
WithdrawParams
} from "contracts/structs/FarmStrategyStructs.sol";
interface IAutomation {
function harvestFor(
Sickle sickle,
Farm calldata farm,
HarvestParams calldata params,
address[] calldata sweepTokens
) external;
function compoundFor(
Sickle sickle,
CompoundParams calldata params,
address[] calldata sweepTokens
) external;
function exitFor(
Sickle sickle,
Farm calldata farm,
HarvestParams calldata harvestParams,
address[] calldata harvestSweepTokens,
WithdrawParams calldata withdrawParams,
address[] calldata withdrawSweepTokens
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { Sickle } from "contracts/Sickle.sol";
import {
NftPosition,
NftRebalance,
NftHarvest,
NftWithdraw,
NftCompound
} from "contracts/structs/NftFarmStrategyStructs.sol";
interface INftAutomation {
function rebalanceFor(
Sickle sickle,
NftRebalance calldata rebalance,
address[] calldata sweepTokens
) external;
function harvestFor(
Sickle sickle,
NftPosition calldata position,
NftHarvest calldata params
) external;
function compoundFor(
Sickle sickle,
NftPosition calldata position,
NftCompound calldata params,
bool inPlace,
address[] memory sweepTokens
) external;
function exitFor(
Sickle sickle,
NftPosition calldata position,
NftHarvest calldata harvestParams,
NftWithdraw calldata withdrawParams,
address[] memory sweepTokens
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { IUniswapV3Pool } from
"contracts/interfaces/external/uniswap/IUniswapV3Pool.sol";
import { INonfungiblePositionManager } from
"contracts/interfaces/external/uniswap/INonfungiblePositionManager.sol";
import { NftZapIn, NftZapOut } from "contracts/structs/NftZapStructs.sol";
import { SwapParams } from "contracts/structs/SwapStructs.sol";
import { Farm } from "contracts/structs/FarmStrategyStructs.sol";
struct NftPosition {
Farm farm;
INonfungiblePositionManager nft;
uint256 tokenId;
}
struct NftIncrease {
address[] tokensIn;
uint256[] amountsIn;
NftZapIn zap;
bytes extraData;
}
struct NftDeposit {
Farm farm;
INonfungiblePositionManager nft;
NftIncrease increase;
}
struct NftWithdraw {
NftZapOut zap;
address[] tokensOut;
bytes extraData;
}
struct SimpleNftHarvest {
address[] rewardTokens;
uint128 amount0Max;
uint128 amount1Max;
bytes extraData;
}
struct NftHarvest {
SimpleNftHarvest harvest;
SwapParams[] swaps;
address[] outputTokens;
address[] sweepTokens;
}
struct NftCompound {
SimpleNftHarvest harvest;
NftZapIn zap;
}
struct NftRebalance {
IUniswapV3Pool pool;
NftPosition position;
NftHarvest harvest;
NftWithdraw withdraw;
NftIncrease increase;
}
struct NftMove {
IUniswapV3Pool pool;
NftPosition position;
NftHarvest harvest;
NftWithdraw withdraw;
NftDeposit deposit;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { ZapIn, ZapOut } from "contracts/structs/ZapStructs.sol";
import { SwapParams } from "contracts/structs/SwapStructs.sol";
struct Farm {
address stakingContract;
uint256 poolIndex;
}
struct DepositParams {
Farm farm;
address[] tokensIn;
uint256[] amountsIn;
ZapIn zap;
bytes extraData;
}
struct WithdrawParams {
bytes extraData;
ZapOut zap;
address[] tokensOut;
}
struct HarvestParams {
SwapParams[] swaps;
bytes extraData;
address[] tokensOut;
}
struct CompoundParams {
Farm claimFarm;
bytes claimExtraData;
address[] rewardTokens;
ZapIn zap;
Farm depositFarm;
bytes depositExtraData;
}
struct SimpleDepositParams {
Farm farm;
address lpToken;
uint256 amountIn;
bytes extraData;
}
struct SimpleHarvestParams {
address[] rewardTokens;
bytes extraData;
}
struct SimpleWithdrawParams {
address lpToken;
uint256 amountOut;
bytes extraData;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
library AutomationPermissions {
uint256 internal constant FARM_HARVEST = 1 << 0;
uint256 internal constant FARM_COMPOUND = 1 << 1;
uint256 internal constant FARM_EXIT = 1 << 2;
uint256 internal constant NFT_HARVEST = 1 << 3;
uint256 internal constant NFT_COMPOUND = 1 << 4;
uint256 internal constant NFT_EXIT = 1 << 5;
uint256 internal constant NFT_REBALANCE = 1 << 6;
uint256 internal constant ALL = (1 << 7) - 1;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { Initializable } from
"@openzeppelin/contracts/proxy/utils/Initializable.sol";
library SickleStorageEvents {
event ApprovedAddressChanged(address newApproved);
}
/// @title SickleStorage contract
/// @author vfat.tools
/// @notice Base storage of the Sickle contract
/// @dev This contract needs to be inherited by stub contracts meant to be used
/// with `delegatecall`
abstract contract SickleStorage is Initializable {
/// ERRORS ///
/// @notice Thrown when the caller is not the owner of the Sickle contract
error NotOwnerError(); // 0x74a21527
/// @notice Thrown when the caller is not a strategy contract or the
/// Flashloan Stub
error NotStrategyError(); // 0x4581ba62
/// STORAGE ///
/// @notice Address of the owner
address public owner;
/// @notice An address that can be set by the owner of the Sickle contract
/// in order to trigger specific functions.
address public approved;
/// MODIFIERS ///
/// @dev Restricts a function call to the owner of the Sickle contract
modifier onlyOwner() {
if (msg.sender != owner) revert NotOwnerError();
_;
}
/// INITIALIZATION ///
/// @param owner_ Address of the owner of this Sickle contract
function _initializeSickleStorage(
address owner_,
address approved_
) internal onlyInitializing {
owner = owner_;
approved = approved_;
}
/// WRITE FUNCTIONS ///
/// @notice Sets the approved address of this Sickle
/// @param newApproved Address meant to be approved by the owner
function setApproved(
address newApproved
) external onlyOwner {
approved = newApproved;
emit SickleStorageEvents.ApprovedAddressChanged(newApproved);
}
/// @notice Checks if `caller` is either the owner of the Sickle contract
/// or was approved by them
/// @param caller Address to check
/// @return True if `caller` is either the owner of the Sickle contract
function isOwnerOrApproved(
address caller
) public view returns (bool) {
return caller == owner || caller == approved;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { SickleRegistry } from "contracts/SickleRegistry.sol";
/// @title Multicall contract
/// @author vfat.tools
/// @notice Enables calling multiple methods in a single call to the contract
abstract contract Multicall {
/// ERRORS ///
error MulticallParamsMismatchError(); // 0xc1e637c9
/// @notice Thrown when the target contract is not whitelisted
/// @param target Address of the non-whitelisted target
error TargetNotWhitelisted(address target); // 0x47ccabe7
/// @notice Thrown when the caller is not whitelisted
/// @param caller Address of the non-whitelisted caller
error CallerNotWhitelisted(address caller); // 0x252c8273
/// STORAGE ///
/// @notice Address of the SickleRegistry contract
/// @dev Needs to be immutable so that it's accessible for Sickle proxies
SickleRegistry public immutable registry;
/// INITIALIZATION ///
/// @param registry_ Address of the SickleRegistry contract
constructor(
SickleRegistry registry_
) {
registry = registry_;
}
/// WRITE FUNCTIONS ///
/// @notice Batch multiple calls together (calls or delegatecalls)
/// @param targets Array of targets to call
/// @param data Array of data to pass with the calls
function multicall(
address[] calldata targets,
bytes[] calldata data
) external payable {
if (targets.length != data.length) {
revert MulticallParamsMismatchError();
}
if (!registry.isWhitelistedCaller(msg.sender)) {
revert CallerNotWhitelisted(msg.sender);
}
for (uint256 i = 0; i != data.length;) {
if (targets[i] == address(0)) {
unchecked {
++i;
}
continue; // No-op
}
if (targets[i] != address(this)) {
if (!registry.isWhitelistedTarget(targets[i])) {
revert TargetNotWhitelisted(targets[i]);
}
}
(bool success, bytes memory result) =
targets[i].delegatecall(data[i]);
if (!success) {
if (result.length == 0) revert();
assembly {
revert(add(32, result), mload(result))
}
}
unchecked {
++i;
}
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Pool state that never changes
/// @notice These parameters are fixed for a pool forever, i.e., the methods
/// will always return the same values
interface IUniswapV3PoolImmutables {
/// @notice The contract that deployed the pool, which must adhere to the
/// IUniswapV3Factory interface
/// @return The contract address
function factory() external view returns (address);
/// @notice The first of the two tokens of the pool, sorted by address
/// @return The token contract address
function token0() external view returns (address);
/// @notice The second of the two tokens of the pool, sorted by address
/// @return The token contract address
function token1() external view returns (address);
/// @notice The pool's fee in hundredths of a bip, i.e. 1e-6
/// @return The fee
function fee() external view returns (uint24);
/// @notice The pool tick spacing
/// @dev Ticks can only be used at multiples of this value, minimum of 1 and
/// always positive
/// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick,
/// i.e., ..., -6, -3, 0, 3, 6, ...
/// This value is an int24 to avoid casting even though it is always
/// positive.
/// @return The tick spacing
function tickSpacing() external view returns (int24);
/// @notice The maximum amount of position liquidity that can use any tick
/// in the range
/// @dev This parameter is enforced per tick to prevent liquidity from
/// overflowing a uint128 at any point, and
/// also prevents out-of-range liquidity from being used to prevent adding
/// in-range liquidity to a pool
/// @return The max amount of liquidity per tick
function maxLiquidityPerTick() external view returns (uint128);
}
/// @title Pool state that can change
/// @notice These methods compose the pool's state, and can change with any
/// frequency including multiple times
/// per transaction
interface IUniswapV3PoolState {
/// @notice The 0th storage slot in the pool stores many values, and is
/// exposed as a single method to save gas
/// when accessed externally.
/// @return sqrtPriceX96 The current price of the pool as a
/// sqrt(token1/token0) Q64.96 value
/// @return tick The current tick of the pool, i.e. according to the last
/// tick transition that was run.
/// This value may not always be equal to
/// SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick
/// boundary.
/// @return observationIndex The index of the last oracle observation that
/// was written,
/// @return observationCardinality The current maximum number of
/// observations stored in the pool,
/// @return observationCardinalityNext The next maximum number of
/// observations, to be updated when the observation.
/// @return feeProtocol The protocol fee for both tokens of the pool.
/// Encoded as two 4 bit values, where the protocol fee of token1 is shifted
/// 4 bits and the protocol fee of token0
/// is the lower 4 bits. Used as the denominator of a fraction of the swap
/// fee, e.g. 4 means 1/4th of the swap fee.
/// unlocked Whether the pool is currently locked to reentrancy
function slot0()
external
view
returns (
uint160 sqrtPriceX96,
int24 tick,
uint16 observationIndex,
uint16 observationCardinality,
uint16 observationCardinalityNext,
uint8 feeProtocol,
bool unlocked
);
/// @notice The fee growth as a Q128.128 fees of token0 collected per unit
/// of liquidity for the entire life of the pool
/// @dev This value can overflow the uint256
function feeGrowthGlobal0X128() external view returns (uint256);
/// @notice The fee growth as a Q128.128 fees of token1 collected per unit
/// of liquidity for the entire life of the pool
/// @dev This value can overflow the uint256
function feeGrowthGlobal1X128() external view returns (uint256);
/// @notice The amounts of token0 and token1 that are owed to the protocol
/// @dev Protocol fees will never exceed uint128 max in either token
function protocolFees()
external
view
returns (uint128 token0, uint128 token1);
/// @notice The currently in range liquidity available to the pool
/// @dev This value has no relationship to the total liquidity across all
/// ticks
/// @return The liquidity at the current price of the pool
function liquidity() external view returns (uint128);
/// @notice Look up information about a specific tick in the pool
/// @param tick The tick to look up
/// @return liquidityGross the total amount of position liquidity that uses
/// the pool either as tick lower or
/// tick upper
/// @return liquidityNet how much liquidity changes when the pool price
/// crosses the tick,
/// @return feeGrowthOutside0X128 the fee growth on the other side of the
/// tick from the current tick in token0,
/// @return feeGrowthOutside1X128 the fee growth on the other side of the
/// tick from the current tick in token1,
/// @return tickCumulativeOutside the cumulative tick value on the other
/// side of the tick from the current tick
/// @return secondsPerLiquidityOutsideX128 the seconds spent per liquidity
/// on the other side of the tick from the current tick,
/// @return secondsOutside the seconds spent on the other side of the tick
/// from the current tick,
/// @return initialized Set to true if the tick is initialized, i.e.
/// liquidityGross is greater than 0, otherwise equal to false.
/// Outside values can only be used if the tick is initialized, i.e. if
/// liquidityGross is greater than 0.
/// In addition, these values are only relative and must be used only in
/// comparison to previous snapshots for
/// a specific position.
function ticks(
int24 tick
)
external
view
returns (
uint128 liquidityGross,
int128 liquidityNet,
uint256 feeGrowthOutside0X128,
uint256 feeGrowthOutside1X128,
int56 tickCumulativeOutside,
uint160 secondsPerLiquidityOutsideX128,
uint32 secondsOutside,
bool initialized
);
/// @notice Returns 256 packed tick initialized boolean values. See
/// TickBitmap for more information
function tickBitmap(
int16 wordPosition
) external view returns (uint256);
/// @notice Returns the information about a position by the position's key
/// @param key The position's key is a hash of a preimage composed by the
/// owner, tickLower and tickUpper
/// @return liquidity The amount of liquidity in the position,
/// @return feeGrowthInside0LastX128 fee growth of token0 inside the tick
/// range as of the last mint/burn/poke,
/// @return feeGrowthInside1LastX128 fee growth of token1 inside the tick
/// range as of the last mint/burn/poke,
/// @return tokensOwed0 the computed amount of token0 owed to the position
/// as of the last mint/burn/poke,
/// @return tokensOwed1 the computed amount of token1 owed to the position
/// as of the last mint/burn/poke
function positions(
bytes32 key
)
external
view
returns (
uint128 liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
uint128 tokensOwed0,
uint128 tokensOwed1
);
/// @notice Returns data about a specific observation index
/// @param index The element of the observations array to fetch
/// @dev You most likely want to use #observe() instead of this method to
/// get an observation as of some amount of time
/// ago, rather than at a specific index in the array.
/// @return blockTimestamp The timestamp of the observation,
/// @return tickCumulative the tick multiplied by seconds elapsed for the
/// life of the pool as of the observation timestamp,
/// @return secondsPerLiquidityCumulativeX128 the seconds per in range
/// liquidity for the life of the pool as of the observation timestamp,
/// @return initialized whether the observation has been initialized and the
/// values are safe to use
function observations(
uint256 index
)
external
view
returns (
uint32 blockTimestamp,
int56 tickCumulative,
uint160 secondsPerLiquidityCumulativeX128,
bool initialized
);
}
interface IUniswapV3Pool is IUniswapV3PoolImmutables, IUniswapV3PoolState {
function flash(
address recipient,
uint256 amount0,
uint256 amount1,
bytes calldata data
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IERC721Enumerable } from
"openzeppelin-contracts/contracts/interfaces/IERC721Enumerable.sol";
interface INonfungiblePositionManager is IERC721Enumerable {
struct IncreaseLiquidityParams {
uint256 tokenId;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
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 DecreaseLiquidityParams {
uint256 tokenId;
uint128 liquidity;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
struct CollectParams {
uint256 tokenId;
address recipient;
uint128 amount0Max;
uint128 amount1Max;
}
function increaseLiquidity(
IncreaseLiquidityParams memory params
)
external
payable
returns (uint256 amount0, uint256 amount1, uint256 liquidity);
function decreaseLiquidity(
DecreaseLiquidityParams calldata params
) external payable returns (uint256 amount0, uint256 amount1);
function mint(
MintParams memory params
)
external
payable
returns (uint256 tokenId, uint256 amount0, uint256 amount1);
function collect(
CollectParams calldata params
) external payable returns (uint256 amount0, uint256 amount1);
function burn(
uint256 tokenId
) external payable;
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
);
function factory() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { SwapParams } from "contracts/structs/SwapStructs.sol";
import {
NftAddLiquidity,
NftRemoveLiquidity
} from "contracts/structs/NftLiquidityStructs.sol";
struct NftZapIn {
SwapParams[] swaps;
NftAddLiquidity addLiquidityParams;
}
struct NftZapOut {
NftRemoveLiquidity removeLiquidityParams;
SwapParams[] swaps;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
struct SwapParams {
address tokenApproval;
address router;
uint256 amountIn;
uint256 desiredAmountOut;
uint256 minAmountOut;
address tokenIn;
address tokenOut;
bytes extraData;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { SwapParams } from "contracts/structs/SwapStructs.sol";
import {
AddLiquidityParams,
RemoveLiquidityParams
} from "contracts/structs/LiquidityStructs.sol";
struct ZapIn {
SwapParams[] swaps;
AddLiquidityParams addLiquidityParams;
}
struct ZapOut {
RemoveLiquidityParams removeLiquidityParams;
SwapParams[] swaps;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/Address.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC721Enumerable.sol) pragma solidity ^0.8.0; import "../token/ERC721/extensions/IERC721Enumerable.sol";
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { INonfungiblePositionManager } from
"contracts/interfaces/external/uniswap/INonfungiblePositionManager.sol";
struct Pool {
address token0;
address token1;
uint24 fee;
}
struct NftPoolKey {
address poolAddress;
bytes32 poolId;
}
struct NftPoolInfo {
address token0;
address token1;
uint24 fee;
uint24 tickSpacing;
uint160 sqrtPriceX96;
int24 tick;
uint128 liquidity;
uint256 feeGrowthGlobal0X128;
uint256 feeGrowthGlobal1X128;
}
// Maintained for backwards compatibility with NftSettingsRegistry
struct NftPositionInfo {
uint128 liquidity;
int24 tickLower;
int24 tickUpper;
}
struct NftAddLiquidity {
INonfungiblePositionManager nft;
uint256 tokenId;
Pool pool;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
bytes extraData;
}
struct NftRemoveLiquidity {
INonfungiblePositionManager nft;
uint256 tokenId;
uint128 liquidity;
uint256 amount0Min; // For decreasing
uint256 amount1Min;
uint128 amount0Max; // For collecting
uint128 amount1Max;
bytes extraData;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
struct AddLiquidityParams {
address router;
address lpToken;
address[] tokens;
uint256[] desiredAmounts;
uint256[] minAmounts;
bytes extraData;
}
struct RemoveLiquidityParams {
address router;
address lpToken;
address[] tokens;
uint256 lpAmountIn;
uint256[] minAmountsOut;
bytes extraData;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)
pragma solidity ^0.8.0;
import "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Enumerable is IERC721 {
/**
* @dev Returns the total amount of tokens stored by the contract.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns a token ID owned by `owner` at a given `index` of its token list.
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
*/
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
/**
* @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
* Use along with {totalSupply} to enumerate all tokens.
*/
function tokenByIndex(uint256 index) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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 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);
}{
"remappings": [
"solmate/=lib/solmate/src/",
"@openzeppelin/=lib/openzeppelin-contracts/",
"@morpho-blue/=lib/morpho-blue/src/",
"ds-test/=lib/solmate/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"morpho-blue/=lib/morpho-blue/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract SickleRegistry","name":"registry","type":"address"},{"internalType":"address","name":"admin","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"approvedAutomator","type":"address"}],"name":"ApprovedAutomatorAlreadySet","type":"error"},{"inputs":[{"internalType":"address","name":"approvedAutomator","type":"address"}],"name":"ApprovedAutomatorNotSet","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerNotWhitelisted","type":"error"},{"inputs":[],"name":"InvalidAutomator","type":"error"},{"inputs":[],"name":"InvalidInputLength","type":"error"},{"inputs":[],"name":"MalformedPermissions","type":"error"},{"inputs":[],"name":"MulticallParamsMismatchError","type":"error"},{"inputs":[],"name":"NotAdminError","type":"error"},{"inputs":[],"name":"NotApprovedAutomator","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"TargetNotWhitelisted","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"approvedAutomator","type":"address"},{"indexed":false,"internalType":"uint256","name":"permissions","type":"uint256"}],"name":"ApprovedAutomatorPermissionsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"approvedAutomator","type":"address"}],"name":"ApprovedAutomatorRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"approvedAutomator","type":"address"}],"name":"ApprovedAutomatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract Sickle","name":"sickle","type":"address"},{"indexed":true,"internalType":"address","name":"claimStakingContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"claimPoolIndex","type":"uint256"},{"indexed":true,"internalType":"address","name":"depositStakingContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"depositPoolIndex","type":"uint256"},{"indexed":false,"internalType":"address","name":"automator","type":"address"}],"name":"CompoundedFor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract Sickle","name":"sickle","type":"address"},{"indexed":true,"internalType":"address","name":"automator","type":"address"},{"indexed":false,"internalType":"uint256","name":"permissions","type":"uint256"}],"name":"CustomAutomatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract Sickle","name":"sickle","type":"address"},{"indexed":true,"internalType":"address","name":"stakingContract","type":"address"},{"indexed":true,"internalType":"uint256","name":"poolIndex","type":"uint256"},{"indexed":false,"internalType":"address","name":"automator","type":"address"}],"name":"ExitedFor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract Sickle","name":"sickle","type":"address"},{"indexed":true,"internalType":"address","name":"stakingContract","type":"address"},{"indexed":true,"internalType":"uint256","name":"poolIndex","type":"uint256"},{"indexed":false,"internalType":"address","name":"automator","type":"address"}],"name":"HarvestedFor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract Sickle","name":"sickle","type":"address"},{"indexed":true,"internalType":"address","name":"nftAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"automator","type":"address"}],"name":"NftCompoundedFor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract Sickle","name":"sickle","type":"address"},{"indexed":true,"internalType":"address","name":"nftAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"automator","type":"address"}],"name":"NftExitedFor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract Sickle","name":"sickle","type":"address"},{"indexed":true,"internalType":"address","name":"nftAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"automator","type":"address"}],"name":"NftHarvestedFor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract Sickle","name":"sickle","type":"address"},{"indexed":true,"internalType":"address","name":"nftAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"automator","type":"address"}],"name":"NftRebalancedFor","type":"event"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"approvedAutomators","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"approvedAutomatorsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract INftAutomation[]","name":"strategies","type":"address[]"},{"internalType":"contract Sickle[]","name":"sickles","type":"address[]"},{"components":[{"components":[{"internalType":"address","name":"stakingContract","type":"address"},{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"internalType":"struct Farm","name":"farm","type":"tuple"},{"internalType":"contract INonfungiblePositionManager","name":"nft","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"internalType":"struct NftPosition[]","name":"positions","type":"tuple[]"},{"components":[{"components":[{"internalType":"address[]","name":"rewardTokens","type":"address[]"},{"internalType":"uint128","name":"amount0Max","type":"uint128"},{"internalType":"uint128","name":"amount1Max","type":"uint128"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct SimpleNftHarvest","name":"harvest","type":"tuple"},{"components":[{"components":[{"internalType":"address","name":"tokenApproval","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"desiredAmountOut","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct SwapParams[]","name":"swaps","type":"tuple[]"},{"components":[{"internalType":"contract INonfungiblePositionManager","name":"nft","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"}],"internalType":"struct Pool","name":"pool","type":"tuple"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint256","name":"amount0Desired","type":"uint256"},{"internalType":"uint256","name":"amount1Desired","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct NftAddLiquidity","name":"addLiquidityParams","type":"tuple"}],"internalType":"struct NftZapIn","name":"zap","type":"tuple"}],"internalType":"struct NftCompound[]","name":"params","type":"tuple[]"},{"internalType":"bool[]","name":"inPlace","type":"bool[]"},{"internalType":"address[][]","name":"sweepTokens","type":"address[][]"}],"name":"compoundFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IAutomation[]","name":"strategies","type":"address[]"},{"internalType":"contract Sickle[]","name":"sickles","type":"address[]"},{"components":[{"components":[{"internalType":"address","name":"stakingContract","type":"address"},{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"internalType":"struct Farm","name":"claimFarm","type":"tuple"},{"internalType":"bytes","name":"claimExtraData","type":"bytes"},{"internalType":"address[]","name":"rewardTokens","type":"address[]"},{"components":[{"components":[{"internalType":"address","name":"tokenApproval","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"desiredAmountOut","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct SwapParams[]","name":"swaps","type":"tuple[]"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"lpToken","type":"address"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"desiredAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"minAmounts","type":"uint256[]"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct AddLiquidityParams","name":"addLiquidityParams","type":"tuple"}],"internalType":"struct ZapIn","name":"zap","type":"tuple"},{"components":[{"internalType":"address","name":"stakingContract","type":"address"},{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"internalType":"struct Farm","name":"depositFarm","type":"tuple"},{"internalType":"bytes","name":"depositExtraData","type":"bytes"}],"internalType":"struct CompoundParams[]","name":"params","type":"tuple[]"},{"internalType":"address[][]","name":"sweepTokens","type":"address[][]"}],"name":"compoundFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Sickle","name":"","type":"address"}],"name":"customAutomatorCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Sickle","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"customAutomatorPermissions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract INftAutomation[]","name":"strategies","type":"address[]"},{"internalType":"contract Sickle[]","name":"sickles","type":"address[]"},{"components":[{"components":[{"internalType":"address","name":"stakingContract","type":"address"},{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"internalType":"struct Farm","name":"farm","type":"tuple"},{"internalType":"contract INonfungiblePositionManager","name":"nft","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"internalType":"struct NftPosition[]","name":"positions","type":"tuple[]"},{"components":[{"components":[{"internalType":"address[]","name":"rewardTokens","type":"address[]"},{"internalType":"uint128","name":"amount0Max","type":"uint128"},{"internalType":"uint128","name":"amount1Max","type":"uint128"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct SimpleNftHarvest","name":"harvest","type":"tuple"},{"components":[{"internalType":"address","name":"tokenApproval","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"desiredAmountOut","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct SwapParams[]","name":"swaps","type":"tuple[]"},{"internalType":"address[]","name":"outputTokens","type":"address[]"},{"internalType":"address[]","name":"sweepTokens","type":"address[]"}],"internalType":"struct NftHarvest[]","name":"harvestParams","type":"tuple[]"},{"components":[{"components":[{"components":[{"internalType":"contract INonfungiblePositionManager","name":"nft","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"uint128","name":"amount0Max","type":"uint128"},{"internalType":"uint128","name":"amount1Max","type":"uint128"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct NftRemoveLiquidity","name":"removeLiquidityParams","type":"tuple"},{"components":[{"internalType":"address","name":"tokenApproval","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"desiredAmountOut","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct SwapParams[]","name":"swaps","type":"tuple[]"}],"internalType":"struct NftZapOut","name":"zap","type":"tuple"},{"internalType":"address[]","name":"tokensOut","type":"address[]"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct NftWithdraw[]","name":"withdrawParams","type":"tuple[]"},{"internalType":"address[][]","name":"sweepTokens","type":"address[][]"}],"name":"exitFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IAutomation[]","name":"strategies","type":"address[]"},{"internalType":"contract Sickle[]","name":"sickles","type":"address[]"},{"components":[{"internalType":"address","name":"stakingContract","type":"address"},{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"internalType":"struct Farm[]","name":"farms","type":"tuple[]"},{"components":[{"components":[{"internalType":"address","name":"tokenApproval","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"desiredAmountOut","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct SwapParams[]","name":"swaps","type":"tuple[]"},{"internalType":"bytes","name":"extraData","type":"bytes"},{"internalType":"address[]","name":"tokensOut","type":"address[]"}],"internalType":"struct HarvestParams[]","name":"harvestParams","type":"tuple[]"},{"internalType":"address[][]","name":"harvestSweepTokens","type":"address[][]"},{"components":[{"internalType":"bytes","name":"extraData","type":"bytes"},{"components":[{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"lpToken","type":"address"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"lpAmountIn","type":"uint256"},{"internalType":"uint256[]","name":"minAmountsOut","type":"uint256[]"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct RemoveLiquidityParams","name":"removeLiquidityParams","type":"tuple"},{"components":[{"internalType":"address","name":"tokenApproval","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"desiredAmountOut","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct SwapParams[]","name":"swaps","type":"tuple[]"}],"internalType":"struct ZapOut","name":"zap","type":"tuple"},{"internalType":"address[]","name":"tokensOut","type":"address[]"}],"internalType":"struct WithdrawParams[]","name":"withdrawParams","type":"tuple[]"},{"internalType":"address[][]","name":"withdrawSweepTokens","type":"address[][]"}],"name":"exitFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"globalAutomatorPermissions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract INftAutomation[]","name":"strategies","type":"address[]"},{"internalType":"contract Sickle[]","name":"sickles","type":"address[]"},{"components":[{"components":[{"internalType":"address","name":"stakingContract","type":"address"},{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"internalType":"struct Farm","name":"farm","type":"tuple"},{"internalType":"contract INonfungiblePositionManager","name":"nft","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"internalType":"struct NftPosition[]","name":"positions","type":"tuple[]"},{"components":[{"components":[{"internalType":"address[]","name":"rewardTokens","type":"address[]"},{"internalType":"uint128","name":"amount0Max","type":"uint128"},{"internalType":"uint128","name":"amount1Max","type":"uint128"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct SimpleNftHarvest","name":"harvest","type":"tuple"},{"components":[{"internalType":"address","name":"tokenApproval","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"desiredAmountOut","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct SwapParams[]","name":"swaps","type":"tuple[]"},{"internalType":"address[]","name":"outputTokens","type":"address[]"},{"internalType":"address[]","name":"sweepTokens","type":"address[]"}],"internalType":"struct NftHarvest[]","name":"params","type":"tuple[]"}],"name":"harvestFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IAutomation[]","name":"strategies","type":"address[]"},{"internalType":"contract Sickle[]","name":"sickles","type":"address[]"},{"components":[{"internalType":"address","name":"stakingContract","type":"address"},{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"internalType":"struct Farm[]","name":"farms","type":"tuple[]"},{"components":[{"components":[{"internalType":"address","name":"tokenApproval","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"desiredAmountOut","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct SwapParams[]","name":"swaps","type":"tuple[]"},{"internalType":"bytes","name":"extraData","type":"bytes"},{"internalType":"address[]","name":"tokensOut","type":"address[]"}],"internalType":"struct HarvestParams[]","name":"params","type":"tuple[]"},{"internalType":"address[][]","name":"sweepTokens","type":"address[][]"}],"name":"harvestFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isApprovedAutomator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract INftAutomation[]","name":"strategies","type":"address[]"},{"internalType":"contract Sickle[]","name":"sickles","type":"address[]"},{"components":[{"internalType":"contract IUniswapV3Pool","name":"pool","type":"address"},{"components":[{"components":[{"internalType":"address","name":"stakingContract","type":"address"},{"internalType":"uint256","name":"poolIndex","type":"uint256"}],"internalType":"struct Farm","name":"farm","type":"tuple"},{"internalType":"contract INonfungiblePositionManager","name":"nft","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"internalType":"struct NftPosition","name":"position","type":"tuple"},{"components":[{"components":[{"internalType":"address[]","name":"rewardTokens","type":"address[]"},{"internalType":"uint128","name":"amount0Max","type":"uint128"},{"internalType":"uint128","name":"amount1Max","type":"uint128"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct SimpleNftHarvest","name":"harvest","type":"tuple"},{"components":[{"internalType":"address","name":"tokenApproval","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"desiredAmountOut","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct SwapParams[]","name":"swaps","type":"tuple[]"},{"internalType":"address[]","name":"outputTokens","type":"address[]"},{"internalType":"address[]","name":"sweepTokens","type":"address[]"}],"internalType":"struct NftHarvest","name":"harvest","type":"tuple"},{"components":[{"components":[{"components":[{"internalType":"contract INonfungiblePositionManager","name":"nft","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"uint128","name":"amount0Max","type":"uint128"},{"internalType":"uint128","name":"amount1Max","type":"uint128"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct NftRemoveLiquidity","name":"removeLiquidityParams","type":"tuple"},{"components":[{"internalType":"address","name":"tokenApproval","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"desiredAmountOut","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct SwapParams[]","name":"swaps","type":"tuple[]"}],"internalType":"struct NftZapOut","name":"zap","type":"tuple"},{"internalType":"address[]","name":"tokensOut","type":"address[]"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct NftWithdraw","name":"withdraw","type":"tuple"},{"components":[{"internalType":"address[]","name":"tokensIn","type":"address[]"},{"internalType":"uint256[]","name":"amountsIn","type":"uint256[]"},{"components":[{"components":[{"internalType":"address","name":"tokenApproval","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"desiredAmountOut","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct SwapParams[]","name":"swaps","type":"tuple[]"},{"components":[{"internalType":"contract INonfungiblePositionManager","name":"nft","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"}],"internalType":"struct Pool","name":"pool","type":"tuple"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint256","name":"amount0Desired","type":"uint256"},{"internalType":"uint256","name":"amount1Desired","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct NftAddLiquidity","name":"addLiquidityParams","type":"tuple"}],"internalType":"struct NftZapIn","name":"zap","type":"tuple"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct NftIncrease","name":"increase","type":"tuple"}],"internalType":"struct NftRebalance[]","name":"params","type":"tuple[]"},{"internalType":"address[][]","name":"sweepTokens","type":"address[][]"}],"name":"rebalanceFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"contract SickleRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"approvedAutomator","type":"address"}],"name":"revokeApprovedAutomator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"approvedAutomator","type":"address"}],"name":"setApprovedAutomator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"approvedAutomator","type":"address"},{"internalType":"uint256","name":"permissions","type":"uint256"}],"name":"setApprovedAutomatorWithPermissions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Sickle","name":"sickle","type":"address"},{"internalType":"address","name":"automator","type":"address"},{"internalType":"uint256","name":"permissions","type":"uint256"}],"name":"setCustomAutomatorForSickle","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a06040523480156200001157600080fd5b5060405162004a1d38038062004a1d8339810160408190526200003491620000bc565b60408051600081526001600160a01b0383166020820152839183917fbf265e8326285a2747e33e54d5945f7111f2b5edb826eb8c08d4677779b3ff97910160405180910390a1600080546001600160a01b0319166001600160a01b039283161790551660805250620000fb9050565b6001600160a01b0381168114620000b957600080fd5b50565b60008060408385031215620000d057600080fd5b8251620000dd81620000a3565b6020840151909250620000f081620000a3565b809150509250929050565b6080516148f862000125600039600081816102d601528181611511015261162401526148f86000f3fe60806040526004361061012a5760003560e01c8063704b6c02116100ab578063a626fb181161006f578063a626fb1814610370578063a70cd9ec14610390578063b7e01c61146103b0578063c64a6646146103dd578063d4b120031461040a578063f851a4401461042a57600080fd5b8063704b6c0214610284578063745a7b3b146102a45780637b103999146102c45780638a34557014610310578063a1ed7dbf1461035057600080fd5b80632f372a8d116100f25780632f372a8d146101fc5780632f51053e1461021c5780634456d1551461023c5780635be6d0621461025c57806363fb0b961461027157600080fd5b806303c325c91461012f57806307914b70146101515780630a1d5c28146101715780630cebe455146101915780631ccb65ff146101dc575b600080fd5b34801561013b57600080fd5b5061014f61014a3660046122a0565b61044a565b005b34801561015d57600080fd5b5061014f61016c366004612b30565b6105a8565b34801561017d57600080fd5b5061014f61018c366004612d4f565b6108ae565b34801561019d57600080fd5b506101c96101ac366004612dfb565b600460209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b3480156101e857600080fd5b5061014f6101f7366004612e34565b610b64565b34801561020857600080fd5b5061014f6102173660046130ae565b610d83565b34801561022857600080fd5b5061014f6102373660046132eb565b610fe0565b34801561024857600080fd5b5061014f61025736600461353e565b611283565b34801561026857600080fd5b506001546101c9565b61014f61027f36600461373d565b6114dc565b34801561029057600080fd5b5061014f61029f366004612e34565b611808565b3480156102b057600080fd5b5061014f6102bf366004612e34565b61189c565b3480156102d057600080fd5b506102f87f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101d3565b34801561031c57600080fd5b5061034061032b366004612e34565b60026020526000908152604090205460ff1681565b60405190151581526020016101d3565b34801561035c57600080fd5b5061014f61036b3660046137a8565b6118d5565b34801561037c57600080fd5b5061014f61038b36600461393d565b6119ab565b34801561039c57600080fd5b5061014f6103ab366004613c42565b611c92565b3480156103bc57600080fd5b506101c96103cb366004612e34565b60036020526000908152604090205481565b3480156103e957600080fd5b506101c96103f8366004612e34565b60056020526000908152604090205481565b34801561041657600080fd5b506102f8610425366004613d5c565b611ffe565b34801561043657600080fd5b506000546102f8906001600160a01b031681565b6000546001600160a01b031633146104755760405163b5c42b3b60e01b815260040160405180910390fd5b80607f81111561049857604051635766676360e11b815260040160405180910390fd5b6001600160a01b03808516600090815260046020908152604080832093871683529290522054801580156104cb57508215155b15610504576001600160a01b03851660009081526005602052604081208054600192906104f9908490613d8b565b909155506105459050565b8015801590610511575082155b15610545576001600160a01b038516600090815260056020526040812080546001929061053f908490613da4565b90915550505b6001600160a01b0385811660008181526004602090815260408083209489168084529482529182902087905590518681527fc8e12a019de4be77a3cda6c88d78af1110a6ed9d92237bf1efe2cfce755943f8910160405180910390a35050505050565b85518551811415806105bb575084518114155b806105c7575083518114155b806105d3575082518114155b806105df575081518114155b156105fd57604051637db491eb60e01b815260040160405180910390fd5b610608866010612028565b6000816001600160401b03811115610622576106226122e1565b60405190808252806020026020018201604052801561064b578160200160208202803683370190505b5090506000826001600160401b03811115610668576106686122e1565b60405190808252806020026020018201604052801561069b57816020015b60608152602001906001900390816106865790505b50905060005b8381101561084b5760008982815181106106bd576106bd613db7565b6020026020010151905060008983815181106106db576106db613db7565b602002602001015190508b83815181106106f7576106f7613db7565b602002602001015185848151811061071157610711613db7565b60200260200101906001600160a01b031690816001600160a01b03168152505081818a858151811061074557610745613db7565b60200260200101518a868151811061075f5761075f613db7565b60200260200101518a878151811061077957610779613db7565b602002602001015160405160240161079595949392919061409f565b60408051601f198184030181529190526020810180516001600160e01b03166371d5234960e11b17905284518590859081106107d3576107d3613db7565b6020026020010181905250806040015181602001516001600160a01b0316836001600160a01b03167fed73c824d2ad87eb6b4bc3bfa75956d9417414a86cefdb6fb8b47629d56fbfe53360405161083991906001600160a01b0391909116815260200190565b60405180910390a450506001016106a1565b506040516331fd85cb60e11b815230906363fb0b96906108719085908590600401614121565b600060405180830381600087803b15801561088b57600080fd5b505af115801561089f573d6000803e3d6000fd5b50505050505050505050505050565b83518351811415806108c1575082518114155b806108cd575081518114155b156108eb57604051637db491eb60e01b815260040160405180910390fd5b6108f6846008612028565b6000816001600160401b03811115610910576109106122e1565b604051908082528060200260200182016040528015610939578160200160208202803683370190505b5090506000826001600160401b03811115610956576109566122e1565b60405190808252806020026020018201604052801561098957816020015b60608152602001906001900390816109745790505b50905060005b83811015610b035760008782815181106109ab576109ab613db7565b6020026020010151905060008783815181106109c9576109c9613db7565b602002602001015190508983815181106109e5576109e5613db7565b60200260200101518584815181106109ff576109ff613db7565b60200260200101906001600160a01b031690816001600160a01b0316815250508181888581518110610a3357610a33613db7565b6020026020010151604051602401610a4d939291906141f5565b60408051601f198184030181529190526020810180516001600160e01b031663d839d94560e01b1790528451859085908110610a8b57610a8b613db7565b6020026020010181905250806040015181602001516001600160a01b0316836001600160a01b03167f697aab48888e7948540cc636dbf061073f4cdad5501a4225494ec07549502d2333604051610af191906001600160a01b0391909116815260200190565b60405180910390a4505060010161098f565b506040516331fd85cb60e11b815230906363fb0b9690610b299085908590600401614121565b600060405180830381600087803b158015610b4357600080fd5b505af1158015610b57573d6000803e3d6000fd5b5050505050505050505050565b6000546001600160a01b03163314610b8f5760405163b5c42b3b60e01b815260040160405180910390fd5b6001600160a01b03811660009081526002602052604090205460ff16610bd8576040516342ad5b3f60e01b81526001600160a01b03821660048201526024015b60405180910390fd5b60005b600154811015610cdf57816001600160a01b031660018281548110610c0257610c02613db7565b6000918252602090912001546001600160a01b031603610ccd5760018054610c2b908290613da4565b81548110610c3b57610c3b613db7565b600091825260209091200154600180546001600160a01b039092169183908110610c6757610c67613db7565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506001805480610ca657610ca6614224565b600082815260209020810160001990810180546001600160a01b0319169055019055610cdf565b80610cd78161423a565b915050610bdb565b506001600160a01b0381166000818152600260209081526040808320805460ff19169055600382528083208390558051938452908301919091527f0e5fb30aa3d58cccbcbf21f7cb9601475127b8811b2a0f047c761734f897d436910160405180910390a16040516001600160a01b03821681527f09c1ab3a33736061b9ab4db19afb80345fb417d89a6b531651d8c51291bf507f9060200160405180910390a150565b8351835181141580610d96575082518114155b80610da2575081518114155b15610dc057604051637db491eb60e01b815260040160405180910390fd5b610dcb846040612028565b6000816001600160401b03811115610de557610de56122e1565b604051908082528060200260200182016040528015610e0e578160200160208202803683370190505b5090506000826001600160401b03811115610e2b57610e2b6122e1565b604051908082528060200260200182016040528015610e5e57816020015b6060815260200190600190039081610e495790505b50905060005b83811015610b03576000868281518110610e8057610e80613db7565b602002602001015190506000888381518110610e9e57610e9e613db7565b60200260200101519050898381518110610eba57610eba613db7565b6020026020010151858481518110610ed457610ed4613db7565b60200260200101906001600160a01b031690816001600160a01b0316815250508082888581518110610f0857610f08613db7565b6020026020010151604051602401610f2293929190614382565b60408051601f198184030181529190526020810180516001600160e01b0316634db46eab60e01b1790528451859085908110610f6057610f60613db7565b60200260200101819052508160200151604001518260200151602001516001600160a01b0316826001600160a01b03167f2105c9cc3bbc588377167aaf889f584bc2f9c7db03c47c3eb58fc21d5a441fa533604051610fce91906001600160a01b0391909116815260200190565b60405180910390a45050600101610e64565b8551855181141580610ff3575084518114155b80610fff575083518114155b8061100b575082518114155b80611017575081518114155b1561103557604051637db491eb60e01b815260040160405180910390fd5b611040866020612028565b6000816001600160401b0381111561105a5761105a6122e1565b604051908082528060200260200182016040528015611083578160200160208202803683370190505b5090506000826001600160401b038111156110a0576110a06122e1565b6040519080825280602002602001820160405280156110d357816020015b60608152602001906001900390816110be5790505b50905060005b8381101561084b5760008982815181106110f5576110f5613db7565b60200260200101519050600089838151811061111357611113613db7565b602002602001015190508b838151811061112f5761112f613db7565b602002602001015185848151811061114957611149613db7565b60200260200101906001600160a01b031690816001600160a01b03168152505081818a858151811061117d5761117d613db7565b60200260200101518a868151811061119757611197613db7565b60200260200101518a87815181106111b1576111b1613db7565b60200260200101516040516024016111cd95949392919061447c565b60408051601f198184030181529190526020810180516001600160e01b0316633966e37160e11b179052845185908590811061120b5761120b613db7565b6020026020010181905250806040015181602001516001600160a01b0316836001600160a01b03167f3da92af9a5afd4c5b6beb1c87ee319fa31033a747261b6bf14f6e523bb0c14b83360405161127191906001600160a01b0391909116815260200190565b60405180910390a450506001016110d9565b8351835181141580611296575082518114155b806112a2575081518114155b156112c057604051637db491eb60e01b815260040160405180910390fd5b6112cb846002612028565b6000816001600160401b038111156112e5576112e56122e1565b60405190808252806020026020018201604052801561130e578160200160208202803683370190505b5090506000826001600160401b0381111561132b5761132b6122e1565b60405190808252806020026020018201604052801561135e57816020015b60608152602001906001900390816113495790505b50905060005b83811015610b0357600087828151811061138057611380613db7565b60200260200101519050600087838151811061139e5761139e613db7565b602002602001015190508983815181106113ba576113ba613db7565b60200260200101518584815181106113d4576113d4613db7565b60200260200101906001600160a01b031690816001600160a01b031681525050818188858151811061140857611408613db7565b6020026020010151604051602401611422939291906144d4565b60408051601f198184030181529190526020810180516001600160e01b0316630378471d60e21b179052845185908590811061146057611460613db7565b602090810291909101810191909152608082015180518351805190840151928401516040805194855294840152338385015292516001600160a01b0391821693821692918616917fda158ff3c523b526cae2e8438fd9ce62d29d5f7519e34c9aa4f157f2831d6951919081900360600190a45050600101611364565b8281146114fc5760405163c1e637c960e01b815260040160405180910390fd5b6040516332afe8a160e21b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063cabfa28490602401602060405180830381865afa158015611560573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115849190614650565b6115a35760405163252c827360e01b8152336004820152602401610bcf565b60005b8082146118015760008585838181106115c1576115c1613db7565b90506020020160208101906115d69190612e34565b6001600160a01b0316036115ec576001016115a6565b308585838181106115ff576115ff613db7565b90506020020160208101906116149190612e34565b6001600160a01b031614611730577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663907caa0086868481811061166357611663613db7565b90506020020160208101906116789190612e34565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156116bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e09190614650565b611730578484828181106116f6576116f6613db7565b905060200201602081019061170b9190612e34565b6040516347ccabe760e01b81526001600160a01b039091166004820152602401610bcf565b60008086868481811061174557611745613db7565b905060200201602081019061175a9190612e34565b6001600160a01b031685858581811061177557611775613db7565b9050602002810190611787919061466d565b6040516117959291906146b3565b6000604051808303816000865af19150503d80600081146117d2576040519150601f19603f3d011682016040523d82523d6000602084013e6117d7565b606091505b5091509150816117f75780516000036117ef57600080fd5b805181602001fd5b50506001016115a6565b5050505050565b6000546001600160a01b031633146118335760405163b5c42b3b60e01b815260040160405180910390fd5b600054604080516001600160a01b03928316815291831660208301527fbf265e8326285a2747e33e54d5945f7111f2b5edb826eb8c08d4677779b3ff97910160405180910390a1600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146118c75760405163b5c42b3b60e01b815260040160405180910390fd5b6118d281607f61212b565b50565b6000546001600160a01b031633146119005760405163b5c42b3b60e01b815260040160405180910390fd5b80607f81111561192357604051635766676360e11b815260040160405180910390fd5b6001600160a01b03831660009081526002602052604090205460ff166119525761194d838361212b565b505050565b6001600160a01b038316600081815260036020908152604091829020859055815192835282018490527f0e5fb30aa3d58cccbcbf21f7cb9601475127b8811b2a0f047c761734f897d436910160405180910390a1505050565b84518451811415806119be575083518114155b806119ca575082518114155b806119d6575081518114155b156119f457604051637db491eb60e01b815260040160405180910390fd5b6119ff856001612028565b6000816001600160401b03811115611a1957611a196122e1565b604051908082528060200260200182016040528015611a42578160200160208202803683370190505b5090506000826001600160401b03811115611a5f57611a5f6122e1565b604051908082528060200260200182016040528015611a9257816020015b6060815260200190600190039081611a7d5790505b50905060005b83811015611c30576000888281518110611ab457611ab4613db7565b602002602001015190506000888381518110611ad257611ad2613db7565b602002602001015190506000888481518110611af057611af0613db7565b602002602001015190508b8481518110611b0c57611b0c613db7565b6020026020010151868581518110611b2657611b26613db7565b60200260200101906001600160a01b031690816001600160a01b0316815250508282828a8781518110611b5b57611b5b613db7565b6020026020010151604051602401611b76949392919061470b565b60408051601f198184030181529190526020810180516001600160e01b031663774b967560e11b1790528551869086908110611bb457611bb4613db7565b6020026020010181905250816020015182600001516001600160a01b0316846001600160a01b03167f786335957c445de8bac6d50869dc5524e567ef2bf4278f874c4cbf29037edd4e33604051611c1a91906001600160a01b0391909116815260200190565b60405180910390a4836001019350505050611a98565b506040516331fd85cb60e11b815230906363fb0b9690611c569085908590600401614121565b600060405180830381600087803b158015611c7057600080fd5b505af1158015611c84573d6000803e3d6000fd5b505050505050505050505050565b8651865181141580611ca5575085518114155b80611cb1575084518114155b80611cbd575082518114155b80611cc9575083518114155b80611cd5575081518114155b15611cf357604051637db491eb60e01b815260040160405180910390fd5b611cfe876004612028565b6000816001600160401b03811115611d1857611d186122e1565b604051908082528060200260200182016040528015611d41578160200160208202803683370190505b5090506000826001600160401b03811115611d5e57611d5e6122e1565b604051908082528060200260200182016040528015611d9157816020015b6060815260200190600190039081611d7c5790505b50905060005b83811015611f9a578a8181518110611db157611db1613db7565b6020026020010151838281518110611dcb57611dcb613db7565b60200260200101906001600160a01b031690816001600160a01b031681525050898181518110611dfd57611dfd613db7565b6020026020010151898281518110611e1757611e17613db7565b6020026020010151898381518110611e3157611e31613db7565b6020026020010151898481518110611e4b57611e4b613db7565b6020026020010151898581518110611e6557611e65613db7565b6020026020010151898681518110611e7f57611e7f613db7565b6020026020010151604051602401611e9c9695949392919061476a565b60408051601f198184030181529190526020810180516001600160e01b0316630839002b60e31b1790528251839083908110611eda57611eda613db7565b6020026020010181905250888181518110611ef757611ef7613db7565b602002602001015160200151898281518110611f1557611f15613db7565b6020026020010151600001516001600160a01b03168b8381518110611f3c57611f3c613db7565b60200260200101516001600160a01b03167ee78976f9d93bf9a08027cf5612c1a44419aa7c74a2eeebb8f8c1f3dba6fdd933604051611f8a91906001600160a01b0391909116815260200190565b60405180910390a4600101611d97565b506040516331fd85cb60e11b815230906363fb0b9690611fc09085908590600401614121565b600060405180830381600087803b158015611fda57600080fd5b505af1158015611fee573d6000803e3d6000fd5b5050505050505050505050505050565b6001818154811061200e57600080fd5b6000918252602090912001546001600160a01b0316905081565b815160005b8181101561212557600084828151811061204957612049613db7565b6020026020010151905060008060056000846001600160a01b03166001600160a01b031681526020019081526020016000205411905080156120cf576001600160a01b0382166000908152600460209081526040808320338452909152812054861690036120ca5760405163198f48cb60e31b815260040160405180910390fd5b61211b565b3360009081526002602052604090205460ff1615806120fd5750336000908152600360205260409020548516155b1561211b5760405163198f48cb60e31b815260040160405180910390fd5b505060010161202d565b50505050565b6001600160a01b03821661215257604051631d8d67b960e11b815260040160405180910390fd5b6001600160a01b03821660009081526002602052604090205460ff161561219757604051631c9ab5b560e01b81526001600160a01b0383166004820152602401610bcf565b6001600160a01b0382166000818152600260209081526040808320805460ff1916600190811790915580548082019091557fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b03191685179055600382529182902084905590519182527f7b24afe53ea3c0eb8558ae101198e86c392b4055609b2be0e0b23b89b2b8f013910160405180910390a1604080516001600160a01b0384168152602081018390527f0e5fb30aa3d58cccbcbf21f7cb9601475127b8811b2a0f047c761734f897d436910160405180910390a15050565b6001600160a01b03811681146118d257600080fd5b803561229b8161227b565b919050565b6000806000606084860312156122b557600080fd5b83356122c08161227b565b925060208401356122d08161227b565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715612319576123196122e1565b60405290565b604051606081016001600160401b0381118282101715612319576123196122e1565b604051608081016001600160401b0381118282101715612319576123196122e1565b60405161010081016001600160401b0381118282101715612319576123196122e1565b60405161014081016001600160401b0381118282101715612319576123196122e1565b60405160a081016001600160401b0381118282101715612319576123196122e1565b60405160c081016001600160401b0381118282101715612319576123196122e1565b604051601f8201601f191681016001600160401b0381118282101715612415576124156122e1565b604052919050565b60006001600160401b03821115612436576124366122e1565b5060051b60200190565b600082601f83011261245157600080fd5b813560206124666124618361241d565b6123ed565b82815260059290921b8401810191818101908684111561248557600080fd5b8286015b848110156124a957803561249c8161227b565b8352918301918301612489565b509695505050505050565b6000604082840312156124c657600080fd5b6124ce6122f7565b905081356124db8161227b565b808252506020820135602082015292915050565b60006080828403121561250157600080fd5b61250961231f565b905061251583836124b4565b815260408201356125258161227b565b6020820152606091909101356040820152919050565b600082601f83011261254c57600080fd5b8135602061255c6124618361241d565b82815260079290921b8401810191818101908684111561257b57600080fd5b8286015b848110156124a95761259188826124ef565b83529183019160800161257f565b80356001600160801b038116811461229b57600080fd5b600082601f8301126125c757600080fd5b81356001600160401b038111156125e0576125e06122e1565b6125f3601f8201601f19166020016123ed565b81815284602083860101111561260857600080fd5b816020850160208301376000918101602001919091529392505050565b60006080828403121561263757600080fd5b61263f612341565b905081356001600160401b038082111561265857600080fd5b61266485838601612440565b83526126726020850161259f565b60208401526126836040850161259f565b6040840152606084013591508082111561269c57600080fd5b506126a9848285016125b6565b60608301525092915050565b600082601f8301126126c657600080fd5b813560206126d66124618361241d565b82815260059290921b840181019181810190868411156126f557600080fd5b8286015b848110156124a95780356001600160401b03808211156127195760008081fd5b90880190610100828b03601f19018113156127345760008081fd5b61273c612363565b612747888501612290565b81526040612756818601612290565b89830152606080860135828401526080915081860135818401525060a0808601358284015260c0915061278a828701612290565b9083015260e061279b868201612290565b838301529285013592848411156127b457600091508182fd5b6127c28e8b868901016125b6565b908301525086525050509183019183016126f9565b6000606082840312156127e957600080fd5b6127f161231f565b905081356127fe8161227b565b8152602082013561280e8161227b565b6020820152604082013562ffffff8116811461282957600080fd5b604082015292915050565b8035600281900b811461229b57600080fd5b60006040828403121561285857600080fd5b6128606122f7565b905081356001600160401b038082111561287957600080fd5b612885858386016126b5565b8352602084013591508082111561289b57600080fd5b9083019061018082860312156128b057600080fd5b6128b8612386565b6128c183612290565b8152602083013560208201526128da86604085016127d7565b60408201526128eb60a08401612834565b60608201526128fc60c08401612834565b608082015260e083013560a08201526101008084013560c08301526101208085013560e08401526101408501358284015261016085013591508382111561294257600080fd5b61294e888387016125b6565b9083015250602084015250909392505050565b600082601f83011261297257600080fd5b813560206129826124618361241d565b82815260059290921b840181019181810190868411156129a157600080fd5b8286015b848110156124a95780356001600160401b03808211156129c55760008081fd5b908801906040828b03601f19018113156129df5760008081fd5b6129e76122f7565b87840135838111156129f95760008081fd5b612a078d8a83880101612625565b825250908301359082821115612a1d5760008081fd5b612a2b8c8984870101612846565b8189015286525050509183019183016129a5565b80151581146118d257600080fd5b600082601f830112612a5e57600080fd5b81356020612a6e6124618361241d565b82815260059290921b84018101918181019086841115612a8d57600080fd5b8286015b848110156124a9578035612aa481612a3f565b8352918301918301612a91565b600082601f830112612ac257600080fd5b81356020612ad26124618361241d565b82815260059290921b84018101918181019086841115612af157600080fd5b8286015b848110156124a95780356001600160401b03811115612b145760008081fd5b612b228986838b0101612440565b845250918301918301612af5565b60008060008060008060c08789031215612b4957600080fd5b86356001600160401b0380821115612b6057600080fd5b612b6c8a838b01612440565b97506020890135915080821115612b8257600080fd5b612b8e8a838b01612440565b96506040890135915080821115612ba457600080fd5b612bb08a838b0161253b565b95506060890135915080821115612bc657600080fd5b612bd28a838b01612961565b94506080890135915080821115612be857600080fd5b612bf48a838b01612a4d565b935060a0890135915080821115612c0a57600080fd5b50612c1789828a01612ab1565b9150509295509295509295565b600060808284031215612c3657600080fd5b612c3e612341565b905081356001600160401b0380821115612c5757600080fd5b612c6385838601612625565b83526020840135915080821115612c7957600080fd5b612c85858386016126b5565b60208401526040840135915080821115612c9e57600080fd5b612caa85838601612440565b60408401526060840135915080821115612cc357600080fd5b506126a984828501612440565b600082601f830112612ce157600080fd5b81356020612cf16124618361241d565b82815260059290921b84018101918181019086841115612d1057600080fd5b8286015b848110156124a95780356001600160401b03811115612d335760008081fd5b612d418986838b0101612c24565b845250918301918301612d14565b60008060008060808587031215612d6557600080fd5b84356001600160401b0380821115612d7c57600080fd5b612d8888838901612440565b95506020870135915080821115612d9e57600080fd5b612daa88838901612440565b94506040870135915080821115612dc057600080fd5b612dcc8883890161253b565b93506060870135915080821115612de257600080fd5b50612def87828801612cd0565b91505092959194509250565b60008060408385031215612e0e57600080fd5b8235612e198161227b565b91506020830135612e298161227b565b809150509250929050565b600060208284031215612e4657600080fd5b8135612e518161227b565b9392505050565b600060608284031215612e6a57600080fd5b612e7261231f565b905081356001600160401b0380821115612e8b57600080fd5b9083019060408286031215612e9f57600080fd5b612ea76122f7565b823582811115612eb657600080fd5b83016101008188031215612ec957600080fd5b612ed1612363565b612eda82612290565b815260208083013581830152612ef26040840161259f565b60408301526060830135606083015260808301356080830152612f1760a0840161259f565b60a0830152612f2860c0840161259f565b60c083015260e083013585811115612f3f57600080fd5b612f4b8a8286016125b6565b60e08401525081845280860135925084831115612f6757600080fd5b612f73898488016126b5565b8185015283875280880135955084861115612f8d57600080fd5b612f9989878a01612440565b908701525050506040840135915080821115612fb457600080fd5b50612fc1848285016125b6565b60408301525092915050565b600082601f830112612fde57600080fd5b81356020612fee6124618361241d565b82815260059290921b8401810191818101908684111561300d57600080fd5b8286015b848110156124a95780358352918301918301613011565b60006080828403121561303a57600080fd5b613042612341565b905081356001600160401b038082111561305b57600080fd5b61306785838601612440565b8352602084013591508082111561307d57600080fd5b61308985838601612fcd565b602084015260408401359150808211156130a257600080fd5b61268385838601612846565b600080600080608085870312156130c457600080fd5b6001600160401b0380863511156130da57600080fd5b6130e78787358801612440565b94506020860135818111156130fb57600080fd5b61310788828901612440565b94505060408601358181111561311c57600080fd5b8601601f8101881361312d57600080fd5b61313a612461823561241d565b81358082526020808301929160051b8401018a81111561315957600080fd5b602084015b8181101561323a57858135111561317457600080fd5b80358501610100818e03601f1901121561318d57600080fd5b6131956123a9565b6131a160208301612290565b81526131b08e604084016124ef565b602082015260c0820135888111156131c757600080fd5b6131d68f602083860101612c24565b60408301525060e0820135888111156131ee57600080fd5b6131fd8f602083860101612e58565b6060830152506101008201358881111561321657600080fd5b6132258f602083860101613028565b6080830152508552506020938401930161315e565b5090955050505060608601358181111561325357600080fd5b61325f88828901612ab1565b9250505092959194509250565b600082601f83011261327d57600080fd5b8135602061328d6124618361241d565b82815260059290921b840181019181810190868411156132ac57600080fd5b8286015b848110156124a95780356001600160401b038111156132cf5760008081fd5b6132dd8986838b0101612e58565b8452509183019183016132b0565b60008060008060008060c0878903121561330457600080fd5b86356001600160401b038082111561331b57600080fd5b6133278a838b01612440565b9750602089013591508082111561333d57600080fd5b6133498a838b01612440565b9650604089013591508082111561335f57600080fd5b61336b8a838b0161253b565b9550606089013591508082111561338157600080fd5b61338d8a838b01612cd0565b945060808901359150808211156133a357600080fd5b612bf48a838b0161326c565b600082601f8301126133c057600080fd5b813560206133d06124618361241d565b82815260059290921b840181019181810190868411156133ef57600080fd5b8286015b848110156124a95780356134068161227b565b83529183019183016133f3565b60006040828403121561342557600080fd5b61342d6122f7565b905081356001600160401b038082111561344657600080fd5b613452858386016126b5565b8352602084013591508082111561346857600080fd5b9083019060c0828603121561347c57600080fd5b6134846123cb565b61348d83612290565b815261349b60208401612290565b60208201526040830135828111156134b257600080fd5b6134be87828601612440565b6040830152506060830135828111156134d657600080fd5b6134e287828601612fcd565b6060830152506080830135828111156134fa57600080fd5b61350687828601612fcd565b60808301525060a08301358281111561351e57600080fd5b61352a878286016125b6565b60a083015250602084015250909392505050565b6000806000806080858703121561355457600080fd5b6001600160401b03808635111561356a57600080fd5b61357787873588016133af565b945060208601358181111561358b57600080fd5b61359788828901612440565b9450506040860135818111156135ac57600080fd5b8601601f810188136135bd57600080fd5b6135ca612461823561241d565b81358082526020808301929160051b8401018a8111156135e957600080fd5b602084015b8181101561323a57858135111561360457600080fd5b80358501610100818e03601f1901121561361d57600080fd5b6136256123cb565b6136328e602084016124b4565b815260608201358881111561364657600080fd5b6136558f6020838601016125b6565b60208301525060808201358881111561366d57600080fd5b61367c8f602083860101612440565b60408301525060a08201358881111561369457600080fd5b6136a38f602083860101613413565b6060830152506136b68e60c084016124b4565b6080820152610100820135888111156136ce57600080fd5b6136dd8f6020838601016125b6565b60a083015250855250602093840193016135ee565b60008083601f84011261370457600080fd5b5081356001600160401b0381111561371b57600080fd5b6020830191508360208260051b850101111561373657600080fd5b9250929050565b6000806000806040858703121561375357600080fd5b84356001600160401b038082111561376a57600080fd5b613776888389016136f2565b9096509450602087013591508082111561378f57600080fd5b5061379c878288016136f2565b95989497509550505050565b600080604083850312156137bb57600080fd5b82356137c68161227b565b946020939093013593505050565b600082601f8301126137e557600080fd5b813560206137f56124618361241d565b82815260069290921b8401810191818101908684111561381457600080fd5b8286015b848110156124a95761382a88826124b4565b835291830191604001613818565b600082601f83011261384957600080fd5b813560206138596124618361241d565b82815260059290921b8401810191818101908684111561387857600080fd5b8286015b848110156124a95780356001600160401b038082111561389c5760008081fd5b908801906060828b03601f19018113156138b65760008081fd5b6138be61231f565b87840135838111156138d05760008081fd5b6138de8d8a838801016126b5565b825250604080850135848111156138f55760008081fd5b6139038e8b838901016125b6565b838b01525091840135918383111561391b5760008081fd5b6139298d8a85880101612440565b90820152865250505091830191830161387c565b600080600080600060a0868803121561395557600080fd5b85356001600160401b038082111561396c57600080fd5b61397889838a016133af565b9650602088013591508082111561398e57600080fd5b61399a89838a01612440565b955060408801359150808211156139b057600080fd5b6139bc89838a016137d4565b945060608801359150808211156139d257600080fd5b6139de89838a01613838565b935060808801359150808211156139f457600080fd5b50613a0188828901612ab1565b9150509295509295909350565b600082601f830112613a1f57600080fd5b613a2c612461833561241d565b82358082526020808301929160051b850101851015613a4a57600080fd5b602084015b6020853560051b860101811015613c39576001600160401b038082351115613a7657600080fd5b81358601601f196060828a0382011215613a8f57600080fd5b613a9761231f565b8360208401351115613aa857600080fd5b613aba8a6020808601358601016125b6565b81528360408401351115613acd57600080fd5b60408301358301604083828d03011215613ae657600080fd5b613aee6122f7565b8560208301351115613aff57600080fd5b6020820135820160c085828f03011215613b1857600080fd5b613b206123cb565b9450613b2e60208201612290565b8552613b3c60408201612290565b60208601528660608201351115613b5257600080fd5b613b658d60206060840135840101612440565b6040860152608081013560608601528660a08201351115613b8557600080fd5b613b988d602060a0840135840101612fcd565b60808601528660c08201351115613bae57600080fd5b613bc18d602060c08401358401016125b6565b60a0860152508381528560408301351115613bdb57600080fd5b613bee8c602060408501358501016126b5565b602082015280602084015250508360608401351115613c0c57600080fd5b613c1f8a60206060860135860101612440565b604082015286525050602093840193919091019050613a4f565b50949350505050565b600080600080600080600060e0888a031215613c5d57600080fd5b87356001600160401b0380821115613c7457600080fd5b613c808b838c016133af565b985060208a0135915080821115613c9657600080fd5b613ca28b838c01612440565b975060408a0135915080821115613cb857600080fd5b613cc48b838c016137d4565b965060608a0135915080821115613cda57600080fd5b613ce68b838c01613838565b955060808a0135915080821115613cfc57600080fd5b613d088b838c01612ab1565b945060a08a0135915080821115613d1e57600080fd5b613d2a8b838c01613a0e565b935060c08a0135915080821115613d4057600080fd5b50613d4d8a828b01612ab1565b91505092959891949750929550565b600060208284031215613d6e57600080fd5b5035919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115613d9e57613d9e613d75565b92915050565b81810381811115613d9e57613d9e613d75565b634e487b7160e01b600052603260045260246000fd5b613deb82825180516001600160a01b03168252602090810151910152565b60208101516001600160a01b03166040838101919091520151606090910152565b600081518084526020808501945080840160005b83811015613e455781516001600160a01b031687529582019590820190600101613e20565b509495945050505050565b6000815180845260005b81811015613e7657602081850181015186830182015201613e5a565b506000602082860101526020601f19601f83011685010191505092915050565b6000815160808452613eab6080850182613e0c565b905060208301516001600160801b038082166020870152806040860151166040870152505060608301518482036060860152613ee78282613e50565b95945050505050565b600081518084526020808501808196508360051b8101915082860160005b85811015613f9d578284038952815180516001600160a01b0390811686528682015181168787015260408083015190870152606080830151908701526080808301519087015260a08083015182169087015260c0808301519091169086015260e09081015161010091860182905290613f8981870183613e50565b9a87019a9550505090840190600101613f0e565b5091979650505050505050565b6000815160408452613fbf6040850182613ef0565b905060208301518482036020860152610180613fe48383516001600160a01b03169052565b6020828101518482015260408084015180516001600160a01b039081168388015292810151909216606086015281015162ffffff16608085015250606082015161403360a085018260020b9052565b50608082015161404860c085018260020b9052565b5060a082015160e084015260c0820151610100818186015260e084015191506101208281870152818501516101408701528085015194505050508061016084015261409581840183613e50565b9695505050505050565b6001600160a01b038616815260006101006140bd6020840188613dcd565b8060a084015285516040828501526140d9610140850182613e96565b915050602086015160ff19848303016101208501526140f88282613faa565b91505084151560c084015282810360e08401526141158185613e0c565b98975050505050505050565b6040815260006141346040830185613e0c565b6020838203818501528185518084528284019150828160051b85010183880160005b8381101561418457601f19878403018552614172838351613e50565b94860194925090850190600101614156565b50909998505050505050505050565b60008151608084526141a86080850182613e96565b9050602083015184820360208601526141c18282613ef0565b915050604083015184820360408601526141db8282613e0c565b91505060608301518482036060860152613ee78282613e0c565b6001600160a01b038416815261420e6020820184613dcd565b60c060a08201526000613ee760c0830184614193565b634e487b7160e01b600052603160045260246000fd5b60006001820161424c5761424c613d75565b5060010190565b600081516060845280516040606086015260018060a01b0381511660a0860152602081015160c0860152604081015161429760e08701826001600160801b03169052565b5060608101516101008181880152608083015161012088015260a083015191506142cd6101408801836001600160801b03169052565b60c08301516001600160801b031661016088015260e090920151610180870192909252506142ff6101a0860182613e50565b905060208201519150605f1985820301608086015261431e8183613ef0565b915050602083015184820360208601526143388282613e0c565b91505060408301518482036040860152613ee78282613e50565b600081518084526020808501945080840160005b83811015613e4557815187529582019590820190600101614366565b6001600160a01b038481168252606060208084018290528551909216908301528301516000906143b56080840182613dcd565b506040840151610100838101526143d0610160840182614193565b90506060850151605f1980858403016101208601526143ef8383614253565b9250608087015191508085840301610140860152508051608083526144176080840182613e0c565b9050602082015183820360208501526144308282614352565b9150506040820151838203604085015261444a8282613faa565b9150506060820151915082810360608401526144668183613e50565b9250505082810360408401526140958185613e0c565b6001600160a01b0386168152600061010061449a6020840188613dcd565b8060a08401526144ac81840187614193565b905082810360c08401526144c08186614253565b905082810360e08401526141158185613e0c565b600060018060a01b038086168352602060608185015261450b60608501875180516001600160a01b03168252602090810151910152565b808601516101008060a0870152614526610160870183613e50565b9150604080890151605f19808986030160c08a01526145458583613e0c565b945060608b01519150808986030160e08a0152815183865261456984870182613ef0565b9050868301519250858103878701528783511681528787840151168782015283830151975060c0848201526145a160c0820189613e0c565b97506060830151965080880360608201526145bc8888614352565b97506080830151965080880360808201526145d78888614352565b975060a0830151965080880360a0820152506145f38787613e50565b965060808b0151955061461b848a018780516001600160a01b03168252602090810151910152565b60a08b0151955080898803016101408a015250506146398585613e50565b945086850381880152505050506140958185613e0c565b60006020828403121561466257600080fd5b8151612e5181612a3f565b6000808335601e1984360301811261468457600080fd5b8301803591506001600160401b0382111561469e57600080fd5b60200191503681900382131561373657600080fd5b8183823760009101908152919050565b60008151606084526146d86060850182613ef0565b9050602083015184820360208601526146f18282613e50565b91505060408301518482036040860152613ee78282613e0c565b6001600160a01b0385168152614737602082018580516001600160a01b03168252602090810151910152565b60a06060820152600061474d60a08301856146c3565b828103608084015261475f8185613e0c565b979650505050505050565b6001600160a01b038781168252600090602061479b8185018a80516001600160a01b03168252602090810151910152565b60e060608501526147af60e08501896146c3565b84810360808601526147c18189613e0c565b905084810360a08601528651606082526147de6060830182613e50565b9050828801518282038484015280516040835285815116604084015285858201511660608401526040810151955060c06080840152614821610100840187613e0c565b9550606081015160a08401526080810151603f19808589030160c08601526148498883614352565b975060a08301519250808589030160e086015250506148688682613e50565b955050838101519050818503848301526148828582613ef0565b94505050604087015191508083036040820152506148a08282613e0c565b91505082810360c08401526148b58185613e0c565b999850505050505050505056fea2646970667358221220a15d5a40466b0e8fb3952c0e3a5324bdfc82d655b11428782953ba92cafd258a64736f6c6343000813003300000000000000000000000053d9780dbd3831e3a797fd215be4131636cd5fdf000000000000000000000000bde48624f9e1dd4107df324d1ba3c07004640206
Deployed Bytecode
0x60806040526004361061012a5760003560e01c8063704b6c02116100ab578063a626fb181161006f578063a626fb1814610370578063a70cd9ec14610390578063b7e01c61146103b0578063c64a6646146103dd578063d4b120031461040a578063f851a4401461042a57600080fd5b8063704b6c0214610284578063745a7b3b146102a45780637b103999146102c45780638a34557014610310578063a1ed7dbf1461035057600080fd5b80632f372a8d116100f25780632f372a8d146101fc5780632f51053e1461021c5780634456d1551461023c5780635be6d0621461025c57806363fb0b961461027157600080fd5b806303c325c91461012f57806307914b70146101515780630a1d5c28146101715780630cebe455146101915780631ccb65ff146101dc575b600080fd5b34801561013b57600080fd5b5061014f61014a3660046122a0565b61044a565b005b34801561015d57600080fd5b5061014f61016c366004612b30565b6105a8565b34801561017d57600080fd5b5061014f61018c366004612d4f565b6108ae565b34801561019d57600080fd5b506101c96101ac366004612dfb565b600460209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b3480156101e857600080fd5b5061014f6101f7366004612e34565b610b64565b34801561020857600080fd5b5061014f6102173660046130ae565b610d83565b34801561022857600080fd5b5061014f6102373660046132eb565b610fe0565b34801561024857600080fd5b5061014f61025736600461353e565b611283565b34801561026857600080fd5b506001546101c9565b61014f61027f36600461373d565b6114dc565b34801561029057600080fd5b5061014f61029f366004612e34565b611808565b3480156102b057600080fd5b5061014f6102bf366004612e34565b61189c565b3480156102d057600080fd5b506102f87f00000000000000000000000053d9780dbd3831e3a797fd215be4131636cd5fdf81565b6040516001600160a01b0390911681526020016101d3565b34801561031c57600080fd5b5061034061032b366004612e34565b60026020526000908152604090205460ff1681565b60405190151581526020016101d3565b34801561035c57600080fd5b5061014f61036b3660046137a8565b6118d5565b34801561037c57600080fd5b5061014f61038b36600461393d565b6119ab565b34801561039c57600080fd5b5061014f6103ab366004613c42565b611c92565b3480156103bc57600080fd5b506101c96103cb366004612e34565b60036020526000908152604090205481565b3480156103e957600080fd5b506101c96103f8366004612e34565b60056020526000908152604090205481565b34801561041657600080fd5b506102f8610425366004613d5c565b611ffe565b34801561043657600080fd5b506000546102f8906001600160a01b031681565b6000546001600160a01b031633146104755760405163b5c42b3b60e01b815260040160405180910390fd5b80607f81111561049857604051635766676360e11b815260040160405180910390fd5b6001600160a01b03808516600090815260046020908152604080832093871683529290522054801580156104cb57508215155b15610504576001600160a01b03851660009081526005602052604081208054600192906104f9908490613d8b565b909155506105459050565b8015801590610511575082155b15610545576001600160a01b038516600090815260056020526040812080546001929061053f908490613da4565b90915550505b6001600160a01b0385811660008181526004602090815260408083209489168084529482529182902087905590518681527fc8e12a019de4be77a3cda6c88d78af1110a6ed9d92237bf1efe2cfce755943f8910160405180910390a35050505050565b85518551811415806105bb575084518114155b806105c7575083518114155b806105d3575082518114155b806105df575081518114155b156105fd57604051637db491eb60e01b815260040160405180910390fd5b610608866010612028565b6000816001600160401b03811115610622576106226122e1565b60405190808252806020026020018201604052801561064b578160200160208202803683370190505b5090506000826001600160401b03811115610668576106686122e1565b60405190808252806020026020018201604052801561069b57816020015b60608152602001906001900390816106865790505b50905060005b8381101561084b5760008982815181106106bd576106bd613db7565b6020026020010151905060008983815181106106db576106db613db7565b602002602001015190508b83815181106106f7576106f7613db7565b602002602001015185848151811061071157610711613db7565b60200260200101906001600160a01b031690816001600160a01b03168152505081818a858151811061074557610745613db7565b60200260200101518a868151811061075f5761075f613db7565b60200260200101518a878151811061077957610779613db7565b602002602001015160405160240161079595949392919061409f565b60408051601f198184030181529190526020810180516001600160e01b03166371d5234960e11b17905284518590859081106107d3576107d3613db7565b6020026020010181905250806040015181602001516001600160a01b0316836001600160a01b03167fed73c824d2ad87eb6b4bc3bfa75956d9417414a86cefdb6fb8b47629d56fbfe53360405161083991906001600160a01b0391909116815260200190565b60405180910390a450506001016106a1565b506040516331fd85cb60e11b815230906363fb0b96906108719085908590600401614121565b600060405180830381600087803b15801561088b57600080fd5b505af115801561089f573d6000803e3d6000fd5b50505050505050505050505050565b83518351811415806108c1575082518114155b806108cd575081518114155b156108eb57604051637db491eb60e01b815260040160405180910390fd5b6108f6846008612028565b6000816001600160401b03811115610910576109106122e1565b604051908082528060200260200182016040528015610939578160200160208202803683370190505b5090506000826001600160401b03811115610956576109566122e1565b60405190808252806020026020018201604052801561098957816020015b60608152602001906001900390816109745790505b50905060005b83811015610b035760008782815181106109ab576109ab613db7565b6020026020010151905060008783815181106109c9576109c9613db7565b602002602001015190508983815181106109e5576109e5613db7565b60200260200101518584815181106109ff576109ff613db7565b60200260200101906001600160a01b031690816001600160a01b0316815250508181888581518110610a3357610a33613db7565b6020026020010151604051602401610a4d939291906141f5565b60408051601f198184030181529190526020810180516001600160e01b031663d839d94560e01b1790528451859085908110610a8b57610a8b613db7565b6020026020010181905250806040015181602001516001600160a01b0316836001600160a01b03167f697aab48888e7948540cc636dbf061073f4cdad5501a4225494ec07549502d2333604051610af191906001600160a01b0391909116815260200190565b60405180910390a4505060010161098f565b506040516331fd85cb60e11b815230906363fb0b9690610b299085908590600401614121565b600060405180830381600087803b158015610b4357600080fd5b505af1158015610b57573d6000803e3d6000fd5b5050505050505050505050565b6000546001600160a01b03163314610b8f5760405163b5c42b3b60e01b815260040160405180910390fd5b6001600160a01b03811660009081526002602052604090205460ff16610bd8576040516342ad5b3f60e01b81526001600160a01b03821660048201526024015b60405180910390fd5b60005b600154811015610cdf57816001600160a01b031660018281548110610c0257610c02613db7565b6000918252602090912001546001600160a01b031603610ccd5760018054610c2b908290613da4565b81548110610c3b57610c3b613db7565b600091825260209091200154600180546001600160a01b039092169183908110610c6757610c67613db7565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506001805480610ca657610ca6614224565b600082815260209020810160001990810180546001600160a01b0319169055019055610cdf565b80610cd78161423a565b915050610bdb565b506001600160a01b0381166000818152600260209081526040808320805460ff19169055600382528083208390558051938452908301919091527f0e5fb30aa3d58cccbcbf21f7cb9601475127b8811b2a0f047c761734f897d436910160405180910390a16040516001600160a01b03821681527f09c1ab3a33736061b9ab4db19afb80345fb417d89a6b531651d8c51291bf507f9060200160405180910390a150565b8351835181141580610d96575082518114155b80610da2575081518114155b15610dc057604051637db491eb60e01b815260040160405180910390fd5b610dcb846040612028565b6000816001600160401b03811115610de557610de56122e1565b604051908082528060200260200182016040528015610e0e578160200160208202803683370190505b5090506000826001600160401b03811115610e2b57610e2b6122e1565b604051908082528060200260200182016040528015610e5e57816020015b6060815260200190600190039081610e495790505b50905060005b83811015610b03576000868281518110610e8057610e80613db7565b602002602001015190506000888381518110610e9e57610e9e613db7565b60200260200101519050898381518110610eba57610eba613db7565b6020026020010151858481518110610ed457610ed4613db7565b60200260200101906001600160a01b031690816001600160a01b0316815250508082888581518110610f0857610f08613db7565b6020026020010151604051602401610f2293929190614382565b60408051601f198184030181529190526020810180516001600160e01b0316634db46eab60e01b1790528451859085908110610f6057610f60613db7565b60200260200101819052508160200151604001518260200151602001516001600160a01b0316826001600160a01b03167f2105c9cc3bbc588377167aaf889f584bc2f9c7db03c47c3eb58fc21d5a441fa533604051610fce91906001600160a01b0391909116815260200190565b60405180910390a45050600101610e64565b8551855181141580610ff3575084518114155b80610fff575083518114155b8061100b575082518114155b80611017575081518114155b1561103557604051637db491eb60e01b815260040160405180910390fd5b611040866020612028565b6000816001600160401b0381111561105a5761105a6122e1565b604051908082528060200260200182016040528015611083578160200160208202803683370190505b5090506000826001600160401b038111156110a0576110a06122e1565b6040519080825280602002602001820160405280156110d357816020015b60608152602001906001900390816110be5790505b50905060005b8381101561084b5760008982815181106110f5576110f5613db7565b60200260200101519050600089838151811061111357611113613db7565b602002602001015190508b838151811061112f5761112f613db7565b602002602001015185848151811061114957611149613db7565b60200260200101906001600160a01b031690816001600160a01b03168152505081818a858151811061117d5761117d613db7565b60200260200101518a868151811061119757611197613db7565b60200260200101518a87815181106111b1576111b1613db7565b60200260200101516040516024016111cd95949392919061447c565b60408051601f198184030181529190526020810180516001600160e01b0316633966e37160e11b179052845185908590811061120b5761120b613db7565b6020026020010181905250806040015181602001516001600160a01b0316836001600160a01b03167f3da92af9a5afd4c5b6beb1c87ee319fa31033a747261b6bf14f6e523bb0c14b83360405161127191906001600160a01b0391909116815260200190565b60405180910390a450506001016110d9565b8351835181141580611296575082518114155b806112a2575081518114155b156112c057604051637db491eb60e01b815260040160405180910390fd5b6112cb846002612028565b6000816001600160401b038111156112e5576112e56122e1565b60405190808252806020026020018201604052801561130e578160200160208202803683370190505b5090506000826001600160401b0381111561132b5761132b6122e1565b60405190808252806020026020018201604052801561135e57816020015b60608152602001906001900390816113495790505b50905060005b83811015610b0357600087828151811061138057611380613db7565b60200260200101519050600087838151811061139e5761139e613db7565b602002602001015190508983815181106113ba576113ba613db7565b60200260200101518584815181106113d4576113d4613db7565b60200260200101906001600160a01b031690816001600160a01b031681525050818188858151811061140857611408613db7565b6020026020010151604051602401611422939291906144d4565b60408051601f198184030181529190526020810180516001600160e01b0316630378471d60e21b179052845185908590811061146057611460613db7565b602090810291909101810191909152608082015180518351805190840151928401516040805194855294840152338385015292516001600160a01b0391821693821692918616917fda158ff3c523b526cae2e8438fd9ce62d29d5f7519e34c9aa4f157f2831d6951919081900360600190a45050600101611364565b8281146114fc5760405163c1e637c960e01b815260040160405180910390fd5b6040516332afe8a160e21b81523360048201527f00000000000000000000000053d9780dbd3831e3a797fd215be4131636cd5fdf6001600160a01b03169063cabfa28490602401602060405180830381865afa158015611560573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115849190614650565b6115a35760405163252c827360e01b8152336004820152602401610bcf565b60005b8082146118015760008585838181106115c1576115c1613db7565b90506020020160208101906115d69190612e34565b6001600160a01b0316036115ec576001016115a6565b308585838181106115ff576115ff613db7565b90506020020160208101906116149190612e34565b6001600160a01b031614611730577f00000000000000000000000053d9780dbd3831e3a797fd215be4131636cd5fdf6001600160a01b031663907caa0086868481811061166357611663613db7565b90506020020160208101906116789190612e34565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156116bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e09190614650565b611730578484828181106116f6576116f6613db7565b905060200201602081019061170b9190612e34565b6040516347ccabe760e01b81526001600160a01b039091166004820152602401610bcf565b60008086868481811061174557611745613db7565b905060200201602081019061175a9190612e34565b6001600160a01b031685858581811061177557611775613db7565b9050602002810190611787919061466d565b6040516117959291906146b3565b6000604051808303816000865af19150503d80600081146117d2576040519150601f19603f3d011682016040523d82523d6000602084013e6117d7565b606091505b5091509150816117f75780516000036117ef57600080fd5b805181602001fd5b50506001016115a6565b5050505050565b6000546001600160a01b031633146118335760405163b5c42b3b60e01b815260040160405180910390fd5b600054604080516001600160a01b03928316815291831660208301527fbf265e8326285a2747e33e54d5945f7111f2b5edb826eb8c08d4677779b3ff97910160405180910390a1600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146118c75760405163b5c42b3b60e01b815260040160405180910390fd5b6118d281607f61212b565b50565b6000546001600160a01b031633146119005760405163b5c42b3b60e01b815260040160405180910390fd5b80607f81111561192357604051635766676360e11b815260040160405180910390fd5b6001600160a01b03831660009081526002602052604090205460ff166119525761194d838361212b565b505050565b6001600160a01b038316600081815260036020908152604091829020859055815192835282018490527f0e5fb30aa3d58cccbcbf21f7cb9601475127b8811b2a0f047c761734f897d436910160405180910390a1505050565b84518451811415806119be575083518114155b806119ca575082518114155b806119d6575081518114155b156119f457604051637db491eb60e01b815260040160405180910390fd5b6119ff856001612028565b6000816001600160401b03811115611a1957611a196122e1565b604051908082528060200260200182016040528015611a42578160200160208202803683370190505b5090506000826001600160401b03811115611a5f57611a5f6122e1565b604051908082528060200260200182016040528015611a9257816020015b6060815260200190600190039081611a7d5790505b50905060005b83811015611c30576000888281518110611ab457611ab4613db7565b602002602001015190506000888381518110611ad257611ad2613db7565b602002602001015190506000888481518110611af057611af0613db7565b602002602001015190508b8481518110611b0c57611b0c613db7565b6020026020010151868581518110611b2657611b26613db7565b60200260200101906001600160a01b031690816001600160a01b0316815250508282828a8781518110611b5b57611b5b613db7565b6020026020010151604051602401611b76949392919061470b565b60408051601f198184030181529190526020810180516001600160e01b031663774b967560e11b1790528551869086908110611bb457611bb4613db7565b6020026020010181905250816020015182600001516001600160a01b0316846001600160a01b03167f786335957c445de8bac6d50869dc5524e567ef2bf4278f874c4cbf29037edd4e33604051611c1a91906001600160a01b0391909116815260200190565b60405180910390a4836001019350505050611a98565b506040516331fd85cb60e11b815230906363fb0b9690611c569085908590600401614121565b600060405180830381600087803b158015611c7057600080fd5b505af1158015611c84573d6000803e3d6000fd5b505050505050505050505050565b8651865181141580611ca5575085518114155b80611cb1575084518114155b80611cbd575082518114155b80611cc9575083518114155b80611cd5575081518114155b15611cf357604051637db491eb60e01b815260040160405180910390fd5b611cfe876004612028565b6000816001600160401b03811115611d1857611d186122e1565b604051908082528060200260200182016040528015611d41578160200160208202803683370190505b5090506000826001600160401b03811115611d5e57611d5e6122e1565b604051908082528060200260200182016040528015611d9157816020015b6060815260200190600190039081611d7c5790505b50905060005b83811015611f9a578a8181518110611db157611db1613db7565b6020026020010151838281518110611dcb57611dcb613db7565b60200260200101906001600160a01b031690816001600160a01b031681525050898181518110611dfd57611dfd613db7565b6020026020010151898281518110611e1757611e17613db7565b6020026020010151898381518110611e3157611e31613db7565b6020026020010151898481518110611e4b57611e4b613db7565b6020026020010151898581518110611e6557611e65613db7565b6020026020010151898681518110611e7f57611e7f613db7565b6020026020010151604051602401611e9c9695949392919061476a565b60408051601f198184030181529190526020810180516001600160e01b0316630839002b60e31b1790528251839083908110611eda57611eda613db7565b6020026020010181905250888181518110611ef757611ef7613db7565b602002602001015160200151898281518110611f1557611f15613db7565b6020026020010151600001516001600160a01b03168b8381518110611f3c57611f3c613db7565b60200260200101516001600160a01b03167ee78976f9d93bf9a08027cf5612c1a44419aa7c74a2eeebb8f8c1f3dba6fdd933604051611f8a91906001600160a01b0391909116815260200190565b60405180910390a4600101611d97565b506040516331fd85cb60e11b815230906363fb0b9690611fc09085908590600401614121565b600060405180830381600087803b158015611fda57600080fd5b505af1158015611fee573d6000803e3d6000fd5b5050505050505050505050505050565b6001818154811061200e57600080fd5b6000918252602090912001546001600160a01b0316905081565b815160005b8181101561212557600084828151811061204957612049613db7565b6020026020010151905060008060056000846001600160a01b03166001600160a01b031681526020019081526020016000205411905080156120cf576001600160a01b0382166000908152600460209081526040808320338452909152812054861690036120ca5760405163198f48cb60e31b815260040160405180910390fd5b61211b565b3360009081526002602052604090205460ff1615806120fd5750336000908152600360205260409020548516155b1561211b5760405163198f48cb60e31b815260040160405180910390fd5b505060010161202d565b50505050565b6001600160a01b03821661215257604051631d8d67b960e11b815260040160405180910390fd5b6001600160a01b03821660009081526002602052604090205460ff161561219757604051631c9ab5b560e01b81526001600160a01b0383166004820152602401610bcf565b6001600160a01b0382166000818152600260209081526040808320805460ff1916600190811790915580548082019091557fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b03191685179055600382529182902084905590519182527f7b24afe53ea3c0eb8558ae101198e86c392b4055609b2be0e0b23b89b2b8f013910160405180910390a1604080516001600160a01b0384168152602081018390527f0e5fb30aa3d58cccbcbf21f7cb9601475127b8811b2a0f047c761734f897d436910160405180910390a15050565b6001600160a01b03811681146118d257600080fd5b803561229b8161227b565b919050565b6000806000606084860312156122b557600080fd5b83356122c08161227b565b925060208401356122d08161227b565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715612319576123196122e1565b60405290565b604051606081016001600160401b0381118282101715612319576123196122e1565b604051608081016001600160401b0381118282101715612319576123196122e1565b60405161010081016001600160401b0381118282101715612319576123196122e1565b60405161014081016001600160401b0381118282101715612319576123196122e1565b60405160a081016001600160401b0381118282101715612319576123196122e1565b60405160c081016001600160401b0381118282101715612319576123196122e1565b604051601f8201601f191681016001600160401b0381118282101715612415576124156122e1565b604052919050565b60006001600160401b03821115612436576124366122e1565b5060051b60200190565b600082601f83011261245157600080fd5b813560206124666124618361241d565b6123ed565b82815260059290921b8401810191818101908684111561248557600080fd5b8286015b848110156124a957803561249c8161227b565b8352918301918301612489565b509695505050505050565b6000604082840312156124c657600080fd5b6124ce6122f7565b905081356124db8161227b565b808252506020820135602082015292915050565b60006080828403121561250157600080fd5b61250961231f565b905061251583836124b4565b815260408201356125258161227b565b6020820152606091909101356040820152919050565b600082601f83011261254c57600080fd5b8135602061255c6124618361241d565b82815260079290921b8401810191818101908684111561257b57600080fd5b8286015b848110156124a95761259188826124ef565b83529183019160800161257f565b80356001600160801b038116811461229b57600080fd5b600082601f8301126125c757600080fd5b81356001600160401b038111156125e0576125e06122e1565b6125f3601f8201601f19166020016123ed565b81815284602083860101111561260857600080fd5b816020850160208301376000918101602001919091529392505050565b60006080828403121561263757600080fd5b61263f612341565b905081356001600160401b038082111561265857600080fd5b61266485838601612440565b83526126726020850161259f565b60208401526126836040850161259f565b6040840152606084013591508082111561269c57600080fd5b506126a9848285016125b6565b60608301525092915050565b600082601f8301126126c657600080fd5b813560206126d66124618361241d565b82815260059290921b840181019181810190868411156126f557600080fd5b8286015b848110156124a95780356001600160401b03808211156127195760008081fd5b90880190610100828b03601f19018113156127345760008081fd5b61273c612363565b612747888501612290565b81526040612756818601612290565b89830152606080860135828401526080915081860135818401525060a0808601358284015260c0915061278a828701612290565b9083015260e061279b868201612290565b838301529285013592848411156127b457600091508182fd5b6127c28e8b868901016125b6565b908301525086525050509183019183016126f9565b6000606082840312156127e957600080fd5b6127f161231f565b905081356127fe8161227b565b8152602082013561280e8161227b565b6020820152604082013562ffffff8116811461282957600080fd5b604082015292915050565b8035600281900b811461229b57600080fd5b60006040828403121561285857600080fd5b6128606122f7565b905081356001600160401b038082111561287957600080fd5b612885858386016126b5565b8352602084013591508082111561289b57600080fd5b9083019061018082860312156128b057600080fd5b6128b8612386565b6128c183612290565b8152602083013560208201526128da86604085016127d7565b60408201526128eb60a08401612834565b60608201526128fc60c08401612834565b608082015260e083013560a08201526101008084013560c08301526101208085013560e08401526101408501358284015261016085013591508382111561294257600080fd5b61294e888387016125b6565b9083015250602084015250909392505050565b600082601f83011261297257600080fd5b813560206129826124618361241d565b82815260059290921b840181019181810190868411156129a157600080fd5b8286015b848110156124a95780356001600160401b03808211156129c55760008081fd5b908801906040828b03601f19018113156129df5760008081fd5b6129e76122f7565b87840135838111156129f95760008081fd5b612a078d8a83880101612625565b825250908301359082821115612a1d5760008081fd5b612a2b8c8984870101612846565b8189015286525050509183019183016129a5565b80151581146118d257600080fd5b600082601f830112612a5e57600080fd5b81356020612a6e6124618361241d565b82815260059290921b84018101918181019086841115612a8d57600080fd5b8286015b848110156124a9578035612aa481612a3f565b8352918301918301612a91565b600082601f830112612ac257600080fd5b81356020612ad26124618361241d565b82815260059290921b84018101918181019086841115612af157600080fd5b8286015b848110156124a95780356001600160401b03811115612b145760008081fd5b612b228986838b0101612440565b845250918301918301612af5565b60008060008060008060c08789031215612b4957600080fd5b86356001600160401b0380821115612b6057600080fd5b612b6c8a838b01612440565b97506020890135915080821115612b8257600080fd5b612b8e8a838b01612440565b96506040890135915080821115612ba457600080fd5b612bb08a838b0161253b565b95506060890135915080821115612bc657600080fd5b612bd28a838b01612961565b94506080890135915080821115612be857600080fd5b612bf48a838b01612a4d565b935060a0890135915080821115612c0a57600080fd5b50612c1789828a01612ab1565b9150509295509295509295565b600060808284031215612c3657600080fd5b612c3e612341565b905081356001600160401b0380821115612c5757600080fd5b612c6385838601612625565b83526020840135915080821115612c7957600080fd5b612c85858386016126b5565b60208401526040840135915080821115612c9e57600080fd5b612caa85838601612440565b60408401526060840135915080821115612cc357600080fd5b506126a984828501612440565b600082601f830112612ce157600080fd5b81356020612cf16124618361241d565b82815260059290921b84018101918181019086841115612d1057600080fd5b8286015b848110156124a95780356001600160401b03811115612d335760008081fd5b612d418986838b0101612c24565b845250918301918301612d14565b60008060008060808587031215612d6557600080fd5b84356001600160401b0380821115612d7c57600080fd5b612d8888838901612440565b95506020870135915080821115612d9e57600080fd5b612daa88838901612440565b94506040870135915080821115612dc057600080fd5b612dcc8883890161253b565b93506060870135915080821115612de257600080fd5b50612def87828801612cd0565b91505092959194509250565b60008060408385031215612e0e57600080fd5b8235612e198161227b565b91506020830135612e298161227b565b809150509250929050565b600060208284031215612e4657600080fd5b8135612e518161227b565b9392505050565b600060608284031215612e6a57600080fd5b612e7261231f565b905081356001600160401b0380821115612e8b57600080fd5b9083019060408286031215612e9f57600080fd5b612ea76122f7565b823582811115612eb657600080fd5b83016101008188031215612ec957600080fd5b612ed1612363565b612eda82612290565b815260208083013581830152612ef26040840161259f565b60408301526060830135606083015260808301356080830152612f1760a0840161259f565b60a0830152612f2860c0840161259f565b60c083015260e083013585811115612f3f57600080fd5b612f4b8a8286016125b6565b60e08401525081845280860135925084831115612f6757600080fd5b612f73898488016126b5565b8185015283875280880135955084861115612f8d57600080fd5b612f9989878a01612440565b908701525050506040840135915080821115612fb457600080fd5b50612fc1848285016125b6565b60408301525092915050565b600082601f830112612fde57600080fd5b81356020612fee6124618361241d565b82815260059290921b8401810191818101908684111561300d57600080fd5b8286015b848110156124a95780358352918301918301613011565b60006080828403121561303a57600080fd5b613042612341565b905081356001600160401b038082111561305b57600080fd5b61306785838601612440565b8352602084013591508082111561307d57600080fd5b61308985838601612fcd565b602084015260408401359150808211156130a257600080fd5b61268385838601612846565b600080600080608085870312156130c457600080fd5b6001600160401b0380863511156130da57600080fd5b6130e78787358801612440565b94506020860135818111156130fb57600080fd5b61310788828901612440565b94505060408601358181111561311c57600080fd5b8601601f8101881361312d57600080fd5b61313a612461823561241d565b81358082526020808301929160051b8401018a81111561315957600080fd5b602084015b8181101561323a57858135111561317457600080fd5b80358501610100818e03601f1901121561318d57600080fd5b6131956123a9565b6131a160208301612290565b81526131b08e604084016124ef565b602082015260c0820135888111156131c757600080fd5b6131d68f602083860101612c24565b60408301525060e0820135888111156131ee57600080fd5b6131fd8f602083860101612e58565b6060830152506101008201358881111561321657600080fd5b6132258f602083860101613028565b6080830152508552506020938401930161315e565b5090955050505060608601358181111561325357600080fd5b61325f88828901612ab1565b9250505092959194509250565b600082601f83011261327d57600080fd5b8135602061328d6124618361241d565b82815260059290921b840181019181810190868411156132ac57600080fd5b8286015b848110156124a95780356001600160401b038111156132cf5760008081fd5b6132dd8986838b0101612e58565b8452509183019183016132b0565b60008060008060008060c0878903121561330457600080fd5b86356001600160401b038082111561331b57600080fd5b6133278a838b01612440565b9750602089013591508082111561333d57600080fd5b6133498a838b01612440565b9650604089013591508082111561335f57600080fd5b61336b8a838b0161253b565b9550606089013591508082111561338157600080fd5b61338d8a838b01612cd0565b945060808901359150808211156133a357600080fd5b612bf48a838b0161326c565b600082601f8301126133c057600080fd5b813560206133d06124618361241d565b82815260059290921b840181019181810190868411156133ef57600080fd5b8286015b848110156124a95780356134068161227b565b83529183019183016133f3565b60006040828403121561342557600080fd5b61342d6122f7565b905081356001600160401b038082111561344657600080fd5b613452858386016126b5565b8352602084013591508082111561346857600080fd5b9083019060c0828603121561347c57600080fd5b6134846123cb565b61348d83612290565b815261349b60208401612290565b60208201526040830135828111156134b257600080fd5b6134be87828601612440565b6040830152506060830135828111156134d657600080fd5b6134e287828601612fcd565b6060830152506080830135828111156134fa57600080fd5b61350687828601612fcd565b60808301525060a08301358281111561351e57600080fd5b61352a878286016125b6565b60a083015250602084015250909392505050565b6000806000806080858703121561355457600080fd5b6001600160401b03808635111561356a57600080fd5b61357787873588016133af565b945060208601358181111561358b57600080fd5b61359788828901612440565b9450506040860135818111156135ac57600080fd5b8601601f810188136135bd57600080fd5b6135ca612461823561241d565b81358082526020808301929160051b8401018a8111156135e957600080fd5b602084015b8181101561323a57858135111561360457600080fd5b80358501610100818e03601f1901121561361d57600080fd5b6136256123cb565b6136328e602084016124b4565b815260608201358881111561364657600080fd5b6136558f6020838601016125b6565b60208301525060808201358881111561366d57600080fd5b61367c8f602083860101612440565b60408301525060a08201358881111561369457600080fd5b6136a38f602083860101613413565b6060830152506136b68e60c084016124b4565b6080820152610100820135888111156136ce57600080fd5b6136dd8f6020838601016125b6565b60a083015250855250602093840193016135ee565b60008083601f84011261370457600080fd5b5081356001600160401b0381111561371b57600080fd5b6020830191508360208260051b850101111561373657600080fd5b9250929050565b6000806000806040858703121561375357600080fd5b84356001600160401b038082111561376a57600080fd5b613776888389016136f2565b9096509450602087013591508082111561378f57600080fd5b5061379c878288016136f2565b95989497509550505050565b600080604083850312156137bb57600080fd5b82356137c68161227b565b946020939093013593505050565b600082601f8301126137e557600080fd5b813560206137f56124618361241d565b82815260069290921b8401810191818101908684111561381457600080fd5b8286015b848110156124a95761382a88826124b4565b835291830191604001613818565b600082601f83011261384957600080fd5b813560206138596124618361241d565b82815260059290921b8401810191818101908684111561387857600080fd5b8286015b848110156124a95780356001600160401b038082111561389c5760008081fd5b908801906060828b03601f19018113156138b65760008081fd5b6138be61231f565b87840135838111156138d05760008081fd5b6138de8d8a838801016126b5565b825250604080850135848111156138f55760008081fd5b6139038e8b838901016125b6565b838b01525091840135918383111561391b5760008081fd5b6139298d8a85880101612440565b90820152865250505091830191830161387c565b600080600080600060a0868803121561395557600080fd5b85356001600160401b038082111561396c57600080fd5b61397889838a016133af565b9650602088013591508082111561398e57600080fd5b61399a89838a01612440565b955060408801359150808211156139b057600080fd5b6139bc89838a016137d4565b945060608801359150808211156139d257600080fd5b6139de89838a01613838565b935060808801359150808211156139f457600080fd5b50613a0188828901612ab1565b9150509295509295909350565b600082601f830112613a1f57600080fd5b613a2c612461833561241d565b82358082526020808301929160051b850101851015613a4a57600080fd5b602084015b6020853560051b860101811015613c39576001600160401b038082351115613a7657600080fd5b81358601601f196060828a0382011215613a8f57600080fd5b613a9761231f565b8360208401351115613aa857600080fd5b613aba8a6020808601358601016125b6565b81528360408401351115613acd57600080fd5b60408301358301604083828d03011215613ae657600080fd5b613aee6122f7565b8560208301351115613aff57600080fd5b6020820135820160c085828f03011215613b1857600080fd5b613b206123cb565b9450613b2e60208201612290565b8552613b3c60408201612290565b60208601528660608201351115613b5257600080fd5b613b658d60206060840135840101612440565b6040860152608081013560608601528660a08201351115613b8557600080fd5b613b988d602060a0840135840101612fcd565b60808601528660c08201351115613bae57600080fd5b613bc18d602060c08401358401016125b6565b60a0860152508381528560408301351115613bdb57600080fd5b613bee8c602060408501358501016126b5565b602082015280602084015250508360608401351115613c0c57600080fd5b613c1f8a60206060860135860101612440565b604082015286525050602093840193919091019050613a4f565b50949350505050565b600080600080600080600060e0888a031215613c5d57600080fd5b87356001600160401b0380821115613c7457600080fd5b613c808b838c016133af565b985060208a0135915080821115613c9657600080fd5b613ca28b838c01612440565b975060408a0135915080821115613cb857600080fd5b613cc48b838c016137d4565b965060608a0135915080821115613cda57600080fd5b613ce68b838c01613838565b955060808a0135915080821115613cfc57600080fd5b613d088b838c01612ab1565b945060a08a0135915080821115613d1e57600080fd5b613d2a8b838c01613a0e565b935060c08a0135915080821115613d4057600080fd5b50613d4d8a828b01612ab1565b91505092959891949750929550565b600060208284031215613d6e57600080fd5b5035919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115613d9e57613d9e613d75565b92915050565b81810381811115613d9e57613d9e613d75565b634e487b7160e01b600052603260045260246000fd5b613deb82825180516001600160a01b03168252602090810151910152565b60208101516001600160a01b03166040838101919091520151606090910152565b600081518084526020808501945080840160005b83811015613e455781516001600160a01b031687529582019590820190600101613e20565b509495945050505050565b6000815180845260005b81811015613e7657602081850181015186830182015201613e5a565b506000602082860101526020601f19601f83011685010191505092915050565b6000815160808452613eab6080850182613e0c565b905060208301516001600160801b038082166020870152806040860151166040870152505060608301518482036060860152613ee78282613e50565b95945050505050565b600081518084526020808501808196508360051b8101915082860160005b85811015613f9d578284038952815180516001600160a01b0390811686528682015181168787015260408083015190870152606080830151908701526080808301519087015260a08083015182169087015260c0808301519091169086015260e09081015161010091860182905290613f8981870183613e50565b9a87019a9550505090840190600101613f0e565b5091979650505050505050565b6000815160408452613fbf6040850182613ef0565b905060208301518482036020860152610180613fe48383516001600160a01b03169052565b6020828101518482015260408084015180516001600160a01b039081168388015292810151909216606086015281015162ffffff16608085015250606082015161403360a085018260020b9052565b50608082015161404860c085018260020b9052565b5060a082015160e084015260c0820151610100818186015260e084015191506101208281870152818501516101408701528085015194505050508061016084015261409581840183613e50565b9695505050505050565b6001600160a01b038616815260006101006140bd6020840188613dcd565b8060a084015285516040828501526140d9610140850182613e96565b915050602086015160ff19848303016101208501526140f88282613faa565b91505084151560c084015282810360e08401526141158185613e0c565b98975050505050505050565b6040815260006141346040830185613e0c565b6020838203818501528185518084528284019150828160051b85010183880160005b8381101561418457601f19878403018552614172838351613e50565b94860194925090850190600101614156565b50909998505050505050505050565b60008151608084526141a86080850182613e96565b9050602083015184820360208601526141c18282613ef0565b915050604083015184820360408601526141db8282613e0c565b91505060608301518482036060860152613ee78282613e0c565b6001600160a01b038416815261420e6020820184613dcd565b60c060a08201526000613ee760c0830184614193565b634e487b7160e01b600052603160045260246000fd5b60006001820161424c5761424c613d75565b5060010190565b600081516060845280516040606086015260018060a01b0381511660a0860152602081015160c0860152604081015161429760e08701826001600160801b03169052565b5060608101516101008181880152608083015161012088015260a083015191506142cd6101408801836001600160801b03169052565b60c08301516001600160801b031661016088015260e090920151610180870192909252506142ff6101a0860182613e50565b905060208201519150605f1985820301608086015261431e8183613ef0565b915050602083015184820360208601526143388282613e0c565b91505060408301518482036040860152613ee78282613e50565b600081518084526020808501945080840160005b83811015613e4557815187529582019590820190600101614366565b6001600160a01b038481168252606060208084018290528551909216908301528301516000906143b56080840182613dcd565b506040840151610100838101526143d0610160840182614193565b90506060850151605f1980858403016101208601526143ef8383614253565b9250608087015191508085840301610140860152508051608083526144176080840182613e0c565b9050602082015183820360208501526144308282614352565b9150506040820151838203604085015261444a8282613faa565b9150506060820151915082810360608401526144668183613e50565b9250505082810360408401526140958185613e0c565b6001600160a01b0386168152600061010061449a6020840188613dcd565b8060a08401526144ac81840187614193565b905082810360c08401526144c08186614253565b905082810360e08401526141158185613e0c565b600060018060a01b038086168352602060608185015261450b60608501875180516001600160a01b03168252602090810151910152565b808601516101008060a0870152614526610160870183613e50565b9150604080890151605f19808986030160c08a01526145458583613e0c565b945060608b01519150808986030160e08a0152815183865261456984870182613ef0565b9050868301519250858103878701528783511681528787840151168782015283830151975060c0848201526145a160c0820189613e0c565b97506060830151965080880360608201526145bc8888614352565b97506080830151965080880360808201526145d78888614352565b975060a0830151965080880360a0820152506145f38787613e50565b965060808b0151955061461b848a018780516001600160a01b03168252602090810151910152565b60a08b0151955080898803016101408a015250506146398585613e50565b945086850381880152505050506140958185613e0c565b60006020828403121561466257600080fd5b8151612e5181612a3f565b6000808335601e1984360301811261468457600080fd5b8301803591506001600160401b0382111561469e57600080fd5b60200191503681900382131561373657600080fd5b8183823760009101908152919050565b60008151606084526146d86060850182613ef0565b9050602083015184820360208601526146f18282613e50565b91505060408301518482036040860152613ee78282613e0c565b6001600160a01b0385168152614737602082018580516001600160a01b03168252602090810151910152565b60a06060820152600061474d60a08301856146c3565b828103608084015261475f8185613e0c565b979650505050505050565b6001600160a01b038781168252600090602061479b8185018a80516001600160a01b03168252602090810151910152565b60e060608501526147af60e08501896146c3565b84810360808601526147c18189613e0c565b905084810360a08601528651606082526147de6060830182613e50565b9050828801518282038484015280516040835285815116604084015285858201511660608401526040810151955060c06080840152614821610100840187613e0c565b9550606081015160a08401526080810151603f19808589030160c08601526148498883614352565b975060a08301519250808589030160e086015250506148688682613e50565b955050838101519050818503848301526148828582613ef0565b94505050604087015191508083036040820152506148a08282613e0c565b91505082810360c08401526148b58185613e0c565b999850505050505050505056fea2646970667358221220a15d5a40466b0e8fb3952c0e3a5324bdfc82d655b11428782953ba92cafd258a64736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000053d9780dbd3831e3a797fd215be4131636cd5fdf000000000000000000000000bde48624f9e1dd4107df324d1ba3c07004640206
-----Decoded View---------------
Arg [0] : registry (address): 0x53d9780DbD3831E3A797Fd215be4131636cD5FDf
Arg [1] : admin (address): 0xBDE48624F9E1dd4107df324D1BA3C07004640206
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000053d9780dbd3831e3a797fd215be4131636cd5fdf
Arg [1] : 000000000000000000000000bde48624f9e1dd4107df324d1ba3c07004640206
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.