Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
DistributionCreator
Compiler Version
v0.8.17+commit.8df45f5f
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 /* * █ ***** ▓▓▓ * ▓▓▓▓▓▓▓ * ///. ▓▓▓▓▓▓▓▓▓▓▓▓▓ ***** //////// ▓▓▓▓▓▓▓ * ///////////// ▓▓▓ ▓▓ ////////////////// █ ▓▓ ▓▓ ▓▓ /////////////////////// ▓▓ ▓▓ ▓▓ ▓▓ //////////////////////////// ▓▓ ▓▓ ▓▓ ▓▓ /////////▓▓▓///////▓▓▓///////// ▓▓ ▓▓ ▓▓ ,////////////////////////////////////// ▓▓ ▓▓ ▓▓ ////////////////////////////////////////// ▓▓ ▓▓ //////////////////////▓▓▓▓///////////////////// ,//////////////////////////////////////////////////// .////////////////////////////////////////////////////////// .//////////////////////////██.,//////////////////////////█ .//////////////////////████..,./////////////////////██ ...////////////////███████.....,.////////////////███ ,.,////////////████████ ........,///////////████ .,.,//////█████████ ,.......///////████ ,..//████████ ........./████ ..,██████ .....,███ .██ ,.,█ ▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓ ▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓▓▓▓ ▓▓▓ ▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ */ pragma solidity ^0.8.17; import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import { IERC20, IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import { SignatureChecker } from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol"; import { IUniswapV3Pool } from "./interfaces/external/uniswap/IUniswapV3Pool.sol"; import "./utils/UUPSHelper.sol"; import { CampaignParameters } from "./struct/CampaignParameters.sol"; import { DistributionParameters } from "./struct/DistributionParameters.sol"; import { RewardTokenAmounts } from "./struct/RewardTokenAmounts.sol"; /// @title DistributionCreator /// @author Angle Labs, Inc. /// @notice Manages the distribution of rewards through the Merkl system /// @dev This contract is mostly a helper for APIs built on top of Merkl /// @dev This contract is an upgraded version and distinguishes two types of different rewards: /// - distributions: type of campaign for concentrated liquidity pools created before Feb 15 2024, /// now deprecated /// - campaigns: the new more global name to describe any reward program on top of Merkl //solhint-disable contract DistributionCreator is UUPSHelper, ReentrancyGuardUpgradeable { using SafeERC20 for IERC20; /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// CONSTANTS / VARIABLES //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ uint32 public constant HOUR = 3600; /// @notice Base for fee computation uint256 public constant BASE_9 = 1e9; uint256 public immutable CHAIN_ID = block.chainid; /// @notice `Core` contract handling access control ICore public core; /// @notice Contract distributing rewards to users address public distributor; /// @notice Address to which fees are forwarded address public feeRecipient; /// @notice Value (in base 10**9) of the fees taken when creating a campaign uint256 public defaultFees; /// @notice Message that needs to be acknowledged by users creating a campaign string public message; /// @notice Hash of the message that needs to be signed bytes32 public messageHash; /// @notice List of all rewards distributed in the contract on campaigns created before mid Feb 2024 /// for concentrated liquidity pools DistributionParameters[] public distributionList; /// @notice Maps an address to its fee rebate mapping(address => uint256) public feeRebate; /// @notice Maps a token to whether it is whitelisted or not. No fees are to be paid for incentives given /// on pools with whitelisted tokens mapping(address => uint256) public isWhitelistedToken; /// @notice Deprecated, kept for storage compatibility mapping(address => uint256) public _nonces; /// @notice Maps an address to the last valid hash signed mapping(address => bytes32) public userSignatures; /// @notice Maps a user to whether it is whitelisted for not signing mapping(address => uint256) public userSignatureWhitelist; /// @notice Maps a token to the minimum amount that must be sent per epoch for a distribution to be valid /// @dev If `rewardTokenMinAmounts[token] == 0`, then `token` cannot be used as a reward mapping(address => uint256) public rewardTokenMinAmounts; /// @notice List of all reward tokens that have at some point been accepted address[] public rewardTokens; /// @notice List of all rewards ever distributed or to be distributed in the contract /// @dev An attacker could try to populate this list. It shouldn't be an issue as only view functions /// iterate on it CampaignParameters[] public campaignList; /// @notice Maps a campaignId to the ID of the campaign in the campaign list + 1 mapping(bytes32 => uint256) internal _campaignLookup; /// @notice Maps a campaign type to the fees for this specific campaign mapping(uint32 => uint256) public campaignSpecificFees; /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ event DistributorUpdated(address indexed _distributor); event FeeRebateUpdated(address indexed user, uint256 userFeeRebate); event FeeRecipientUpdated(address indexed _feeRecipient); event FeesSet(uint256 _fees); event CampaignSpecificFeesSet(uint32 campaignType, uint256 _fees); event MessageUpdated(bytes32 _messageHash); event NewCampaign(CampaignParameters campaign); event NewDistribution(DistributionParameters distribution, address indexed sender); event RewardTokenMinimumAmountUpdated(address indexed token, uint256 amount); event TokenWhitelistToggled(address indexed token, uint256 toggleStatus); event UserSigned(bytes32 messageHash, address indexed user); event UserSigningWhitelistToggled(address indexed user, uint256 toggleStatus); /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// MODIFIERS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ /// @notice Checks whether the `msg.sender` has the governor role or the guardian role modifier onlyGovernorOrGuardian() { if (!core.isGovernorOrGuardian(msg.sender)) revert NotGovernorOrGuardian(); _; } /// @notice Checks whether the `msg.sender` has the governor role or the guardian role modifier onlyGovernor() { if (!core.isGovernor(msg.sender)) revert NotGovernor(); _; } /// @notice Checks whether an address has signed the message or not modifier hasSigned() { if ( userSignatureWhitelist[msg.sender] == 0 && userSignatures[msg.sender] != messageHash && userSignatureWhitelist[tx.origin] == 0 && userSignatures[tx.origin] != messageHash ) revert NotSigned(); _; } /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ function initialize(ICore _core, address _distributor, uint256 _fees) external initializer { if (address(_core) == address(0) || _distributor == address(0)) revert ZeroAddress(); if (_fees >= BASE_9) revert InvalidParam(); distributor = _distributor; core = _core; defaultFees = _fees; } constructor() initializer {} /// @inheritdoc UUPSUpgradeable function _authorizeUpgrade(address) internal view override onlyGovernorUpgrader(core) {} /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// USER FACING FUNCTIONS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ /// @notice Creates a `campaign` to incentivize a given pool for a specific period of time /// @return The campaignId of the new campaign /// @dev If the campaign is badly specified, it will not be handled by the campaign script and rewards may be lost /// @dev Reward tokens sent as part of campaigns must have been whitelisted before and amounts /// sent should be bigger than a minimum amount specific to each token /// @dev This function reverts if the sender has not accepted the terms and conditions function createCampaign(CampaignParameters memory newCampaign) external nonReentrant hasSigned returns (bytes32) { return _createCampaign(newCampaign); } /// @notice Same as the function above but for multiple campaigns at once /// @return List of all the campaign amounts actually deposited for each `campaign` in the `campaigns` list function createCampaigns( CampaignParameters[] memory campaigns ) external nonReentrant hasSigned returns (bytes32[] memory) { uint256 campaignsLength = campaigns.length; bytes32[] memory campaignIds = new bytes32[](campaignsLength); for (uint256 i; i < campaignsLength; ) { campaignIds[i] = _createCampaign(campaigns[i]); unchecked { ++i; } } return campaignIds; } /// @notice Allows a user to accept the conditions without signing the message /// @dev Users may either call `acceptConditions` here or `sign` the message function acceptConditions() external { userSignatureWhitelist[msg.sender] = 1; } /// @notice Checks whether the `msg.sender`'s `signature` is compatible with the message /// to sign and stores the signature /// @dev If you signed the message once, and the message has not been modified, then you do not /// need to sign again function sign(bytes calldata signature) external { _sign(signature); } /// @notice Combines signing the message and creating a campaign function signAndCreateCampaign( CampaignParameters memory newCampaign, bytes calldata signature ) external returns (bytes32) { _sign(signature); return _createCampaign(newCampaign); } /// @notice Creates a `distribution` to incentivize a given pool for a specific period of time function createDistribution( DistributionParameters memory newDistribution ) external nonReentrant hasSigned returns (uint256 distributionAmount) { return _createDistribution(newDistribution); } /// @notice Same as the function above but for multiple distributions at once function createDistributions( DistributionParameters[] memory distributions ) external nonReentrant hasSigned returns (uint256[] memory) { uint256 distributionsLength = distributions.length; uint256[] memory distributionAmounts = new uint256[](distributionsLength); for (uint256 i; i < distributionsLength; ) { distributionAmounts[i] = _createDistribution(distributions[i]); unchecked { ++i; } } return distributionAmounts; } /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// GETTERS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ /// @notice Returns the distribution at a given index converted into a campaign function distribution(uint256 index) external view returns (CampaignParameters memory) { return _convertDistribution(distributionList[index]); } /// @notice Returns the index of a campaign in the campaign list function campaignLookup(bytes32 _campaignId) public view returns (uint256) { uint256 index = _campaignLookup[_campaignId]; if (index == 0) revert CampaignDoesNotExist(); return index - 1; } /// @notice Returns the campaign parameters of a given campaignId function campaign(bytes32 _campaignId) external view returns (CampaignParameters memory) { return campaignList[campaignLookup(_campaignId)]; } /// @notice Returns the campaign ID for a given campaign /// @dev The campaign ID is computed as the hash of the following parameters: /// - `campaign.creator` /// - `campaign.rewardToken` /// - `campaign.campaignType` /// - `campaign.startTimestamp` /// - `campaign.duration` /// - `campaign.campaignData` /// This prevents the creation by the same account of two campaigns with the same parameters /// which is not a huge issue function campaignId(CampaignParameters memory campaignData) public view returns (bytes32) { return bytes32( keccak256( abi.encodePacked( CHAIN_ID, campaignData.creator, campaignData.rewardToken, campaignData.campaignType, campaignData.startTimestamp, campaignData.duration, campaignData.campaignData ) ) ); } /// @notice Returns the list of all the reward tokens supported as well as their minimum amounts /// @dev Not to be queried on-chain and hence not optimized for gas consumption function getValidRewardTokens() external view returns (RewardTokenAmounts[] memory) { (RewardTokenAmounts[] memory validRewardTokens, ) = _getValidRewardTokens(0, type(uint32).max); return validRewardTokens; } /// @dev Not to be queried on-chain and hence not optimized for gas consumption function getValidRewardTokens( uint32 skip, uint32 first ) external view returns (RewardTokenAmounts[] memory, uint256) { return _getValidRewardTokens(skip, first); } /// @notice Gets all the campaigns which were live at some point between `start` and `end` timestamp /// @param skip Disregard distibutions with a global index lower than `skip` /// @param first Limit the length of the returned array to `first` /// @return searchCampaigns Eligible campaigns /// @return lastIndexCampaign Index of the last campaign assessed in the list of all campaigns /// @dev For pagniation purpose, in case of out of gas, you can call back the same function but with `skip` set to `lastIndexCampaign` /// @dev Not to be queried on-chain and hence not optimized for gas consumption function getCampaignsBetween( uint32 start, uint32 end, uint32 skip, uint32 first ) external view returns (CampaignParameters[] memory, uint256 lastIndexCampaign) { return _getCampaignsBetween(start, end, skip, first); } /// @notice Gets all the distributions which were live at some point between `start` and `end` timestamp /// @param skip Disregard distibutions with a global index lower than `skip` /// @param first Limit the length of the returned array to `first` /// @return searchDistributions Eligible distributions /// @return lastIndexDistribution Index of the last distribution assessed in the list of all distributions /// @dev For pagniation purpose, in case of out of gas, you can call back the same function but with `skip` set to `lastIndexDistribution` /// @dev Not to be queried on-chain and hence not optimized for gas consumption function getDistributionsBetweenEpochs( uint32 epochStart, uint32 epochEnd, uint32 skip, uint32 first ) external view returns (DistributionParameters[] memory, uint256 lastIndexDistribution) { return _getDistributionsBetweenEpochs(_getRoundedEpoch(epochStart), _getRoundedEpoch(epochEnd), skip, first); } /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// GOVERNANCE FUNCTIONS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ /// @notice Sets a new `distributor` to which rewards should be distributed function setNewDistributor(address _distributor) external onlyGovernor { if (_distributor == address(0)) revert InvalidParam(); distributor = _distributor; emit DistributorUpdated(_distributor); } /// @notice Sets the defaultFees on deposit function setFees(uint256 _defaultFees) external onlyGovernor { if (_defaultFees >= BASE_9) revert InvalidParam(); defaultFees = _defaultFees; emit FeesSet(_defaultFees); } /// @notice Sets the fees specific for a campaign /// @dev To waive the fees for a campaign, set its fees to 1 function setCampaignFees(uint32 campaignType, uint256 _fees) external onlyGovernorOrGuardian { if (_fees >= BASE_9) revert InvalidParam(); campaignSpecificFees[campaignType] = _fees; emit CampaignSpecificFeesSet(campaignType, _fees); } /// @notice Toggles the fee whitelist for `token` function toggleTokenWhitelist(address token) external onlyGovernorOrGuardian { uint256 toggleStatus = 1 - isWhitelistedToken[token]; isWhitelistedToken[token] = toggleStatus; emit TokenWhitelistToggled(token, toggleStatus); } /// @notice Recovers fees accrued on the contract for a list of `tokens` function recoverFees(IERC20[] calldata tokens, address to) external onlyGovernor { uint256 tokensLength = tokens.length; for (uint256 i; i < tokensLength; ) { tokens[i].safeTransfer(to, tokens[i].balanceOf(address(this))); unchecked { ++i; } } } /// @notice Sets fee rebates for a given user function setUserFeeRebate(address user, uint256 userFeeRebate) external onlyGovernorOrGuardian { feeRebate[user] = userFeeRebate; emit FeeRebateUpdated(user, userFeeRebate); } /// @notice Sets the minimum amounts per distribution epoch for different reward tokens function setRewardTokenMinAmounts( address[] calldata tokens, uint256[] calldata amounts ) external onlyGovernorOrGuardian { uint256 tokensLength = tokens.length; if (tokensLength != amounts.length) revert InvalidLengths(); for (uint256 i; i < tokensLength; ++i) { uint256 amount = amounts[i]; // Basic logic check to make sure there are no duplicates in the `rewardTokens` table. If a token is // removed then re-added, it will appear as a duplicate in the list if (amount > 0 && rewardTokenMinAmounts[tokens[i]] == 0) rewardTokens.push(tokens[i]); rewardTokenMinAmounts[tokens[i]] = amount; emit RewardTokenMinimumAmountUpdated(tokens[i], amount); } } /// @notice Sets a new address to receive fees function setFeeRecipient(address _feeRecipient) external onlyGovernor { feeRecipient = _feeRecipient; emit FeeRecipientUpdated(_feeRecipient); } /// @notice Sets the message that needs to be signed by users before posting rewards function setMessage(string memory _message) external onlyGovernor { message = _message; bytes32 _messageHash = ECDSA.toEthSignedMessageHash(bytes(_message)); messageHash = _messageHash; emit MessageUpdated(_messageHash); } /// @notice Toggles the whitelist status for `user` when it comes to signing messages before depositing rewards. function toggleSigningWhitelist(address user) external onlyGovernorOrGuardian { uint256 whitelistStatus = 1 - userSignatureWhitelist[user]; userSignatureWhitelist[user] = whitelistStatus; emit UserSigningWhitelistToggled(user, whitelistStatus); } /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////// INTERNAL //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ /// @notice Internal version of `createCampaign` function _createCampaign(CampaignParameters memory newCampaign) internal returns (bytes32) { uint256 rewardTokenMinAmount = rewardTokenMinAmounts[newCampaign.rewardToken]; // if epoch parameters lead to a past campaign if (newCampaign.startTimestamp < block.timestamp) revert CampaignSouldStartInFuture(); // if the campaign doesn't last at least one hour if (newCampaign.duration < HOUR) revert CampaignDurationBelowHour(); // if the reward token is not whitelisted as an incentive token if (rewardTokenMinAmount == 0) revert CampaignRewardTokenNotWhitelisted(); // if the amount distributed is too small with respect to what is allowed if ((newCampaign.amount * HOUR) / newCampaign.duration < rewardTokenMinAmount) revert CampaignRewardTooLow(); if (newCampaign.creator == address(0)) newCampaign.creator = msg.sender; // Computing fees: these are waived for whitelisted addresses and if there is a whitelisted token in a pool uint256 _fees = campaignSpecificFees[newCampaign.campaignType]; if (_fees == 1) _fees = 0; else if (_fees == 0) _fees = defaultFees; uint256 campaignAmountMinusFees = _computeFees(_fees, newCampaign.amount, newCampaign.rewardToken); newCampaign.amount = campaignAmountMinusFees; newCampaign.campaignId = campaignId(newCampaign); if (_campaignLookup[newCampaign.campaignId] != 0) revert CampaignAlreadyExists(); _campaignLookup[newCampaign.campaignId] = campaignList.length + 1; campaignList.push(newCampaign); emit NewCampaign(newCampaign); return newCampaign.campaignId; } /// @notice Creates a distribution from a deprecated distribution type function _createDistribution(DistributionParameters memory newDistribution) internal returns (uint256) { _createCampaign(_convertDistribution(newDistribution)); // Not gas efficient but deprecated return campaignList[campaignList.length - 1].amount; } /// @notice Converts the deprecated distribution type into a campaign function _convertDistribution( DistributionParameters memory distributionToConvert ) internal view returns (CampaignParameters memory) { uint256 wrapperLength = distributionToConvert.wrapperTypes.length; address[] memory whitelist = new address[](wrapperLength); address[] memory blacklist = new address[](wrapperLength); uint256 whitelistLength; uint256 blacklistLength; for (uint256 k = 0; k < wrapperLength; k++) { if (distributionToConvert.wrapperTypes[k] == 0) { whitelist[whitelistLength] = (distributionToConvert.positionWrappers[k]); whitelistLength += 1; } if (distributionToConvert.wrapperTypes[k] == 3) { blacklist[blacklistLength] = (distributionToConvert.positionWrappers[k]); blacklistLength += 1; } } assembly { mstore(whitelist, whitelistLength) mstore(blacklist, blacklistLength) } return CampaignParameters({ campaignId: distributionToConvert.rewardId, creator: msg.sender, rewardToken: distributionToConvert.rewardToken, amount: distributionToConvert.amount, campaignType: 2, startTimestamp: distributionToConvert.epochStart, duration: distributionToConvert.numEpoch * HOUR, campaignData: abi.encode( distributionToConvert.uniV3Pool, distributionToConvert.propFees, // eg. 6000 distributionToConvert.propToken0, // eg. 3000 distributionToConvert.propToken1, // eg. 1000 distributionToConvert.isOutOfRangeIncentivized, // eg. 0 distributionToConvert.boostingAddress, // eg. NULL_ADDRESS distributionToConvert.boostedReward, // eg. 0 whitelist, // eg. [] blacklist, // eg. [] "0x" ) }); } /// @notice Computes the fees to be taken on a campaign and transfers them to the fee recipient function _computeFees( uint256 baseFeesValue, uint256 distributionAmount, address rewardToken ) internal returns (uint256 distributionAmountMinusFees) { uint256 _fees = (baseFeesValue * (BASE_9 - feeRebate[msg.sender])) / BASE_9; distributionAmountMinusFees = distributionAmount; if (_fees != 0) { distributionAmountMinusFees = (distributionAmount * (BASE_9 - _fees)) / BASE_9; address _feeRecipient = feeRecipient; _feeRecipient = _feeRecipient == address(0) ? address(this) : _feeRecipient; IERC20(rewardToken).safeTransferFrom( msg.sender, _feeRecipient, distributionAmount - distributionAmountMinusFees ); } IERC20(rewardToken).safeTransferFrom(msg.sender, distributor, distributionAmountMinusFees); } /// @notice Internal version of the `sign` function function _sign(bytes calldata signature) internal { bytes32 _messageHash = messageHash; if (!SignatureChecker.isValidSignatureNow(msg.sender, _messageHash, signature)) revert InvalidSignature(); userSignatures[msg.sender] = _messageHash; emit UserSigned(_messageHash, msg.sender); } /// @notice Rounds an `epoch` timestamp to the start of the corresponding period function _getRoundedEpoch(uint32 epoch) internal pure returns (uint32) { return (epoch / HOUR) * HOUR; } /// @notice Internal version of `getCampaignsBetween` function _getCampaignsBetween( uint32 start, uint32 end, uint32 skip, uint32 first ) internal view returns (CampaignParameters[] memory, uint256) { uint256 length; uint256 campaignListLength = campaignList.length; uint256 returnSize = first > campaignListLength ? campaignListLength : first; CampaignParameters[] memory activeRewards = new CampaignParameters[](returnSize); uint32 i = skip; while (i < campaignListLength) { CampaignParameters memory campaignToProcess = campaignList[i]; if ( campaignToProcess.startTimestamp + campaignToProcess.duration > start && campaignToProcess.startTimestamp < end ) { activeRewards[length] = campaignToProcess; length += 1; } unchecked { ++i; } if (length == returnSize) break; } assembly { mstore(activeRewards, length) } return (activeRewards, i); } /// @notice Internal version of `getDistributionsBetweenEpochs` function _getDistributionsBetweenEpochs( uint32 epochStart, uint32 epochEnd, uint32 skip, uint32 first ) internal view returns (DistributionParameters[] memory, uint256) { uint256 length; uint256 distributionListLength = distributionList.length; uint256 returnSize = first > distributionListLength ? distributionListLength : first; DistributionParameters[] memory activeRewards = new DistributionParameters[](returnSize); uint32 i = skip; while (i < distributionListLength) { DistributionParameters memory d = distributionList[i]; if (d.epochStart + d.numEpoch * HOUR > epochStart && d.epochStart < epochEnd) { activeRewards[length] = d; length += 1; } unchecked { ++i; } if (length == returnSize) break; } assembly { mstore(activeRewards, length) } return (activeRewards, i); } /// @notice Builds the list of valid reward tokens function _getValidRewardTokens( uint32 skip, uint32 first ) internal view returns (RewardTokenAmounts[] memory, uint256) { uint256 length; uint256 rewardTokenListLength = rewardTokens.length; uint256 returnSize = first > rewardTokenListLength ? rewardTokenListLength : first; RewardTokenAmounts[] memory validRewardTokens = new RewardTokenAmounts[](returnSize); uint32 i = skip; while (i < rewardTokenListLength) { address token = rewardTokens[i]; uint256 minAmount = rewardTokenMinAmounts[token]; if (minAmount > 0) { validRewardTokens[length] = RewardTokenAmounts(token, minAmount); length += 1; } unchecked { ++i; } if (length == returnSize) break; } assembly { mstore(validRewardTokens, length) } return (validRewardTokens, i); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[33] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822ProxiableUpgradeable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeaconUpgradeable { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeaconUpgradeable.sol"; import "../../interfaces/draft-IERC1822Upgradeable.sol"; import "../../utils/AddressUpgradeable.sol"; import "../../utils/StorageSlotUpgradeable.sol"; import "../utils/Initializable.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ * * @custom:oz-upgrades-unsafe-allow delegatecall */ abstract contract ERC1967UpgradeUpgradeable is Initializable { function __ERC1967Upgrade_init() internal onlyInitializing { } function __ERC1967Upgrade_init_unchained() internal onlyInitializing { } // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall( address newImplementation, bytes memory data, bool forceCall ) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { _functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS( address newImplementation, bytes memory data, bool forceCall ) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Emitted when the beacon is upgraded. */ event BeaconUpgraded(address indexed beacon); /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall( address newBeacon, bytes memory data, bool forceCall ) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data); } } /** * @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) private returns (bytes memory) { require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed"); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.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) || (!AddressUpgradeable.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 (last updated v4.8.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.0; import "../../interfaces/draft-IERC1822Upgradeable.sol"; import "../ERC1967/ERC1967UpgradeUpgradeable.sol"; import "./Initializable.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. * * _Available since v4.1._ */ abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable { function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment address private immutable __self = address(this); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { require(address(this) != __self, "Function must be called through delegatecall"); require(_getImplementation() == __self, "Function must be called through active proxy"); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall"); _; } /** * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual override notDelegated returns (bytes32) { return _IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ function upgradeTo(address newImplementation) external virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, new bytes(0), false); } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data, true); } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeTo} and {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal override onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// 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 AddressUpgradeable { /** * @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 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.7.0) (utils/StorageSlot.sol) pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ``` * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ */ library StorageSlotUpgradeable { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC1271 standard signature validation method for * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. * * _Available since v4.1._ */ interface IERC1271 { /** * @dev Should return whether the signature provided is valid for the provided data * @param hash Hash of the data to be signed * @param signature Signature byte array associated with _data */ function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: 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.8.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/SignatureChecker.sol) pragma solidity ^0.8.0; import "./ECDSA.sol"; import "../Address.sol"; import "../../interfaces/IERC1271.sol"; /** * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like * Argent and Gnosis Safe. * * _Available since v4.1._ */ library SignatureChecker { /** * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`. * * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus * change through time. It could return true at block N and false at block N+1 (or the opposite). */ function isValidSignatureNow( address signer, bytes32 hash, bytes memory signature ) internal view returns (bool) { (address recovered, ECDSA.RecoverError error) = ECDSA.tryRecover(hash, signature); if (error == ECDSA.RecoverError.NoError && recovered == signer) { return true; } (bool success, bytes memory result) = signer.staticcall( abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature) ); return (success && result.length == 32 && abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: GPL-3.0 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 IUniswapV3Pool { /// @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); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.17; /// @title ICore /// @author Angle Labs, Inc. /// @notice Interface for the `Core` contracts of smart contract modules used in Angle Labs contracts interface ICore { /// @notice Checks whether an address is governor /// @param admin Address to check /// @return Whether the address has the `GOVERNOR_ROLE` or not function isGovernor(address admin) external view returns (bool); /// @notice Checks whether an address is a governor or a guardian of a module /// @param admin Address to check /// @return Whether the address has the `GUARDIAN_ROLE` or not /// @dev Governance should make sure when adding a governor to also give this governor the guardian /// role by calling the `addGovernor` function function isGovernorOrGuardian(address admin) external view returns (bool); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.17; struct CampaignParameters { // POPULATED ONCE CREATED // ID of the campaign. This can be left as a null bytes32 when creating campaigns // on Merkl. bytes32 campaignId; // CHOSEN BY CAMPAIGN CREATOR // Address of the campaign creator, if marked as address(0), it will be overriden with the // address of the `msg.sender` creating the campaign address creator; // Address of the token used as a reward address rewardToken; // Amount of `rewardToken` to distribute across all the epochs // Amount distributed per epoch is `amount/numEpoch` uint256 amount; // Type of campaign uint32 campaignType; // Timestamp at which the campaign should start uint32 startTimestamp; // Duration of the campaign in seconds. Has to be a multiple of EPOCH = 3600 uint32 duration; // Extra data to pass to specify the campaign bytes campaignData; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.17; struct DistributionParameters { // ID of the reward (populated once created). This can be left as a null bytes32 when creating distributions // on Merkl. bytes32 rewardId; // Address of the UniswapV3 pool that needs to be incentivized address uniV3Pool; // Address of the reward token for the incentives address rewardToken; // Amount of `rewardToken` to distribute across all the epochs // Amount distributed per epoch is `amount/numEpoch` uint256 amount; // List of all position wrappers to consider or not for this contract. Some wrappers like Gamma or Arrakis // are automatically detected and so there is no need to specify them here. Check out the docs to find out // which need to be specified and which are not automatically detected. address[] positionWrappers; // Type (blacklist==3, whitelist==0, ...) encoded as a `uint32` for each wrapper in the list above. Mapping between // wrapper types and their corresponding `uint32` value can be found in Angle Docs uint32[] wrapperTypes; // In the incentivization formula, how much of the fees should go to holders of token0 // in base 10**4 uint32 propToken0; // Proportion for holding token1 (in base 10**4) uint32 propToken1; // Proportion for providing a useful liquidity (in base 10**4) that generates fees uint32 propFees; // Timestamp at which the incentivization should start. This is in the same units as `block.timestamp`. uint32 epochStart; // Amount of epochs for which incentivization should last. Epochs are expressed in hours here, so for a // campaign of 1 week `numEpoch` should for instance be 168. uint32 numEpoch; // Whether out of range liquidity should still be incentivized or not // This should be equal to 1 if out of range liquidity should still be incentivized // and 0 otherwise. uint32 isOutOfRangeIncentivized; // How much more addresses with a maximum boost can get with respect to addresses // which do not have a boost (in base 4). In the case of Curve where addresses get 2.5x more // this would be 25000. uint32 boostedReward; // Address of the token which dictates who gets boosted rewards or not. This is optional // and if the zero address is given no boost will be taken into account. In the case of Curve, this address // would for instance be the veBoostProxy address, or in other cases the veToken address. address boostingAddress; // Additional data passed when distributing rewards. This parameter may be used in case // the reward distribution script needs to look into other parameters beyond the ones above. // In most cases, when creating a campaign on Merkl, you can leave this as an empty bytes. bytes additionalData; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.17; struct RewardTokenAmounts { address token; uint256 minimumAmountPerEpoch; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.17; error CampaignDoesNotExist(); error CampaignAlreadyExists(); error CampaignDurationBelowHour(); error CampaignRewardTokenNotWhitelisted(); error CampaignRewardTooLow(); error CampaignSouldStartInFuture(); error InvalidDispute(); error InvalidLengths(); error InvalidParam(); error InvalidParams(); error InvalidProof(); error InvalidUninitializedRoot(); error InvalidReward(); error InvalidSignature(); error NoDispute(); error NotGovernor(); error NotGovernorOrGuardian(); error NotSigned(); error NotTrusted(); error NotWhitelisted(); error UnresolvedDispute(); error ZeroAddress();
// SPDX-License-Identifier: GPL-3.0 /* * █ ***** ▓▓▓ * ▓▓▓▓▓▓▓ * ///. ▓▓▓▓▓▓▓▓▓▓▓▓▓ ***** //////// ▓▓▓▓▓▓▓ * ///////////// ▓▓▓ ▓▓ ////////////////// █ ▓▓ ▓▓ ▓▓ /////////////////////// ▓▓ ▓▓ ▓▓ ▓▓ //////////////////////////// ▓▓ ▓▓ ▓▓ ▓▓ /////////▓▓▓///////▓▓▓///////// ▓▓ ▓▓ ▓▓ ,////////////////////////////////////// ▓▓ ▓▓ ▓▓ ////////////////////////////////////////// ▓▓ ▓▓ //////////////////////▓▓▓▓///////////////////// ,//////////////////////////////////////////////////// .////////////////////////////////////////////////////////// .//////////////////////////██.,//////////////////////////█ .//////////////////////████..,./////////////////////██ ...////////////////███████.....,.////////////////███ ,.,////////////████████ ........,///////////████ .,.,//////█████████ ,.......///////████ ,..//████████ ........./████ ..,██████ .....,███ .██ ,.,█ ▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓ ▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓▓▓▓ ▓▓▓ ▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ */ pragma solidity ^0.8.17; import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import { ICore } from "../interfaces/ICore.sol"; import "../utils/Errors.sol"; /// @title UUPSHelper /// @notice Helper contract for UUPSUpgradeable contracts where the upgradeability is controlled by a specific address /// @author Angle Labs., Inc /// @dev The 0 address check in the modifier allows the use of these modifiers during initialization abstract contract UUPSHelper is UUPSUpgradeable { modifier onlyGuardianUpgrader(ICore _core) { if (address(_core) != address(0) && !_core.isGovernorOrGuardian(msg.sender)) revert NotGovernorOrGuardian(); _; } modifier onlyGovernorUpgrader(ICore _core) { if (address(_core) != address(0) && !_core.isGovernor(msg.sender)) revert NotGovernor(); _; } constructor() initializer {} }
{ "optimizer": { "enabled": true, "runs": 1 }, "viaIR": false, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CampaignAlreadyExists","type":"error"},{"inputs":[],"name":"CampaignDoesNotExist","type":"error"},{"inputs":[],"name":"CampaignDurationBelowHour","type":"error"},{"inputs":[],"name":"CampaignRewardTokenNotWhitelisted","type":"error"},{"inputs":[],"name":"CampaignRewardTooLow","type":"error"},{"inputs":[],"name":"CampaignSouldStartInFuture","type":"error"},{"inputs":[],"name":"InvalidLengths","type":"error"},{"inputs":[],"name":"InvalidParam","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"NotGovernor","type":"error"},{"inputs":[],"name":"NotGovernorOrGuardian","type":"error"},{"inputs":[],"name":"NotSigned","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"campaignType","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"_fees","type":"uint256"}],"name":"CampaignSpecificFeesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_distributor","type":"address"}],"name":"DistributorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"userFeeRebate","type":"uint256"}],"name":"FeeRebateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_feeRecipient","type":"address"}],"name":"FeeRecipientUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_fees","type":"uint256"}],"name":"FeesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"_messageHash","type":"bytes32"}],"name":"MessageUpdated","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"bytes32","name":"campaignId","type":"bytes32"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint32","name":"campaignType","type":"uint32"},{"internalType":"uint32","name":"startTimestamp","type":"uint32"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"bytes","name":"campaignData","type":"bytes"}],"indexed":false,"internalType":"struct CampaignParameters","name":"campaign","type":"tuple"}],"name":"NewCampaign","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"bytes32","name":"rewardId","type":"bytes32"},{"internalType":"address","name":"uniV3Pool","type":"address"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address[]","name":"positionWrappers","type":"address[]"},{"internalType":"uint32[]","name":"wrapperTypes","type":"uint32[]"},{"internalType":"uint32","name":"propToken0","type":"uint32"},{"internalType":"uint32","name":"propToken1","type":"uint32"},{"internalType":"uint32","name":"propFees","type":"uint32"},{"internalType":"uint32","name":"epochStart","type":"uint32"},{"internalType":"uint32","name":"numEpoch","type":"uint32"},{"internalType":"uint32","name":"isOutOfRangeIncentivized","type":"uint32"},{"internalType":"uint32","name":"boostedReward","type":"uint32"},{"internalType":"address","name":"boostingAddress","type":"address"},{"internalType":"bytes","name":"additionalData","type":"bytes"}],"indexed":false,"internalType":"struct DistributionParameters","name":"distribution","type":"tuple"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"NewDistribution","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardTokenMinimumAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"toggleStatus","type":"uint256"}],"name":"TokenWhitelistToggled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"messageHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"UserSigned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"toggleStatus","type":"uint256"}],"name":"UserSigningWhitelistToggled","type":"event"},{"inputs":[],"name":"BASE_9","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CHAIN_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"HOUR","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptConditions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_campaignId","type":"bytes32"}],"name":"campaign","outputs":[{"components":[{"internalType":"bytes32","name":"campaignId","type":"bytes32"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint32","name":"campaignType","type":"uint32"},{"internalType":"uint32","name":"startTimestamp","type":"uint32"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"bytes","name":"campaignData","type":"bytes"}],"internalType":"struct CampaignParameters","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"campaignId","type":"bytes32"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint32","name":"campaignType","type":"uint32"},{"internalType":"uint32","name":"startTimestamp","type":"uint32"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"bytes","name":"campaignData","type":"bytes"}],"internalType":"struct CampaignParameters","name":"campaignData","type":"tuple"}],"name":"campaignId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"campaignList","outputs":[{"internalType":"bytes32","name":"campaignId","type":"bytes32"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint32","name":"campaignType","type":"uint32"},{"internalType":"uint32","name":"startTimestamp","type":"uint32"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"bytes","name":"campaignData","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_campaignId","type":"bytes32"}],"name":"campaignLookup","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"campaignSpecificFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"core","outputs":[{"internalType":"contract ICore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"campaignId","type":"bytes32"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint32","name":"campaignType","type":"uint32"},{"internalType":"uint32","name":"startTimestamp","type":"uint32"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"bytes","name":"campaignData","type":"bytes"}],"internalType":"struct CampaignParameters","name":"newCampaign","type":"tuple"}],"name":"createCampaign","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"campaignId","type":"bytes32"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint32","name":"campaignType","type":"uint32"},{"internalType":"uint32","name":"startTimestamp","type":"uint32"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"bytes","name":"campaignData","type":"bytes"}],"internalType":"struct CampaignParameters[]","name":"campaigns","type":"tuple[]"}],"name":"createCampaigns","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"rewardId","type":"bytes32"},{"internalType":"address","name":"uniV3Pool","type":"address"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address[]","name":"positionWrappers","type":"address[]"},{"internalType":"uint32[]","name":"wrapperTypes","type":"uint32[]"},{"internalType":"uint32","name":"propToken0","type":"uint32"},{"internalType":"uint32","name":"propToken1","type":"uint32"},{"internalType":"uint32","name":"propFees","type":"uint32"},{"internalType":"uint32","name":"epochStart","type":"uint32"},{"internalType":"uint32","name":"numEpoch","type":"uint32"},{"internalType":"uint32","name":"isOutOfRangeIncentivized","type":"uint32"},{"internalType":"uint32","name":"boostedReward","type":"uint32"},{"internalType":"address","name":"boostingAddress","type":"address"},{"internalType":"bytes","name":"additionalData","type":"bytes"}],"internalType":"struct DistributionParameters","name":"newDistribution","type":"tuple"}],"name":"createDistribution","outputs":[{"internalType":"uint256","name":"distributionAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"rewardId","type":"bytes32"},{"internalType":"address","name":"uniV3Pool","type":"address"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address[]","name":"positionWrappers","type":"address[]"},{"internalType":"uint32[]","name":"wrapperTypes","type":"uint32[]"},{"internalType":"uint32","name":"propToken0","type":"uint32"},{"internalType":"uint32","name":"propToken1","type":"uint32"},{"internalType":"uint32","name":"propFees","type":"uint32"},{"internalType":"uint32","name":"epochStart","type":"uint32"},{"internalType":"uint32","name":"numEpoch","type":"uint32"},{"internalType":"uint32","name":"isOutOfRangeIncentivized","type":"uint32"},{"internalType":"uint32","name":"boostedReward","type":"uint32"},{"internalType":"address","name":"boostingAddress","type":"address"},{"internalType":"bytes","name":"additionalData","type":"bytes"}],"internalType":"struct DistributionParameters[]","name":"distributions","type":"tuple[]"}],"name":"createDistributions","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"distribution","outputs":[{"components":[{"internalType":"bytes32","name":"campaignId","type":"bytes32"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint32","name":"campaignType","type":"uint32"},{"internalType":"uint32","name":"startTimestamp","type":"uint32"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"bytes","name":"campaignData","type":"bytes"}],"internalType":"struct CampaignParameters","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"distributionList","outputs":[{"internalType":"bytes32","name":"rewardId","type":"bytes32"},{"internalType":"address","name":"uniV3Pool","type":"address"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint32","name":"propToken0","type":"uint32"},{"internalType":"uint32","name":"propToken1","type":"uint32"},{"internalType":"uint32","name":"propFees","type":"uint32"},{"internalType":"uint32","name":"epochStart","type":"uint32"},{"internalType":"uint32","name":"numEpoch","type":"uint32"},{"internalType":"uint32","name":"isOutOfRangeIncentivized","type":"uint32"},{"internalType":"uint32","name":"boostedReward","type":"uint32"},{"internalType":"address","name":"boostingAddress","type":"address"},{"internalType":"bytes","name":"additionalData","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"distributor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"feeRebate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"start","type":"uint32"},{"internalType":"uint32","name":"end","type":"uint32"},{"internalType":"uint32","name":"skip","type":"uint32"},{"internalType":"uint32","name":"first","type":"uint32"}],"name":"getCampaignsBetween","outputs":[{"components":[{"internalType":"bytes32","name":"campaignId","type":"bytes32"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint32","name":"campaignType","type":"uint32"},{"internalType":"uint32","name":"startTimestamp","type":"uint32"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"bytes","name":"campaignData","type":"bytes"}],"internalType":"struct CampaignParameters[]","name":"","type":"tuple[]"},{"internalType":"uint256","name":"lastIndexCampaign","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"epochStart","type":"uint32"},{"internalType":"uint32","name":"epochEnd","type":"uint32"},{"internalType":"uint32","name":"skip","type":"uint32"},{"internalType":"uint32","name":"first","type":"uint32"}],"name":"getDistributionsBetweenEpochs","outputs":[{"components":[{"internalType":"bytes32","name":"rewardId","type":"bytes32"},{"internalType":"address","name":"uniV3Pool","type":"address"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address[]","name":"positionWrappers","type":"address[]"},{"internalType":"uint32[]","name":"wrapperTypes","type":"uint32[]"},{"internalType":"uint32","name":"propToken0","type":"uint32"},{"internalType":"uint32","name":"propToken1","type":"uint32"},{"internalType":"uint32","name":"propFees","type":"uint32"},{"internalType":"uint32","name":"epochStart","type":"uint32"},{"internalType":"uint32","name":"numEpoch","type":"uint32"},{"internalType":"uint32","name":"isOutOfRangeIncentivized","type":"uint32"},{"internalType":"uint32","name":"boostedReward","type":"uint32"},{"internalType":"address","name":"boostingAddress","type":"address"},{"internalType":"bytes","name":"additionalData","type":"bytes"}],"internalType":"struct DistributionParameters[]","name":"","type":"tuple[]"},{"internalType":"uint256","name":"lastIndexDistribution","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getValidRewardTokens","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"minimumAmountPerEpoch","type":"uint256"}],"internalType":"struct RewardTokenAmounts[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"skip","type":"uint32"},{"internalType":"uint32","name":"first","type":"uint32"}],"name":"getValidRewardTokens","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"minimumAmountPerEpoch","type":"uint256"}],"internalType":"struct RewardTokenAmounts[]","name":"","type":"tuple[]"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ICore","name":"_core","type":"address"},{"internalType":"address","name":"_distributor","type":"address"},{"internalType":"uint256","name":"_fees","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isWhitelistedToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"message","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"messageHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"address","name":"to","type":"address"}],"name":"recoverFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardTokenMinAmounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"campaignType","type":"uint32"},{"internalType":"uint256","name":"_fees","type":"uint256"}],"name":"setCampaignFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeRecipient","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_defaultFees","type":"uint256"}],"name":"setFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_message","type":"string"}],"name":"setMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_distributor","type":"address"}],"name":"setNewDistributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"setRewardTokenMinAmounts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"userFeeRebate","type":"uint256"}],"name":"setUserFeeRebate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"sign","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"campaignId","type":"bytes32"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint32","name":"campaignType","type":"uint32"},{"internalType":"uint32","name":"startTimestamp","type":"uint32"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"bytes","name":"campaignData","type":"bytes"}],"internalType":"struct CampaignParameters","name":"newCampaign","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"signAndCreateCampaign","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"toggleSigningWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"toggleTokenWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userSignatureWhitelist","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userSignatures","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60c0604052306080524660a0523480156200001957600080fd5b50600054610100900460ff16158080156200003b5750600054600160ff909116105b806200006b57506200005830620001bf60201b620023b41760201c565b1580156200006b575060005460ff166001145b620000935760405162461bcd60e51b81526004016200008a90620001ce565b60405180910390fd5b6000805460ff191660011790558015620000b7576000805461ff0019166101001790555b8015620000ed576000805461ff001916905560405160018152600080516020620055dd8339815191529060200160405180910390a15b50600054610100900460ff16158080156200010f5750600054600160ff909116105b806200013f57506200012c30620001bf60201b620023b41760201c565b1580156200013f575060005460ff166001145b6200015e5760405162461bcd60e51b81526004016200008a90620001ce565b6000805460ff19166001179055801562000182576000805461ff0019166101001790555b8015620001b8576000805461ff001916905560405160018152600080516020620055dd8339815191529060200160405180910390a15b506200021c565b6001600160a01b03163b151590565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60805160a05161537862000265600039600081816105f1015261124a015260008181610e7c01528181610ebc015281816113c101528181611401015261147d01526153786000f3fe6080604052600436106102235760003560e01c80630241d8f91461022857806303d2944c1461024a578063118b48e51461026a578063141df503146102935780631794bb3c146102b35780632acd7ec4146102d3578063304440171461030057806330ebe7511461031657806331dc7722146103445780633659cfe614610364578063368b8772146103845780633a2c3e24146103a45780633d18678e146103d15780634129fe4c146103f1578063469048401461041e57806348c11a2f1461044b5780634912c6581461046b5780634f1ef2861461049f57806352d1902d146104b2578063586db1f5146104c757806363b87bf0146104f55780636a8b4a321461051a5780636c1550b1146105475780636cca84bd14610567578063752e87491461058757806376cd7cbc1461059f5780637bb7bed1146105bf57806385e1f4d0146105df57806395d3d5d81461061357806396b3ce5414610635578063a218404014610662578063a2686e2314610682578063a39dc9be146106a2578063a63f05ad146106cd578063aa8b0670146106ed578063ab37f4861461070d578063b33335621461073a578063b9844d8d1461075a578063b9d81abc14610787578063ba5c3a9d146107a7578063bfe10928146107e0578063d7fa562514610800578063de6a533a1461082d578063e21f37ce1461085b578063e55f577b1461087d578063e74b981b1461089d578063f2f4eb26146108bd578063feba1ed2146108dd575b600080fd5b34801561023457600080fd5b50610248610243366004613f1f565b61090a565b005b34801561025657600080fd5b50610248610265366004613f4b565b6109f1565b34801561027657600080fd5b50610280609a5481565b6040519081526020015b60405180910390f35b34801561029f57600080fd5b506102486102ae366004613fac565b610af0565b3480156102bf57600080fd5b506102486102ce366004614002565b610c67565b3480156102df57600080fd5b506102806102ee366004613f4b565b60a36020526000908152604090205481565b34801561030c57600080fd5b50610280609c5481565b34801561032257600080fd5b50610336610331366004614057565b610e13565b60405161028a92919061418c565b34801561035057600080fd5b5061028061035f3660046141f5565b610e31565b34801561037057600080fd5b5061024861037f366004613f4b565b610e72565b34801561039057600080fd5b5061024861039f3660046142f7565b610f3a565b3480156103b057600080fd5b506102806103bf36600461433f565b60a76020526000908152604090205481565b3480156103dd57600080fd5b506102486103ec3660046141f5565b611020565b3480156103fd57600080fd5b5061041161040c36600461444e565b61110d565b60405161028a9190614503565b34801561042a57600080fd5b5060995461043e906001600160a01b031681565b60405161028a9190614547565b34801561045757600080fd5b5061028061046636600461455b565b611246565b34801561047757600080fd5b5061048b6104863660046141f5565b6112ba565b60405161028a98979695949392919061458f565b6102486104ad3660046145f4565b6113b7565b3480156104be57600080fd5b50610280611470565b3480156104d357600080fd5b506104e76104e2366004614057565b61151e565b60405161028a9291906146bd565b34801561050157600080fd5b5061024833600090815260a26020526040902060019055565b34801561052657600080fd5b5061053a6105353660046141f5565b61153e565b60405161028a9190614829565b34801561055357600080fd5b50610411610562366004614a73565b61167f565b34801561057357600080fd5b50610248610582366004613f4b565b6117a5565b34801561059357600080fd5b50610280633b9aca0081565b3480156105ab57600080fd5b506102486105ba366004614b57565b6118a8565b3480156105cb57600080fd5b5061043e6105da3660046141f5565b6118b2565b3480156105eb57600080fd5b506102807f000000000000000000000000000000000000000000000000000000000000000081565b34801561061f57600080fd5b506106286118dc565b60405161028a9190614bdc565b34801561064157600080fd5b50610280610650366004613f4b565b60a16020526000908152604090205481565b34801561066e57600080fd5b5061024861067d366004614bef565b6118f6565b34801561068e57600080fd5b5061024861069d366004613f4b565b611b48565b3480156106ae57600080fd5b506106b8610e1081565b60405163ffffffff909116815260200161028a565b3480156106d957600080fd5b506102806106e836600461455b565b611c4b565b3480156106f957600080fd5b5061053a6107083660046141f5565b611cec565b34801561071957600080fd5b50610280610728366004613f4b565b609f6020526000908152604090205481565b34801561074657600080fd5b50610248610755366004614c5a565b611f55565b34801561076657600080fd5b50610280610775366004613f4b565b60a06020526000908152604090205481565b34801561079357600080fd5b506102806107a2366004614c76565b612055565b3480156107b357600080fd5b506107c76107c23660046141f5565b6120ea565b60405161028a9d9c9b9a99989796959493929190614caa565b3480156107ec57600080fd5b5060985461043e906001600160a01b031681565b34801561080c57600080fd5b5061028061081b366004613f4b565b60a26020526000908152604090205481565b34801561083957600080fd5b5061084d610848366004614d54565b612217565b60405161028a929190614d87565b34801561086757600080fd5b50610870612231565b60405161028a9190614da9565b34801561088957600080fd5b50610280610898366004614dbc565b6122bf565b3480156108a957600080fd5b506102486108b8366004613f4b565b6122dc565b3480156108c957600080fd5b5060975461043e906001600160a01b031681565b3480156108e957600080fd5b506102806108f8366004613f4b565b609e6020526000908152604090205481565b60975460405163521d4de960e01b81526001600160a01b039091169063521d4de99061093a903390600401614547565b602060405180830381865afa158015610957573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097b9190614e24565b61099857604051632678482f60e21b815260040160405180910390fd5b6001600160a01b0382166000818152609e602052604090819020839055517fab1d37d0b21937f334fc4164d147abbfdbfd7ef37ab9ea0ae73f2a58ffb7f1cc906109e59084815260200190565b60405180910390a25050565b609754604051631c86b03760e31b81526001600160a01b039091169063e43581b890610a21903390600401614547565b602060405180830381865afa158015610a3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a629190614e24565b610a7f57604051633b8d9d7560e21b815260040160405180910390fd5b6001600160a01b038116610aa657604051633494a40d60e21b815260040160405180910390fd5b609880546001600160a01b0319166001600160a01b0383169081179091556040517fc0ebb188f905d128bcd7e4282dd1f9cf24cd331b69071002e488349aca6a867b90600090a250565b609754604051631c86b03760e31b81526001600160a01b039091169063e43581b890610b20903390600401614547565b602060405180830381865afa158015610b3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b619190614e24565b610b7e57604051633b8d9d7560e21b815260040160405180910390fd5b8160005b81811015610c6057610c5883868684818110610ba057610ba0614e46565b9050602002016020810190610bb59190613f4b565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610be09190614547565b602060405180830381865afa158015610bfd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c219190614e5c565b878785818110610c3357610c33614e46565b9050602002016020810190610c489190613f4b565b6001600160a01b031691906123c3565b600101610b82565b5050505050565b600054610100900460ff1615808015610c875750600054600160ff909116105b80610ca85750610c96306123b4565b158015610ca8575060005460ff166001145b610d105760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610d33576000805461ff0019166101001790555b6001600160a01b0384161580610d5057506001600160a01b038316155b15610d6e5760405163d92e233d60e01b815260040160405180910390fd5b633b9aca008210610d9257604051633494a40d60e21b815260040160405180910390fd5b609880546001600160a01b038086166001600160a01b0319928316179092556097805492871692909116919091179055609a8290558015610e0d576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b60606000610e238686868661242b565b915091505b94509492505050565b600081815260a66020526040812054808203610e6057604051639b35ed3b60e01b815260040160405180910390fd5b610e6b600182614e8b565b9392505050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610eba5760405162461bcd60e51b8152600401610d0790614e9e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610eec61268e565b6001600160a01b031614610f125760405162461bcd60e51b8152600401610d0790614ed8565b610f1b816126aa565b60408051600080825260208201909252610f379183919061274d565b50565b609754604051631c86b03760e31b81526001600160a01b039091169063e43581b890610f6a903390600401614547565b602060405180830381865afa158015610f87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fab9190614e24565b610fc857604051633b8d9d7560e21b815260040160405180910390fd5b609b610fd48282614f92565b506000610fe0826128b8565b609c8190556040518181529091507fde3dc3335dea4d1a1060ef6cefcfcc109eb0a1e78ce151818d3f17a01e1f8a05906020015b60405180910390a15050565b609754604051631c86b03760e31b81526001600160a01b039091169063e43581b890611050903390600401614547565b602060405180830381865afa15801561106d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110919190614e24565b6110ae57604051633b8d9d7560e21b815260040160405180910390fd5b633b9aca0081106110d257604051633494a40d60e21b815260040160405180910390fd5b609a8190556040518181527f3346af6da1932164d501f2ec28f8c5d686db5828a36b77f2da4332d89184fe7b9060200160405180910390a150565b60606111176128d6565b33600090815260a260205260409020541580156111455750609c5433600090815260a1602052604090205414155b801561115e575032600090815260a26020526040902054155b801561117b5750609c5432600090815260a1602052604090205414155b15611199576040516314e52a5b60e31b815260040160405180910390fd5b81516000816001600160401b038111156111b5576111b561420e565b6040519080825280602002602001820160405280156111de578160200160208202803683370190505b50905060005b828110156112335761120e85828151811061120157611201614e46565b602002602001015161292f565b82828151811061122057611220614e46565b60209081029190910101526001016111e4565b509150506112416001606555565b919050565b60007f00000000000000000000000000000000000000000000000000000000000000008260200151836040015184608001518560a001518660c001518760e0015160405160200161129d9796959493929190615051565b604051602081830303815290604052805190602001209050919050565b60a581815481106112ca57600080fd5b60009182526020909120600690910201805460018201546002830154600384015460048501546005860180549597506001600160a01b03948516969490931694919363ffffffff80831694600160201b8404821694600160401b9094049091169261133490614f12565b80601f016020809104026020016040519081016040528092919081815260200182805461136090614f12565b80156113ad5780601f10611382576101008083540402835291602001916113ad565b820191906000526020600020905b81548152906001019060200180831161139057829003601f168201915b5050505050905088565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036113ff5760405162461bcd60e51b8152600401610d0790614e9e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661143161268e565b6001600160a01b0316146114575760405162461bcd60e51b8152600401610d0790614ed8565b611460826126aa565b61146c8282600161274d565b5050565b6000306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461150b5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c6044820152771b1959081d1a1c9bdd59da0819195b1959d85d1958d85b1b60421b6064820152608401610d07565b506000805160206152fc83398151915290565b60606000610e2361152e87612cab565b61153787612cab565b8686612cc4565b611546613eb9565b60a561155183610e31565b8154811061156157611561614e46565b6000918252602091829020604080516101008101825260069093029091018054835260018101546001600160a01b039081169484019490945260028101549093169082015260038201546060820152600482015463ffffffff8082166080840152600160201b8204811660a0840152600160401b9091041660c082015260058201805491929160e0840191906115f690614f12565b80601f016020809104026020016040519081016040528092919081815260200182805461162290614f12565b801561166f5780601f106116445761010080835404028352916020019161166f565b820191906000526020600020905b81548152906001019060200180831161165257829003601f168201915b5050505050815250509050919050565b60606116896128d6565b33600090815260a260205260409020541580156116b75750609c5433600090815260a1602052604090205414155b80156116d0575032600090815260a26020526040902054155b80156116ed5750609c5432600090815260a1602052604090205414155b1561170b576040516314e52a5b60e31b815260040160405180910390fd5b81516000816001600160401b038111156117275761172761420e565b604051908082528060200260200182016040528015611750578160200160208202803683370190505b50905060005b828110156112335761178085828151811061177357611773614e46565b60200260200101516130b7565b82828151811061179257611792614e46565b6020908102919091010152600101611756565b60975460405163521d4de960e01b81526001600160a01b039091169063521d4de9906117d5903390600401614547565b602060405180830381865afa1580156117f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118169190614e24565b61183357604051632678482f60e21b815260040160405180910390fd5b6001600160a01b0381166000908152609f6020526040812054611857906001614e8b565b6001600160a01b0383166000818152609f60205260409081902083905551919250907fc6cd32b1acffa550abf886a9b443ff3ce485bfdb05e35ef5b26e745739a1eac1906109e59084815260200190565b61146c8282613104565b60a481815481106118c257600080fd5b6000918252602090912001546001600160a01b0316905081565b606060006118ef600063ffffffff6131ba565b5092915050565b60975460405163521d4de960e01b81526001600160a01b039091169063521d4de990611926903390600401614547565b602060405180830381865afa158015611943573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119679190614e24565b61198457604051632678482f60e21b815260040160405180910390fd5b828181146119a557604051631df89e8b60e01b815260040160405180910390fd5b60005b81811015611b405760008484838181106119c4576119c4614e46565b905060200201359050600081118015611a1f575060a360008888858181106119ee576119ee614e46565b9050602002016020810190611a039190613f4b565b6001600160a01b03168152602081019190915260400160002054155b15611a805760a4878784818110611a3857611a38614e46565b9050602002016020810190611a4d9190613f4b565b81546001810183556000928352602090922090910180546001600160a01b0319166001600160a01b039092169190911790555b8060a36000898986818110611a9757611a97614e46565b9050602002016020810190611aac9190613f4b565b6001600160a01b03168152602081019190915260400160002055868683818110611ad857611ad8614e46565b9050602002016020810190611aed9190613f4b565b6001600160a01b03167f3a5e6418e38cae10bf66eaf3e68c4e9c6b14df195e24fec169ab3a5b123c96e582604051611b2791815260200190565b60405180910390a250611b39816150c5565b90506119a8565b505050505050565b60975460405163521d4de960e01b81526001600160a01b039091169063521d4de990611b78903390600401614547565b602060405180830381865afa158015611b95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bb99190614e24565b611bd657604051632678482f60e21b815260040160405180910390fd5b6001600160a01b038116600090815260a26020526040812054611bfa906001614e8b565b6001600160a01b038316600081815260a260205260409081902083905551919250907f9c759941da0b7ce56c059c1497218796e62035024afb77a00ff49a980a62078f906109e59084815260200190565b6000611c556128d6565b33600090815260a26020526040902054158015611c835750609c5433600090815260a1602052604090205414155b8015611c9c575032600090815260a26020526040902054155b8015611cb95750609c5432600090815260a1602052604090205414155b15611cd7576040516314e52a5b60e31b815260040160405180910390fd5b611ce08261292f565b90506112416001606555565b611cf4613eb9565b611f4f609d8381548110611d0a57611d0a614e46565b6000918252602091829020604080516101e08101825260099093029091018054835260018101546001600160a01b0390811684860152600282015416838301526003810154606084015260048101805483518187028101870190945280845293949193608086019392830182828015611dac57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611d8e575b5050505050815260200160058201805480602002602001604051908101604052809291908181526020018280548015611e3057602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff1681526020019060040190602082600301049283019260010382029150808411611df35790505b5050509183525050600682015463ffffffff8082166020840152600160201b820481166040840152600160401b820481166060840152600160601b820481166080840152600160801b8204811660a0840152600160a01b8204811660c0840152600160c01b9091041660e082015260078201546001600160a01b031661010082015260088201805461012090920191611ec890614f12565b80601f0160208091040260200160405190810160405280929190818152602001828054611ef490614f12565b8015611f415780601f10611f1657610100808354040283529160200191611f41565b820191906000526020600020905b815481529060010190602001808311611f2457829003601f168201915b505050505081525050613319565b92915050565b60975460405163521d4de960e01b81526001600160a01b039091169063521d4de990611f85903390600401614547565b602060405180830381865afa158015611fa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc69190614e24565b611fe357604051632678482f60e21b815260040160405180910390fd5b633b9aca00811061200757604051633494a40d60e21b815260040160405180910390fd5b63ffffffff8216600081815260a76020908152604091829020849055815192835282018390527fb718143758782f8d3b9a4c9a0e6e54c43f2790e1e447d639c916a41a71151f5f9101611014565b600061205f6128d6565b33600090815260a2602052604090205415801561208d5750609c5433600090815260a1602052604090205414155b80156120a6575032600090815260a26020526040902054155b80156120c35750609c5432600090815260a1602052604090205414155b156120e1576040516314e52a5b60e31b815260040160405180910390fd5b611ce0826130b7565b609d81815481106120fa57600080fd5b600091825260209091206009909102018054600182015460028301546003840154600685015460078601546008870180549698506001600160a01b039586169794861696939563ffffffff80851696600160201b8604821696600160401b8704831696600160601b8104841696600160801b8204851696600160a01b8304861696600160c01b909304909516949116929161219490614f12565b80601f01602080910402602001604051908101604052809291908181526020018280546121c090614f12565b801561220d5780601f106121e25761010080835404028352916020019161220d565b820191906000526020600020905b8154815290600101906020018083116121f057829003601f168201915b505050505090508d565b6060600061222584846131ba565b915091505b9250929050565b609b805461223e90614f12565b80601f016020809104026020016040519081016040528092919081815260200182805461226a90614f12565b80156122b75780601f1061228c576101008083540402835291602001916122b7565b820191906000526020600020905b81548152906001019060200180831161229a57829003601f168201915b505050505081565b60006122cb8383613104565b6122d48461292f565b949350505050565b609754604051631c86b03760e31b81526001600160a01b039091169063e43581b89061230c903390600401614547565b602060405180830381865afa158015612329573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061234d9190614e24565b61236a57604051633b8d9d7560e21b815260040160405180910390fd5b609980546001600160a01b0319166001600160a01b0383169081179091556040517f7a7b5a0a132f9e0581eb8527f66eae9ee89c2a3e79d4ac7e41a1f1f4d48a7fc290600090a250565b6001600160a01b03163b151590565b6040516001600160a01b03831660248201526044810182905261242690849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526135b8565b505050565b60a55460609060009081908163ffffffff86168210612450578563ffffffff16612452565b815b90506000816001600160401b0381111561246e5761246e61420e565b6040519080825280602002602001820160405280156124a757816020015b612494613eb9565b81526020019060019003908161248c5790505b509050875b838163ffffffff16101561267557600060a58263ffffffff16815481106124d5576124d5614e46565b6000918252602091829020604080516101008101825260069093029091018054835260018101546001600160a01b039081169484019490945260028101549093169082015260038201546060820152600482015463ffffffff8082166080840152600160201b8204811660a0840152600160401b9091041660c082015260058201805491929160e08401919061256a90614f12565b80601f016020809104026020016040519081016040528092919081815260200182805461259690614f12565b80156125e35780601f106125b8576101008083540402835291602001916125e3565b820191906000526020600020905b8154815290600101906020018083116125c657829003601f168201915b50505050508152505090508b63ffffffff168160c001518260a0015161260991906150de565b63ffffffff1611801561262b57508a63ffffffff168160a0015163ffffffff16105b1561265c578083878151811061264357612643614e46565b60209081029190910101526126596001876150fb565b95505b81600101915083860361266f5750612675565b506124ac565b9381529963ffffffff9093169850919650505050505050565b6000805160206152fc833981519152546001600160a01b031690565b6097546001600160a01b0316801580159061272f5750604051631c86b03760e31b81526001600160a01b0382169063e43581b8906126ec903390600401614547565b602060405180830381865afa158015612709573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061272d9190614e24565b155b1561146c57604051633b8d9d7560e21b815260040160405180910390fd5b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612780576124268361368a565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156127da575060408051601f3d908101601f191682019092526127d791810190614e5c565b60015b61283d5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610d07565b6000805160206152fc83398151915281146128ac5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610d07565b50612426838383613724565b60006128c48251613749565b8260405160200161129d92919061510e565b6002606554036129285760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d07565b6002606555565b6040808201516001600160a01b0316600090815260a36020529081205460a08301514263ffffffff9091161015612979576040516332dcdf7360e21b815260040160405180910390fd5b610e1063ffffffff168360c0015163ffffffff1610156129ac57604051631b5982fd60e01b815260040160405180910390fd5b806000036129cd5760405163c0460cfb60e01b815260040160405180910390fd5b808360c0015163ffffffff16610e1063ffffffff1685606001516129f19190615167565b6129fb9190615194565b1015612a1a5760405163912f27bf60e01b815260040160405180910390fd5b60208301516001600160a01b0316612a33573360208401525b608083015163ffffffff16600090815260a760205260409020546001819003612a5e57506000612a6b565b80600003612a6b5750609a545b6000612a8082866060015187604001516137dc565b606086018190529050612a9285611246565b808652600090815260a6602052604090205415612ac257604051637e31d8a360e01b815260040160405180910390fd5b60a554612ad09060016150fb565b8551600090815260a6602090815260408083209390935560a580546001810182559252875160069092027fb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddeff8101928355908801517fb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddf00820180546001600160a01b039283166001600160a01b031991821617909155938901517fb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddf01830180549190921694169390931790925560608701517fb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddf0283015560808701517fb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddf038301805460a08a015160c08b015163ffffffff908116600160401b0263ffffffff60401b19928216600160201b026001600160401b03199094169190951617919091171691909117905560e087015187927fb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddf040190612c679082614f92565b5050507f6e3c6fa6d4815a856783888c5c3ea2ad7e7303ac0cca66c99f5bd93502c4429985604051612c999190614829565b60405180910390a15050915192915050565b6000610e10612cba81846151a8565b611f4f91906151cb565b609d5460609060009081908163ffffffff86168210612ce9578563ffffffff16612ceb565b815b90506000816001600160401b03811115612d0757612d0761420e565b604051908082528060200260200182016040528015612db057816020015b604080516101e0810182526000808252602080830182905292820181905260608083018290526080830181905260a0830181905260c0830182905260e08301829052610100830182905261012083018290526101408301829052610160830182905261018083018290526101a08301919091526101c08201528252600019909201910181612d255790505b509050875b838163ffffffff161015612675576000609d8263ffffffff1681548110612dde57612dde614e46565b6000918252602091829020604080516101e08101825260099093029091018054835260018101546001600160a01b0390811684860152600282015416838301526003810154606084015260048101805483518187028101870190945280845293949193608086019392830182828015612e8057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612e62575b5050505050815260200160058201805480602002602001604051908101604052809291908181526020018280548015612f0457602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff1681526020019060040190602082600301049283019260010382029150808411612ec75790505b5050509183525050600682015463ffffffff8082166020840152600160201b820481166040840152600160401b820481166060840152600160601b820481166080840152600160801b8204811660a0840152600160a01b8204811660c0840152600160c01b9091041660e082015260078201546001600160a01b031661010082015260088201805461012090920191612f9c90614f12565b80601f0160208091040260200160405190810160405280929190818152602001828054612fc890614f12565b80156130155780601f10612fea57610100808354040283529160200191613015565b820191906000526020600020905b815481529060010190602001808311612ff857829003601f168201915b50505050508152505090508b63ffffffff16610e1082610140015161303a91906151cb565b82610120015161304a91906150de565b63ffffffff1611801561306d57508a63ffffffff1681610120015163ffffffff16105b1561309e578083878151811061308557613085614e46565b602090810291909101015261309b6001876150fb565b95505b8160010191508386036130b15750612675565b50612db5565b60006130ca6130c583613319565b61292f565b5060a580546130db90600190614e8b565b815481106130eb576130eb614e46565b9060005260206000209060060201600301549050919050565b6000609c54905061314c338285858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061389e92505050565b61316957604051638baa579f60e01b815260040160405180910390fd5b33600081815260a1602052604090819020839055517fc48bbd4f009ad78a336beb65bf44688651e9aa52ac98d9054f0fce0573fefbc3906131ad9084815260200190565b60405180910390a2505050565b60a45460609060009081908163ffffffff861682106131df578563ffffffff166131e1565b815b90506000816001600160401b038111156131fd576131fd61420e565b60405190808252806020026020018201604052801561324257816020015b604080518082019091526000808252602082015281526020019060019003908161321b5790505b509050875b838163ffffffff16101561330257600060a48263ffffffff168154811061327057613270614e46565b60009182526020808320909101546001600160a01b031680835260a390915260409091205490915080156132e7576040518060400160405280836001600160a01b03168152602001828152508488815181106132ce576132ce614e46565b60209081029190910101526132e46001886150fb565b96505b8260010192508487036132fb575050613302565b5050613247565b9381529763ffffffff909316965091945050505050565b613321613eb9565b60a0820151516000816001600160401b038111156133415761334161420e565b60405190808252806020026020018201604052801561336a578160200160208202803683370190505b5090506000826001600160401b038111156133875761338761420e565b6040519080825280602002602001820160405280156133b0578160200160208202803683370190505b50905060008060005b858110156134d5578760a0015181815181106133d7576133d7614e46565b602002602001015163ffffffff16600003613442578760800151818151811061340257613402614e46565b602002602001015185848151811061341c5761341c614e46565b6001600160a01b039092166020928302919091019091015261343f6001846150fb565b92505b8760a00151818151811061345857613458614e46565b602002602001015163ffffffff166003036134c3578760800151818151811061348357613483614e46565b602002602001015184838151811061349d5761349d614e46565b6001600160a01b03909216602092830291909101909101526134c06001836150fb565b91505b806134cd816150c5565b9150506133b9565b5081845280835260405180610100016040528088600001518152602001336001600160a01b0316815260200188604001516001600160a01b0316815260200188606001518152602001600263ffffffff16815260200188610120015163ffffffff168152602001610e1089610140015161354f91906151cb565b63ffffffff16815260200188602001518961010001518a60c001518b60e001518c61016001518d6101a001518e61018001518c8c60405160200161359b999897969594939291906151f3565b60408051601f198184030181529190529052979650505050505050565b600061360d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166139e09092919063ffffffff16565b805190915015612426578080602001905181019061362b9190614e24565b6124265760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610d07565b613693816123b4565b6136f55760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610d07565b6000805160206152fc83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b61372d836139ef565b60008251118061373a5750805b1561242657610e0d8383613a2f565b6060600061375683613b21565b60010190506000816001600160401b038111156137755761377561420e565b6040519080825280601f01601f19166020018201604052801561379f576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a85049450846137a9575b509392505050565b336000908152609e60205260408120548190633b9aca00906137fe9082614e8b565b6138089087615167565b6138129190615194565b8492509050801561388257633b9aca0061382c8282614e8b565b6138369086615167565b6138409190615194565b6099549092506001600160a01b0316801561385b578061385d565b305b9050613880338261386e8689614e8b565b6001600160a01b038816929190613bf7565b505b6098546137d4906001600160a01b038581169133911685613bf7565b60008060006138ad8585613c2f565b909250905060008160048111156138c6576138c6615290565b1480156138e45750856001600160a01b0316826001600160a01b0316145b156138f457600192505050610e6b565b600080876001600160a01b0316631626ba7e60e01b888860405160240161391c9291906152a6565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161395a91906152bf565b600060405180830381855afa9150503d8060008114613995576040519150601f19603f3d011682016040523d82523d6000602084013e61399a565b606091505b50915091508180156139ad575080516020145b80156139d457508051630b135d3f60e11b906139d29083016020908101908401614e5c565b145b98975050505050505050565b60606122d48484600085613c71565b6139f88161368a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060613a3a836123b4565b613a955760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610d07565b600080846001600160a01b031684604051613ab091906152bf565b600060405180830381855af49150503d8060008114613aeb576040519150601f19603f3d011682016040523d82523d6000602084013e613af0565b606091505b5091509150613b18828260405180606001604052806027815260200161531c60279139613d4c565b95945050505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310613b605772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6904ee2d6d415b85acef8160201b8310613b8a576904ee2d6d415b85acef8160201b830492506020015b662386f26fc100008310613ba857662386f26fc10000830492506010015b6305f5e1008310613bc0576305f5e100830492506008015b6127108310613bd457612710830492506004015b60648310613be6576064830492506002015b600a8310611f4f5760010192915050565b6040516001600160a01b0380851660248301528316604482015260648101829052610e0d9085906323b872dd60e01b906084016123ef565b6000808251604103613c655760208301516040840151606085015160001a613c5987828585613d65565b9450945050505061222a565b5060009050600261222a565b606082471015613cd25760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610d07565b600080866001600160a01b03168587604051613cee91906152bf565b60006040518083038185875af1925050503d8060008114613d2b576040519150601f19603f3d011682016040523d82523d6000602084013e613d30565b606091505b5091509150613d4187838387613e1c565b979650505050505050565b60608315613d5b575081610e6b565b610e6b8383613e8f565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b03831115613d925750600090506003610e28565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613de6573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116613e0f57600060019250925050610e28565b9660009650945050505050565b60608315613e89578251600003613e8257613e36856123b4565b613e825760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d07565b50816122d4565b6122d483835b815115613e9f5781518083602001fd5b8060405162461bcd60e51b8152600401610d079190614da9565b604080516101008101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c082019290925260e081019190915290565b6001600160a01b0381168114610f3757600080fd5b803561124181613eff565b60008060408385031215613f3257600080fd5b8235613f3d81613eff565b946020939093013593505050565b600060208284031215613f5d57600080fd5b8135610e6b81613eff565b60008083601f840112613f7a57600080fd5b5081356001600160401b03811115613f9157600080fd5b6020830191508360208260051b850101111561222a57600080fd5b600080600060408486031215613fc157600080fd5b83356001600160401b03811115613fd757600080fd5b613fe386828701613f68565b9094509250506020840135613ff781613eff565b809150509250925092565b60008060006060848603121561401757600080fd5b833561402281613eff565b9250602084013561403281613eff565b929592945050506040919091013590565b803563ffffffff8116811461124157600080fd5b6000806000806080858703121561406d57600080fd5b61407685614043565b935061408460208601614043565b925061409260408601614043565b91506140a060608601614043565b905092959194509250565b6001600160a01b03169052565b60005b838110156140d35781810151838201526020016140bb565b50506000910152565b600081518084526140f48160208601602086016140b8565b601f01601f19169290920160200192915050565b600061010082518452602083015160018060a01b038082166020870152806040860151166040870152505060608301516060850152608083015163ffffffff80821660808701528060a08601511660a0870152505060c083015161417460c086018263ffffffff169052565b5060e08301518160e0860152613b18828601826140dc565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b838110156141e357605f198887030185526141d1868351614108565b955093820193908201906001016141b5565b50509490940194909452949350505050565b60006020828403121561420757600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60405161010081016001600160401b03811182821017156142475761424761420e565b60405290565b6040516101e081016001600160401b03811182821017156142475761424761420e565b604051601f8201601f191681016001600160401b03811182821017156142985761429861420e565b604052919050565b60006001600160401b038311156142b9576142b961420e565b6142cc601f8401601f1916602001614270565b90508281528383830111156142e057600080fd5b828260208301376000602084830101529392505050565b60006020828403121561430957600080fd5b81356001600160401b0381111561431f57600080fd5b8201601f8101841361433057600080fd5b6122d4848235602084016142a0565b60006020828403121561435157600080fd5b610e6b82614043565b60006001600160401b038211156143735761437361420e565b5060051b60200190565b600082601f83011261438e57600080fd5b610e6b838335602085016142a0565b600061010082840312156143b057600080fd5b6143b8614224565b9050813581526143ca60208301613f14565b60208201526143db60408301613f14565b6040820152606082013560608201526143f660808301614043565b608082015261440760a08301614043565b60a082015261441860c08301614043565b60c082015260e08201356001600160401b0381111561443657600080fd5b6144428482850161437d565b60e08301525092915050565b6000602080838503121561446157600080fd5b82356001600160401b038082111561447857600080fd5b818501915085601f83011261448c57600080fd5b813561449f61449a8261435a565b614270565b81815260059190911b830184019084810190888311156144be57600080fd5b8585015b838110156144f6578035858111156144da5760008081fd5b6144e88b89838a010161439d565b8452509186019186016144c2565b5098975050505050505050565b6020808252825182820181905260009190848201906040850190845b8181101561453b5783518352928401929184019160010161451f565b50909695505050505050565b6001600160a01b0391909116815260200190565b60006020828403121561456d57600080fd5b81356001600160401b0381111561458357600080fd5b6122d48482850161439d565b8881526001600160a01b038881166020830152871660408201526060810186905263ffffffff858116608083015284811660a0830152831660c082015261010060e082018190526000906145e5838201856140dc565b9b9a5050505050505050505050565b6000806040838503121561460757600080fd5b823561461281613eff565b915060208301356001600160401b0381111561462d57600080fd5b6146398582860161437d565b9150509250929050565b600081518084526020808501945080840160005b8381101561467c5781516001600160a01b031687529582019590820190600101614657565b509495945050505050565b600081518084526020808501945080840160005b8381101561467c57815163ffffffff168752958201959082019060010161469b565b60006040808301818452808651808352606092508286019150828160051b8701016020808a0160005b8481101561481457605f198a850301865281516101e08151865284820151614710868801826140ab565b50898201516147218b8801826140ab565b508882015189870152608080830151828289015261474183890182614643565b9250505060a0808301518783038289015261475c8382614687565b9250505060c0808301516147778289018263ffffffff169052565b505060e08281015163ffffffff908116918801919091526101008084015182169088015261012080840151821690880152610140808401518216908801526101608084015182169088015261018080840151909116908701526101a0808301516147e3828901826140ab565b50506101c0808301519250868203818801525061480081836140dc565b9785019795505050908201906001016146e6565b50509690960196909652509295945050505050565b602081526000610e6b6020830184614108565b600082601f83011261484d57600080fd5b8135602061485d61449a8361435a565b82815260059290921b8401810191818101908684111561487c57600080fd5b8286015b848110156148a057803561489381613eff565b8352918301918301614880565b509695505050505050565b600082601f8301126148bc57600080fd5b813560206148cc61449a8361435a565b82815260059290921b840181019181810190868411156148eb57600080fd5b8286015b848110156148a05761490081614043565b83529183019183016148ef565b60006101e0828403121561492057600080fd5b61492861424d565b90508135815261493a60208301613f14565b602082015261494b60408301613f14565b60408201526060828101359082015260808201356001600160401b038082111561497457600080fd5b6149808583860161483c565b608084015260a084013591508082111561499957600080fd5b6149a5858386016148ab565b60a08401526149b660c08501614043565b60c08401526149c760e08501614043565b60e084015261010091506149dc828501614043565b8284015261012091506149f0828501614043565b828401526101409150614a04828501614043565b828401526101609150614a18828501614043565b828401526101809150614a2c828501614043565b828401526101a09150614a40828501613f14565b828401526101c091508184013581811115614a5a57600080fd5b614a668682870161437d565b8385015250505092915050565b60006020808385031215614a8657600080fd5b82356001600160401b0380821115614a9d57600080fd5b818501915085601f830112614ab157600080fd5b8135614abf61449a8261435a565b81815260059190911b83018401908481019088831115614ade57600080fd5b8585015b838110156144f657803585811115614afa5760008081fd5b614b088b89838a010161490d565b845250918601918601614ae2565b60008083601f840112614b2857600080fd5b5081356001600160401b03811115614b3f57600080fd5b60208301915083602082850101111561222a57600080fd5b60008060208385031215614b6a57600080fd5b82356001600160401b03811115614b8057600080fd5b614b8c85828601614b16565b90969095509350505050565b600081518084526020808501945080840160005b8381101561467c57815180516001600160a01b031688528301518388015260409096019590820190600101614bac565b602081526000610e6b6020830184614b98565b60008060008060408587031215614c0557600080fd5b84356001600160401b0380821115614c1c57600080fd5b614c2888838901613f68565b90965094506020870135915080821115614c4157600080fd5b50614c4e87828801613f68565b95989497509550505050565b60008060408385031215614c6d57600080fd5b613f3d83614043565b600060208284031215614c8857600080fd5b81356001600160401b03811115614c9e57600080fd5b6122d48482850161490d565b8d81526001600160a01b038d811660208301528c166040820152606081018b905263ffffffff8a8116608083015289811660a0830152881660c0820152600063ffffffff881660e083015263ffffffff871661010083015263ffffffff861661012083015263ffffffff8516610140830152614d2a6101608301856140ab565b6101a0610180830152614d416101a08301846140dc565b9f9e505050505050505050505050505050565b60008060408385031215614d6757600080fd5b614d7083614043565b9150614d7e60208401614043565b90509250929050565b604081526000614d9a6040830185614b98565b90508260208301529392505050565b602081526000610e6b60208301846140dc565b600080600060408486031215614dd157600080fd5b83356001600160401b0380821115614de857600080fd5b614df48783880161439d565b94506020860135915080821115614e0a57600080fd5b50614e1786828701614b16565b9497909650939450505050565b600060208284031215614e3657600080fd5b81518015158114610e6b57600080fd5b634e487b7160e01b600052603260045260246000fd5b600060208284031215614e6e57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b81810381811115611f4f57611f4f614e75565b6020808252602c908201526000805160206152dc83398151915260408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201526000805160206152dc83398151915260408201526b6163746976652070726f787960a01b606082015260800190565b600181811c90821680614f2657607f821691505b602082108103614f4657634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561242657600081815260208120601f850160051c81016020861015614f735750805b601f850160051c820191505b81811015611b4057828155600101614f7f565b81516001600160401b03811115614fab57614fab61420e565b614fbf81614fb98454614f12565b84614f4c565b602080601f831160018114614ff45760008415614fdc5750858301515b600019600386901b1c1916600185901b178555611b40565b600085815260208120601f198616915b8281101561502357888601518255948401946001909101908401615004565b50858210156150415787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b878152600060018060601b0319808960601b166020840152808860601b1660348401525063ffffffff60e01b808760e01b166048840152808660e01b16604c840152808560e01b1660508401525082516150b28160548501602087016140b8565b9190910160540198975050505050505050565b6000600182016150d7576150d7614e75565b5060010190565b63ffffffff8181168382160190808211156118ef576118ef614e75565b80820180821115611f4f57611f4f614e75565b790ca2ba3432b932bab69029b4b3b732b21026b2b9b9b0b3b29d0560311b8152825160009061514481601a8501602088016140b8565b83519083019061515b81601a8401602088016140b8565b01601a01949350505050565b8082028115828204841417611f4f57611f4f614e75565b634e487b7160e01b600052601260045260246000fd5b6000826151a3576151a361517e565b500490565b600063ffffffff808416806151bf576151bf61517e565b92169190910492915050565b63ffffffff8181168382160280821691908281146151eb576151eb614e75565b505092915050565b6001600160a01b038a8116825263ffffffff8a8116602084015289811660408401528881166060840152878116608084015290861660a0830152841660c082015261014060e0820181905260009061524d83820186614643565b90508281036101008401526152628185614643565b8381036101209094019390935250506002815261060f60f31b60208201526040019998505050505050505050565b634e487b7160e01b600052602160045260246000fd5b8281526040602082015260006122d460408301846140dc565b600082516152d18184602087016140b8565b919091019291505056fe46756e6374696f6e206d7573742062652063616c6c6564207468726f75676820360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212203e7b5847def8884fd78ced53ebd0fe3d1727ca520ba02cd4803705992b78f64b64736f6c634300081100337f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498
Deployed Bytecode
0x6080604052600436106102235760003560e01c80630241d8f91461022857806303d2944c1461024a578063118b48e51461026a578063141df503146102935780631794bb3c146102b35780632acd7ec4146102d3578063304440171461030057806330ebe7511461031657806331dc7722146103445780633659cfe614610364578063368b8772146103845780633a2c3e24146103a45780633d18678e146103d15780634129fe4c146103f1578063469048401461041e57806348c11a2f1461044b5780634912c6581461046b5780634f1ef2861461049f57806352d1902d146104b2578063586db1f5146104c757806363b87bf0146104f55780636a8b4a321461051a5780636c1550b1146105475780636cca84bd14610567578063752e87491461058757806376cd7cbc1461059f5780637bb7bed1146105bf57806385e1f4d0146105df57806395d3d5d81461061357806396b3ce5414610635578063a218404014610662578063a2686e2314610682578063a39dc9be146106a2578063a63f05ad146106cd578063aa8b0670146106ed578063ab37f4861461070d578063b33335621461073a578063b9844d8d1461075a578063b9d81abc14610787578063ba5c3a9d146107a7578063bfe10928146107e0578063d7fa562514610800578063de6a533a1461082d578063e21f37ce1461085b578063e55f577b1461087d578063e74b981b1461089d578063f2f4eb26146108bd578063feba1ed2146108dd575b600080fd5b34801561023457600080fd5b50610248610243366004613f1f565b61090a565b005b34801561025657600080fd5b50610248610265366004613f4b565b6109f1565b34801561027657600080fd5b50610280609a5481565b6040519081526020015b60405180910390f35b34801561029f57600080fd5b506102486102ae366004613fac565b610af0565b3480156102bf57600080fd5b506102486102ce366004614002565b610c67565b3480156102df57600080fd5b506102806102ee366004613f4b565b60a36020526000908152604090205481565b34801561030c57600080fd5b50610280609c5481565b34801561032257600080fd5b50610336610331366004614057565b610e13565b60405161028a92919061418c565b34801561035057600080fd5b5061028061035f3660046141f5565b610e31565b34801561037057600080fd5b5061024861037f366004613f4b565b610e72565b34801561039057600080fd5b5061024861039f3660046142f7565b610f3a565b3480156103b057600080fd5b506102806103bf36600461433f565b60a76020526000908152604090205481565b3480156103dd57600080fd5b506102486103ec3660046141f5565b611020565b3480156103fd57600080fd5b5061041161040c36600461444e565b61110d565b60405161028a9190614503565b34801561042a57600080fd5b5060995461043e906001600160a01b031681565b60405161028a9190614547565b34801561045757600080fd5b5061028061046636600461455b565b611246565b34801561047757600080fd5b5061048b6104863660046141f5565b6112ba565b60405161028a98979695949392919061458f565b6102486104ad3660046145f4565b6113b7565b3480156104be57600080fd5b50610280611470565b3480156104d357600080fd5b506104e76104e2366004614057565b61151e565b60405161028a9291906146bd565b34801561050157600080fd5b5061024833600090815260a26020526040902060019055565b34801561052657600080fd5b5061053a6105353660046141f5565b61153e565b60405161028a9190614829565b34801561055357600080fd5b50610411610562366004614a73565b61167f565b34801561057357600080fd5b50610248610582366004613f4b565b6117a5565b34801561059357600080fd5b50610280633b9aca0081565b3480156105ab57600080fd5b506102486105ba366004614b57565b6118a8565b3480156105cb57600080fd5b5061043e6105da3660046141f5565b6118b2565b3480156105eb57600080fd5b506102807f000000000000000000000000000000000000000000000000000000000000000181565b34801561061f57600080fd5b506106286118dc565b60405161028a9190614bdc565b34801561064157600080fd5b50610280610650366004613f4b565b60a16020526000908152604090205481565b34801561066e57600080fd5b5061024861067d366004614bef565b6118f6565b34801561068e57600080fd5b5061024861069d366004613f4b565b611b48565b3480156106ae57600080fd5b506106b8610e1081565b60405163ffffffff909116815260200161028a565b3480156106d957600080fd5b506102806106e836600461455b565b611c4b565b3480156106f957600080fd5b5061053a6107083660046141f5565b611cec565b34801561071957600080fd5b50610280610728366004613f4b565b609f6020526000908152604090205481565b34801561074657600080fd5b50610248610755366004614c5a565b611f55565b34801561076657600080fd5b50610280610775366004613f4b565b60a06020526000908152604090205481565b34801561079357600080fd5b506102806107a2366004614c76565b612055565b3480156107b357600080fd5b506107c76107c23660046141f5565b6120ea565b60405161028a9d9c9b9a99989796959493929190614caa565b3480156107ec57600080fd5b5060985461043e906001600160a01b031681565b34801561080c57600080fd5b5061028061081b366004613f4b565b60a26020526000908152604090205481565b34801561083957600080fd5b5061084d610848366004614d54565b612217565b60405161028a929190614d87565b34801561086757600080fd5b50610870612231565b60405161028a9190614da9565b34801561088957600080fd5b50610280610898366004614dbc565b6122bf565b3480156108a957600080fd5b506102486108b8366004613f4b565b6122dc565b3480156108c957600080fd5b5060975461043e906001600160a01b031681565b3480156108e957600080fd5b506102806108f8366004613f4b565b609e6020526000908152604090205481565b60975460405163521d4de960e01b81526001600160a01b039091169063521d4de99061093a903390600401614547565b602060405180830381865afa158015610957573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097b9190614e24565b61099857604051632678482f60e21b815260040160405180910390fd5b6001600160a01b0382166000818152609e602052604090819020839055517fab1d37d0b21937f334fc4164d147abbfdbfd7ef37ab9ea0ae73f2a58ffb7f1cc906109e59084815260200190565b60405180910390a25050565b609754604051631c86b03760e31b81526001600160a01b039091169063e43581b890610a21903390600401614547565b602060405180830381865afa158015610a3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a629190614e24565b610a7f57604051633b8d9d7560e21b815260040160405180910390fd5b6001600160a01b038116610aa657604051633494a40d60e21b815260040160405180910390fd5b609880546001600160a01b0319166001600160a01b0383169081179091556040517fc0ebb188f905d128bcd7e4282dd1f9cf24cd331b69071002e488349aca6a867b90600090a250565b609754604051631c86b03760e31b81526001600160a01b039091169063e43581b890610b20903390600401614547565b602060405180830381865afa158015610b3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b619190614e24565b610b7e57604051633b8d9d7560e21b815260040160405180910390fd5b8160005b81811015610c6057610c5883868684818110610ba057610ba0614e46565b9050602002016020810190610bb59190613f4b565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610be09190614547565b602060405180830381865afa158015610bfd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c219190614e5c565b878785818110610c3357610c33614e46565b9050602002016020810190610c489190613f4b565b6001600160a01b031691906123c3565b600101610b82565b5050505050565b600054610100900460ff1615808015610c875750600054600160ff909116105b80610ca85750610c96306123b4565b158015610ca8575060005460ff166001145b610d105760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610d33576000805461ff0019166101001790555b6001600160a01b0384161580610d5057506001600160a01b038316155b15610d6e5760405163d92e233d60e01b815260040160405180910390fd5b633b9aca008210610d9257604051633494a40d60e21b815260040160405180910390fd5b609880546001600160a01b038086166001600160a01b0319928316179092556097805492871692909116919091179055609a8290558015610e0d576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b60606000610e238686868661242b565b915091505b94509492505050565b600081815260a66020526040812054808203610e6057604051639b35ed3b60e01b815260040160405180910390fd5b610e6b600182614e8b565b9392505050565b6001600160a01b037f0000000000000000000000009a0f97fac6154d9233a0fdfce4dc27dcb48b95ff163003610eba5760405162461bcd60e51b8152600401610d0790614e9e565b7f0000000000000000000000009a0f97fac6154d9233a0fdfce4dc27dcb48b95ff6001600160a01b0316610eec61268e565b6001600160a01b031614610f125760405162461bcd60e51b8152600401610d0790614ed8565b610f1b816126aa565b60408051600080825260208201909252610f379183919061274d565b50565b609754604051631c86b03760e31b81526001600160a01b039091169063e43581b890610f6a903390600401614547565b602060405180830381865afa158015610f87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fab9190614e24565b610fc857604051633b8d9d7560e21b815260040160405180910390fd5b609b610fd48282614f92565b506000610fe0826128b8565b609c8190556040518181529091507fde3dc3335dea4d1a1060ef6cefcfcc109eb0a1e78ce151818d3f17a01e1f8a05906020015b60405180910390a15050565b609754604051631c86b03760e31b81526001600160a01b039091169063e43581b890611050903390600401614547565b602060405180830381865afa15801561106d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110919190614e24565b6110ae57604051633b8d9d7560e21b815260040160405180910390fd5b633b9aca0081106110d257604051633494a40d60e21b815260040160405180910390fd5b609a8190556040518181527f3346af6da1932164d501f2ec28f8c5d686db5828a36b77f2da4332d89184fe7b9060200160405180910390a150565b60606111176128d6565b33600090815260a260205260409020541580156111455750609c5433600090815260a1602052604090205414155b801561115e575032600090815260a26020526040902054155b801561117b5750609c5432600090815260a1602052604090205414155b15611199576040516314e52a5b60e31b815260040160405180910390fd5b81516000816001600160401b038111156111b5576111b561420e565b6040519080825280602002602001820160405280156111de578160200160208202803683370190505b50905060005b828110156112335761120e85828151811061120157611201614e46565b602002602001015161292f565b82828151811061122057611220614e46565b60209081029190910101526001016111e4565b509150506112416001606555565b919050565b60007f00000000000000000000000000000000000000000000000000000000000000018260200151836040015184608001518560a001518660c001518760e0015160405160200161129d9796959493929190615051565b604051602081830303815290604052805190602001209050919050565b60a581815481106112ca57600080fd5b60009182526020909120600690910201805460018201546002830154600384015460048501546005860180549597506001600160a01b03948516969490931694919363ffffffff80831694600160201b8404821694600160401b9094049091169261133490614f12565b80601f016020809104026020016040519081016040528092919081815260200182805461136090614f12565b80156113ad5780601f10611382576101008083540402835291602001916113ad565b820191906000526020600020905b81548152906001019060200180831161139057829003601f168201915b5050505050905088565b6001600160a01b037f0000000000000000000000009a0f97fac6154d9233a0fdfce4dc27dcb48b95ff1630036113ff5760405162461bcd60e51b8152600401610d0790614e9e565b7f0000000000000000000000009a0f97fac6154d9233a0fdfce4dc27dcb48b95ff6001600160a01b031661143161268e565b6001600160a01b0316146114575760405162461bcd60e51b8152600401610d0790614ed8565b611460826126aa565b61146c8282600161274d565b5050565b6000306001600160a01b037f0000000000000000000000009a0f97fac6154d9233a0fdfce4dc27dcb48b95ff161461150b5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c6044820152771b1959081d1a1c9bdd59da0819195b1959d85d1958d85b1b60421b6064820152608401610d07565b506000805160206152fc83398151915290565b60606000610e2361152e87612cab565b61153787612cab565b8686612cc4565b611546613eb9565b60a561155183610e31565b8154811061156157611561614e46565b6000918252602091829020604080516101008101825260069093029091018054835260018101546001600160a01b039081169484019490945260028101549093169082015260038201546060820152600482015463ffffffff8082166080840152600160201b8204811660a0840152600160401b9091041660c082015260058201805491929160e0840191906115f690614f12565b80601f016020809104026020016040519081016040528092919081815260200182805461162290614f12565b801561166f5780601f106116445761010080835404028352916020019161166f565b820191906000526020600020905b81548152906001019060200180831161165257829003601f168201915b5050505050815250509050919050565b60606116896128d6565b33600090815260a260205260409020541580156116b75750609c5433600090815260a1602052604090205414155b80156116d0575032600090815260a26020526040902054155b80156116ed5750609c5432600090815260a1602052604090205414155b1561170b576040516314e52a5b60e31b815260040160405180910390fd5b81516000816001600160401b038111156117275761172761420e565b604051908082528060200260200182016040528015611750578160200160208202803683370190505b50905060005b828110156112335761178085828151811061177357611773614e46565b60200260200101516130b7565b82828151811061179257611792614e46565b6020908102919091010152600101611756565b60975460405163521d4de960e01b81526001600160a01b039091169063521d4de9906117d5903390600401614547565b602060405180830381865afa1580156117f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118169190614e24565b61183357604051632678482f60e21b815260040160405180910390fd5b6001600160a01b0381166000908152609f6020526040812054611857906001614e8b565b6001600160a01b0383166000818152609f60205260409081902083905551919250907fc6cd32b1acffa550abf886a9b443ff3ce485bfdb05e35ef5b26e745739a1eac1906109e59084815260200190565b61146c8282613104565b60a481815481106118c257600080fd5b6000918252602090912001546001600160a01b0316905081565b606060006118ef600063ffffffff6131ba565b5092915050565b60975460405163521d4de960e01b81526001600160a01b039091169063521d4de990611926903390600401614547565b602060405180830381865afa158015611943573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119679190614e24565b61198457604051632678482f60e21b815260040160405180910390fd5b828181146119a557604051631df89e8b60e01b815260040160405180910390fd5b60005b81811015611b405760008484838181106119c4576119c4614e46565b905060200201359050600081118015611a1f575060a360008888858181106119ee576119ee614e46565b9050602002016020810190611a039190613f4b565b6001600160a01b03168152602081019190915260400160002054155b15611a805760a4878784818110611a3857611a38614e46565b9050602002016020810190611a4d9190613f4b565b81546001810183556000928352602090922090910180546001600160a01b0319166001600160a01b039092169190911790555b8060a36000898986818110611a9757611a97614e46565b9050602002016020810190611aac9190613f4b565b6001600160a01b03168152602081019190915260400160002055868683818110611ad857611ad8614e46565b9050602002016020810190611aed9190613f4b565b6001600160a01b03167f3a5e6418e38cae10bf66eaf3e68c4e9c6b14df195e24fec169ab3a5b123c96e582604051611b2791815260200190565b60405180910390a250611b39816150c5565b90506119a8565b505050505050565b60975460405163521d4de960e01b81526001600160a01b039091169063521d4de990611b78903390600401614547565b602060405180830381865afa158015611b95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bb99190614e24565b611bd657604051632678482f60e21b815260040160405180910390fd5b6001600160a01b038116600090815260a26020526040812054611bfa906001614e8b565b6001600160a01b038316600081815260a260205260409081902083905551919250907f9c759941da0b7ce56c059c1497218796e62035024afb77a00ff49a980a62078f906109e59084815260200190565b6000611c556128d6565b33600090815260a26020526040902054158015611c835750609c5433600090815260a1602052604090205414155b8015611c9c575032600090815260a26020526040902054155b8015611cb95750609c5432600090815260a1602052604090205414155b15611cd7576040516314e52a5b60e31b815260040160405180910390fd5b611ce08261292f565b90506112416001606555565b611cf4613eb9565b611f4f609d8381548110611d0a57611d0a614e46565b6000918252602091829020604080516101e08101825260099093029091018054835260018101546001600160a01b0390811684860152600282015416838301526003810154606084015260048101805483518187028101870190945280845293949193608086019392830182828015611dac57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611d8e575b5050505050815260200160058201805480602002602001604051908101604052809291908181526020018280548015611e3057602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff1681526020019060040190602082600301049283019260010382029150808411611df35790505b5050509183525050600682015463ffffffff8082166020840152600160201b820481166040840152600160401b820481166060840152600160601b820481166080840152600160801b8204811660a0840152600160a01b8204811660c0840152600160c01b9091041660e082015260078201546001600160a01b031661010082015260088201805461012090920191611ec890614f12565b80601f0160208091040260200160405190810160405280929190818152602001828054611ef490614f12565b8015611f415780601f10611f1657610100808354040283529160200191611f41565b820191906000526020600020905b815481529060010190602001808311611f2457829003601f168201915b505050505081525050613319565b92915050565b60975460405163521d4de960e01b81526001600160a01b039091169063521d4de990611f85903390600401614547565b602060405180830381865afa158015611fa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc69190614e24565b611fe357604051632678482f60e21b815260040160405180910390fd5b633b9aca00811061200757604051633494a40d60e21b815260040160405180910390fd5b63ffffffff8216600081815260a76020908152604091829020849055815192835282018390527fb718143758782f8d3b9a4c9a0e6e54c43f2790e1e447d639c916a41a71151f5f9101611014565b600061205f6128d6565b33600090815260a2602052604090205415801561208d5750609c5433600090815260a1602052604090205414155b80156120a6575032600090815260a26020526040902054155b80156120c35750609c5432600090815260a1602052604090205414155b156120e1576040516314e52a5b60e31b815260040160405180910390fd5b611ce0826130b7565b609d81815481106120fa57600080fd5b600091825260209091206009909102018054600182015460028301546003840154600685015460078601546008870180549698506001600160a01b039586169794861696939563ffffffff80851696600160201b8604821696600160401b8704831696600160601b8104841696600160801b8204851696600160a01b8304861696600160c01b909304909516949116929161219490614f12565b80601f01602080910402602001604051908101604052809291908181526020018280546121c090614f12565b801561220d5780601f106121e25761010080835404028352916020019161220d565b820191906000526020600020905b8154815290600101906020018083116121f057829003601f168201915b505050505090508d565b6060600061222584846131ba565b915091505b9250929050565b609b805461223e90614f12565b80601f016020809104026020016040519081016040528092919081815260200182805461226a90614f12565b80156122b75780601f1061228c576101008083540402835291602001916122b7565b820191906000526020600020905b81548152906001019060200180831161229a57829003601f168201915b505050505081565b60006122cb8383613104565b6122d48461292f565b949350505050565b609754604051631c86b03760e31b81526001600160a01b039091169063e43581b89061230c903390600401614547565b602060405180830381865afa158015612329573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061234d9190614e24565b61236a57604051633b8d9d7560e21b815260040160405180910390fd5b609980546001600160a01b0319166001600160a01b0383169081179091556040517f7a7b5a0a132f9e0581eb8527f66eae9ee89c2a3e79d4ac7e41a1f1f4d48a7fc290600090a250565b6001600160a01b03163b151590565b6040516001600160a01b03831660248201526044810182905261242690849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526135b8565b505050565b60a55460609060009081908163ffffffff86168210612450578563ffffffff16612452565b815b90506000816001600160401b0381111561246e5761246e61420e565b6040519080825280602002602001820160405280156124a757816020015b612494613eb9565b81526020019060019003908161248c5790505b509050875b838163ffffffff16101561267557600060a58263ffffffff16815481106124d5576124d5614e46565b6000918252602091829020604080516101008101825260069093029091018054835260018101546001600160a01b039081169484019490945260028101549093169082015260038201546060820152600482015463ffffffff8082166080840152600160201b8204811660a0840152600160401b9091041660c082015260058201805491929160e08401919061256a90614f12565b80601f016020809104026020016040519081016040528092919081815260200182805461259690614f12565b80156125e35780601f106125b8576101008083540402835291602001916125e3565b820191906000526020600020905b8154815290600101906020018083116125c657829003601f168201915b50505050508152505090508b63ffffffff168160c001518260a0015161260991906150de565b63ffffffff1611801561262b57508a63ffffffff168160a0015163ffffffff16105b1561265c578083878151811061264357612643614e46565b60209081029190910101526126596001876150fb565b95505b81600101915083860361266f5750612675565b506124ac565b9381529963ffffffff9093169850919650505050505050565b6000805160206152fc833981519152546001600160a01b031690565b6097546001600160a01b0316801580159061272f5750604051631c86b03760e31b81526001600160a01b0382169063e43581b8906126ec903390600401614547565b602060405180830381865afa158015612709573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061272d9190614e24565b155b1561146c57604051633b8d9d7560e21b815260040160405180910390fd5b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612780576124268361368a565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156127da575060408051601f3d908101601f191682019092526127d791810190614e5c565b60015b61283d5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610d07565b6000805160206152fc83398151915281146128ac5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610d07565b50612426838383613724565b60006128c48251613749565b8260405160200161129d92919061510e565b6002606554036129285760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d07565b6002606555565b6040808201516001600160a01b0316600090815260a36020529081205460a08301514263ffffffff9091161015612979576040516332dcdf7360e21b815260040160405180910390fd5b610e1063ffffffff168360c0015163ffffffff1610156129ac57604051631b5982fd60e01b815260040160405180910390fd5b806000036129cd5760405163c0460cfb60e01b815260040160405180910390fd5b808360c0015163ffffffff16610e1063ffffffff1685606001516129f19190615167565b6129fb9190615194565b1015612a1a5760405163912f27bf60e01b815260040160405180910390fd5b60208301516001600160a01b0316612a33573360208401525b608083015163ffffffff16600090815260a760205260409020546001819003612a5e57506000612a6b565b80600003612a6b5750609a545b6000612a8082866060015187604001516137dc565b606086018190529050612a9285611246565b808652600090815260a6602052604090205415612ac257604051637e31d8a360e01b815260040160405180910390fd5b60a554612ad09060016150fb565b8551600090815260a6602090815260408083209390935560a580546001810182559252875160069092027fb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddeff8101928355908801517fb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddf00820180546001600160a01b039283166001600160a01b031991821617909155938901517fb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddf01830180549190921694169390931790925560608701517fb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddf0283015560808701517fb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddf038301805460a08a015160c08b015163ffffffff908116600160401b0263ffffffff60401b19928216600160201b026001600160401b03199094169190951617919091171691909117905560e087015187927fb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddf040190612c679082614f92565b5050507f6e3c6fa6d4815a856783888c5c3ea2ad7e7303ac0cca66c99f5bd93502c4429985604051612c999190614829565b60405180910390a15050915192915050565b6000610e10612cba81846151a8565b611f4f91906151cb565b609d5460609060009081908163ffffffff86168210612ce9578563ffffffff16612ceb565b815b90506000816001600160401b03811115612d0757612d0761420e565b604051908082528060200260200182016040528015612db057816020015b604080516101e0810182526000808252602080830182905292820181905260608083018290526080830181905260a0830181905260c0830182905260e08301829052610100830182905261012083018290526101408301829052610160830182905261018083018290526101a08301919091526101c08201528252600019909201910181612d255790505b509050875b838163ffffffff161015612675576000609d8263ffffffff1681548110612dde57612dde614e46565b6000918252602091829020604080516101e08101825260099093029091018054835260018101546001600160a01b0390811684860152600282015416838301526003810154606084015260048101805483518187028101870190945280845293949193608086019392830182828015612e8057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612e62575b5050505050815260200160058201805480602002602001604051908101604052809291908181526020018280548015612f0457602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff1681526020019060040190602082600301049283019260010382029150808411612ec75790505b5050509183525050600682015463ffffffff8082166020840152600160201b820481166040840152600160401b820481166060840152600160601b820481166080840152600160801b8204811660a0840152600160a01b8204811660c0840152600160c01b9091041660e082015260078201546001600160a01b031661010082015260088201805461012090920191612f9c90614f12565b80601f0160208091040260200160405190810160405280929190818152602001828054612fc890614f12565b80156130155780601f10612fea57610100808354040283529160200191613015565b820191906000526020600020905b815481529060010190602001808311612ff857829003601f168201915b50505050508152505090508b63ffffffff16610e1082610140015161303a91906151cb565b82610120015161304a91906150de565b63ffffffff1611801561306d57508a63ffffffff1681610120015163ffffffff16105b1561309e578083878151811061308557613085614e46565b602090810291909101015261309b6001876150fb565b95505b8160010191508386036130b15750612675565b50612db5565b60006130ca6130c583613319565b61292f565b5060a580546130db90600190614e8b565b815481106130eb576130eb614e46565b9060005260206000209060060201600301549050919050565b6000609c54905061314c338285858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061389e92505050565b61316957604051638baa579f60e01b815260040160405180910390fd5b33600081815260a1602052604090819020839055517fc48bbd4f009ad78a336beb65bf44688651e9aa52ac98d9054f0fce0573fefbc3906131ad9084815260200190565b60405180910390a2505050565b60a45460609060009081908163ffffffff861682106131df578563ffffffff166131e1565b815b90506000816001600160401b038111156131fd576131fd61420e565b60405190808252806020026020018201604052801561324257816020015b604080518082019091526000808252602082015281526020019060019003908161321b5790505b509050875b838163ffffffff16101561330257600060a48263ffffffff168154811061327057613270614e46565b60009182526020808320909101546001600160a01b031680835260a390915260409091205490915080156132e7576040518060400160405280836001600160a01b03168152602001828152508488815181106132ce576132ce614e46565b60209081029190910101526132e46001886150fb565b96505b8260010192508487036132fb575050613302565b5050613247565b9381529763ffffffff909316965091945050505050565b613321613eb9565b60a0820151516000816001600160401b038111156133415761334161420e565b60405190808252806020026020018201604052801561336a578160200160208202803683370190505b5090506000826001600160401b038111156133875761338761420e565b6040519080825280602002602001820160405280156133b0578160200160208202803683370190505b50905060008060005b858110156134d5578760a0015181815181106133d7576133d7614e46565b602002602001015163ffffffff16600003613442578760800151818151811061340257613402614e46565b602002602001015185848151811061341c5761341c614e46565b6001600160a01b039092166020928302919091019091015261343f6001846150fb565b92505b8760a00151818151811061345857613458614e46565b602002602001015163ffffffff166003036134c3578760800151818151811061348357613483614e46565b602002602001015184838151811061349d5761349d614e46565b6001600160a01b03909216602092830291909101909101526134c06001836150fb565b91505b806134cd816150c5565b9150506133b9565b5081845280835260405180610100016040528088600001518152602001336001600160a01b0316815260200188604001516001600160a01b0316815260200188606001518152602001600263ffffffff16815260200188610120015163ffffffff168152602001610e1089610140015161354f91906151cb565b63ffffffff16815260200188602001518961010001518a60c001518b60e001518c61016001518d6101a001518e61018001518c8c60405160200161359b999897969594939291906151f3565b60408051601f198184030181529190529052979650505050505050565b600061360d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166139e09092919063ffffffff16565b805190915015612426578080602001905181019061362b9190614e24565b6124265760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610d07565b613693816123b4565b6136f55760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610d07565b6000805160206152fc83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b61372d836139ef565b60008251118061373a5750805b1561242657610e0d8383613a2f565b6060600061375683613b21565b60010190506000816001600160401b038111156137755761377561420e565b6040519080825280601f01601f19166020018201604052801561379f576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a85049450846137a9575b509392505050565b336000908152609e60205260408120548190633b9aca00906137fe9082614e8b565b6138089087615167565b6138129190615194565b8492509050801561388257633b9aca0061382c8282614e8b565b6138369086615167565b6138409190615194565b6099549092506001600160a01b0316801561385b578061385d565b305b9050613880338261386e8689614e8b565b6001600160a01b038816929190613bf7565b505b6098546137d4906001600160a01b038581169133911685613bf7565b60008060006138ad8585613c2f565b909250905060008160048111156138c6576138c6615290565b1480156138e45750856001600160a01b0316826001600160a01b0316145b156138f457600192505050610e6b565b600080876001600160a01b0316631626ba7e60e01b888860405160240161391c9291906152a6565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161395a91906152bf565b600060405180830381855afa9150503d8060008114613995576040519150601f19603f3d011682016040523d82523d6000602084013e61399a565b606091505b50915091508180156139ad575080516020145b80156139d457508051630b135d3f60e11b906139d29083016020908101908401614e5c565b145b98975050505050505050565b60606122d48484600085613c71565b6139f88161368a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060613a3a836123b4565b613a955760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610d07565b600080846001600160a01b031684604051613ab091906152bf565b600060405180830381855af49150503d8060008114613aeb576040519150601f19603f3d011682016040523d82523d6000602084013e613af0565b606091505b5091509150613b18828260405180606001604052806027815260200161531c60279139613d4c565b95945050505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310613b605772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6904ee2d6d415b85acef8160201b8310613b8a576904ee2d6d415b85acef8160201b830492506020015b662386f26fc100008310613ba857662386f26fc10000830492506010015b6305f5e1008310613bc0576305f5e100830492506008015b6127108310613bd457612710830492506004015b60648310613be6576064830492506002015b600a8310611f4f5760010192915050565b6040516001600160a01b0380851660248301528316604482015260648101829052610e0d9085906323b872dd60e01b906084016123ef565b6000808251604103613c655760208301516040840151606085015160001a613c5987828585613d65565b9450945050505061222a565b5060009050600261222a565b606082471015613cd25760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610d07565b600080866001600160a01b03168587604051613cee91906152bf565b60006040518083038185875af1925050503d8060008114613d2b576040519150601f19603f3d011682016040523d82523d6000602084013e613d30565b606091505b5091509150613d4187838387613e1c565b979650505050505050565b60608315613d5b575081610e6b565b610e6b8383613e8f565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b03831115613d925750600090506003610e28565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613de6573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116613e0f57600060019250925050610e28565b9660009650945050505050565b60608315613e89578251600003613e8257613e36856123b4565b613e825760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d07565b50816122d4565b6122d483835b815115613e9f5781518083602001fd5b8060405162461bcd60e51b8152600401610d079190614da9565b604080516101008101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c082019290925260e081019190915290565b6001600160a01b0381168114610f3757600080fd5b803561124181613eff565b60008060408385031215613f3257600080fd5b8235613f3d81613eff565b946020939093013593505050565b600060208284031215613f5d57600080fd5b8135610e6b81613eff565b60008083601f840112613f7a57600080fd5b5081356001600160401b03811115613f9157600080fd5b6020830191508360208260051b850101111561222a57600080fd5b600080600060408486031215613fc157600080fd5b83356001600160401b03811115613fd757600080fd5b613fe386828701613f68565b9094509250506020840135613ff781613eff565b809150509250925092565b60008060006060848603121561401757600080fd5b833561402281613eff565b9250602084013561403281613eff565b929592945050506040919091013590565b803563ffffffff8116811461124157600080fd5b6000806000806080858703121561406d57600080fd5b61407685614043565b935061408460208601614043565b925061409260408601614043565b91506140a060608601614043565b905092959194509250565b6001600160a01b03169052565b60005b838110156140d35781810151838201526020016140bb565b50506000910152565b600081518084526140f48160208601602086016140b8565b601f01601f19169290920160200192915050565b600061010082518452602083015160018060a01b038082166020870152806040860151166040870152505060608301516060850152608083015163ffffffff80821660808701528060a08601511660a0870152505060c083015161417460c086018263ffffffff169052565b5060e08301518160e0860152613b18828601826140dc565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b838110156141e357605f198887030185526141d1868351614108565b955093820193908201906001016141b5565b50509490940194909452949350505050565b60006020828403121561420757600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60405161010081016001600160401b03811182821017156142475761424761420e565b60405290565b6040516101e081016001600160401b03811182821017156142475761424761420e565b604051601f8201601f191681016001600160401b03811182821017156142985761429861420e565b604052919050565b60006001600160401b038311156142b9576142b961420e565b6142cc601f8401601f1916602001614270565b90508281528383830111156142e057600080fd5b828260208301376000602084830101529392505050565b60006020828403121561430957600080fd5b81356001600160401b0381111561431f57600080fd5b8201601f8101841361433057600080fd5b6122d4848235602084016142a0565b60006020828403121561435157600080fd5b610e6b82614043565b60006001600160401b038211156143735761437361420e565b5060051b60200190565b600082601f83011261438e57600080fd5b610e6b838335602085016142a0565b600061010082840312156143b057600080fd5b6143b8614224565b9050813581526143ca60208301613f14565b60208201526143db60408301613f14565b6040820152606082013560608201526143f660808301614043565b608082015261440760a08301614043565b60a082015261441860c08301614043565b60c082015260e08201356001600160401b0381111561443657600080fd5b6144428482850161437d565b60e08301525092915050565b6000602080838503121561446157600080fd5b82356001600160401b038082111561447857600080fd5b818501915085601f83011261448c57600080fd5b813561449f61449a8261435a565b614270565b81815260059190911b830184019084810190888311156144be57600080fd5b8585015b838110156144f6578035858111156144da5760008081fd5b6144e88b89838a010161439d565b8452509186019186016144c2565b5098975050505050505050565b6020808252825182820181905260009190848201906040850190845b8181101561453b5783518352928401929184019160010161451f565b50909695505050505050565b6001600160a01b0391909116815260200190565b60006020828403121561456d57600080fd5b81356001600160401b0381111561458357600080fd5b6122d48482850161439d565b8881526001600160a01b038881166020830152871660408201526060810186905263ffffffff858116608083015284811660a0830152831660c082015261010060e082018190526000906145e5838201856140dc565b9b9a5050505050505050505050565b6000806040838503121561460757600080fd5b823561461281613eff565b915060208301356001600160401b0381111561462d57600080fd5b6146398582860161437d565b9150509250929050565b600081518084526020808501945080840160005b8381101561467c5781516001600160a01b031687529582019590820190600101614657565b509495945050505050565b600081518084526020808501945080840160005b8381101561467c57815163ffffffff168752958201959082019060010161469b565b60006040808301818452808651808352606092508286019150828160051b8701016020808a0160005b8481101561481457605f198a850301865281516101e08151865284820151614710868801826140ab565b50898201516147218b8801826140ab565b508882015189870152608080830151828289015261474183890182614643565b9250505060a0808301518783038289015261475c8382614687565b9250505060c0808301516147778289018263ffffffff169052565b505060e08281015163ffffffff908116918801919091526101008084015182169088015261012080840151821690880152610140808401518216908801526101608084015182169088015261018080840151909116908701526101a0808301516147e3828901826140ab565b50506101c0808301519250868203818801525061480081836140dc565b9785019795505050908201906001016146e6565b50509690960196909652509295945050505050565b602081526000610e6b6020830184614108565b600082601f83011261484d57600080fd5b8135602061485d61449a8361435a565b82815260059290921b8401810191818101908684111561487c57600080fd5b8286015b848110156148a057803561489381613eff565b8352918301918301614880565b509695505050505050565b600082601f8301126148bc57600080fd5b813560206148cc61449a8361435a565b82815260059290921b840181019181810190868411156148eb57600080fd5b8286015b848110156148a05761490081614043565b83529183019183016148ef565b60006101e0828403121561492057600080fd5b61492861424d565b90508135815261493a60208301613f14565b602082015261494b60408301613f14565b60408201526060828101359082015260808201356001600160401b038082111561497457600080fd5b6149808583860161483c565b608084015260a084013591508082111561499957600080fd5b6149a5858386016148ab565b60a08401526149b660c08501614043565b60c08401526149c760e08501614043565b60e084015261010091506149dc828501614043565b8284015261012091506149f0828501614043565b828401526101409150614a04828501614043565b828401526101609150614a18828501614043565b828401526101809150614a2c828501614043565b828401526101a09150614a40828501613f14565b828401526101c091508184013581811115614a5a57600080fd5b614a668682870161437d565b8385015250505092915050565b60006020808385031215614a8657600080fd5b82356001600160401b0380821115614a9d57600080fd5b818501915085601f830112614ab157600080fd5b8135614abf61449a8261435a565b81815260059190911b83018401908481019088831115614ade57600080fd5b8585015b838110156144f657803585811115614afa5760008081fd5b614b088b89838a010161490d565b845250918601918601614ae2565b60008083601f840112614b2857600080fd5b5081356001600160401b03811115614b3f57600080fd5b60208301915083602082850101111561222a57600080fd5b60008060208385031215614b6a57600080fd5b82356001600160401b03811115614b8057600080fd5b614b8c85828601614b16565b90969095509350505050565b600081518084526020808501945080840160005b8381101561467c57815180516001600160a01b031688528301518388015260409096019590820190600101614bac565b602081526000610e6b6020830184614b98565b60008060008060408587031215614c0557600080fd5b84356001600160401b0380821115614c1c57600080fd5b614c2888838901613f68565b90965094506020870135915080821115614c4157600080fd5b50614c4e87828801613f68565b95989497509550505050565b60008060408385031215614c6d57600080fd5b613f3d83614043565b600060208284031215614c8857600080fd5b81356001600160401b03811115614c9e57600080fd5b6122d48482850161490d565b8d81526001600160a01b038d811660208301528c166040820152606081018b905263ffffffff8a8116608083015289811660a0830152881660c0820152600063ffffffff881660e083015263ffffffff871661010083015263ffffffff861661012083015263ffffffff8516610140830152614d2a6101608301856140ab565b6101a0610180830152614d416101a08301846140dc565b9f9e505050505050505050505050505050565b60008060408385031215614d6757600080fd5b614d7083614043565b9150614d7e60208401614043565b90509250929050565b604081526000614d9a6040830185614b98565b90508260208301529392505050565b602081526000610e6b60208301846140dc565b600080600060408486031215614dd157600080fd5b83356001600160401b0380821115614de857600080fd5b614df48783880161439d565b94506020860135915080821115614e0a57600080fd5b50614e1786828701614b16565b9497909650939450505050565b600060208284031215614e3657600080fd5b81518015158114610e6b57600080fd5b634e487b7160e01b600052603260045260246000fd5b600060208284031215614e6e57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b81810381811115611f4f57611f4f614e75565b6020808252602c908201526000805160206152dc83398151915260408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201526000805160206152dc83398151915260408201526b6163746976652070726f787960a01b606082015260800190565b600181811c90821680614f2657607f821691505b602082108103614f4657634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561242657600081815260208120601f850160051c81016020861015614f735750805b601f850160051c820191505b81811015611b4057828155600101614f7f565b81516001600160401b03811115614fab57614fab61420e565b614fbf81614fb98454614f12565b84614f4c565b602080601f831160018114614ff45760008415614fdc5750858301515b600019600386901b1c1916600185901b178555611b40565b600085815260208120601f198616915b8281101561502357888601518255948401946001909101908401615004565b50858210156150415787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b878152600060018060601b0319808960601b166020840152808860601b1660348401525063ffffffff60e01b808760e01b166048840152808660e01b16604c840152808560e01b1660508401525082516150b28160548501602087016140b8565b9190910160540198975050505050505050565b6000600182016150d7576150d7614e75565b5060010190565b63ffffffff8181168382160190808211156118ef576118ef614e75565b80820180821115611f4f57611f4f614e75565b790ca2ba3432b932bab69029b4b3b732b21026b2b9b9b0b3b29d0560311b8152825160009061514481601a8501602088016140b8565b83519083019061515b81601a8401602088016140b8565b01601a01949350505050565b8082028115828204841417611f4f57611f4f614e75565b634e487b7160e01b600052601260045260246000fd5b6000826151a3576151a361517e565b500490565b600063ffffffff808416806151bf576151bf61517e565b92169190910492915050565b63ffffffff8181168382160280821691908281146151eb576151eb614e75565b505092915050565b6001600160a01b038a8116825263ffffffff8a8116602084015289811660408401528881166060840152878116608084015290861660a0830152841660c082015261014060e0820181905260009061524d83820186614643565b90508281036101008401526152628185614643565b8381036101209094019390935250506002815261060f60f31b60208201526040019998505050505050505050565b634e487b7160e01b600052602160045260246000fd5b8281526040602082015260006122d460408301846140dc565b600082516152d18184602087016140b8565b919091019291505056fe46756e6374696f6e206d7573742062652063616c6c6564207468726f75676820360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212203e7b5847def8884fd78ced53ebd0fe3d1727ca520ba02cd4803705992b78f64b64736f6c63430008110033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.