Source Code
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Advanced mode: Intended for advanced users or developers and will display all Internal Transactions including zero value transfers.
Latest 7 internal transactions
Advanced mode:
Cross-Chain Transactions
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
Optimization Enabled:
Yes with 1 runs
Other Settings:
default evmVersion
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"
]
}
},
"libraries": {}
}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
0x6080604052600436106102235760003560e01c80630241d8f91461022857806303d2944c1461024a578063118b48e51461026a578063141df503146102935780631794bb3c146102b35780632acd7ec4146102d3578063304440171461030057806330ebe7511461031657806331dc7722146103445780633659cfe614610364578063368b8772146103845780633a2c3e24146103a45780633d18678e146103d15780634129fe4c146103f1578063469048401461041e57806348c11a2f1461044b5780634912c6581461046b5780634f1ef2861461049f57806352d1902d146104b2578063586db1f5146104c757806363b87bf0146104f55780636a8b4a321461051a5780636c1550b1146105475780636cca84bd14610567578063752e87491461058757806376cd7cbc1461059f5780637bb7bed1146105bf57806385e1f4d0146105df57806395d3d5d81461061357806396b3ce5414610635578063a218404014610662578063a2686e2314610682578063a39dc9be146106a2578063a63f05ad146106cd578063aa8b0670146106ed578063ab37f4861461070d578063b33335621461073a578063b9844d8d1461075a578063b9d81abc14610787578063ba5c3a9d146107a7578063bfe10928146107e0578063d7fa562514610800578063de6a533a1461082d578063e21f37ce1461085b578063e55f577b1461087d578063e74b981b1461089d578063f2f4eb26146108bd578063feba1ed2146108dd575b600080fd5b34801561023457600080fd5b50610248610243366004613f1f565b61090a565b005b34801561025657600080fd5b50610248610265366004613f4b565b6109f1565b34801561027657600080fd5b50610280609a5481565b6040519081526020015b60405180910390f35b34801561029f57600080fd5b506102486102ae366004613fac565b610af0565b3480156102bf57600080fd5b506102486102ce366004614002565b610c67565b3480156102df57600080fd5b506102806102ee366004613f4b565b60a36020526000908152604090205481565b34801561030c57600080fd5b50610280609c5481565b34801561032257600080fd5b50610336610331366004614057565b610e13565b60405161028a92919061418c565b34801561035057600080fd5b5061028061035f3660046141f5565b610e31565b34801561037057600080fd5b5061024861037f366004613f4b565b610e72565b34801561039057600080fd5b5061024861039f3660046142f7565b610f3a565b3480156103b057600080fd5b506102806103bf36600461433f565b60a76020526000908152604090205481565b3480156103dd57600080fd5b506102486103ec3660046141f5565b611020565b3480156103fd57600080fd5b5061041161040c36600461444e565b61110d565b60405161028a9190614503565b34801561042a57600080fd5b5060995461043e906001600160a01b031681565b60405161028a9190614547565b34801561045757600080fd5b5061028061046636600461455b565b611246565b34801561047757600080fd5b5061048b6104863660046141f5565b6112ba565b60405161028a98979695949392919061458f565b6102486104ad3660046145f4565b6113b7565b3480156104be57600080fd5b50610280611470565b3480156104d357600080fd5b506104e76104e2366004614057565b61151e565b60405161028a9291906146bd565b34801561050157600080fd5b5061024833600090815260a26020526040902060019055565b34801561052657600080fd5b5061053a6105353660046141f5565b61153e565b60405161028a9190614829565b34801561055357600080fd5b50610411610562366004614a73565b61167f565b34801561057357600080fd5b50610248610582366004613f4b565b6117a5565b34801561059357600080fd5b50610280633b9aca0081565b3480156105ab57600080fd5b506102486105ba366004614b57565b6118a8565b3480156105cb57600080fd5b5061043e6105da3660046141f5565b6118b2565b3480156105eb57600080fd5b506102807f00000000000000000000000000000000000000000000000000000000000000fc81565b34801561061f57600080fd5b506106286118dc565b60405161028a9190614bdc565b34801561064157600080fd5b50610280610650366004613f4b565b60a16020526000908152604090205481565b34801561066e57600080fd5b5061024861067d366004614bef565b6118f6565b34801561068e57600080fd5b5061024861069d366004613f4b565b611b48565b3480156106ae57600080fd5b506106b8610e1081565b60405163ffffffff909116815260200161028a565b3480156106d957600080fd5b506102806106e836600461455b565b611c4b565b3480156106f957600080fd5b5061053a6107083660046141f5565b611cec565b34801561071957600080fd5b50610280610728366004613f4b565b609f6020526000908152604090205481565b34801561074657600080fd5b50610248610755366004614c5a565b611f55565b34801561076657600080fd5b50610280610775366004613f4b565b60a06020526000908152604090205481565b34801561079357600080fd5b506102806107a2366004614c76565b612055565b3480156107b357600080fd5b506107c76107c23660046141f5565b6120ea565b60405161028a9d9c9b9a99989796959493929190614caa565b3480156107ec57600080fd5b5060985461043e906001600160a01b031681565b34801561080c57600080fd5b5061028061081b366004613f4b565b60a26020526000908152604090205481565b34801561083957600080fd5b5061084d610848366004614d54565b612217565b60405161028a929190614d87565b34801561086757600080fd5b50610870612231565b60405161028a9190614da9565b34801561088957600080fd5b50610280610898366004614dbc565b6122bf565b3480156108a957600080fd5b506102486108b8366004613f4b565b6122dc565b3480156108c957600080fd5b5060975461043e906001600160a01b031681565b3480156108e957600080fd5b506102806108f8366004613f4b565b609e6020526000908152604090205481565b60975460405163521d4de960e01b81526001600160a01b039091169063521d4de99061093a903390600401614547565b602060405180830381865afa158015610957573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097b9190614e24565b61099857604051632678482f60e21b815260040160405180910390fd5b6001600160a01b0382166000818152609e602052604090819020839055517fab1d37d0b21937f334fc4164d147abbfdbfd7ef37ab9ea0ae73f2a58ffb7f1cc906109e59084815260200190565b60405180910390a25050565b609754604051631c86b03760e31b81526001600160a01b039091169063e43581b890610a21903390600401614547565b602060405180830381865afa158015610a3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a629190614e24565b610a7f57604051633b8d9d7560e21b815260040160405180910390fd5b6001600160a01b038116610aa657604051633494a40d60e21b815260040160405180910390fd5b609880546001600160a01b0319166001600160a01b0383169081179091556040517fc0ebb188f905d128bcd7e4282dd1f9cf24cd331b69071002e488349aca6a867b90600090a250565b609754604051631c86b03760e31b81526001600160a01b039091169063e43581b890610b20903390600401614547565b602060405180830381865afa158015610b3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b619190614e24565b610b7e57604051633b8d9d7560e21b815260040160405180910390fd5b8160005b81811015610c6057610c5883868684818110610ba057610ba0614e46565b9050602002016020810190610bb59190613f4b565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610be09190614547565b602060405180830381865afa158015610bfd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c219190614e5c565b878785818110610c3357610c33614e46565b9050602002016020810190610c489190613f4b565b6001600160a01b031691906123c3565b600101610b82565b5050505050565b600054610100900460ff1615808015610c875750600054600160ff909116105b80610ca85750610c96306123b4565b158015610ca8575060005460ff166001145b610d105760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610d33576000805461ff0019166101001790555b6001600160a01b0384161580610d5057506001600160a01b038316155b15610d6e5760405163d92e233d60e01b815260040160405180910390fd5b633b9aca008210610d9257604051633494a40d60e21b815260040160405180910390fd5b609880546001600160a01b038086166001600160a01b0319928316179092556097805492871692909116919091179055609a8290558015610e0d576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b60606000610e238686868661242b565b915091505b94509492505050565b600081815260a66020526040812054808203610e6057604051639b35ed3b60e01b815260040160405180910390fd5b610e6b600182614e8b565b9392505050565b6001600160a01b037f0000000000000000000000007db28175b63f154587bbb1cae62d39ea80a23383163003610eba5760405162461bcd60e51b8152600401610d0790614e9e565b7f0000000000000000000000007db28175b63f154587bbb1cae62d39ea80a233836001600160a01b0316610eec61268e565b6001600160a01b031614610f125760405162461bcd60e51b8152600401610d0790614ed8565b610f1b816126aa565b60408051600080825260208201909252610f379183919061274d565b50565b609754604051631c86b03760e31b81526001600160a01b039091169063e43581b890610f6a903390600401614547565b602060405180830381865afa158015610f87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fab9190614e24565b610fc857604051633b8d9d7560e21b815260040160405180910390fd5b609b610fd48282614f92565b506000610fe0826128b8565b609c8190556040518181529091507fde3dc3335dea4d1a1060ef6cefcfcc109eb0a1e78ce151818d3f17a01e1f8a05906020015b60405180910390a15050565b609754604051631c86b03760e31b81526001600160a01b039091169063e43581b890611050903390600401614547565b602060405180830381865afa15801561106d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110919190614e24565b6110ae57604051633b8d9d7560e21b815260040160405180910390fd5b633b9aca0081106110d257604051633494a40d60e21b815260040160405180910390fd5b609a8190556040518181527f3346af6da1932164d501f2ec28f8c5d686db5828a36b77f2da4332d89184fe7b9060200160405180910390a150565b60606111176128d6565b33600090815260a260205260409020541580156111455750609c5433600090815260a1602052604090205414155b801561115e575032600090815260a26020526040902054155b801561117b5750609c5432600090815260a1602052604090205414155b15611199576040516314e52a5b60e31b815260040160405180910390fd5b81516000816001600160401b038111156111b5576111b561420e565b6040519080825280602002602001820160405280156111de578160200160208202803683370190505b50905060005b828110156112335761120e85828151811061120157611201614e46565b602002602001015161292f565b82828151811061122057611220614e46565b60209081029190910101526001016111e4565b509150506112416001606555565b919050565b60007f00000000000000000000000000000000000000000000000000000000000000fc8260200151836040015184608001518560a001518660c001518760e0015160405160200161129d9796959493929190615051565b604051602081830303815290604052805190602001209050919050565b60a581815481106112ca57600080fd5b60009182526020909120600690910201805460018201546002830154600384015460048501546005860180549597506001600160a01b03948516969490931694919363ffffffff80831694600160201b8404821694600160401b9094049091169261133490614f12565b80601f016020809104026020016040519081016040528092919081815260200182805461136090614f12565b80156113ad5780601f10611382576101008083540402835291602001916113ad565b820191906000526020600020905b81548152906001019060200180831161139057829003601f168201915b5050505050905088565b6001600160a01b037f0000000000000000000000007db28175b63f154587bbb1cae62d39ea80a233831630036113ff5760405162461bcd60e51b8152600401610d0790614e9e565b7f0000000000000000000000007db28175b63f154587bbb1cae62d39ea80a233836001600160a01b031661143161268e565b6001600160a01b0316146114575760405162461bcd60e51b8152600401610d0790614ed8565b611460826126aa565b61146c8282600161274d565b5050565b6000306001600160a01b037f0000000000000000000000007db28175b63f154587bbb1cae62d39ea80a23383161461150b5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c6044820152771b1959081d1a1c9bdd59da0819195b1959d85d1958d85b1b60421b6064820152608401610d07565b506000805160206152fc83398151915290565b60606000610e2361152e87612cab565b61153787612cab565b8686612cc4565b611546613eb9565b60a561155183610e31565b8154811061156157611561614e46565b6000918252602091829020604080516101008101825260069093029091018054835260018101546001600160a01b039081169484019490945260028101549093169082015260038201546060820152600482015463ffffffff8082166080840152600160201b8204811660a0840152600160401b9091041660c082015260058201805491929160e0840191906115f690614f12565b80601f016020809104026020016040519081016040528092919081815260200182805461162290614f12565b801561166f5780601f106116445761010080835404028352916020019161166f565b820191906000526020600020905b81548152906001019060200180831161165257829003601f168201915b5050505050815250509050919050565b60606116896128d6565b33600090815260a260205260409020541580156116b75750609c5433600090815260a1602052604090205414155b80156116d0575032600090815260a26020526040902054155b80156116ed5750609c5432600090815260a1602052604090205414155b1561170b576040516314e52a5b60e31b815260040160405180910390fd5b81516000816001600160401b038111156117275761172761420e565b604051908082528060200260200182016040528015611750578160200160208202803683370190505b50905060005b828110156112335761178085828151811061177357611773614e46565b60200260200101516130b7565b82828151811061179257611792614e46565b6020908102919091010152600101611756565b60975460405163521d4de960e01b81526001600160a01b039091169063521d4de9906117d5903390600401614547565b602060405180830381865afa1580156117f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118169190614e24565b61183357604051632678482f60e21b815260040160405180910390fd5b6001600160a01b0381166000908152609f6020526040812054611857906001614e8b565b6001600160a01b0383166000818152609f60205260409081902083905551919250907fc6cd32b1acffa550abf886a9b443ff3ce485bfdb05e35ef5b26e745739a1eac1906109e59084815260200190565b61146c8282613104565b60a481815481106118c257600080fd5b6000918252602090912001546001600160a01b0316905081565b606060006118ef600063ffffffff6131ba565b5092915050565b60975460405163521d4de960e01b81526001600160a01b039091169063521d4de990611926903390600401614547565b602060405180830381865afa158015611943573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119679190614e24565b61198457604051632678482f60e21b815260040160405180910390fd5b828181146119a557604051631df89e8b60e01b815260040160405180910390fd5b60005b81811015611b405760008484838181106119c4576119c4614e46565b905060200201359050600081118015611a1f575060a360008888858181106119ee576119ee614e46565b9050602002016020810190611a039190613f4b565b6001600160a01b03168152602081019190915260400160002054155b15611a805760a4878784818110611a3857611a38614e46565b9050602002016020810190611a4d9190613f4b565b81546001810183556000928352602090922090910180546001600160a01b0319166001600160a01b039092169190911790555b8060a36000898986818110611a9757611a97614e46565b9050602002016020810190611aac9190613f4b565b6001600160a01b03168152602081019190915260400160002055868683818110611ad857611ad8614e46565b9050602002016020810190611aed9190613f4b565b6001600160a01b03167f3a5e6418e38cae10bf66eaf3e68c4e9c6b14df195e24fec169ab3a5b123c96e582604051611b2791815260200190565b60405180910390a250611b39816150c5565b90506119a8565b505050505050565b60975460405163521d4de960e01b81526001600160a01b039091169063521d4de990611b78903390600401614547565b602060405180830381865afa158015611b95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bb99190614e24565b611bd657604051632678482f60e21b815260040160405180910390fd5b6001600160a01b038116600090815260a26020526040812054611bfa906001614e8b565b6001600160a01b038316600081815260a260205260409081902083905551919250907f9c759941da0b7ce56c059c1497218796e62035024afb77a00ff49a980a62078f906109e59084815260200190565b6000611c556128d6565b33600090815260a26020526040902054158015611c835750609c5433600090815260a1602052604090205414155b8015611c9c575032600090815260a26020526040902054155b8015611cb95750609c5432600090815260a1602052604090205414155b15611cd7576040516314e52a5b60e31b815260040160405180910390fd5b611ce08261292f565b90506112416001606555565b611cf4613eb9565b611f4f609d8381548110611d0a57611d0a614e46565b6000918252602091829020604080516101e08101825260099093029091018054835260018101546001600160a01b0390811684860152600282015416838301526003810154606084015260048101805483518187028101870190945280845293949193608086019392830182828015611dac57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611d8e575b5050505050815260200160058201805480602002602001604051908101604052809291908181526020018280548015611e3057602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff1681526020019060040190602082600301049283019260010382029150808411611df35790505b5050509183525050600682015463ffffffff8082166020840152600160201b820481166040840152600160401b820481166060840152600160601b820481166080840152600160801b8204811660a0840152600160a01b8204811660c0840152600160c01b9091041660e082015260078201546001600160a01b031661010082015260088201805461012090920191611ec890614f12565b80601f0160208091040260200160405190810160405280929190818152602001828054611ef490614f12565b8015611f415780601f10611f1657610100808354040283529160200191611f41565b820191906000526020600020905b815481529060010190602001808311611f2457829003601f168201915b505050505081525050613319565b92915050565b60975460405163521d4de960e01b81526001600160a01b039091169063521d4de990611f85903390600401614547565b602060405180830381865afa158015611fa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc69190614e24565b611fe357604051632678482f60e21b815260040160405180910390fd5b633b9aca00811061200757604051633494a40d60e21b815260040160405180910390fd5b63ffffffff8216600081815260a76020908152604091829020849055815192835282018390527fb718143758782f8d3b9a4c9a0e6e54c43f2790e1e447d639c916a41a71151f5f9101611014565b600061205f6128d6565b33600090815260a2602052604090205415801561208d5750609c5433600090815260a1602052604090205414155b80156120a6575032600090815260a26020526040902054155b80156120c35750609c5432600090815260a1602052604090205414155b156120e1576040516314e52a5b60e31b815260040160405180910390fd5b611ce0826130b7565b609d81815481106120fa57600080fd5b600091825260209091206009909102018054600182015460028301546003840154600685015460078601546008870180549698506001600160a01b039586169794861696939563ffffffff80851696600160201b8604821696600160401b8704831696600160601b8104841696600160801b8204851696600160a01b8304861696600160c01b909304909516949116929161219490614f12565b80601f01602080910402602001604051908101604052809291908181526020018280546121c090614f12565b801561220d5780601f106121e25761010080835404028352916020019161220d565b820191906000526020600020905b8154815290600101906020018083116121f057829003601f168201915b505050505090508d565b6060600061222584846131ba565b915091505b9250929050565b609b805461223e90614f12565b80601f016020809104026020016040519081016040528092919081815260200182805461226a90614f12565b80156122b75780601f1061228c576101008083540402835291602001916122b7565b820191906000526020600020905b81548152906001019060200180831161229a57829003601f168201915b505050505081565b60006122cb8383613104565b6122d48461292f565b949350505050565b609754604051631c86b03760e31b81526001600160a01b039091169063e43581b89061230c903390600401614547565b602060405180830381865afa158015612329573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061234d9190614e24565b61236a57604051633b8d9d7560e21b815260040160405180910390fd5b609980546001600160a01b0319166001600160a01b0383169081179091556040517f7a7b5a0a132f9e0581eb8527f66eae9ee89c2a3e79d4ac7e41a1f1f4d48a7fc290600090a250565b6001600160a01b03163b151590565b6040516001600160a01b03831660248201526044810182905261242690849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526135b8565b505050565b60a55460609060009081908163ffffffff86168210612450578563ffffffff16612452565b815b90506000816001600160401b0381111561246e5761246e61420e565b6040519080825280602002602001820160405280156124a757816020015b612494613eb9565b81526020019060019003908161248c5790505b509050875b838163ffffffff16101561267557600060a58263ffffffff16815481106124d5576124d5614e46565b6000918252602091829020604080516101008101825260069093029091018054835260018101546001600160a01b039081169484019490945260028101549093169082015260038201546060820152600482015463ffffffff8082166080840152600160201b8204811660a0840152600160401b9091041660c082015260058201805491929160e08401919061256a90614f12565b80601f016020809104026020016040519081016040528092919081815260200182805461259690614f12565b80156125e35780601f106125b8576101008083540402835291602001916125e3565b820191906000526020600020905b8154815290600101906020018083116125c657829003601f168201915b50505050508152505090508b63ffffffff168160c001518260a0015161260991906150de565b63ffffffff1611801561262b57508a63ffffffff168160a0015163ffffffff16105b1561265c578083878151811061264357612643614e46565b60209081029190910101526126596001876150fb565b95505b81600101915083860361266f5750612675565b506124ac565b9381529963ffffffff9093169850919650505050505050565b6000805160206152fc833981519152546001600160a01b031690565b6097546001600160a01b0316801580159061272f5750604051631c86b03760e31b81526001600160a01b0382169063e43581b8906126ec903390600401614547565b602060405180830381865afa158015612709573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061272d9190614e24565b155b1561146c57604051633b8d9d7560e21b815260040160405180910390fd5b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612780576124268361368a565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156127da575060408051601f3d908101601f191682019092526127d791810190614e5c565b60015b61283d5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610d07565b6000805160206152fc83398151915281146128ac5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610d07565b50612426838383613724565b60006128c48251613749565b8260405160200161129d92919061510e565b6002606554036129285760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d07565b6002606555565b6040808201516001600160a01b0316600090815260a36020529081205460a08301514263ffffffff9091161015612979576040516332dcdf7360e21b815260040160405180910390fd5b610e1063ffffffff168360c0015163ffffffff1610156129ac57604051631b5982fd60e01b815260040160405180910390fd5b806000036129cd5760405163c0460cfb60e01b815260040160405180910390fd5b808360c0015163ffffffff16610e1063ffffffff1685606001516129f19190615167565b6129fb9190615194565b1015612a1a5760405163912f27bf60e01b815260040160405180910390fd5b60208301516001600160a01b0316612a33573360208401525b608083015163ffffffff16600090815260a760205260409020546001819003612a5e57506000612a6b565b80600003612a6b5750609a545b6000612a8082866060015187604001516137dc565b606086018190529050612a9285611246565b808652600090815260a6602052604090205415612ac257604051637e31d8a360e01b815260040160405180910390fd5b60a554612ad09060016150fb565b8551600090815260a6602090815260408083209390935560a580546001810182559252875160069092027fb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddeff8101928355908801517fb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddf00820180546001600160a01b039283166001600160a01b031991821617909155938901517fb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddf01830180549190921694169390931790925560608701517fb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddf0283015560808701517fb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddf038301805460a08a015160c08b015163ffffffff908116600160401b0263ffffffff60401b19928216600160201b026001600160401b03199094169190951617919091171691909117905560e087015187927fb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddf040190612c679082614f92565b5050507f6e3c6fa6d4815a856783888c5c3ea2ad7e7303ac0cca66c99f5bd93502c4429985604051612c999190614829565b60405180910390a15050915192915050565b6000610e10612cba81846151a8565b611f4f91906151cb565b609d5460609060009081908163ffffffff86168210612ce9578563ffffffff16612ceb565b815b90506000816001600160401b03811115612d0757612d0761420e565b604051908082528060200260200182016040528015612db057816020015b604080516101e0810182526000808252602080830182905292820181905260608083018290526080830181905260a0830181905260c0830182905260e08301829052610100830182905261012083018290526101408301829052610160830182905261018083018290526101a08301919091526101c08201528252600019909201910181612d255790505b509050875b838163ffffffff161015612675576000609d8263ffffffff1681548110612dde57612dde614e46565b6000918252602091829020604080516101e08101825260099093029091018054835260018101546001600160a01b0390811684860152600282015416838301526003810154606084015260048101805483518187028101870190945280845293949193608086019392830182828015612e8057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612e62575b5050505050815260200160058201805480602002602001604051908101604052809291908181526020018280548015612f0457602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff1681526020019060040190602082600301049283019260010382029150808411612ec75790505b5050509183525050600682015463ffffffff8082166020840152600160201b820481166040840152600160401b820481166060840152600160601b820481166080840152600160801b8204811660a0840152600160a01b8204811660c0840152600160c01b9091041660e082015260078201546001600160a01b031661010082015260088201805461012090920191612f9c90614f12565b80601f0160208091040260200160405190810160405280929190818152602001828054612fc890614f12565b80156130155780601f10612fea57610100808354040283529160200191613015565b820191906000526020600020905b815481529060010190602001808311612ff857829003601f168201915b50505050508152505090508b63ffffffff16610e1082610140015161303a91906151cb565b82610120015161304a91906150de565b63ffffffff1611801561306d57508a63ffffffff1681610120015163ffffffff16105b1561309e578083878151811061308557613085614e46565b602090810291909101015261309b6001876150fb565b95505b8160010191508386036130b15750612675565b50612db5565b60006130ca6130c583613319565b61292f565b5060a580546130db90600190614e8b565b815481106130eb576130eb614e46565b9060005260206000209060060201600301549050919050565b6000609c54905061314c338285858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061389e92505050565b61316957604051638baa579f60e01b815260040160405180910390fd5b33600081815260a1602052604090819020839055517fc48bbd4f009ad78a336beb65bf44688651e9aa52ac98d9054f0fce0573fefbc3906131ad9084815260200190565b60405180910390a2505050565b60a45460609060009081908163ffffffff861682106131df578563ffffffff166131e1565b815b90506000816001600160401b038111156131fd576131fd61420e565b60405190808252806020026020018201604052801561324257816020015b604080518082019091526000808252602082015281526020019060019003908161321b5790505b509050875b838163ffffffff16101561330257600060a48263ffffffff168154811061327057613270614e46565b60009182526020808320909101546001600160a01b031680835260a390915260409091205490915080156132e7576040518060400160405280836001600160a01b03168152602001828152508488815181106132ce576132ce614e46565b60209081029190910101526132e46001886150fb565b96505b8260010192508487036132fb575050613302565b5050613247565b9381529763ffffffff909316965091945050505050565b613321613eb9565b60a0820151516000816001600160401b038111156133415761334161420e565b60405190808252806020026020018201604052801561336a578160200160208202803683370190505b5090506000826001600160401b038111156133875761338761420e565b6040519080825280602002602001820160405280156133b0578160200160208202803683370190505b50905060008060005b858110156134d5578760a0015181815181106133d7576133d7614e46565b602002602001015163ffffffff16600003613442578760800151818151811061340257613402614e46565b602002602001015185848151811061341c5761341c614e46565b6001600160a01b039092166020928302919091019091015261343f6001846150fb565b92505b8760a00151818151811061345857613458614e46565b602002602001015163ffffffff166003036134c3578760800151818151811061348357613483614e46565b602002602001015184838151811061349d5761349d614e46565b6001600160a01b03909216602092830291909101909101526134c06001836150fb565b91505b806134cd816150c5565b9150506133b9565b5081845280835260405180610100016040528088600001518152602001336001600160a01b0316815260200188604001516001600160a01b0316815260200188606001518152602001600263ffffffff16815260200188610120015163ffffffff168152602001610e1089610140015161354f91906151cb565b63ffffffff16815260200188602001518961010001518a60c001518b60e001518c61016001518d6101a001518e61018001518c8c60405160200161359b999897969594939291906151f3565b60408051601f198184030181529190529052979650505050505050565b600061360d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166139e09092919063ffffffff16565b805190915015612426578080602001905181019061362b9190614e24565b6124265760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610d07565b613693816123b4565b6136f55760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610d07565b6000805160206152fc83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b61372d836139ef565b60008251118061373a5750805b1561242657610e0d8383613a2f565b6060600061375683613b21565b60010190506000816001600160401b038111156137755761377561420e565b6040519080825280601f01601f19166020018201604052801561379f576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a85049450846137a9575b509392505050565b336000908152609e60205260408120548190633b9aca00906137fe9082614e8b565b6138089087615167565b6138129190615194565b8492509050801561388257633b9aca0061382c8282614e8b565b6138369086615167565b6138409190615194565b6099549092506001600160a01b0316801561385b578061385d565b305b9050613880338261386e8689614e8b565b6001600160a01b038816929190613bf7565b505b6098546137d4906001600160a01b038581169133911685613bf7565b60008060006138ad8585613c2f565b909250905060008160048111156138c6576138c6615290565b1480156138e45750856001600160a01b0316826001600160a01b0316145b156138f457600192505050610e6b565b600080876001600160a01b0316631626ba7e60e01b888860405160240161391c9291906152a6565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161395a91906152bf565b600060405180830381855afa9150503d8060008114613995576040519150601f19603f3d011682016040523d82523d6000602084013e61399a565b606091505b50915091508180156139ad575080516020145b80156139d457508051630b135d3f60e11b906139d29083016020908101908401614e5c565b145b98975050505050505050565b60606122d48484600085613c71565b6139f88161368a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060613a3a836123b4565b613a955760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610d07565b600080846001600160a01b031684604051613ab091906152bf565b600060405180830381855af49150503d8060008114613aeb576040519150601f19603f3d011682016040523d82523d6000602084013e613af0565b606091505b5091509150613b18828260405180606001604052806027815260200161531c60279139613d4c565b95945050505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310613b605772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6904ee2d6d415b85acef8160201b8310613b8a576904ee2d6d415b85acef8160201b830492506020015b662386f26fc100008310613ba857662386f26fc10000830492506010015b6305f5e1008310613bc0576305f5e100830492506008015b6127108310613bd457612710830492506004015b60648310613be6576064830492506002015b600a8310611f4f5760010192915050565b6040516001600160a01b0380851660248301528316604482015260648101829052610e0d9085906323b872dd60e01b906084016123ef565b6000808251604103613c655760208301516040840151606085015160001a613c5987828585613d65565b9450945050505061222a565b5060009050600261222a565b606082471015613cd25760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610d07565b600080866001600160a01b03168587604051613cee91906152bf565b60006040518083038185875af1925050503d8060008114613d2b576040519150601f19603f3d011682016040523d82523d6000602084013e613d30565b606091505b5091509150613d4187838387613e1c565b979650505050505050565b60608315613d5b575081610e6b565b610e6b8383613e8f565b6000806fa2a8918ca85bafe22016d0b997e4df60600160ff1b03831115613d925750600090506003610e28565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613de6573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116613e0f57600060019250925050610e28565b9660009650945050505050565b60608315613e89578251600003613e8257613e36856123b4565b613e825760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d07565b50816122d4565b6122d483835b815115613e9f5781518083602001fd5b8060405162461bcd60e51b8152600401610d079190614da9565b604080516101008101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c082019290925260e081019190915290565b6001600160a01b0381168114610f3757600080fd5b803561124181613eff565b60008060408385031215613f3257600080fd5b8235613f3d81613eff565b946020939093013593505050565b600060208284031215613f5d57600080fd5b8135610e6b81613eff565b60008083601f840112613f7a57600080fd5b5081356001600160401b03811115613f9157600080fd5b6020830191508360208260051b850101111561222a57600080fd5b600080600060408486031215613fc157600080fd5b83356001600160401b03811115613fd757600080fd5b613fe386828701613f68565b9094509250506020840135613ff781613eff565b809150509250925092565b60008060006060848603121561401757600080fd5b833561402281613eff565b9250602084013561403281613eff565b929592945050506040919091013590565b803563ffffffff8116811461124157600080fd5b6000806000806080858703121561406d57600080fd5b61407685614043565b935061408460208601614043565b925061409260408601614043565b91506140a060608601614043565b905092959194509250565b6001600160a01b03169052565b60005b838110156140d35781810151838201526020016140bb565b50506000910152565b600081518084526140f48160208601602086016140b8565b601f01601f19169290920160200192915050565b600061010082518452602083015160018060a01b038082166020870152806040860151166040870152505060608301516060850152608083015163ffffffff80821660808701528060a08601511660a0870152505060c083015161417460c086018263ffffffff169052565b5060e08301518160e0860152613b18828601826140dc565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b838110156141e357605f198887030185526141d1868351614108565b955093820193908201906001016141b5565b50509490940194909452949350505050565b60006020828403121561420757600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60405161010081016001600160401b03811182821017156142475761424761420e565b60405290565b6040516101e081016001600160401b03811182821017156142475761424761420e565b604051601f8201601f191681016001600160401b03811182821017156142985761429861420e565b604052919050565b60006001600160401b038311156142b9576142b961420e565b6142cc601f8401601f1916602001614270565b90508281528383830111156142e057600080fd5b828260208301376000602084830101529392505050565b60006020828403121561430957600080fd5b81356001600160401b0381111561431f57600080fd5b8201601f8101841361433057600080fd5b6122d4848235602084016142a0565b60006020828403121561435157600080fd5b610e6b82614043565b60006001600160401b038211156143735761437361420e565b5060051b60200190565b600082601f83011261438e57600080fd5b610e6b838335602085016142a0565b600061010082840312156143b057600080fd5b6143b8614224565b9050813581526143ca60208301613f14565b60208201526143db60408301613f14565b6040820152606082013560608201526143f660808301614043565b608082015261440760a08301614043565b60a082015261441860c08301614043565b60c082015260e08201356001600160401b0381111561443657600080fd5b6144428482850161437d565b60e08301525092915050565b6000602080838503121561446157600080fd5b82356001600160401b038082111561447857600080fd5b818501915085601f83011261448c57600080fd5b813561449f61449a8261435a565b614270565b81815260059190911b830184019084810190888311156144be57600080fd5b8585015b838110156144f6578035858111156144da5760008081fd5b6144e88b89838a010161439d565b8452509186019186016144c2565b5098975050505050505050565b6020808252825182820181905260009190848201906040850190845b8181101561453b5783518352928401929184019160010161451f565b50909695505050505050565b6001600160a01b0391909116815260200190565b60006020828403121561456d57600080fd5b81356001600160401b0381111561458357600080fd5b6122d48482850161439d565b8881526001600160a01b038881166020830152871660408201526060810186905263ffffffff858116608083015284811660a0830152831660c082015261010060e082018190526000906145e5838201856140dc565b9b9a5050505050505050505050565b6000806040838503121561460757600080fd5b823561461281613eff565b915060208301356001600160401b0381111561462d57600080fd5b6146398582860161437d565b9150509250929050565b600081518084526020808501945080840160005b8381101561467c5781516001600160a01b031687529582019590820190600101614657565b509495945050505050565b600081518084526020808501945080840160005b8381101561467c57815163ffffffff168752958201959082019060010161469b565b60006040808301818452808651808352606092508286019150828160051b8701016020808a0160005b8481101561481457605f198a850301865281516101e08151865284820151614710868801826140ab565b50898201516147218b8801826140ab565b508882015189870152608080830151828289015261474183890182614643565b9250505060a0808301518783038289015261475c8382614687565b9250505060c0808301516147778289018263ffffffff169052565b505060e08281015163ffffffff908116918801919091526101008084015182169088015261012080840151821690880152610140808401518216908801526101608084015182169088015261018080840151909116908701526101a0808301516147e3828901826140ab565b50506101c0808301519250868203818801525061480081836140dc565b9785019795505050908201906001016146e6565b50509690960196909652509295945050505050565b602081526000610e6b6020830184614108565b600082601f83011261484d57600080fd5b8135602061485d61449a8361435a565b82815260059290921b8401810191818101908684111561487c57600080fd5b8286015b848110156148a057803561489381613eff565b8352918301918301614880565b509695505050505050565b600082601f8301126148bc57600080fd5b813560206148cc61449a8361435a565b82815260059290921b840181019181810190868411156148eb57600080fd5b8286015b848110156148a05761490081614043565b83529183019183016148ef565b60006101e0828403121561492057600080fd5b61492861424d565b90508135815261493a60208301613f14565b602082015261494b60408301613f14565b60408201526060828101359082015260808201356001600160401b038082111561497457600080fd5b6149808583860161483c565b608084015260a084013591508082111561499957600080fd5b6149a5858386016148ab565b60a08401526149b660c08501614043565b60c08401526149c760e08501614043565b60e084015261010091506149dc828501614043565b8284015261012091506149f0828501614043565b828401526101409150614a04828501614043565b828401526101609150614a18828501614043565b828401526101809150614a2c828501614043565b828401526101a09150614a40828501613f14565b828401526101c091508184013581811115614a5a57600080fd5b614a668682870161437d565b8385015250505092915050565b60006020808385031215614a8657600080fd5b82356001600160401b0380821115614a9d57600080fd5b818501915085601f830112614ab157600080fd5b8135614abf61449a8261435a565b81815260059190911b83018401908481019088831115614ade57600080fd5b8585015b838110156144f657803585811115614afa5760008081fd5b614b088b89838a010161490d565b845250918601918601614ae2565b60008083601f840112614b2857600080fd5b5081356001600160401b03811115614b3f57600080fd5b60208301915083602082850101111561222a57600080fd5b60008060208385031215614b6a57600080fd5b82356001600160401b03811115614b8057600080fd5b614b8c85828601614b16565b90969095509350505050565b600081518084526020808501945080840160005b8381101561467c57815180516001600160a01b031688528301518388015260409096019590820190600101614bac565b602081526000610e6b6020830184614b98565b60008060008060408587031215614c0557600080fd5b84356001600160401b0380821115614c1c57600080fd5b614c2888838901613f68565b90965094506020870135915080821115614c4157600080fd5b50614c4e87828801613f68565b95989497509550505050565b60008060408385031215614c6d57600080fd5b613f3d83614043565b600060208284031215614c8857600080fd5b81356001600160401b03811115614c9e57600080fd5b6122d48482850161490d565b8d81526001600160a01b038d811660208301528c166040820152606081018b905263ffffffff8a8116608083015289811660a0830152881660c0820152600063ffffffff881660e083015263ffffffff871661010083015263ffffffff861661012083015263ffffffff8516610140830152614d2a6101608301856140ab565b6101a0610180830152614d416101a08301846140dc565b9f9e505050505050505050505050505050565b60008060408385031215614d6757600080fd5b614d7083614043565b9150614d7e60208401614043565b90509250929050565b604081526000614d9a6040830185614b98565b90508260208301529392505050565b602081526000610e6b60208301846140dc565b600080600060408486031215614dd157600080fd5b83356001600160401b0380821115614de857600080fd5b614df48783880161439d565b94506020860135915080821115614e0a57600080fd5b50614e1786828701614b16565b9497909650939450505050565b600060208284031215614e3657600080fd5b81518015158114610e6b57600080fd5b634e487b7160e01b600052603260045260246000fd5b600060208284031215614e6e57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b81810381811115611f4f57611f4f614e75565b6020808252602c908201526000805160206152dc83398151915260408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201526000805160206152dc83398151915260408201526b6163746976652070726f787960a01b606082015260800190565b600181811c90821680614f2657607f821691505b602082108103614f4657634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561242657600081815260208120601f850160051c81016020861015614f735750805b601f850160051c820191505b81811015611b4057828155600101614f7f565b81516001600160401b03811115614fab57614fab61420e565b614fbf81614fb98454614f12565b84614f4c565b602080601f831160018114614ff45760008415614fdc5750858301515b600019600386901b1c1916600185901b178555611b40565b600085815260208120601f198616915b8281101561502357888601518255948401946001909101908401615004565b50858210156150415787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b878152600060018060601b0319808960601b166020840152808860601b1660348401525063ffffffff60e01b808760e01b166048840152808660e01b16604c840152808560e01b1660508401525082516150b28160548501602087016140b8565b9190910160540198975050505050505050565b6000600182016150d7576150d7614e75565b5060010190565b63ffffffff8181168382160190808211156118ef576118ef614e75565b80820180821115611f4f57611f4f614e75565b790ca2ba3432b932bab69029b4b3b732b21026b2b9b9b0b3b29d0560311b8152825160009061514481601a8501602088016140b8565b83519083019061515b81601a8401602088016140b8565b01601a01949350505050565b8082028115828204841417611f4f57611f4f614e75565b634e487b7160e01b600052601260045260246000fd5b6000826151a3576151a361517e565b500490565b600063ffffffff808416806151bf576151bf61517e565b92169190910492915050565b63ffffffff8181168382160280821691908281146151eb576151eb614e75565b505092915050565b6001600160a01b038a8116825263ffffffff8a8116602084015289811660408401528881166060840152878116608084015290861660a0830152841660c082015261014060e0820181905260009061524d83820186614643565b90508281036101008401526152628185614643565b8381036101209094019390935250506002815261060f60f31b60208201526040019998505050505050505050565b634e487b7160e01b600052602160045260246000fd5b8281526040602082015260006122d460408301846140dc565b600082516152d18184602087016140b8565b919091019291505056fe46756e6374696f6e206d7573742062652063616c6c6564207468726f75676820360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212203e7b5847def8884fd78ced53ebd0fe3d1727ca520ba02cd4803705992b78f64b64736f6c63430008110033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in FRAX
0
Multichain Portfolio | 35 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.