Source Code
Latest 25 from a total of 1,097 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Perform Upkeep | 10679197 | 270 days ago | IN | 0 GLMR | 0.04058066 | ||||
| Perform Upkeep | 10669873 | 271 days ago | IN | 0 GLMR | 0.04058066 | ||||
| Perform Upkeep | 10665762 | 271 days ago | IN | 0 GLMR | 0.03673266 | ||||
| Perform Upkeep | 10663416 | 271 days ago | IN | 0 GLMR | 0.04058066 | ||||
| Perform Upkeep | 10656264 | 272 days ago | IN | 0 GLMR | 0.03857666 | ||||
| Perform Upkeep | 10650358 | 272 days ago | IN | 0 GLMR | 0.04058066 | ||||
| Perform Upkeep | 10645667 | 273 days ago | IN | 0 GLMR | 0.04058066 | ||||
| Perform Upkeep | 10643902 | 273 days ago | IN | 0 GLMR | 0.04058066 | ||||
| Perform Upkeep | 10639789 | 273 days ago | IN | 0 GLMR | 0.04058066 | ||||
| Perform Upkeep | 10635080 | 273 days ago | IN | 0 GLMR | 0.04058066 | ||||
| Perform Upkeep | 10633936 | 273 days ago | IN | 0 GLMR | 0.04058066 | ||||
| Perform Upkeep | 10632173 | 274 days ago | IN | 0 GLMR | 0.04058066 | ||||
| Perform Upkeep | 10616334 | 275 days ago | IN | 0 GLMR | 0.04058066 | ||||
| Perform Upkeep | 10613968 | 275 days ago | IN | 0 GLMR | 0.03857666 | ||||
| Perform Upkeep | 10612799 | 275 days ago | IN | 0 GLMR | 0.04058066 | ||||
| Perform Upkeep | 10605222 | 275 days ago | IN | 0 GLMR | 0.04058066 | ||||
| Perform Upkeep | 10598147 | 276 days ago | IN | 0 GLMR | 0.04058066 | ||||
| Perform Upkeep | 10594502 | 276 days ago | IN | 0 GLMR | 0.04058066 | ||||
| Perform Upkeep | 10590389 | 277 days ago | IN | 0 GLMR | 0.06763733 | ||||
| Perform Upkeep | 10585087 | 277 days ago | IN | 0 GLMR | 0.06763733 | ||||
| Perform Upkeep | 10582117 | 277 days ago | IN | 0 GLMR | 0.04058066 | ||||
| Perform Upkeep | 10576224 | 278 days ago | IN | 0 GLMR | 0.03857666 | ||||
| Perform Upkeep | 10570900 | 278 days ago | IN | 0 GLMR | 0.04058066 | ||||
| Perform Upkeep | 10566197 | 278 days ago | IN | 0 GLMR | 0.04058066 | ||||
| Perform Upkeep | 10556185 | 279 days ago | IN | 0 GLMR | 0.04058066 |
View more zero value Internal Transactions in Advanced View mode
Cross-Chain Transactions
Loading...
Loading
Contract Name:
LinkAvailableBalanceMonitor
Compiler Version
v0.8.19+commit.7dd6d404
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {AutomationCompatibleInterface} from "../interfaces/AutomationCompatibleInterface.sol";
import {AccessControl} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/access/AccessControl.sol";
import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableMap.sol";
import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol";
import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
import {Pausable} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/security/Pausable.sol";
interface IAggregatorProxy {
function aggregator() external view returns (address);
}
interface ILinkAvailable {
function linkAvailableForPayment() external view returns (int256 availableBalance);
}
/// @title The LinkAvailableBalanceMonitor contract.
/// @notice A keeper-compatible contract that monitors target contracts for balance from a custom
/// function linkAvailableForPayment() and funds them with LINK if it falls below a defined
/// threshold. Also supports aggregator proxy contracts monitoring which require fetching the actual
/// target contract through a predefined interface.
/// @dev with 30 addresses as the s_maxPerform, the measured max gas usage of performUpkeep is around 2M
/// therefore, we recommend an upkeep gas limit of 3M (this has a 33% margin of safety). Although, nothing
/// prevents us from using 5M gas and increasing s_maxPerform, 30 seems like a reasonable batch size that
/// is probably plenty for most needs.
/// @dev with 130 addresses as the s_maxCheck, the measured max gas usage of checkUpkeep is around 3.5M,
/// which is 30% below the 5M limit.
/// Note that testing conditions DO NOT match live chain gas usage, hence the margins. Change
/// at your own risk!!!
/// @dev some areas for improvement / acknowledgement of limitations:
/// validate that all addresses conform to interface when adding them to the watchlist
/// this is a "trustless" upkeep, meaning it does not trust the caller of performUpkeep;
/// we could save a fair amount of gas and re-write this upkeep for use with Automation v2.0+,
/// which has significantly different trust assumptions
contract LinkAvailableBalanceMonitor is AccessControl, AutomationCompatibleInterface, Pausable {
using EnumerableMap for EnumerableMap.UintToAddressMap;
using EnumerableSet for EnumerableSet.AddressSet;
event BalanceUpdated(address indexed addr, uint256 oldBalance, uint256 newBalance);
event FundsWithdrawn(uint256 amountWithdrawn, address payee);
event UpkeepIntervalSet(uint256 oldUpkeepInterval, uint256 newUpkeepInterval);
event MaxCheckSet(uint256 oldMaxCheck, uint256 newMaxCheck);
event MaxPerformSet(uint256 oldMaxPerform, uint256 newMaxPerform);
event MinWaitPeriodSet(uint256 s_minWaitPeriodSeconds, uint256 minWaitPeriodSeconds);
event TopUpBlocked(address indexed topUpAddress);
event TopUpFailed(address indexed recipient);
event TopUpSucceeded(address indexed topUpAddress, uint256 amount);
event TopUpUpdated(address indexed addr, uint256 oldTopUpAmount, uint256 newTopUpAmount);
event WatchlistUpdated();
error InvalidAddress(address target);
error InvalidMaxCheck(uint16 maxCheck);
error InvalixMaxPerform(uint16 maxPerform);
error InvalidMinBalance(uint96 minBalance);
error InvalidTopUpAmount(uint96 topUpAmount);
error InvalidUpkeepInterval(uint8 upkeepInterval);
error InvalidLinkTokenAddress(address lt);
error InvalidWatchList();
error InvalidChainSelector();
error DuplicateAddress(address duplicate);
error ReentrantCall();
struct MonitoredAddress {
uint96 minBalance;
uint96 topUpAmount;
uint56 lastTopUpTimestamp;
bool isActive;
}
bytes32 private constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
bytes32 private constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE");
uint96 private constant DEFAULT_TOP_UP_AMOUNT_JUELS = 9000000000000000000;
uint96 private constant DEFAULT_MIN_BALANCE_JUELS = 1000000000000000000;
IERC20 private immutable i_linkToken;
uint256 private s_minWaitPeriodSeconds;
uint16 private s_maxPerform;
uint16 private s_maxCheck;
uint8 private s_upkeepInterval;
/// @notice s_watchList contains all the addresses watched by this monitor
/// @dev It mainly provides the length() function
EnumerableSet.AddressSet private s_watchList;
/// @notice s_targets contains all the addresses watched by this monitor
/// Each key points to a MonitoredAddress with all the needed metadata
mapping(address targetAddress => MonitoredAddress targetProperties) private s_targets;
/// @notice s_onRampAddresses represents a list of CCIP onRamp addresses watched on this contract
/// There has to be only one onRamp per dstChainSelector.
/// dstChainSelector is needed as we have to track the live onRamp, and delete the onRamp
/// whenever a new one is deployed with the same dstChainSelector.
EnumerableMap.UintToAddressMap private s_onRampAddresses;
bool private reentrancyGuard;
/// @param admin is the administrator address of this contract
/// @param linkToken the LINK token address
/// @param minWaitPeriodSeconds represents the amount of time that has to wait a contract to be funded
/// @param maxPerform maximum amount of contracts to fund
/// @param maxCheck maximum amount of contracts to check
/// @param upkeepInterval randomizes the check for underfunded contracts
constructor(
address admin,
IERC20 linkToken,
uint256 minWaitPeriodSeconds,
uint16 maxPerform,
uint16 maxCheck,
uint8 upkeepInterval
) {
_setRoleAdmin(ADMIN_ROLE, ADMIN_ROLE);
_setRoleAdmin(EXECUTOR_ROLE, ADMIN_ROLE);
_grantRole(ADMIN_ROLE, admin);
i_linkToken = linkToken;
setMinWaitPeriodSeconds(minWaitPeriodSeconds);
setMaxPerform(maxPerform);
setMaxCheck(maxCheck);
setUpkeepInterval(upkeepInterval);
reentrancyGuard = false;
}
/// @notice Sets the list of subscriptions to watch and their funding parameters
/// @param addresses the list of target addresses to watch (could be direct target or IAggregatorProxy)
/// @param minBalances the list of corresponding minBalance for the target address
/// @param topUpAmounts the list of corresponding minTopUp for the target address
function setWatchList(
address[] calldata addresses,
uint96[] calldata minBalances,
uint96[] calldata topUpAmounts,
uint64[] calldata dstChainSelectors
) external onlyAdminOrExecutor {
if (
addresses.length != minBalances.length ||
addresses.length != topUpAmounts.length ||
addresses.length != dstChainSelectors.length
) {
revert InvalidWatchList();
}
for (uint256 idx = s_watchList.length(); idx > 0; idx--) {
address member = s_watchList.at(idx - 1);
s_watchList.remove(member);
delete s_targets[member];
}
// s_onRampAddresses is not the same length as s_watchList, so it has
// to be clean in a separate loop
for (uint256 idx = s_onRampAddresses.length(); idx > 0; idx--) {
(uint256 key, ) = s_onRampAddresses.at(idx - 1);
s_onRampAddresses.remove(key);
}
for (uint256 idx = 0; idx < addresses.length; idx++) {
address targetAddress = addresses[idx];
if (s_targets[targetAddress].isActive) revert DuplicateAddress(targetAddress);
if (targetAddress == address(0)) revert InvalidWatchList();
if (minBalances[idx] == 0) revert InvalidWatchList();
if (topUpAmounts[idx] == 0) revert InvalidWatchList();
s_targets[targetAddress] = MonitoredAddress({
isActive: true,
minBalance: minBalances[idx],
topUpAmount: topUpAmounts[idx],
lastTopUpTimestamp: 0
});
if (dstChainSelectors[idx] > 0) {
s_onRampAddresses.set(dstChainSelectors[idx], targetAddress);
}
s_watchList.add(targetAddress);
}
emit WatchlistUpdated();
}
/// @notice Adds a new address to the watchlist
/// @param targetAddress the address to be added to the watchlist
/// @param dstChainSelector carries a non-zero value in case the targetAddress is an onRamp, otherwise it carries a 0
/// @dev this function has to be compatible with the event onRampSet(address, dstChainSelector) emitted by
/// the CCIP router. Important detail to know is this event is also emitted when an onRamp is decommissioned,
/// in which case it will carry the proper dstChainSelector along with the 0x0 address
function addToWatchListOrDecommission(address targetAddress, uint64 dstChainSelector) public onlyAdminOrExecutor {
if (s_targets[targetAddress].isActive) revert DuplicateAddress(targetAddress);
if (targetAddress == address(0) && dstChainSelector == 0) revert InvalidAddress(targetAddress);
bool onRampExists = s_onRampAddresses.contains(dstChainSelector);
// if targetAddress is an existing onRamp, there's a need of cleaning the previous onRamp associated to this dstChainSelector
// there's no need to remove any other address that's not an onRamp
if (dstChainSelector > 0 && onRampExists) {
address oldAddress = s_onRampAddresses.get(dstChainSelector);
removeFromWatchList(oldAddress);
}
// only add the new address if it's not 0x0
if (targetAddress != address(0)) {
s_targets[targetAddress] = MonitoredAddress({
isActive: true,
minBalance: DEFAULT_MIN_BALANCE_JUELS,
topUpAmount: DEFAULT_TOP_UP_AMOUNT_JUELS,
lastTopUpTimestamp: 0
});
s_watchList.add(targetAddress);
// add the contract to onRampAddresses if it carries a valid dstChainSelector
if (dstChainSelector > 0) {
s_onRampAddresses.set(dstChainSelector, targetAddress);
}
// else if is redundant as this is the only corner case left, maintaining it for legibility
} else if (targetAddress == address(0) && dstChainSelector > 0) {
s_onRampAddresses.remove(dstChainSelector);
}
}
/// @notice Delete an address from the watchlist and sets the target to inactive
/// @param targetAddress the address to be deleted
function removeFromWatchList(address targetAddress) public onlyAdminOrExecutor returns (bool) {
if (s_watchList.remove(targetAddress)) {
delete s_targets[targetAddress];
return true;
}
return false;
}
/// @notice Gets a list of proxies that are underfunded, up to the s_maxPerform size
/// @dev the function starts at a random index in the list to avoid biasing the first
/// addresses in the list over latter ones.
/// @dev the function will check at most s_maxCheck proxies in a single call
/// @dev the function returns a list with a max length of s_maxPerform
/// @return list of target addresses which are underfunded
function sampleUnderfundedAddresses() public view returns (address[] memory) {
uint16 maxPerform = s_maxPerform;
uint16 maxCheck = s_maxCheck;
uint256 numTargets = s_watchList.length();
uint256 idx = uint256(blockhash(block.number - (block.number % s_upkeepInterval) - 1)) % numTargets;
uint256 numToCheck = numTargets < maxCheck ? numTargets : maxCheck;
uint256 numFound = 0;
uint256 minWaitPeriod = s_minWaitPeriodSeconds;
address[] memory targetsToFund = new address[](maxPerform);
MonitoredAddress memory contractToFund;
address targetAddress;
for (
uint256 numChecked = 0;
numChecked < numToCheck;
(idx, numChecked) = ((idx + 1) % numTargets, numChecked + 1)
) {
targetAddress = s_watchList.at(idx);
contractToFund = s_targets[targetAddress];
(bool fundingNeeded, ) = _needsFunding(
targetAddress,
contractToFund.lastTopUpTimestamp + minWaitPeriod,
contractToFund.minBalance,
contractToFund.isActive
);
if (fundingNeeded) {
targetsToFund[numFound] = targetAddress;
numFound++;
if (numFound == maxPerform) {
break; // max number of addresses in batch reached
}
}
}
if (numFound != maxPerform) {
assembly {
mstore(targetsToFund, numFound) // resize array to number of valid targets
}
}
return targetsToFund;
}
/// @notice tries to fund an array of target addresses, checking if they're underfunded in the process
/// @param targetAddresses is an array of contract addresses to be funded in case they're underfunded
function topUp(address[] memory targetAddresses) public whenNotPaused nonReentrant {
MonitoredAddress memory contractToFund;
uint256 minWaitPeriod = s_minWaitPeriodSeconds;
uint256 localBalance = i_linkToken.balanceOf(address(this));
for (uint256 idx = 0; idx < targetAddresses.length; idx++) {
address targetAddress = targetAddresses[idx];
contractToFund = s_targets[targetAddress];
(bool fundingNeeded, address target) = _needsFunding(
targetAddress,
contractToFund.lastTopUpTimestamp + minWaitPeriod,
contractToFund.minBalance,
contractToFund.isActive
);
if (localBalance >= contractToFund.topUpAmount && fundingNeeded) {
bool success = i_linkToken.transfer(target, contractToFund.topUpAmount);
if (success) {
localBalance -= contractToFund.topUpAmount;
s_targets[targetAddress].lastTopUpTimestamp = uint56(block.timestamp);
emit TopUpSucceeded(target, contractToFund.topUpAmount);
} else {
emit TopUpFailed(targetAddress);
}
} else {
emit TopUpBlocked(targetAddress);
}
}
}
/// @notice checks the target (could be direct target or IAggregatorProxy), and determines
/// if it is eligible for funding
/// @param targetAddress the target to check
/// @param minBalance minimum balance required for the target
/// @param minWaitPeriodPassed the minimum wait period (target lastTopUpTimestamp + minWaitPeriod)
/// @return bool whether the target needs funding or not
/// @return address the address to fund. for DF, this is the aggregator address behind the proxy address.
/// for other products, it's the original target address
function _needsFunding(
address targetAddress,
uint256 minWaitPeriodPassed,
uint256 minBalance,
bool contractIsActive
) private view returns (bool, address) {
// Explicitly check if the targetAddress is the zero address
// or if it's not a contract. In both cases return with false,
// to prevent target.linkAvailableForPayment from running,
// which would revert the operation.
if (targetAddress == address(0) || targetAddress.code.length == 0) {
return (false, address(0));
}
ILinkAvailable target;
IAggregatorProxy proxy = IAggregatorProxy(targetAddress);
try proxy.aggregator() returns (address aggregatorAddress) {
// proxy.aggregator() can return a 0 address if the address is not an aggregator
if (aggregatorAddress == address(0)) return (false, address(0));
target = ILinkAvailable(aggregatorAddress);
} catch {
target = ILinkAvailable(targetAddress);
}
try target.linkAvailableForPayment() returns (int256 balance) {
if (balance < int256(minBalance) && minWaitPeriodPassed <= block.timestamp && contractIsActive) {
return (true, address(target));
}
} catch {}
return (false, address(0));
}
/// @notice Gets list of subscription ids that are underfunded and returns a keeper-compatible payload.
/// @return upkeepNeeded signals if upkeep is needed
/// @return performData is an abi encoded list of subscription ids that need funds
function checkUpkeep(
bytes calldata
) external view override whenNotPaused returns (bool upkeepNeeded, bytes memory performData) {
address[] memory needsFunding = sampleUnderfundedAddresses();
if (needsFunding.length == 0) {
return (false, "");
}
uint96 total_batch_balance;
for (uint256 idx = 0; idx < needsFunding.length; idx++) {
address targetAddress = needsFunding[idx];
total_batch_balance = total_batch_balance + s_targets[targetAddress].topUpAmount;
}
if (i_linkToken.balanceOf(address(this)) >= total_batch_balance) {
return (true, abi.encode(needsFunding));
}
return (false, "");
}
/// @notice Called by the keeper to send funds to underfunded addresses.
/// @param performData the abi encoded list of addresses to fund
function performUpkeep(bytes calldata performData) external override {
address[] memory needsFunding = abi.decode(performData, (address[]));
topUp(needsFunding);
}
/// @notice Withdraws the contract balance in the LINK token.
/// @param amount the amount of the LINK to withdraw
/// @param payee the address to pay
function withdraw(uint256 amount, address payable payee) external onlyAdminOrExecutor {
if (payee == address(0)) revert InvalidAddress(payee);
i_linkToken.transfer(payee, amount);
emit FundsWithdrawn(amount, payee);
}
/// @notice Sets the minimum balance for the given target address
function setMinBalance(address target, uint96 minBalance) external onlyRole(ADMIN_ROLE) {
if (target == address(0)) revert InvalidAddress(target);
if (minBalance == 0) revert InvalidMinBalance(minBalance);
if (!s_targets[target].isActive) revert InvalidWatchList();
uint256 oldBalance = s_targets[target].minBalance;
s_targets[target].minBalance = minBalance;
emit BalanceUpdated(target, oldBalance, minBalance);
}
/// @notice Sets the minimum balance for the given target address
function setTopUpAmount(address target, uint96 topUpAmount) external onlyRole(ADMIN_ROLE) {
if (target == address(0)) revert InvalidAddress(target);
if (topUpAmount == 0) revert InvalidTopUpAmount(topUpAmount);
if (!s_targets[target].isActive) revert InvalidWatchList();
uint256 oldTopUpAmount = s_targets[target].topUpAmount;
s_targets[target].topUpAmount = topUpAmount;
emit BalanceUpdated(target, oldTopUpAmount, topUpAmount);
}
/// @notice Update s_maxPerform
function setMaxPerform(uint16 maxPerform) public onlyRole(ADMIN_ROLE) {
emit MaxPerformSet(s_maxPerform, maxPerform);
s_maxPerform = maxPerform;
}
/// @notice Update s_maxCheck
function setMaxCheck(uint16 maxCheck) public onlyRole(ADMIN_ROLE) {
emit MaxCheckSet(s_maxCheck, maxCheck);
s_maxCheck = maxCheck;
}
/// @notice Sets the minimum wait period (in seconds) for addresses between funding
function setMinWaitPeriodSeconds(uint256 minWaitPeriodSeconds) public onlyRole(ADMIN_ROLE) {
emit MinWaitPeriodSet(s_minWaitPeriodSeconds, minWaitPeriodSeconds);
s_minWaitPeriodSeconds = minWaitPeriodSeconds;
}
/// @notice Update s_upkeepInterval
function setUpkeepInterval(uint8 upkeepInterval) public onlyRole(ADMIN_ROLE) {
if (upkeepInterval > 255) revert InvalidUpkeepInterval(upkeepInterval);
emit UpkeepIntervalSet(s_upkeepInterval, upkeepInterval);
s_upkeepInterval = upkeepInterval;
}
/// @notice Gets maxPerform
function getMaxPerform() external view returns (uint16) {
return s_maxPerform;
}
/// @notice Gets maxCheck
function getMaxCheck() external view returns (uint16) {
return s_maxCheck;
}
/// @notice Gets the minimum wait period
function getMinWaitPeriodSeconds() external view returns (uint256) {
return s_minWaitPeriodSeconds;
}
/// @notice Gets upkeepInterval
function getUpkeepInterval() external view returns (uint8) {
return s_upkeepInterval;
}
/// @notice Gets the list of subscription ids being watched
function getWatchList() external view returns (address[] memory) {
return s_watchList.values();
}
/// @notice Gets the onRamp address with the specified dstChainSelector
function getOnRampAddressAtChainSelector(uint64 dstChainSelector) external view returns (address) {
if (dstChainSelector == 0) revert InvalidChainSelector();
return s_onRampAddresses.get(dstChainSelector);
}
/// @notice Gets configuration information for an address on the watchlist
function getAccountInfo(
address targetAddress
) external view returns (bool isActive, uint96 minBalance, uint96 topUpAmount, uint56 lastTopUpTimestamp) {
MonitoredAddress memory target = s_targets[targetAddress];
return (target.isActive, target.minBalance, target.topUpAmount, target.lastTopUpTimestamp);
}
/// @dev Modifier to make a function callable only by executor role or the
/// admin role.
modifier onlyAdminOrExecutor() {
address sender = _msgSender();
if (!hasRole(ADMIN_ROLE, sender)) {
_checkRole(EXECUTOR_ROLE, sender);
}
_;
}
modifier nonReentrant() {
if (reentrancyGuard) revert ReentrantCall();
reentrancyGuard = true;
_;
reentrancyGuard = false;
}
/// @notice Pause the contract, which prevents executing performUpkeep
function pause() external onlyRole(ADMIN_ROLE) {
_pause();
}
/// @notice Unpause the contract
function unpause() external onlyRole(ADMIN_ROLE) {
_unpause();
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// solhint-disable-next-line interface-starts-with-i
interface AutomationCompatibleInterface {
/**
* @notice method that is simulated by the keepers to see if any work actually
* needs to be performed. This method does does not actually need to be
* executable, and since it is only ever simulated it can consume lots of gas.
* @dev To ensure that it is never called, you may want to add the
* cannotExecute modifier from KeeperBase to your implementation of this
* method.
* @param checkData specified in the upkeep registration so it is always the
* same for a registered upkeep. This can easily be broken down into specific
* arguments using `abi.decode`, so multiple upkeeps can be registered on the
* same contract and easily differentiated by the contract.
* @return upkeepNeeded boolean to indicate whether the keeper should call
* performUpkeep or not.
* @return performData bytes that the keeper should call performUpkeep with, if
* upkeep is needed. If you would like to encode data to decode later, try
* `abi.encode`.
*/
function checkUpkeep(bytes calldata checkData) external returns (bool upkeepNeeded, bytes memory performData);
/**
* @notice method that is actually executed by the keepers, via the registry.
* The data returned by the checkUpkeep simulation will be passed into
* this method to actually be executed.
* @dev The input to this method should not be trusted, and the caller of the
* method should not even be restricted to any single registry. Anyone should
* be able call it, and the input should be validated, there is no guarantee
* that the data passed in is the performData returned from checkUpkeep. This
* could happen due to malicious keepers, racing keepers, or simply a state
* change while the performUpkeep transaction is waiting for confirmation.
* Always validate the data passed in.
* @param performData is the data which was passed back from the checkData
* simulation. If it is encoded, it can easily be decoded into other types by
* calling `abi.decode`. This data should not be trusted, and should be
* validated against the contract's current state.
*/
function performUpkeep(bytes calldata performData) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(account),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.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 v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// 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: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableMap.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js.
pragma solidity ^0.8.0;
import "./EnumerableSet.sol";
/**
* @dev Library for managing an enumerable variant of Solidity's
* https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
* type.
*
* Maps have the following properties:
*
* - Entries are added, removed, and checked for existence in constant time
* (O(1)).
* - Entries are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableMap for EnumerableMap.UintToAddressMap;
*
* // Declare a set state variable
* EnumerableMap.UintToAddressMap private myMap;
* }
* ```
*
* The following map types are supported:
*
* - `uint256 -> address` (`UintToAddressMap`) since v3.0.0
* - `address -> uint256` (`AddressToUintMap`) since v4.6.0
* - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0
* - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0
* - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableMap.
* ====
*/
library EnumerableMap {
using EnumerableSet for EnumerableSet.Bytes32Set;
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Map type with
// bytes32 keys and values.
// The Map implementation uses private functions, and user-facing
// implementations (such as Uint256ToAddressMap) are just wrappers around
// the underlying Map.
// This means that we can only create new EnumerableMaps for types that fit
// in bytes32.
struct Bytes32ToBytes32Map {
// Storage of keys
EnumerableSet.Bytes32Set _keys;
mapping(bytes32 => bytes32) _values;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(
Bytes32ToBytes32Map storage map,
bytes32 key,
bytes32 value
) internal returns (bool) {
map._values[key] = value;
return map._keys.add(key);
}
/**
* @dev Removes a key-value pair from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) {
delete map._values[key];
return map._keys.remove(key);
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) {
return map._keys.contains(key);
}
/**
* @dev Returns the number of key-value pairs in the map. O(1).
*/
function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) {
return map._keys.length();
}
/**
* @dev Returns the key-value pair stored at position `index` in the map. O(1).
*
* Note that there are no guarantees on the ordering of entries inside the
* array, and it may change when more entries are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) {
bytes32 key = map._keys.at(index);
return (key, map._values[key]);
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) {
bytes32 value = map._values[key];
if (value == bytes32(0)) {
return (contains(map, key), bytes32(0));
} else {
return (true, value);
}
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) {
bytes32 value = map._values[key];
require(value != 0 || contains(map, key), "EnumerableMap: nonexistent key");
return value;
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
Bytes32ToBytes32Map storage map,
bytes32 key,
string memory errorMessage
) internal view returns (bytes32) {
bytes32 value = map._values[key];
require(value != 0 || contains(map, key), errorMessage);
return value;
}
// UintToUintMap
struct UintToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(
UintToUintMap storage map,
uint256 key,
uint256 value
) internal returns (bool) {
return set(map._inner, bytes32(key), bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(UintToUintMap storage map, uint256 key) internal returns (bool) {
return remove(map._inner, bytes32(key));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) {
return contains(map._inner, bytes32(key));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(UintToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the set. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (uint256(key), uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(key)));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
UintToUintMap storage map,
uint256 key,
string memory errorMessage
) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(key), errorMessage));
}
// UintToAddressMap
struct UintToAddressMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(
UintToAddressMap storage map,
uint256 key,
address value
) internal returns (bool) {
return set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
return remove(map._inner, bytes32(key));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
return contains(map._inner, bytes32(key));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(UintToAddressMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the set. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (uint256(key), address(uint160(uint256(value))));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
return (success, address(uint160(uint256(value))));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
return address(uint160(uint256(get(map._inner, bytes32(key)))));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
UintToAddressMap storage map,
uint256 key,
string memory errorMessage
) internal view returns (address) {
return address(uint160(uint256(get(map._inner, bytes32(key), errorMessage))));
}
// AddressToUintMap
struct AddressToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(
AddressToUintMap storage map,
address key,
uint256 value
) internal returns (bool) {
return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(AddressToUintMap storage map, address key) internal returns (bool) {
return remove(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(AddressToUintMap storage map, address key) internal view returns (bool) {
return contains(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(AddressToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the set. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (address(uint160(uint256(key))), uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key))));
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(AddressToUintMap storage map, address key) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(uint256(uint160(key)))));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
AddressToUintMap storage map,
address key,
string memory errorMessage
) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(uint256(uint160(key))), errorMessage));
}
// Bytes32ToUintMap
struct Bytes32ToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(
Bytes32ToUintMap storage map,
bytes32 key,
uint256 value
) internal returns (bool) {
return set(map._inner, key, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) {
return remove(map._inner, key);
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) {
return contains(map._inner, key);
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(Bytes32ToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the set. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (key, uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, key);
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) {
return uint256(get(map._inner, key));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
Bytes32ToUintMap storage map,
bytes32 key,
string memory errorMessage
) internal view returns (uint256) {
return uint256(get(map._inner, key, errorMessage));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}{
"optimizer": {
"enabled": true,
"runs": 1000000
},
"metadata": {
"bytecodeHash": "none"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"contract IERC20","name":"linkToken","type":"address"},{"internalType":"uint256","name":"minWaitPeriodSeconds","type":"uint256"},{"internalType":"uint16","name":"maxPerform","type":"uint16"},{"internalType":"uint16","name":"maxCheck","type":"uint16"},{"internalType":"uint8","name":"upkeepInterval","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"duplicate","type":"address"}],"name":"DuplicateAddress","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidChainSelector","type":"error"},{"inputs":[{"internalType":"address","name":"lt","type":"address"}],"name":"InvalidLinkTokenAddress","type":"error"},{"inputs":[{"internalType":"uint16","name":"maxCheck","type":"uint16"}],"name":"InvalidMaxCheck","type":"error"},{"inputs":[{"internalType":"uint96","name":"minBalance","type":"uint96"}],"name":"InvalidMinBalance","type":"error"},{"inputs":[{"internalType":"uint96","name":"topUpAmount","type":"uint96"}],"name":"InvalidTopUpAmount","type":"error"},{"inputs":[{"internalType":"uint8","name":"upkeepInterval","type":"uint8"}],"name":"InvalidUpkeepInterval","type":"error"},{"inputs":[],"name":"InvalidWatchList","type":"error"},{"inputs":[{"internalType":"uint16","name":"maxPerform","type":"uint16"}],"name":"InvalixMaxPerform","type":"error"},{"inputs":[],"name":"ReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBalance","type":"uint256"}],"name":"BalanceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amountWithdrawn","type":"uint256"},{"indexed":false,"internalType":"address","name":"payee","type":"address"}],"name":"FundsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMaxCheck","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMaxCheck","type":"uint256"}],"name":"MaxCheckSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMaxPerform","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMaxPerform","type":"uint256"}],"name":"MaxPerformSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"s_minWaitPeriodSeconds","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minWaitPeriodSeconds","type":"uint256"}],"name":"MinWaitPeriodSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"topUpAddress","type":"address"}],"name":"TopUpBlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"}],"name":"TopUpFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"topUpAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TopUpSucceeded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldTopUpAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTopUpAmount","type":"uint256"}],"name":"TopUpUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldUpkeepInterval","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newUpkeepInterval","type":"uint256"}],"name":"UpkeepIntervalSet","type":"event"},{"anonymous":false,"inputs":[],"name":"WatchlistUpdated","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"targetAddress","type":"address"},{"internalType":"uint64","name":"dstChainSelector","type":"uint64"}],"name":"addToWatchListOrDecommission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"checkUpkeep","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"targetAddress","type":"address"}],"name":"getAccountInfo","outputs":[{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"uint96","name":"minBalance","type":"uint96"},{"internalType":"uint96","name":"topUpAmount","type":"uint96"},{"internalType":"uint56","name":"lastTopUpTimestamp","type":"uint56"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxCheck","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxPerform","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMinWaitPeriodSeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"dstChainSelector","type":"uint64"}],"name":"getOnRampAddressAtChainSelector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUpkeepInterval","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWatchList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"performData","type":"bytes"}],"name":"performUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"targetAddress","type":"address"}],"name":"removeFromWatchList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sampleUnderfundedAddresses","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"maxCheck","type":"uint16"}],"name":"setMaxCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"maxPerform","type":"uint16"}],"name":"setMaxPerform","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint96","name":"minBalance","type":"uint96"}],"name":"setMinBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minWaitPeriodSeconds","type":"uint256"}],"name":"setMinWaitPeriodSeconds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint96","name":"topUpAmount","type":"uint96"}],"name":"setTopUpAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"upkeepInterval","type":"uint8"}],"name":"setUpkeepInterval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"addresses","type":"address[]"},{"internalType":"uint96[]","name":"minBalances","type":"uint96[]"},{"internalType":"uint96[]","name":"topUpAmounts","type":"uint96[]"},{"internalType":"uint64[]","name":"dstChainSelectors","type":"uint64[]"}],"name":"setWatchList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"targetAddresses","type":"address[]"}],"name":"topUp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"payee","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a06040523480156200001157600080fd5b50604051620041793803806200417983398101604081905262000034916200067f565b6001805460ff19169055620000596000805160206200415983398151915280620000ff565b620000947fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6360008051602062004159833981519152620000ff565b620000af60008051602062004159833981519152876200014a565b6001600160a01b038516608052620000c784620001d3565b620000d28362000230565b620000dd82620002a6565b620000e8816200032a565b5050600a805460ff19169055506200086692505050565b600082815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b620001568282620003e0565b620001cf576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556200018e3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b60008051602062004159833981519152620001ee816200040b565b60025460408051918252602082018490527ff2b1d9e58f462028f9adf2763241bf5cf547edf76fa5293f40cd32e6647eb0b6910160405180910390a150600255565b600080516020620041598339815191526200024b816200040b565b6003546040805161ffff928316815291841660208301527ffbbc9ad96b08be5ffb0da53171d30710e564c4f591376544b6334809d7a993ec910160405180910390a1506003805461ffff191661ffff92909216919091179055565b60008051602062004159833981519152620002c1816200040b565b6003546040805161ffff620100009093048316815291841660208301527f9d83a57b5411f892fb01f5b534b69ce2c21f0594ba04c05344547e08e0eddb81910160405180910390a1506003805461ffff909216620100000263ffff000019909216919091179055565b6000805160206200415983398151915262000345816200040b565b60ff8260ff161115620003755760405163459e0a6160e11b815260ff831660048201526024015b60405180910390fd5b6003546040805160ff6401000000009093048316815291841660208301527f0cf38f82689f15f658c0dbcb00cfa212c86d35f943c3a511678dd201b58b6028910160405180910390a1506003805460ff9092166401000000000260ff60201b19909216919091179055565b6000828152602081815260408083206001600160a01b038516845290915290205460ff165b92915050565b6200041781336200041a565b50565b620004268282620003e0565b620001cf5762000436816200047e565b6200044383602062000491565b604051602001620004569291906200072c565b60408051601f198184030181529082905262461bcd60e51b82526200036c91600401620007a5565b6060620004056001600160a01b03831660145b60606000620004a2836002620007f0565b620004af9060026200080a565b6001600160401b03811115620004c957620004c962000820565b6040519080825280601f01601f191660200182016040528015620004f4576020820181803683370190505b509050600360fc1b8160008151811062000512576200051262000836565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811062000544576200054462000836565b60200101906001600160f81b031916908160001a90535060006200056a846002620007f0565b620005779060016200080a565b90505b6001811115620005f9576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110620005af57620005af62000836565b1a60f81b828281518110620005c857620005c862000836565b60200101906001600160f81b031916908160001a90535060049490941c93620005f1816200084c565b90506200057a565b5083156200064a5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016200036c565b9392505050565b6001600160a01b03811681146200041757600080fd5b805161ffff811681146200067a57600080fd5b919050565b60008060008060008060c087890312156200069957600080fd5b8651620006a68162000651565b6020880151909650620006b98162000651565b60408801519095509350620006d16060880162000667565b9250620006e16080880162000667565b915060a087015160ff81168114620006f857600080fd5b809150509295509295509295565b60005b838110156200072357818101518382015260200162000709565b50506000910152565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516200076681601785016020880162000706565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516200079981602884016020880162000706565b01602801949350505050565b6020815260008251806020840152620007c681604085016020870162000706565b601f01601f19169190910160400192915050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417620004055762000405620007da565b80820180821115620004055762000405620007da565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000816200085e576200085e620007da565b506000190190565b6080516138c262000897600039600081816106b801528181610b0501528181610d2601526119b301526138c26000f3fe608060405234801561001057600080fd5b50600436106101e45760003560e01c80636b89c0881161010f5780638ded04f5116100a2578063ab66c9f511610071578063ab66c9f514610556578063bc8684da14610569578063d547741f1461057c578063deb6184a1461058f57600080fd5b80638ded04f5146104de57806391d14854146104fe5780639c1a692514610542578063a217fddf1461054e57600080fd5b8063728584b7116100de578063728584b7146103ac57806377ddcf32146103b45780637b510fe8146103c75780638456cb59146104d657600080fd5b80636b89c088146103505780636dc0e790146103635780636e04ff0d14610376578063707c69e91461039757600080fd5b80633e4ca6771161018757806341c119371161015657806341c119371461030957806341d2052e1461032a5780634585e33b146103325780635c975abb1461034557600080fd5b80633e4ca677146102c85780633f4ba83a146102db5780633f85861f146102e35780633fcc3686146102f657600080fd5b80630916430b116101c35780630916430b1461025e578063248a9ca3146102715780632f2ff15d146102a257806336568abe146102b557600080fd5b8062f714ce146101e957806301ffc9a7146101fe57806303004df414610226575b600080fd5b6101fc6101f73660046130f8565b6105a2565b005b61021161020c366004613128565b610779565b60405190151581526020015b60405180910390f35b610239610234366004613187565b610812565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161021d565b6101fc61026c3660046131a2565b61086d565b61029461027f3660046131c5565b60009081526020819052604090206001015490565b60405190815260200161021d565b6101fc6102b03660046130f8565b610960565b6101fc6102c33660046130f8565b61098a565b6101fc6102d6366004613218565b610a3d565b6101fc610f4c565b6101fc6102f13660046131c5565b610f81565b6101fc610304366004613317565b610fed565b60035462010000900461ffff165b60405161ffff909116815260200161021d565b600254610294565b6101fc61034036600461334c565b61120c565b60015460ff16610211565b6101fc61035e3660046133be565b611225565b6101fc610371366004613427565b6112d3565b61038961038436600461334c565b6118a5565b60405161021d929190613559565b61039f611a85565b60405161021d9190613574565b61039f611d22565b6101fc6103c23660046135ce565b611d33565b6104966103d53660046135fa565b73ffffffffffffffffffffffffffffffffffffffff16600090815260066020908152604091829020825160808101845290546bffffffffffffffffffffffff8082168084526c0100000000000000000000000083049091169383018490527801000000000000000000000000000000000000000000000000820466ffffffffffffff169483018590527f010000000000000000000000000000000000000000000000000000000000000090910460ff16151560609092018290529093909290565b60405161021d949392919093151584526bffffffffffffffffffffffff92831660208501529116604083015266ffffffffffffff16606082015260800190565b6101fc6120ec565b600354640100000000900460ff1660405160ff909116815260200161021d565b61021161050c3660046130f8565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b60035461ffff16610317565b610294600081565b6101fc610564366004613317565b61211e565b6102116105773660046135fa565b612323565b6101fc61058a3660046130f8565b6123d0565b6101fc61059d3660046133be565b6123f5565b3360008181527f7d7ffb7a348e1c6a02869081a26547b49160dd3df72d1d75a570eb9b698292ec602052604090205460ff16610602576106027fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6382612497565b73ffffffffffffffffffffffffffffffffffffffff821661066c576040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024015b60405180910390fd5b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018590527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015610701573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107259190613617565b506040805184815273ffffffffffffffffffffffffffffffffffffffff841660208201527f6141b54b56b8a52a8c6f5cd2a857f6117b18ffbf4d46bd3106f300a839cbf5ea910160405180910390a1505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061080c57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60008167ffffffffffffffff16600003610858576040517f656535ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61080c600767ffffffffffffffff841661254f565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561089781612562565b60ff8260ff1611156108da576040517f8b3c14c200000000000000000000000000000000000000000000000000000000815260ff83166004820152602401610663565b6003546040805160ff6401000000009093048316815291841660208301527f0cf38f82689f15f658c0dbcb00cfa212c86d35f943c3a511678dd201b58b6028910160405180910390a1506003805460ff909216640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff909216919091179055565b60008281526020819052604090206001015461097b81612562565b610985838361256c565b505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610a2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610663565b610a39828261265c565b5050565b610a45612713565b600a5460ff1615610a82576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040805160808101825260008082526020820181905291810182905260608101919091526002546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610b61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b859190613639565b905060005b8451811015610f1d576000858281518110610ba757610ba7613652565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff81166000908152600683526040808220815160808101835290546bffffffffffffffffffffffff80821683526c01000000000000000000000000820416958201959095527801000000000000000000000000000000000000000000000000850466ffffffffffffff169181018290527f010000000000000000000000000000000000000000000000000000000000000090940460ff1615156060850152929750909250908190610c9c908490610c7f9089906136b0565b89600001516bffffffffffffffffffffffff168a60600151612782565b9150915086602001516bffffffffffffffffffffffff168510158015610cbf5750815b15610ec55760208701516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526bffffffffffffffffffffffff90921660248201526000917f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015610d6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d939190613617565b90508015610e7d576020880151610db8906bffffffffffffffffffffffff16876136c3565b73ffffffffffffffffffffffffffffffffffffffff85811660009081526006602090815260409182902080547fff00000000000000ffffffffffffffffffffffffffffffffffffffffffffffff1678010000000000000000000000000000000000000000000000004266ffffffffffffff16021790558b81015191516bffffffffffffffffffffffff9092168252929850908416917f5fec4d72a579fa6fbce9b8225812805663c6ac1d75e7eb85ae596f67df158cc6910160405180910390a2610ebf565b60405173ffffffffffffffffffffffffffffffffffffffff8516907fa9ff7a9b96721b0e16adb7de9db0764fbfd6a4516d4d165f9564e8c3755eb10590600090a25b50610f07565b60405173ffffffffffffffffffffffffffffffffffffffff8416907f4d012ceef4d21203fc49000fc6d4ea5f0ac25f746cc7da267a2f6e3f538474ae90600090a25b5050508080610f15906136d6565b915050610b8a565b5050600a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610f7681612562565b610f7e61295c565b50565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610fab81612562565b60025460408051918252602082018490527ff2b1d9e58f462028f9adf2763241bf5cf547edf76fa5293f40cd32e6647eb0b6910160405180910390a150600255565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561101781612562565b73ffffffffffffffffffffffffffffffffffffffff831661107c576040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610663565b816bffffffffffffffffffffffff166000036110d4576040517f3e748a020000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff83166004820152602401610663565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600660205260409020547f0100000000000000000000000000000000000000000000000000000000000000900460ff16611156576040517f3869bbe600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff831660008181526006602090815260409182902080546bffffffffffffffffffffffff8781166c010000000000000000000000008181027fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff85161790945585519390920416808352928201529092917f5e00297b9c4f8fef460c4d7123316eeeb08a64a0930d1d9cae0b61b7f663b25491015b60405180910390a250505050565b600061121a82840184613218565b905061098581610a3d565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561124f81612562565b6003546040805161ffff620100009093048316815291841660208301527f9d83a57b5411f892fb01f5b534b69ce2c21f0594ba04c05344547e08e0eddb81910160405180910390a1506003805461ffff90921662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffff909216919091179055565b3360008181527f7d7ffb7a348e1c6a02869081a26547b49160dd3df72d1d75a570eb9b698292ec602052604090205460ff16611333576113337fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6382612497565b87861415806113425750878414155b8061134d5750878214155b15611384576040517f3869bbe600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061139060046129d9565b90505b80156113f65760006113b16113a96001846136c3565b6004906129e3565b90506113be6004826129ef565b5073ffffffffffffffffffffffffffffffffffffffff16600090815260066020526040812055806113ee8161370e565b915050611393565b5060006114036007612a11565b90505b801561144757600061142461141c6001846136c3565b600790612a1c565b509050611432600782612a38565b5050808061143f9061370e565b915050611406565b5060005b888110156118705760008a8a8381811061146757611467613652565b905060200201602081019061147c91906135fa565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600660205260409020549091507f0100000000000000000000000000000000000000000000000000000000000000900460ff161561151a576040517f9f2277f300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610663565b73ffffffffffffffffffffffffffffffffffffffff8116611567576040517f3869bbe600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b88888381811061157957611579613652565b905060200201602081019061158e9190613743565b6bffffffffffffffffffffffff166000036115d5576040517f3869bbe600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8686838181106115e7576115e7613652565b90506020020160208101906115fc9190613743565b6bffffffffffffffffffffffff16600003611643576040517f3869bbe600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180608001604052808a8a8581811061166057611660613652565b90506020020160208101906116759190613743565b6bffffffffffffffffffffffff16815260200188888581811061169a5761169a613652565b90506020020160208101906116af9190613743565b6bffffffffffffffffffffffff908116825260006020808401829052600160409485015273ffffffffffffffffffffffffffffffffffffffff861682526006815283822085518154928701519587015160609097015115157f0100000000000000000000000000000000000000000000000000000000000000027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff66ffffffffffffff989098167801000000000000000000000000000000000000000000000000029790971677ffffffffffffffffffffffffffffffffffffffffffffffff9686166c01000000000000000000000000027fffffffffffffffff00000000000000000000000000000000000000000000000090941691909516179190911793909316919091179290921790558585848181106117ec576117ec613652565b90506020020160208101906118019190613187565b67ffffffffffffffff1611156118505761184e85858481811061182657611826613652565b905060200201602081019061183b9190613187565b60079067ffffffffffffffff1683612a44565b505b61185b600482612a6f565b50508080611868906136d6565b91505061144b565b506040517f1dc3753221bdd8306e249da907041a3de685f38f5bf250f063e5a4e347cedeed90600090a1505050505050505050565b600060606118b1612713565b60006118bb611a85565b905080516000036118df575050604080516020810190915260008082529150611a7e565b6000805b825181101561197457600083828151811061190057611900613652565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff81166000908152600690925260409091205490915061195e906c0100000000000000000000000090046bffffffffffffffffffffffff168461375e565b925050808061196c906136d6565b9150506118e3565b506040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526bffffffffffffffffffffffff8216907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611a0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a339190613639565b10611a6557600182604051602001611a4b9190613574565b604051602081830303815290604052935093505050611a7e565b6000604051806020016040528060008152509350935050505b9250929050565b60035460609061ffff80821691620100009004166000611aa560046129d9565b6003549091506000908290600190611ac890640100000000900460ff1643613783565b611ad290436136c3565b611adc91906136c3565b611ae7919040613783565b905060008361ffff168310611b00578361ffff16611b02565b825b6002549091506000908161ffff881667ffffffffffffffff811115611b2957611b296131e9565b604051908082528060200260200182016040528015611b52578160200160208202803683370190505b506040805160808101825260008082526020820181905291810182905260608101829052919250805b86811015611d0357611b8e6004896129e3565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600660209081526040808320815160808101835290546bffffffffffffffffffffffff80821683526c01000000000000000000000000820416938201939093527801000000000000000000000000000000000000000000000000830466ffffffffffffff169181018290527f010000000000000000000000000000000000000000000000000000000000000090920460ff161515606083015290955091935090611c78908490611c5b9089906136b0565b86600001516bffffffffffffffffffffffff168760600151612782565b5090508015611cd75782858881518110611c9457611c94613652565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015286611cc3816136d6565b9750508b61ffff168703611cd75750611d03565b5088611ce48960016136b0565b611cee9190613783565b611cf98260016136b0565b9098509050611b7b565b508961ffff168514611d13578483525b50909998505050505050505050565b6060611d2e6004612a91565b905090565b3360008181527f7d7ffb7a348e1c6a02869081a26547b49160dd3df72d1d75a570eb9b698292ec602052604090205460ff16611d9357611d937fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6382612497565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600660205260409020547f0100000000000000000000000000000000000000000000000000000000000000900460ff1615611e2e576040517f9f2277f300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610663565b73ffffffffffffffffffffffffffffffffffffffff8316158015611e5a575067ffffffffffffffff8216155b15611ea9576040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610663565b6000611ec0600767ffffffffffffffff8516612a9e565b905060008367ffffffffffffffff16118015611ed95750805b15611f03576000611ef5600767ffffffffffffffff861661254f565b9050611f0081612323565b50505b73ffffffffffffffffffffffffffffffffffffffff84161561209c5760408051608081018252670de0b6b3a76400008152677ce66c50e28400006020808301918252600083850181815260016060860190815273ffffffffffffffffffffffffffffffffffffffff8b16835260069093529490209251835492519451915115157f0100000000000000000000000000000000000000000000000000000000000000027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff66ffffffffffffff939093167801000000000000000000000000000000000000000000000000029290921677ffffffffffffffffffffffffffffffffffffffffffffffff6bffffffffffffffffffffffff9687166c01000000000000000000000000027fffffffffffffffff000000000000000000000000000000000000000000000000909516929096169190911792909217939093161791909117905561206e600485612a6f565b5067ffffffffffffffff83161561209757612095600767ffffffffffffffff851686612a44565b505b6120e6565b73ffffffffffffffffffffffffffffffffffffffff84161580156120ca575060008367ffffffffffffffff16115b156120e6576120e4600767ffffffffffffffff8516612a38565b505b50505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561211681612562565b610f7e612aaa565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561214881612562565b73ffffffffffffffffffffffffffffffffffffffff83166121ad576040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610663565b816bffffffffffffffffffffffff16600003612205576040517ffd89b5fc0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff83166004820152602401610663565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600660205260409020547f0100000000000000000000000000000000000000000000000000000000000000900460ff16612287576040517f3869bbe600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff831660008181526006602090815260409182902080547fffffffffffffffffffffffffffffffffffffffff00000000000000000000000081166bffffffffffffffffffffffff888116918217909355845192909116808352928201529092917f5e00297b9c4f8fef460c4d7123316eeeb08a64a0930d1d9cae0b61b7f663b25491016111fe565b3360008181527f7d7ffb7a348e1c6a02869081a26547b49160dd3df72d1d75a570eb9b698292ec602052604081205490919060ff16612386576123867fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6382612497565b6123916004846129ef565b156123c55773ffffffffffffffffffffffffffffffffffffffff8316600090815260066020526040812055600191506123ca565b600091505b50919050565b6000828152602081905260409020600101546123eb81612562565b610985838361265c565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561241f81612562565b6003546040805161ffff928316815291841660208301527ffbbc9ad96b08be5ffb0da53171d30710e564c4f591376544b6334809d7a993ec910160405180910390a150600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff92909216919091179055565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a39576124d581612b03565b6124e0836020612b22565b6040516020016124f19291906137be565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a00000000000000000000000000000000000000000000000000000000082526106639160040161383f565b600061255b8383612d65565b9392505050565b610f7e8133612497565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a395760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556125fe3390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615610a395760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60015460ff1615612780576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610663565b565b60008073ffffffffffffffffffffffffffffffffffffffff861615806127bd575073ffffffffffffffffffffffffffffffffffffffff86163b155b156127cd57506000905080612953565b6000808790508073ffffffffffffffffffffffffffffffffffffffff1663245a7bfc6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612858575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261285591810190613852565b60015b61286457879150612891565b73ffffffffffffffffffffffffffffffffffffffff811661288e5760008094509450505050612953565b91505b8173ffffffffffffffffffffffffffffffffffffffff1663d09dc3396040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612916575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261291391810190613639565b60015b1561294957868112801561292a5750428811155b80156129335750855b156129475760018394509450505050612953565b505b6000809350935050505b94509492505050565b612964612def565b600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b600061080c825490565b600061255b8383612e5b565b600061255b8373ffffffffffffffffffffffffffffffffffffffff8416612e85565b600061080c82612f7f565b6000808080612a2b8686612f8a565b9097909650945050505050565b600061255b8383612fb5565b6000612a67848473ffffffffffffffffffffffffffffffffffffffff8516612fd2565b949350505050565b600061255b8373ffffffffffffffffffffffffffffffffffffffff8416612fef565b6060600061255b8361303e565b600061255b838361309a565b612ab2612713565b600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016811790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258336129af565b606061080c73ffffffffffffffffffffffffffffffffffffffff831660145b60606000612b3183600261386f565b612b3c9060026136b0565b67ffffffffffffffff811115612b5457612b546131e9565b6040519080825280601f01601f191660200182016040528015612b7e576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110612bb557612bb5613652565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110612c1857612c18613652565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000612c5484600261386f565b612c5f9060016136b0565b90505b6001811115612cfc577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110612ca057612ca0613652565b1a60f81b828281518110612cb657612cb6613652565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93612cf58161370e565b9050612c62565b50831561255b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610663565b600081815260028301602052604081205480151580612d895750612d89848461309a565b61255b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b657900006044820152606401610663565b60015460ff16612780576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610663565b6000826000018281548110612e7257612e72613652565b9060005260206000200154905092915050565b60008181526001830160205260408120548015612f6e576000612ea96001836136c3565b8554909150600090612ebd906001906136c3565b9050818114612f22576000866000018281548110612edd57612edd613652565b9060005260206000200154905080876000018481548110612f0057612f00613652565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612f3357612f33613886565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061080c565b600091505061080c565b5092915050565b600061080c826129d9565b60008080612f9885856129e3565b600081815260029690960160205260409095205494959350505050565b6000818152600283016020526040812081905561255b83836130a6565b60008281526002840160205260408120829055612a6784846130b2565b60008181526001830160205260408120546130365750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561080c565b50600061080c565b60608160000180548060200260200160405190810160405280929190818152602001828054801561308e57602002820191906000526020600020905b81548152602001906001019080831161307a575b50505050509050919050565b600061255b83836130be565b600061255b8383612e85565b600061255b8383612fef565b6000818152600183016020526040812054151561255b565b73ffffffffffffffffffffffffffffffffffffffff81168114610f7e57600080fd5b6000806040838503121561310b57600080fd5b82359150602083013561311d816130d6565b809150509250929050565b60006020828403121561313a57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461255b57600080fd5b803567ffffffffffffffff8116811461318257600080fd5b919050565b60006020828403121561319957600080fd5b61255b8261316a565b6000602082840312156131b457600080fd5b813560ff8116811461255b57600080fd5b6000602082840312156131d757600080fd5b5035919050565b8035613182816130d6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602080838503121561322b57600080fd5b823567ffffffffffffffff8082111561324357600080fd5b818501915085601f83011261325757600080fd5b813581811115613269576132696131e9565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811085821117156132ac576132ac6131e9565b6040529182528482019250838101850191888311156132ca57600080fd5b938501935b828510156132ef576132e0856131de565b845293850193928501926132cf565b98975050505050505050565b80356bffffffffffffffffffffffff8116811461318257600080fd5b6000806040838503121561332a57600080fd5b8235613335816130d6565b9150613343602084016132fb565b90509250929050565b6000806020838503121561335f57600080fd5b823567ffffffffffffffff8082111561337757600080fd5b818501915085601f83011261338b57600080fd5b81358181111561339a57600080fd5b8660208285010111156133ac57600080fd5b60209290920196919550909350505050565b6000602082840312156133d057600080fd5b813561ffff8116811461255b57600080fd5b60008083601f8401126133f457600080fd5b50813567ffffffffffffffff81111561340c57600080fd5b6020830191508360208260051b8501011115611a7e57600080fd5b6000806000806000806000806080898b03121561344357600080fd5b883567ffffffffffffffff8082111561345b57600080fd5b6134678c838d016133e2565b909a50985060208b013591508082111561348057600080fd5b61348c8c838d016133e2565b909850965060408b01359150808211156134a557600080fd5b6134b18c838d016133e2565b909650945060608b01359150808211156134ca57600080fd5b506134d78b828c016133e2565b999c989b5096995094979396929594505050565b60005b838110156135065781810151838201526020016134ee565b50506000910152565b600081518084526135278160208601602086016134eb565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8215158152604060208201526000612a67604083018461350f565b6020808252825182820181905260009190848201906040850190845b818110156135c257835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101613590565b50909695505050505050565b600080604083850312156135e157600080fd5b82356135ec816130d6565b91506133436020840161316a565b60006020828403121561360c57600080fd5b813561255b816130d6565b60006020828403121561362957600080fd5b8151801515811461255b57600080fd5b60006020828403121561364b57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561080c5761080c613681565b8181038181111561080c5761080c613681565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361370757613707613681565b5060010190565b60008161371d5761371d613681565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b60006020828403121561375557600080fd5b61255b826132fb565b6bffffffffffffffffffffffff818116838216019080821115612f7857612f78613681565b6000826137b9577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516137f68160178501602088016134eb565b7f206973206d697373696e6720726f6c652000000000000000000000000000000060179184019182015283516138338160288401602088016134eb565b01602801949350505050565b60208152600061255b602083018461350f565b60006020828403121561386457600080fd5b815161255b816130d6565b808202811582820484141761080c5761080c613681565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000813000aa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217750000000000000000000000001c911eec9b3016716c5e708b02d3b4f679807954000000000000000000000000012414a392f9fa442a3109f1320c439c45518ac30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000a
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101e45760003560e01c80636b89c0881161010f5780638ded04f5116100a2578063ab66c9f511610071578063ab66c9f514610556578063bc8684da14610569578063d547741f1461057c578063deb6184a1461058f57600080fd5b80638ded04f5146104de57806391d14854146104fe5780639c1a692514610542578063a217fddf1461054e57600080fd5b8063728584b7116100de578063728584b7146103ac57806377ddcf32146103b45780637b510fe8146103c75780638456cb59146104d657600080fd5b80636b89c088146103505780636dc0e790146103635780636e04ff0d14610376578063707c69e91461039757600080fd5b80633e4ca6771161018757806341c119371161015657806341c119371461030957806341d2052e1461032a5780634585e33b146103325780635c975abb1461034557600080fd5b80633e4ca677146102c85780633f4ba83a146102db5780633f85861f146102e35780633fcc3686146102f657600080fd5b80630916430b116101c35780630916430b1461025e578063248a9ca3146102715780632f2ff15d146102a257806336568abe146102b557600080fd5b8062f714ce146101e957806301ffc9a7146101fe57806303004df414610226575b600080fd5b6101fc6101f73660046130f8565b6105a2565b005b61021161020c366004613128565b610779565b60405190151581526020015b60405180910390f35b610239610234366004613187565b610812565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161021d565b6101fc61026c3660046131a2565b61086d565b61029461027f3660046131c5565b60009081526020819052604090206001015490565b60405190815260200161021d565b6101fc6102b03660046130f8565b610960565b6101fc6102c33660046130f8565b61098a565b6101fc6102d6366004613218565b610a3d565b6101fc610f4c565b6101fc6102f13660046131c5565b610f81565b6101fc610304366004613317565b610fed565b60035462010000900461ffff165b60405161ffff909116815260200161021d565b600254610294565b6101fc61034036600461334c565b61120c565b60015460ff16610211565b6101fc61035e3660046133be565b611225565b6101fc610371366004613427565b6112d3565b61038961038436600461334c565b6118a5565b60405161021d929190613559565b61039f611a85565b60405161021d9190613574565b61039f611d22565b6101fc6103c23660046135ce565b611d33565b6104966103d53660046135fa565b73ffffffffffffffffffffffffffffffffffffffff16600090815260066020908152604091829020825160808101845290546bffffffffffffffffffffffff8082168084526c0100000000000000000000000083049091169383018490527801000000000000000000000000000000000000000000000000820466ffffffffffffff169483018590527f010000000000000000000000000000000000000000000000000000000000000090910460ff16151560609092018290529093909290565b60405161021d949392919093151584526bffffffffffffffffffffffff92831660208501529116604083015266ffffffffffffff16606082015260800190565b6101fc6120ec565b600354640100000000900460ff1660405160ff909116815260200161021d565b61021161050c3660046130f8565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b60035461ffff16610317565b610294600081565b6101fc610564366004613317565b61211e565b6102116105773660046135fa565b612323565b6101fc61058a3660046130f8565b6123d0565b6101fc61059d3660046133be565b6123f5565b3360008181527f7d7ffb7a348e1c6a02869081a26547b49160dd3df72d1d75a570eb9b698292ec602052604090205460ff16610602576106027fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6382612497565b73ffffffffffffffffffffffffffffffffffffffff821661066c576040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024015b60405180910390fd5b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018590527f000000000000000000000000012414a392f9fa442a3109f1320c439c45518ac3169063a9059cbb906044016020604051808303816000875af1158015610701573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107259190613617565b506040805184815273ffffffffffffffffffffffffffffffffffffffff841660208201527f6141b54b56b8a52a8c6f5cd2a857f6117b18ffbf4d46bd3106f300a839cbf5ea910160405180910390a1505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061080c57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60008167ffffffffffffffff16600003610858576040517f656535ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61080c600767ffffffffffffffff841661254f565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561089781612562565b60ff8260ff1611156108da576040517f8b3c14c200000000000000000000000000000000000000000000000000000000815260ff83166004820152602401610663565b6003546040805160ff6401000000009093048316815291841660208301527f0cf38f82689f15f658c0dbcb00cfa212c86d35f943c3a511678dd201b58b6028910160405180910390a1506003805460ff909216640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff909216919091179055565b60008281526020819052604090206001015461097b81612562565b610985838361256c565b505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610a2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610663565b610a39828261265c565b5050565b610a45612713565b600a5460ff1615610a82576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040805160808101825260008082526020820181905291810182905260608101919091526002546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000012414a392f9fa442a3109f1320c439c45518ac373ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610b61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b859190613639565b905060005b8451811015610f1d576000858281518110610ba757610ba7613652565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff81166000908152600683526040808220815160808101835290546bffffffffffffffffffffffff80821683526c01000000000000000000000000820416958201959095527801000000000000000000000000000000000000000000000000850466ffffffffffffff169181018290527f010000000000000000000000000000000000000000000000000000000000000090940460ff1615156060850152929750909250908190610c9c908490610c7f9089906136b0565b89600001516bffffffffffffffffffffffff168a60600151612782565b9150915086602001516bffffffffffffffffffffffff168510158015610cbf5750815b15610ec55760208701516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526bffffffffffffffffffffffff90921660248201526000917f000000000000000000000000012414a392f9fa442a3109f1320c439c45518ac3169063a9059cbb906044016020604051808303816000875af1158015610d6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d939190613617565b90508015610e7d576020880151610db8906bffffffffffffffffffffffff16876136c3565b73ffffffffffffffffffffffffffffffffffffffff85811660009081526006602090815260409182902080547fff00000000000000ffffffffffffffffffffffffffffffffffffffffffffffff1678010000000000000000000000000000000000000000000000004266ffffffffffffff16021790558b81015191516bffffffffffffffffffffffff9092168252929850908416917f5fec4d72a579fa6fbce9b8225812805663c6ac1d75e7eb85ae596f67df158cc6910160405180910390a2610ebf565b60405173ffffffffffffffffffffffffffffffffffffffff8516907fa9ff7a9b96721b0e16adb7de9db0764fbfd6a4516d4d165f9564e8c3755eb10590600090a25b50610f07565b60405173ffffffffffffffffffffffffffffffffffffffff8416907f4d012ceef4d21203fc49000fc6d4ea5f0ac25f746cc7da267a2f6e3f538474ae90600090a25b5050508080610f15906136d6565b915050610b8a565b5050600a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610f7681612562565b610f7e61295c565b50565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610fab81612562565b60025460408051918252602082018490527ff2b1d9e58f462028f9adf2763241bf5cf547edf76fa5293f40cd32e6647eb0b6910160405180910390a150600255565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561101781612562565b73ffffffffffffffffffffffffffffffffffffffff831661107c576040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610663565b816bffffffffffffffffffffffff166000036110d4576040517f3e748a020000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff83166004820152602401610663565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600660205260409020547f0100000000000000000000000000000000000000000000000000000000000000900460ff16611156576040517f3869bbe600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff831660008181526006602090815260409182902080546bffffffffffffffffffffffff8781166c010000000000000000000000008181027fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff85161790945585519390920416808352928201529092917f5e00297b9c4f8fef460c4d7123316eeeb08a64a0930d1d9cae0b61b7f663b25491015b60405180910390a250505050565b600061121a82840184613218565b905061098581610a3d565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561124f81612562565b6003546040805161ffff620100009093048316815291841660208301527f9d83a57b5411f892fb01f5b534b69ce2c21f0594ba04c05344547e08e0eddb81910160405180910390a1506003805461ffff90921662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffff909216919091179055565b3360008181527f7d7ffb7a348e1c6a02869081a26547b49160dd3df72d1d75a570eb9b698292ec602052604090205460ff16611333576113337fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6382612497565b87861415806113425750878414155b8061134d5750878214155b15611384576040517f3869bbe600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061139060046129d9565b90505b80156113f65760006113b16113a96001846136c3565b6004906129e3565b90506113be6004826129ef565b5073ffffffffffffffffffffffffffffffffffffffff16600090815260066020526040812055806113ee8161370e565b915050611393565b5060006114036007612a11565b90505b801561144757600061142461141c6001846136c3565b600790612a1c565b509050611432600782612a38565b5050808061143f9061370e565b915050611406565b5060005b888110156118705760008a8a8381811061146757611467613652565b905060200201602081019061147c91906135fa565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600660205260409020549091507f0100000000000000000000000000000000000000000000000000000000000000900460ff161561151a576040517f9f2277f300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610663565b73ffffffffffffffffffffffffffffffffffffffff8116611567576040517f3869bbe600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b88888381811061157957611579613652565b905060200201602081019061158e9190613743565b6bffffffffffffffffffffffff166000036115d5576040517f3869bbe600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8686838181106115e7576115e7613652565b90506020020160208101906115fc9190613743565b6bffffffffffffffffffffffff16600003611643576040517f3869bbe600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180608001604052808a8a8581811061166057611660613652565b90506020020160208101906116759190613743565b6bffffffffffffffffffffffff16815260200188888581811061169a5761169a613652565b90506020020160208101906116af9190613743565b6bffffffffffffffffffffffff908116825260006020808401829052600160409485015273ffffffffffffffffffffffffffffffffffffffff861682526006815283822085518154928701519587015160609097015115157f0100000000000000000000000000000000000000000000000000000000000000027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff66ffffffffffffff989098167801000000000000000000000000000000000000000000000000029790971677ffffffffffffffffffffffffffffffffffffffffffffffff9686166c01000000000000000000000000027fffffffffffffffff00000000000000000000000000000000000000000000000090941691909516179190911793909316919091179290921790558585848181106117ec576117ec613652565b90506020020160208101906118019190613187565b67ffffffffffffffff1611156118505761184e85858481811061182657611826613652565b905060200201602081019061183b9190613187565b60079067ffffffffffffffff1683612a44565b505b61185b600482612a6f565b50508080611868906136d6565b91505061144b565b506040517f1dc3753221bdd8306e249da907041a3de685f38f5bf250f063e5a4e347cedeed90600090a1505050505050505050565b600060606118b1612713565b60006118bb611a85565b905080516000036118df575050604080516020810190915260008082529150611a7e565b6000805b825181101561197457600083828151811061190057611900613652565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff81166000908152600690925260409091205490915061195e906c0100000000000000000000000090046bffffffffffffffffffffffff168461375e565b925050808061196c906136d6565b9150506118e3565b506040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526bffffffffffffffffffffffff8216907f000000000000000000000000012414a392f9fa442a3109f1320c439c45518ac373ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611a0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a339190613639565b10611a6557600182604051602001611a4b9190613574565b604051602081830303815290604052935093505050611a7e565b6000604051806020016040528060008152509350935050505b9250929050565b60035460609061ffff80821691620100009004166000611aa560046129d9565b6003549091506000908290600190611ac890640100000000900460ff1643613783565b611ad290436136c3565b611adc91906136c3565b611ae7919040613783565b905060008361ffff168310611b00578361ffff16611b02565b825b6002549091506000908161ffff881667ffffffffffffffff811115611b2957611b296131e9565b604051908082528060200260200182016040528015611b52578160200160208202803683370190505b506040805160808101825260008082526020820181905291810182905260608101829052919250805b86811015611d0357611b8e6004896129e3565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600660209081526040808320815160808101835290546bffffffffffffffffffffffff80821683526c01000000000000000000000000820416938201939093527801000000000000000000000000000000000000000000000000830466ffffffffffffff169181018290527f010000000000000000000000000000000000000000000000000000000000000090920460ff161515606083015290955091935090611c78908490611c5b9089906136b0565b86600001516bffffffffffffffffffffffff168760600151612782565b5090508015611cd75782858881518110611c9457611c94613652565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015286611cc3816136d6565b9750508b61ffff168703611cd75750611d03565b5088611ce48960016136b0565b611cee9190613783565b611cf98260016136b0565b9098509050611b7b565b508961ffff168514611d13578483525b50909998505050505050505050565b6060611d2e6004612a91565b905090565b3360008181527f7d7ffb7a348e1c6a02869081a26547b49160dd3df72d1d75a570eb9b698292ec602052604090205460ff16611d9357611d937fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6382612497565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600660205260409020547f0100000000000000000000000000000000000000000000000000000000000000900460ff1615611e2e576040517f9f2277f300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610663565b73ffffffffffffffffffffffffffffffffffffffff8316158015611e5a575067ffffffffffffffff8216155b15611ea9576040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610663565b6000611ec0600767ffffffffffffffff8516612a9e565b905060008367ffffffffffffffff16118015611ed95750805b15611f03576000611ef5600767ffffffffffffffff861661254f565b9050611f0081612323565b50505b73ffffffffffffffffffffffffffffffffffffffff84161561209c5760408051608081018252670de0b6b3a76400008152677ce66c50e28400006020808301918252600083850181815260016060860190815273ffffffffffffffffffffffffffffffffffffffff8b16835260069093529490209251835492519451915115157f0100000000000000000000000000000000000000000000000000000000000000027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff66ffffffffffffff939093167801000000000000000000000000000000000000000000000000029290921677ffffffffffffffffffffffffffffffffffffffffffffffff6bffffffffffffffffffffffff9687166c01000000000000000000000000027fffffffffffffffff000000000000000000000000000000000000000000000000909516929096169190911792909217939093161791909117905561206e600485612a6f565b5067ffffffffffffffff83161561209757612095600767ffffffffffffffff851686612a44565b505b6120e6565b73ffffffffffffffffffffffffffffffffffffffff84161580156120ca575060008367ffffffffffffffff16115b156120e6576120e4600767ffffffffffffffff8516612a38565b505b50505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561211681612562565b610f7e612aaa565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561214881612562565b73ffffffffffffffffffffffffffffffffffffffff83166121ad576040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610663565b816bffffffffffffffffffffffff16600003612205576040517ffd89b5fc0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff83166004820152602401610663565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600660205260409020547f0100000000000000000000000000000000000000000000000000000000000000900460ff16612287576040517f3869bbe600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff831660008181526006602090815260409182902080547fffffffffffffffffffffffffffffffffffffffff00000000000000000000000081166bffffffffffffffffffffffff888116918217909355845192909116808352928201529092917f5e00297b9c4f8fef460c4d7123316eeeb08a64a0930d1d9cae0b61b7f663b25491016111fe565b3360008181527f7d7ffb7a348e1c6a02869081a26547b49160dd3df72d1d75a570eb9b698292ec602052604081205490919060ff16612386576123867fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6382612497565b6123916004846129ef565b156123c55773ffffffffffffffffffffffffffffffffffffffff8316600090815260066020526040812055600191506123ca565b600091505b50919050565b6000828152602081905260409020600101546123eb81612562565b610985838361265c565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561241f81612562565b6003546040805161ffff928316815291841660208301527ffbbc9ad96b08be5ffb0da53171d30710e564c4f591376544b6334809d7a993ec910160405180910390a150600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff92909216919091179055565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a39576124d581612b03565b6124e0836020612b22565b6040516020016124f19291906137be565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a00000000000000000000000000000000000000000000000000000000082526106639160040161383f565b600061255b8383612d65565b9392505050565b610f7e8133612497565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a395760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556125fe3390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615610a395760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60015460ff1615612780576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610663565b565b60008073ffffffffffffffffffffffffffffffffffffffff861615806127bd575073ffffffffffffffffffffffffffffffffffffffff86163b155b156127cd57506000905080612953565b6000808790508073ffffffffffffffffffffffffffffffffffffffff1663245a7bfc6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612858575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261285591810190613852565b60015b61286457879150612891565b73ffffffffffffffffffffffffffffffffffffffff811661288e5760008094509450505050612953565b91505b8173ffffffffffffffffffffffffffffffffffffffff1663d09dc3396040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612916575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261291391810190613639565b60015b1561294957868112801561292a5750428811155b80156129335750855b156129475760018394509450505050612953565b505b6000809350935050505b94509492505050565b612964612def565b600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b600061080c825490565b600061255b8383612e5b565b600061255b8373ffffffffffffffffffffffffffffffffffffffff8416612e85565b600061080c82612f7f565b6000808080612a2b8686612f8a565b9097909650945050505050565b600061255b8383612fb5565b6000612a67848473ffffffffffffffffffffffffffffffffffffffff8516612fd2565b949350505050565b600061255b8373ffffffffffffffffffffffffffffffffffffffff8416612fef565b6060600061255b8361303e565b600061255b838361309a565b612ab2612713565b600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016811790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258336129af565b606061080c73ffffffffffffffffffffffffffffffffffffffff831660145b60606000612b3183600261386f565b612b3c9060026136b0565b67ffffffffffffffff811115612b5457612b546131e9565b6040519080825280601f01601f191660200182016040528015612b7e576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110612bb557612bb5613652565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110612c1857612c18613652565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000612c5484600261386f565b612c5f9060016136b0565b90505b6001811115612cfc577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110612ca057612ca0613652565b1a60f81b828281518110612cb657612cb6613652565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93612cf58161370e565b9050612c62565b50831561255b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610663565b600081815260028301602052604081205480151580612d895750612d89848461309a565b61255b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b657900006044820152606401610663565b60015460ff16612780576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610663565b6000826000018281548110612e7257612e72613652565b9060005260206000200154905092915050565b60008181526001830160205260408120548015612f6e576000612ea96001836136c3565b8554909150600090612ebd906001906136c3565b9050818114612f22576000866000018281548110612edd57612edd613652565b9060005260206000200154905080876000018481548110612f0057612f00613652565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612f3357612f33613886565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061080c565b600091505061080c565b5092915050565b600061080c826129d9565b60008080612f9885856129e3565b600081815260029690960160205260409095205494959350505050565b6000818152600283016020526040812081905561255b83836130a6565b60008281526002840160205260408120829055612a6784846130b2565b60008181526001830160205260408120546130365750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561080c565b50600061080c565b60608160000180548060200260200160405190810160405280929190818152602001828054801561308e57602002820191906000526020600020905b81548152602001906001019080831161307a575b50505050509050919050565b600061255b83836130be565b600061255b8383612e85565b600061255b8383612fef565b6000818152600183016020526040812054151561255b565b73ffffffffffffffffffffffffffffffffffffffff81168114610f7e57600080fd5b6000806040838503121561310b57600080fd5b82359150602083013561311d816130d6565b809150509250929050565b60006020828403121561313a57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461255b57600080fd5b803567ffffffffffffffff8116811461318257600080fd5b919050565b60006020828403121561319957600080fd5b61255b8261316a565b6000602082840312156131b457600080fd5b813560ff8116811461255b57600080fd5b6000602082840312156131d757600080fd5b5035919050565b8035613182816130d6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602080838503121561322b57600080fd5b823567ffffffffffffffff8082111561324357600080fd5b818501915085601f83011261325757600080fd5b813581811115613269576132696131e9565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811085821117156132ac576132ac6131e9565b6040529182528482019250838101850191888311156132ca57600080fd5b938501935b828510156132ef576132e0856131de565b845293850193928501926132cf565b98975050505050505050565b80356bffffffffffffffffffffffff8116811461318257600080fd5b6000806040838503121561332a57600080fd5b8235613335816130d6565b9150613343602084016132fb565b90509250929050565b6000806020838503121561335f57600080fd5b823567ffffffffffffffff8082111561337757600080fd5b818501915085601f83011261338b57600080fd5b81358181111561339a57600080fd5b8660208285010111156133ac57600080fd5b60209290920196919550909350505050565b6000602082840312156133d057600080fd5b813561ffff8116811461255b57600080fd5b60008083601f8401126133f457600080fd5b50813567ffffffffffffffff81111561340c57600080fd5b6020830191508360208260051b8501011115611a7e57600080fd5b6000806000806000806000806080898b03121561344357600080fd5b883567ffffffffffffffff8082111561345b57600080fd5b6134678c838d016133e2565b909a50985060208b013591508082111561348057600080fd5b61348c8c838d016133e2565b909850965060408b01359150808211156134a557600080fd5b6134b18c838d016133e2565b909650945060608b01359150808211156134ca57600080fd5b506134d78b828c016133e2565b999c989b5096995094979396929594505050565b60005b838110156135065781810151838201526020016134ee565b50506000910152565b600081518084526135278160208601602086016134eb565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8215158152604060208201526000612a67604083018461350f565b6020808252825182820181905260009190848201906040850190845b818110156135c257835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101613590565b50909695505050505050565b600080604083850312156135e157600080fd5b82356135ec816130d6565b91506133436020840161316a565b60006020828403121561360c57600080fd5b813561255b816130d6565b60006020828403121561362957600080fd5b8151801515811461255b57600080fd5b60006020828403121561364b57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561080c5761080c613681565b8181038181111561080c5761080c613681565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361370757613707613681565b5060010190565b60008161371d5761371d613681565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b60006020828403121561375557600080fd5b61255b826132fb565b6bffffffffffffffffffffffff818116838216019080821115612f7857612f78613681565b6000826137b9577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516137f68160178501602088016134eb565b7f206973206d697373696e6720726f6c652000000000000000000000000000000060179184019182015283516138338160288401602088016134eb565b01602801949350505050565b60208152600061255b602083018461350f565b60006020828403121561386457600080fd5b815161255b816130d6565b808202811582820484141761080c5761080c613681565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000813000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000001c911eec9b3016716c5e708b02d3b4f679807954000000000000000000000000012414a392f9fa442a3109f1320c439c45518ac30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000a
-----Decoded View---------------
Arg [0] : admin (address): 0x1C911EEc9B3016716c5E708B02d3B4f679807954
Arg [1] : linkToken (address): 0x012414A392F9FA442a3109f1320c439C45518aC3
Arg [2] : minWaitPeriodSeconds (uint256): 0
Arg [3] : maxPerform (uint16): 10
Arg [4] : maxCheck (uint16): 30
Arg [5] : upkeepInterval (uint8): 10
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000001c911eec9b3016716c5e708b02d3b4f679807954
Arg [1] : 000000000000000000000000012414a392f9fa442a3109f1320c439c45518ac3
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [3] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [4] : 000000000000000000000000000000000000000000000000000000000000001e
Arg [5] : 000000000000000000000000000000000000000000000000000000000000000a
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in GLMR
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.