Overview
ETH Balance
ETH Value
$0.00Latest 25 from a total of 4,850,439 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Perform Upkeep | 22056643 | 6 secs ago | IN | 0 ETH | 0.00000078 | ||||
| Perform Upkeep | 22056642 | 8 secs ago | IN | 0 ETH | 0.00000018 | ||||
| Perform Upkeep | 22056641 | 10 secs ago | IN | 0 ETH | 0.00000017 | ||||
| Perform Upkeep | 22056639 | 14 secs ago | IN | 0 ETH | 0.00000018 | ||||
| Perform Upkeep | 22056638 | 16 secs ago | IN | 0 ETH | 0.00000055 | ||||
| Perform Upkeep | 22056635 | 22 secs ago | IN | 0 ETH | 0.00000017 | ||||
| Perform Upkeep | 22056631 | 30 secs ago | IN | 0 ETH | 0.0000011 | ||||
| Perform Upkeep | 22056630 | 32 secs ago | IN | 0 ETH | 0.00000063 | ||||
| Perform Upkeep | 22056627 | 38 secs ago | IN | 0 ETH | 0.00000041 | ||||
| Perform Upkeep | 22056625 | 42 secs ago | IN | 0 ETH | 0.00000016 | ||||
| Perform Upkeep | 22056620 | 52 secs ago | IN | 0 ETH | 0.00000059 | ||||
| Perform Upkeep | 22056619 | 54 secs ago | IN | 0 ETH | 0.00000036 | ||||
| Perform Upkeep | 22056619 | 54 secs ago | IN | 0 ETH | 0.00000015 | ||||
| Perform Upkeep | 22056617 | 58 secs ago | IN | 0 ETH | 0.00000015 | ||||
| Perform Upkeep | 22056613 | 1 min ago | IN | 0 ETH | 0.00000028 | ||||
| Perform Upkeep | 22056612 | 1 min ago | IN | 0 ETH | 0.00000047 | ||||
| Perform Upkeep | 22056607 | 1 min ago | IN | 0 ETH | 0.00000055 | ||||
| Perform Upkeep | 22056606 | 1 min ago | IN | 0 ETH | 0.00000015 | ||||
| Perform Upkeep | 22056601 | 1 min ago | IN | 0 ETH | 0.0000006 | ||||
| Perform Upkeep | 22056601 | 1 min ago | IN | 0 ETH | 0.00000044 | ||||
| Perform Upkeep | 22056601 | 1 min ago | IN | 0 ETH | 0.00000015 | ||||
| Perform Upkeep | 22056599 | 1 min ago | IN | 0 ETH | 0.00000024 | ||||
| Perform Upkeep | 22056595 | 1 min ago | IN | 0 ETH | 0.00000051 | ||||
| Perform Upkeep | 22056595 | 1 min ago | IN | 0 ETH | 0.00000014 | ||||
| Perform Upkeep | 22056594 | 1 min ago | IN | 0 ETH | 0.00000013 |
View more zero value Internal Transactions in Advanced View mode
Cross-Chain Transactions
Contract Source Code Verified (Exact Match)
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";
import {AdrastiaDataStreamsUpdater} from "./AdrastiaDataStreamsUpdater.sol";
interface IWorldChainFeed {
function FEED_ID() external view returns (bytes32);
function updatePriceData(
bytes memory verifyReportRequest,
bytes memory parameterPayload
) external returns (bytes memory);
}
/**
* @title AdrastiaWorldChainDataStreamsUpdater
* @author Tyler Loewen, TRILEZ SOFTWARE INC. dba. Adrastia
* @notice This contract is an implementation of the AdrastiaDataStreamsUpdater for World Chain feeds.
*
* These feeds handle verification themselves, so this contract changes performUpkeep to call the feed contract
* directly with the unverified report. The feed contract will then verify the report and update the price data.
*
* This contract assumes that there are no LINK token fees associated with the verification of the report. The
* perforkUpkeep function does not implement access control because it's unable to spend LINK tokens. The
* approveVerifierFeeSpend function is a no-op.
*/
contract AdrastiaWorldChainDataStreamsUpdater is AdrastiaDataStreamsUpdater {
using EnumerableMap for EnumerableMap.Bytes32ToAddressMap;
constructor(address initialAdmin) AdrastiaDataStreamsUpdater(address(0), initialAdmin, initialAdmin) {}
function performUpkeep(bytes calldata performData) external payable virtual override {
bytes[] memory unverifiedReports = abi.decode(performData, (bytes[]));
bytes memory parameterPayload = abi.encode(address(0));
uint256 successCount = 0;
for (uint256 i = 0; i < unverifiedReports.length; ++i) {
// Decode unverified report to extract report data
(, bytes memory reportData) = abi.decode(unverifiedReports[i], (bytes32[3], bytes));
// Extract extract the feedId from the reportData, which is always stored in the first 32 bytes of the
// report data.
// Extract the observationsTimestamp for the report. Used for short-circuiting the update if old.
(bytes32 feedId, , uint32 feedObservationsTimestamp) = abi.decode(reportData, (bytes32, uint32, uint32));
// Get the data stream address
(bool feedExists_, address targetFeed) = _feedTargets.tryGet(feedId);
if (!feedExists_) {
// The updater should never try to update a feed that is not registered
revert FeedNotRegistered(feedId);
}
// Get the contract latest report timestamp
(, uint256 storedTimestamp) = readUnderlyingFeed(feedId);
if (storedTimestamp >= feedObservationsTimestamp) {
// The provided report is old, skip it
emit FeedUpdateSkipped(feedId, targetFeed, storedTimestamp, feedObservationsTimestamp, block.timestamp);
continue;
}
// Pass the unverified report to the feed contract for verification and update
(bool success, bytes memory data) = targetFeed.call(
abi.encodeWithSelector(IWorldChainFeed.updatePriceData.selector, unverifiedReports[i], parameterPayload)
);
if (success) {
// Emit an event for the successful update
emit FeedUpdatePerformed(feedId, targetFeed, block.timestamp);
++successCount;
} else {
// Log the error
emit FeedUpdateFailed(feedId, targetFeed, data, block.timestamp);
}
}
if (successCount == 0) {
revert NoFeedsUpdated();
}
}
function approveVerifierFeeSpend() public virtual override {
// NO-OP
}
function _getIdFromFeed(address feed) internal view virtual override returns (bytes32) {
return IWorldChainFeed(feed).FEED_ID();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../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:
*
* ```solidity
* 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}:
*
* ```solidity
* 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. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
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 returns (bool) {
return _roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @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 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 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 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 `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @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 Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/extensions/AccessControlEnumerable.sol)
pragma solidity ^0.8.20;
import {IAccessControlEnumerable} from "./IAccessControlEnumerable.sol";
import {AccessControl} from "../AccessControl.sol";
import {EnumerableSet} from "../../utils/structs/EnumerableSet.sol";
/**
* @dev Extension of {AccessControl} that allows enumerating the members of each role.
*/
abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {
using EnumerableSet for EnumerableSet.AddressSet;
mapping(bytes32 role => EnumerableSet.AddressSet) private _roleMembers;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {
return _roleMembers[role].at(index);
}
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {
return _roleMembers[role].length();
}
/**
* @dev Return all accounts that have `role`
*
* 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 getRoleMembers(bytes32 role) public view virtual returns (address[] memory) {
return _roleMembers[role].values();
}
/**
* @dev Overload {AccessControl-_grantRole} to track enumerable memberships
*/
function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {
bool granted = super._grantRole(role, account);
if (granted) {
_roleMembers[role].add(account);
}
return granted;
}
/**
* @dev Overload {AccessControl-_revokeRole} to track enumerable memberships
*/
function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {
bool revoked = super._revokeRole(role, account);
if (revoked) {
_roleMembers[role].remove(account);
}
return revoked;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/extensions/IAccessControlEnumerable.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "../IAccessControl.sol";
/**
* @dev External interface of AccessControlEnumerable declared to support ERC-165 detection.
*/
interface IAccessControlEnumerable is IAccessControl {
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) external view returns (address);
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC-165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @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.
*/
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. This account bears the admin role (for the granted role).
* Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
*/
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 `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
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 value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` 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 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 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);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* 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[ERC 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 v5.1.0) (utils/structs/EnumerableMap.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js.
pragma solidity ^0.8.20;
import {EnumerableSet} from "./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.
*
* ```solidity
* 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
* - `uint256 -> bytes32` (`UintToBytes32Map`) since v5.1.0
* - `address -> address` (`AddressToAddressMap`) since v5.1.0
* - `address -> bytes32` (`AddressToBytes32Map`) since v5.1.0
* - `bytes32 -> address` (`Bytes32ToAddressMap`) since v5.1.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 `UintToAddressMap` are just wrappers around the underlying Map.
// This means that we can only create new EnumerableMaps for types that fit in bytes32.
/**
* @dev Query for a nonexistent map key.
*/
error EnumerableMapNonexistentKey(bytes32 key);
struct Bytes32ToBytes32Map {
// Storage of keys
EnumerableSet.Bytes32Set _keys;
mapping(bytes32 key => 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 key, bytes32 value) {
bytes32 atKey = map._keys.at(index);
return (atKey, map._values[atKey]);
}
/**
* @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 exists, bytes32 value) {
bytes32 val = map._values[key];
if (val == bytes32(0)) {
return (contains(map, key), bytes32(0));
} else {
return (true, val);
}
}
/**
* @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];
if (value == 0 && !contains(map, key)) {
revert EnumerableMapNonexistentKey(key);
}
return value;
}
/**
* @dev Return the an array containing all the keys
*
* 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) {
return map._keys.values();
}
// 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 map. 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 map. 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 key, uint256 value) {
(bytes32 atKey, bytes32 val) = at(map._inner, index);
return (uint256(atKey), uint256(val));
}
/**
* @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 exists, uint256 value) {
(bool success, bytes32 val) = tryGet(map._inner, bytes32(key));
return (success, uint256(val));
}
/**
* @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 Return the an array containing all the keys
*
* 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(UintToUintMap storage map) internal view returns (uint256[] memory) {
bytes32[] memory store = keys(map._inner);
uint256[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// 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 map. 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 map. 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 key, address value) {
(bytes32 atKey, bytes32 val) = at(map._inner, index);
return (uint256(atKey), address(uint160(uint256(val))));
}
/**
* @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 exists, address value) {
(bool success, bytes32 val) = tryGet(map._inner, bytes32(key));
return (success, address(uint160(uint256(val))));
}
/**
* @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 Return the an array containing all the keys
*
* 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) {
bytes32[] memory store = keys(map._inner);
uint256[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// UintToBytes32Map
struct UintToBytes32Map {
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(UintToBytes32Map storage map, uint256 key, bytes32 value) internal returns (bool) {
return set(map._inner, bytes32(key), value);
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(UintToBytes32Map 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(UintToBytes32Map 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(UintToBytes32Map storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. 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(UintToBytes32Map storage map, uint256 index) internal view returns (uint256 key, bytes32 value) {
(bytes32 atKey, bytes32 val) = at(map._inner, index);
return (uint256(atKey), val);
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(UintToBytes32Map storage map, uint256 key) internal view returns (bool exists, bytes32 value) {
(bool success, bytes32 val) = tryGet(map._inner, bytes32(key));
return (success, val);
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(UintToBytes32Map storage map, uint256 key) internal view returns (bytes32) {
return get(map._inner, bytes32(key));
}
/**
* @dev Return the an array containing all the keys
*
* 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(UintToBytes32Map storage map) internal view returns (uint256[] memory) {
bytes32[] memory store = keys(map._inner);
uint256[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// 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 map. 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 map. 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 key, uint256 value) {
(bytes32 atKey, bytes32 val) = at(map._inner, index);
return (address(uint160(uint256(atKey))), uint256(val));
}
/**
* @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 exists, uint256 value) {
(bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key))));
return (success, uint256(val));
}
/**
* @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 Return the an array containing all the keys
*
* 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(AddressToUintMap storage map) internal view returns (address[] memory) {
bytes32[] memory store = keys(map._inner);
address[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// AddressToAddressMap
struct AddressToAddressMap {
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(AddressToAddressMap storage map, address key, address value) internal returns (bool) {
return set(map._inner, bytes32(uint256(uint160(key))), bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(AddressToAddressMap 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(AddressToAddressMap 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(AddressToAddressMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. 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(AddressToAddressMap storage map, uint256 index) internal view returns (address key, address value) {
(bytes32 atKey, bytes32 val) = at(map._inner, index);
return (address(uint160(uint256(atKey))), address(uint160(uint256(val))));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(AddressToAddressMap storage map, address key) internal view returns (bool exists, address value) {
(bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key))));
return (success, address(uint160(uint256(val))));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(AddressToAddressMap storage map, address key) internal view returns (address) {
return address(uint160(uint256(get(map._inner, bytes32(uint256(uint160(key)))))));
}
/**
* @dev Return the an array containing all the keys
*
* 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(AddressToAddressMap storage map) internal view returns (address[] memory) {
bytes32[] memory store = keys(map._inner);
address[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// AddressToBytes32Map
struct AddressToBytes32Map {
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(AddressToBytes32Map storage map, address key, bytes32 value) internal returns (bool) {
return set(map._inner, bytes32(uint256(uint160(key))), value);
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(AddressToBytes32Map 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(AddressToBytes32Map 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(AddressToBytes32Map storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. 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(AddressToBytes32Map storage map, uint256 index) internal view returns (address key, bytes32 value) {
(bytes32 atKey, bytes32 val) = at(map._inner, index);
return (address(uint160(uint256(atKey))), val);
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(AddressToBytes32Map storage map, address key) internal view returns (bool exists, bytes32 value) {
(bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key))));
return (success, val);
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(AddressToBytes32Map storage map, address key) internal view returns (bytes32) {
return get(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Return the an array containing all the keys
*
* 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(AddressToBytes32Map storage map) internal view returns (address[] memory) {
bytes32[] memory store = keys(map._inner);
address[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// 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 map. 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 map. 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 key, uint256 value) {
(bytes32 atKey, bytes32 val) = at(map._inner, index);
return (atKey, uint256(val));
}
/**
* @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 exists, uint256 value) {
(bool success, bytes32 val) = tryGet(map._inner, key);
return (success, uint256(val));
}
/**
* @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 Return the an array containing all the keys
*
* 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) {
bytes32[] memory store = keys(map._inner);
bytes32[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// Bytes32ToAddressMap
struct Bytes32ToAddressMap {
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(Bytes32ToAddressMap storage map, bytes32 key, address value) internal returns (bool) {
return set(map._inner, key, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(Bytes32ToAddressMap 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(Bytes32ToAddressMap 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(Bytes32ToAddressMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. 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(Bytes32ToAddressMap storage map, uint256 index) internal view returns (bytes32 key, address value) {
(bytes32 atKey, bytes32 val) = at(map._inner, index);
return (atKey, address(uint160(uint256(val))));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (bool exists, address value) {
(bool success, bytes32 val) = tryGet(map._inner, key);
return (success, address(uint160(uint256(val))));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (address) {
return address(uint160(uint256(get(map._inner, key))));
}
/**
* @dev Return the an array containing all the keys
*
* 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(Bytes32ToAddressMap storage map) internal view returns (bytes32[] memory) {
bytes32[] memory store = keys(map._inner);
bytes32[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
/**
* @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.
*
* ```solidity
* 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 is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @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._positions[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 cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 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 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[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._positions[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;
assembly ("memory-safe") {
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;
assembly ("memory-safe") {
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;
assembly ("memory-safe") {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
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 payable;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface AdrastiaDataStreamsCommon {
error InvalidReportVersion(uint16 reportVersion);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import {AccessControlEnumerable} from "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";
import {AutomationCompatibleInterface} from "../AutomationCompatibleInterface.sol";
import {AdrastiaDataStreamsCommon} from "./AdrastiaDataStreamsCommon.sol";
import {IDataStreamsFeed} from "./IDataStreamsFeed.sol";
import {IVerifierProxy} from "./vendor/IVerifierProxy.sol";
import {IFeeManager} from "./vendor/IFeeManager.sol";
import {Common} from "./vendor/Common.sol";
import {AggregatorV3Interface} from "./vendor/AggregatorV3Interface.sol";
/**
* @title AdrastiaDataStreamsUpdater
* @author Tyler Loewen, TRILEZ SOFTWARE INC. dba. Adrastia
* @notice The Adrastia Data Streams Updater contract is responsible for updating registered Data Streams feeds with new
* reports. It verifies the reports using the Chainlink verifier proxy and its verifyBulk function, then passes
* the verified reports to the respective Data Streams feed for processing.
*
* Access is controlled using OpenZeppelin's AccessControlEnumerable, allowing for fine-grained permissions.
* The roles are setup as follows:
* - ADMIN: Can withdraw ERC20 and native tokens, and manage the role and sub-roles.
* - CONFIG_ADMIN: Can register, unregister, and change feeds.
* - UPDATER_ADMIN: Can manage the ORACLE_UPDATER role.
* - ORACLE_UPDATER: Can call performUpkeep to update feeds.
*
* Granting the ORACLE_UPDATER role to `address(0)` allows anyone to call performUpkeep to update feeds.
*/
contract AdrastiaDataStreamsUpdater is
AutomationCompatibleInterface,
AdrastiaDataStreamsCommon,
AccessControlEnumerable
{
using EnumerableMap for EnumerableMap.Bytes32ToAddressMap;
/**
* @notice The action to take when registering or unregistering a feed.
*/
enum FeedRegistrationAction {
REGISTER,
UNREGISTER
}
struct FeedIdAndAddress {
bytes32 feedId;
address feed;
}
bytes32 public constant ADMIN = keccak256("ADMIN_ROLE");
bytes32 public constant CONFIG_ADMIN = keccak256("CONFIG_ADMIN_ROLE");
bytes32 public constant UPDATER_ADMIN = keccak256("UPDATER_ADMIN_ROLE");
bytes32 public constant ORACLE_UPDATER = keccak256("ORACLE_UPDATER_ROLE");
/**
* @notice The precision factor to use when calculating the change between two numbers.
* @dev Fixed to 8 decimal places.
*/
uint256 public constant CHANGE_PRECISION = 10 ** 8;
/**
* @notice The Chainlink verifier proxy contract.
*/
IVerifierProxy public immutable verifierProxy;
/**
* @notice The mapping of feed IDs to their respective feed addresses.
*/
EnumerableMap.Bytes32ToAddressMap internal _feedTargets;
/**
* @notice Emitted when a feed update is skipped due to the provided report timestamp being older than the stored
* timestamp.
*
* @param feedId The feed ID.
* @param feed The feed address.
* @param storedTimestamp The stored timestamp of the feed.
* @param providedTimestamp The provided timestamp of the report.
* @param timestamp The timestamp of the event.
*/
event FeedUpdateSkipped(
bytes32 indexed feedId,
address indexed feed,
uint256 storedTimestamp,
uint256 providedTimestamp,
uint256 timestamp
);
/**
* @notice Emitted when a feed update is performed successfully.
*
* @param feedId The feed ID.
* @param feed The feed address.
* @param timestamp The timestamp of the event.
*/
event FeedUpdatePerformed(bytes32 indexed feedId, address indexed feed, uint256 timestamp);
/**
* @notice Emitted when a feed update fails.
*
* @param feedId The feed ID.
* @param feed The feed address.
* @param data The error data.
* @param timestamp The timestamp of the event.
*/
event FeedUpdateFailed(bytes32 indexed feedId, address indexed feed, bytes data, uint256 timestamp);
/**
* @notice Emitted when a feed is registered or unregistered.
* @param feedId The feed ID.
* @param action The action taken.
* @param timestamp The timestamp of the event.
*/
event FeedRegistrationChanged(bytes32 indexed feedId, FeedRegistrationAction indexed action, uint256 timestamp);
/**
* @notice Emitted when a feed target is changed.
* @param feedId The feed ID.
* @param oldFeed The old feed address.
* @param newFeed The new feed address.
* @param timestamp The timestamp of the event.
*/
event FeedTargetChanged(
bytes32 indexed feedId,
address indexed oldFeed,
address indexed newFeed,
uint256 timestamp
);
/**
* @notice Thrown when performing an operation using a feed ID that is not registered.
* @param feedId The feed ID.
*/
error FeedNotRegistered(bytes32 feedId);
/**
* @notice Thrown when a feed is already registered.
* @param feedId The feed ID.
*/
error FeedAlreadyRegistered(bytes32 feedId);
/**
* @notice Thrown when the provided feed ID does not match the expected feed ID.
*/
error FeedMismatch(bytes32 expectedFeedId, bytes32 providedFeedId);
/**
* @notice Thrown when no feeds were updated during a performUpkeep call.
*/
error NoFeedsUpdated();
/**
* @notice Thrown when the verified reports length does not match the unverified reports length.
* @param unverifiedReportsLength The length of the unverified reports.
* @param verifiedReportsLength The length of the verified reports.
*/
error ReportLengthMismatch(uint256 unverifiedReportsLength, uint256 verifiedReportsLength);
/**
* @notice Modifier to make a function callable only by a certain role. In addition to checking the sender's role,
* `address(0)` 's role is also considered. Granting a role to `address(0)` is equivalent to enabling this role for
* everyone.
* @param role The role to check.
*/
modifier onlyRoleOrOpenRole(bytes32 role) {
if (!hasRole(role, address(0))) {
if (!hasRole(role, msg.sender)) revert AccessControlUnauthorizedAccount(msg.sender, role);
}
_;
}
/**
* @notice Constructs the Adrastia Data Streams Updater contract.
* @param _verifierProxy The Chainlink verifier proxy contract.
* @param initialAdmin The initial admin address.
* @param initialUpdaterAdmin The initial updater admin address.
*/
constructor(address _verifierProxy, address initialAdmin, address initialUpdaterAdmin) {
if (initialAdmin == address(0) || initialUpdaterAdmin == address(0)) {
revert("Invalid initial admins");
}
verifierProxy = IVerifierProxy(_verifierProxy);
_initializeRoles(initialAdmin, initialUpdaterAdmin);
approveVerifierFeeSpend();
}
/**
* @notice Registers a new feed with the contract.
* @param feedId The feed ID.
* @param feed The feed address.
*/
function registerFeed(bytes32 feedId, address feed) external virtual onlyRole(CONFIG_ADMIN) {
bytes32 contractFeedId = _getIdFromFeed(feed);
if (feedId != contractFeedId) {
revert FeedMismatch(contractFeedId, feedId);
}
(bool feedExists_, address oldFeed) = _feedTargets.tryGet(feedId);
if (feedExists_) {
revert FeedAlreadyRegistered(feedId);
}
_feedTargets.set(feedId, feed);
emit FeedRegistrationChanged(feedId, FeedRegistrationAction.REGISTER, block.timestamp);
emit FeedTargetChanged(feedId, oldFeed, feed, block.timestamp);
}
/**
* @notice Changes the feed address for a registered feed.
* @param feedId The feed ID.
* @param feed The new feed address.
*/
function changeFeed(bytes32 feedId, address feed) external virtual onlyRole(CONFIG_ADMIN) {
bytes32 contractFeedId = _getIdFromFeed(feed);
if (feedId != contractFeedId) {
revert FeedMismatch(contractFeedId, feedId);
}
(bool feedExists_, address oldFeed) = _feedTargets.tryGet(feedId);
if (!feedExists_) {
revert FeedNotRegistered(feedId);
}
_feedTargets.set(feedId, feed);
emit FeedTargetChanged(feedId, oldFeed, feed, block.timestamp);
}
/**
* @notice Unregisters a feed from the contract.
* @param feedId The feed ID.
*/
function unregisterFeed(bytes32 feedId) external virtual onlyRole(CONFIG_ADMIN) {
(bool feedExists_, address oldFeed) = _feedTargets.tryGet(feedId);
if (!feedExists_) {
revert FeedNotRegistered(feedId);
}
_feedTargets.remove(feedId);
emit FeedTargetChanged(feedId, oldFeed, address(0), block.timestamp);
emit FeedRegistrationChanged(feedId, FeedRegistrationAction.UNREGISTER, block.timestamp);
}
/**
* @notice Gets the feed address for a given feed ID, if it exists.
*
* @param feedId The feed ID.
*
* @custom:throws FeedNotRegistered if the feed ID is not registered.
*
* @return The feed address.
*/
function getFeed(bytes32 feedId) external view virtual returns (address) {
(bool feedExists_, address targetFeed) = _feedTargets.tryGet(feedId);
if (!feedExists_) {
revert FeedNotRegistered(feedId);
}
return targetFeed;
}
/**
* @notice Checks if a feed exists for a given feed ID.
*
* @param feedId The feed ID.
*
* @return True if the feed exists, false otherwise.
*/
function feedExists(bytes32 feedId) external view virtual returns (bool) {
return _feedTargets.contains(feedId);
}
/**
* @notice Gets the number of registered feeds.
*
* @return The number of registered feeds.
*/
function getFeedCount() external view virtual returns (uint256) {
return _feedTargets.length();
}
/**
* @notice Gets the feed IDs of all registered feeds.
*
* @return An array of feed IDs.
*/
function getFeedIds() external view virtual returns (bytes32[] memory) {
return _feedTargets.keys();
}
/**
* @notice Gets all of the pairs of feed IDs and their respective feed addresses.
*
* @return An array of FeedIdAndAddress structs containing the feed ID and feed address.
*/
function getFeedMapping() external view virtual returns (FeedIdAndAddress[] memory) {
uint256 length = _feedTargets.length();
FeedIdAndAddress[] memory feedMapping = new FeedIdAndAddress[](length);
for (uint256 i = 0; i < length; ++i) {
(bytes32 feedId, address feed) = _feedTargets.at(i);
feedMapping[i] = FeedIdAndAddress({feedId: feedId, feed: feed});
}
return feedMapping;
}
/**
* @notice Withdraws ERC20 tokens from the contract.
* @param token The token address.
* @param to The recipient address.
* @param amount The amount to withdraw.
*/
function withdrawErc20(address token, address to, uint256 amount) external virtual onlyRole(ADMIN) {
SafeERC20.safeTransfer(IERC20(token), to, amount);
}
/**
* @notice Withdraws native tokens from the contract.
* @param to The recipient address.
* @param amount The amount to withdraw.
*/
function withdrawNative(address to, uint256 amount) external virtual onlyRole(ADMIN) {
(bool success, ) = to.call{value: amount}("");
require(success, "Transfer failed");
}
/**
* @notice Approves the current verifier reward manager to spend an unlimited amount of LINK.
* @dev Can only be called once, unless the fee manager returns a different LINK address. Impotent otherwise.
*/
function approveVerifierFeeSpend() public virtual {
// Retrieve fee manager and reward manager
IFeeManager feeManager = IFeeManager(address(verifierProxy.s_feeManager()));
if (address(feeManager) == address(0)) {
// Fees are disabled. Nothing to approve.
return;
}
address rewardManager = feeManager.i_rewardManager();
if (rewardManager == address(0)) {
// No reward manager. Nothing to approve.
return;
}
IERC20 feeToken = IERC20(feeManager.i_linkAddress());
if (address(feeToken) == address(0)) {
// No fee token. Nothing to approve.
return;
}
uint256 allowance = feeToken.allowance(address(this), rewardManager);
if (allowance == 0) {
feeToken.approve(rewardManager, type(uint256).max);
}
}
/**
* @notice Checks if an update is needed for a specific price feed.
* @dev The feed being checked must be registered with the contract.
* @param checkData An array of bytes containing:
* - feedId: First 32 bytes - The feed ID.
* - updateThreshold: Second 32 bytes - The percentage change threshold that must be met for an update to be needed.
* - heartbeat: Third 32 bytes - The maximum time in seconds since the last update before an update is needed.
* - offchainPrice: Fourth 32 bytes - The offchain price to compare the current onchain value against.
* - offchainPublishTime: Fifth 32 bytes - The timestamp of the offchain price.
* @return upkeepNeeded True if an update is needed, false otherwise.
* @return performData Encoded onchain price, timestamp, whether the heartbeat was triggered, and whether the price
* deviation was triggered. The onchain price and timestamp will be zero if the onchain report is expired or missing.
*/
function checkUpkeep(
bytes memory checkData
) public view virtual returns (bool upkeepNeeded, bytes memory performData) {
if (checkData.length != 160) {
require(checkData.length >= 96, "Missing feed data.");
if (checkData.length < 128) {
revert("Missing offchain price.");
}
if (checkData.length < 160) {
revert("Missing offchain timestamp.");
}
revert("Too much data.");
}
(
bytes32 feedId,
uint256 updateThreshold,
uint256 heartbeat,
int256 offchainPrice,
uint256 offchainPublishTime
) = abi.decode(checkData, (bytes32, uint256, uint256, int256, uint256));
if (!_feedTargets.contains(feedId)) {
revert FeedNotRegistered(feedId);
}
(int256 price, uint256 timestamp) = readUnderlyingFeed(feedId);
bool heartbeatTriggered = false;
bool priceDeviationTriggered = false;
// Only check trigger conditions if the offchain price is not older than the onchain price
if (offchainPublishTime >= timestamp) {
uint256 timeSinceUpdate = offchainPublishTime - timestamp;
if (timeSinceUpdate >= heartbeat) {
heartbeatTriggered = true;
}
(uint256 change, bool isMaximalChange) = calculateChange(price, offchainPrice);
if (isMaximalChange || change >= updateThreshold) {
priceDeviationTriggered = true;
}
}
upkeepNeeded = heartbeatTriggered || priceDeviationTriggered;
performData = abi.encode(price, timestamp, heartbeatTriggered, priceDeviationTriggered);
}
/**
* @notice Updates the latest reports for registered feeds.
* @param performData An encoded array of bytes representing the unverified reports.
*/
function performUpkeep(bytes calldata performData) external payable virtual onlyRoleOrOpenRole(ORACLE_UPDATER) {
bytes[] memory unverifiedReports = abi.decode(performData, (bytes[]));
// Retrieve fee manager and reward manager
IFeeManager feeManager = IFeeManager(address(verifierProxy.s_feeManager()));
// Set the fee token address (LINK in this case)
address feeTokenAddress;
if (address(feeManager) == address(0)) {
// No fee manager... are fees disabled?
feeTokenAddress = address(0);
} else {
feeTokenAddress = feeManager.i_linkAddress();
}
bytes[] memory verifiedReports = verifierProxy.verifyBulk(unverifiedReports, abi.encode(feeTokenAddress));
if (verifiedReports.length != unverifiedReports.length) {
revert ReportLengthMismatch(unverifiedReports.length, verifiedReports.length);
}
uint256 successCount = 0;
for (uint256 i = 0; i < unverifiedReports.length; ++i) {
// Decode unverified report to extract report data
(, bytes memory reportData) = abi.decode(unverifiedReports[i], (bytes32[3], bytes));
// Extract report version from reportData
uint16 reportVersion = (uint16(uint8(reportData[0])) << 8) | uint16(uint8(reportData[1]));
// Extract extract the feedId from the reportData, which is always stored in the first 32 bytes of the
// report data.
// Extract the observationsTimestamp for the report. Used for short-circuiting the update if old.
(bytes32 feedId, , uint32 feedObservationsTimestamp) = abi.decode(reportData, (bytes32, uint32, uint32));
// Get the data stream address
(bool feedExists_, address targetFeed) = _feedTargets.tryGet(feedId);
if (!feedExists_) {
// The updater should never try to update a feed that is not registered
revert FeedNotRegistered(feedId);
}
// Get the contract latest report timestamp
(, uint256 storedTimestamp) = readUnderlyingFeed(feedId);
if (storedTimestamp >= feedObservationsTimestamp) {
// The provided report is old, skip it
emit FeedUpdateSkipped(feedId, targetFeed, storedTimestamp, feedObservationsTimestamp, block.timestamp);
continue;
}
// Attempt to write the report to the data stream
(bool success, bytes memory data) = targetFeed.call(
abi.encodeWithSelector(IDataStreamsFeed.updateReport.selector, reportVersion, verifiedReports[i])
);
if (success) {
// Emit an event for the successful update
emit FeedUpdatePerformed(feedId, targetFeed, block.timestamp);
++successCount;
} else {
// Log the error
emit FeedUpdateFailed(feedId, targetFeed, data, block.timestamp);
}
}
if (successCount == 0) {
revert NoFeedsUpdated();
}
}
/**
* @notice Reads the latest onchain price and timestamp for a Data Streams feed.
* @param feedId The feed ID.
* @return price The latest onchain price.
* @return timestamp The timestamp of the latest onchain price.
*/
function readUnderlyingFeed(bytes32 feedId) internal view virtual returns (int256 price, uint256 timestamp) {
// Get the data stream address
(bool feedExists_, address targetFeed) = _feedTargets.tryGet(feedId);
if (!feedExists_) {
// The updater should never try to update a feed that is not registered
revert FeedNotRegistered(feedId);
}
(bool success, bytes memory data) = targetFeed.staticcall(
abi.encodeWithSelector(AggregatorV3Interface.latestRoundData.selector)
);
if (!success) {
// The call fails if the report is expired or missing. Return zeros to signal this.
return (0, 0);
} else {
(, int256 answer, , uint256 updatedAt, ) = abi.decode(data, (uint80, int256, uint256, uint256, uint80));
return (answer, updatedAt);
}
}
/**
* @notice Calculates the change between two numbers, scaled by the CHANGE_PRECISION.
* @param a A number.
* @param b Another number.
* @return change The normalized percentage change between a and b. See Adrastia Documentation (docs.adrastia.io)
* for more information regarding normalization.
* @return maximalChange If one value is zero and other is non-zero, returns true. If the change is so large that
* overflow occurs, returns true. Otherwise, returns false. If one value is negative, and the other is non-negative,
* returns true.
*/
function calculateChange(int256 a, int256 b) internal pure virtual returns (uint256 change, bool maximalChange) {
// If one is zero and the other is not, treat as maximal change
if (a == 0 && b == 0) {
return (0, false);
} else if (a == 0 || b == 0) {
return (0, true);
}
unchecked {
// Check for sign flips
if ((a > 0 && b < 0) || (a < 0 && b > 0)) {
return (0, true); // sign flip = maximum deviation
}
int256 delta = a - b;
// We use absolute change scaled by CHANGE_PRECISION, divided by absolute base
uint256 uDelta = uint256(delta >= 0 ? delta : -delta);
uint256 uBase = uint256(b >= 0 ? b : -b);
uint256 preciseDelta = uDelta * CHANGE_PRECISION;
if (preciseDelta / CHANGE_PRECISION != uDelta) {
// multiplication overflow
return (0, true);
}
change = preciseDelta / uBase;
maximalChange = false;
}
}
/**
* @notice Gets the feed ID for a given feed address from the feed contract itself. Used to verify that the feed ID
* matches the expected feed ID.
*
* @param feed The feed address.
*
* @return The feed ID.
*/
function _getIdFromFeed(address feed) internal view virtual returns (bytes32) {
return IDataStreamsFeed(feed).feedId();
}
function _initializeRoles(address initialAdmin, address initialUpdaterAdmin) internal virtual {
// Admin self manages its own role
_setRoleAdmin(ADMIN, ADMIN);
// Admin manages the config admin role
_setRoleAdmin(CONFIG_ADMIN, ADMIN);
// Oracle updater admin self manages its own role
_setRoleAdmin(UPDATER_ADMIN, UPDATER_ADMIN);
// Oracle updater admin manages the oracle updater role
_setRoleAdmin(ORACLE_UPDATER, UPDATER_ADMIN);
// Grant the admin role to the initial admin
_grantRole(ADMIN, initialAdmin);
// Grant the updater admin role to the initial updater admin
_grantRole(UPDATER_ADMIN, initialUpdaterAdmin);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IDataStreamsFeed {
function feedId() external view returns (bytes32);
function updateReport(uint16 reportVersion, bytes calldata verifiedReportData) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// solhint-disable-next-line interface-starts-with-i
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(
uint80 _roundId
)
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
function latestRoundData()
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/*
* @title Common
* @author Michael Fletcher
* @notice Common functions and structs
*/
library Common {
// @notice The asset struct to hold the address of an asset and amount
struct Asset {
address assetAddress;
uint256 amount;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Common} from "./Common.sol";
interface IFeeManager {
/**
* @notice Calculates the fee and reward associated with verifying a report, including discounts for subscribers.
* This function assesses the fee and reward for report verification, applying a discount for recognized subscriber addresses.
* @param subscriber The address attempting to verify the report. A discount is applied if this address
* is recognized as a subscriber.
* @param unverifiedReport The report data awaiting verification. The content of this report is used to
* determine the base fee and reward, before considering subscriber discounts.
* @param quoteAddress The payment token address used for quoting fees and rewards.
* @return fee The fee assessed for verifying the report, with subscriber discounts applied where applicable.
* @return reward The reward allocated to the caller for successfully verifying the report.
* @return totalDiscount The total discount amount deducted from the fee for subscribers
*/
function getFeeAndReward(
address subscriber,
bytes memory unverifiedReport,
address quoteAddress
) external returns (Common.Asset memory, Common.Asset memory, uint256);
function i_linkAddress() external view returns (address);
function i_nativeAddress() external view returns (address);
function i_rewardManager() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IVerifierProxy {
/**
* @notice Verifies that the data encoded has been signed.
* correctly by routing to the correct verifier, and bills the user if applicable.
* @param payload The encoded data to be verified, including the signed
* report.
* @param parameterPayload Fee metadata for billing. For the current implementation this is just the abi-encoded fee token ERC-20 address.
* @return verifierResponse The encoded report from the verifier.
*/
function verify(
bytes calldata payload,
bytes calldata parameterPayload
) external payable returns (bytes memory verifierResponse);
/**
* @notice Verifies multiple reports in bulk, ensuring that each is signed correctly, routes them to the appropriate verifier, and handles billing for the verification process.
* @param payloads An array of encoded data to be verified, where each entry includes the signed report.
* @param parameterPayload Fee metadata for billing. In the current implementation, this consists of the abi-encoded address of the ERC-20 token used for fees.
* @return verifiedReports An array of encoded reports returned from the verifier.
*/
function verifyBulk(
bytes[] calldata payloads,
bytes calldata parameterPayload
) external payable returns (bytes[] memory verifiedReports);
function s_feeManager() external view returns (address);
}{
"viaIR": true,
"optimizer": {
"enabled": true,
"runs": 2000
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"initialAdmin","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"}],"name":"FeedAlreadyRegistered","type":"error"},{"inputs":[{"internalType":"bytes32","name":"expectedFeedId","type":"bytes32"},{"internalType":"bytes32","name":"providedFeedId","type":"bytes32"}],"name":"FeedMismatch","type":"error"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"}],"name":"FeedNotRegistered","type":"error"},{"inputs":[{"internalType":"uint16","name":"reportVersion","type":"uint16"}],"name":"InvalidReportVersion","type":"error"},{"inputs":[],"name":"NoFeedsUpdated","type":"error"},{"inputs":[{"internalType":"uint256","name":"unverifiedReportsLength","type":"uint256"},{"internalType":"uint256","name":"verifiedReportsLength","type":"uint256"}],"name":"ReportLengthMismatch","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"feedId","type":"bytes32"},{"indexed":true,"internalType":"enum AdrastiaDataStreamsUpdater.FeedRegistrationAction","name":"action","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"FeedRegistrationChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"feedId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"oldFeed","type":"address"},{"indexed":true,"internalType":"address","name":"newFeed","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"FeedTargetChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"feedId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"feed","type":"address"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"FeedUpdateFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"feedId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"feed","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"FeedUpdatePerformed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"feedId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"feed","type":"address"},{"indexed":false,"internalType":"uint256","name":"storedTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"providedTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"FeedUpdateSkipped","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"},{"inputs":[],"name":"ADMIN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CHANGE_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CONFIG_ADMIN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ORACLE_UPDATER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UPDATER_ADMIN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"approveVerifierFeeSpend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"},{"internalType":"address","name":"feed","type":"address"}],"name":"changeFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"checkData","type":"bytes"}],"name":"checkUpkeep","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"}],"name":"feedExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"}],"name":"getFeed","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFeedCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFeedIds","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFeedMapping","outputs":[{"components":[{"internalType":"bytes32","name":"feedId","type":"bytes32"},{"internalType":"address","name":"feed","type":"address"}],"internalType":"struct AdrastiaDataStreamsUpdater.FeedIdAndAddress[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMembers","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":[{"internalType":"bytes","name":"performData","type":"bytes"}],"name":"performUpkeep","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"},{"internalType":"address","name":"feed","type":"address"}],"name":"registerFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","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":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"}],"name":"unregisterFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"verifierProxy","outputs":[{"internalType":"contract IVerifierProxy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawErc20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawNative","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a03461030757601f6121ad38819003918201601f19168301916001600160401b0383118484101761030c5780849260209460405283398101031261030757516001600160a01b038116908181036103075781158015610302575b6102bd576000608081905260008051602061218d83398151915280825260208290527f7d7ffb7a348e1c6a02869081a26547b49160dd3df72d1d75a570eb9b698292ed8054908290556102119392829060008051602061210d8339815191529080a47fb92d52e77ebaa0cae5c23e882d85609efbcb44029214147dd132daf9ef1018af600081815260208190527f88b4af5b933fdc1fcd68c2f9c47ec4f55dd961e785ecbbca61f1df8bed3ceffe805460008051602061218d833981519152918290559092909160008051602061210d8339815191529080a460008051602061212d833981519152600081815260208190527f93f956adba6c072fd936983f727a6152a8261208a80865e45d1d2b53f6de5fcb80549083905590829060008051602061210d8339815191529080a47f9792fdc19ab98adfa72ab2fa98d342618c661e01c406979c105b31eda87f5e6f600081815260208190527fedb88efb1d399b0da6f79caf435895256e371666ffd10d48d8fcc014b50fc926805460008051602061212d833981519152918290559092909160008051602061210d8339815191529080a461020881610322565b610276576103ae565b61022e575b604051611c3e90816104af8239608051816108990152f35b60008051602061212d833981519152600052600160205261026f907f2f5548e6c1fbe94de15cb3f3d7b569a8a69d06f58016b7928f56cf14dd930f3d610434565b5038610216565b60008051602061218d83398151915260005260016020526102b7837f50efbde2d46c37e9785f1791697f77e94bb7b701e19f1930a668820722d37694610434565b506103ae565b60405162461bcd60e51b815260206004820152601660248201527f496e76616c696420696e697469616c2061646d696e73000000000000000000006044820152606490fd5b61005a565b600080fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116600090815260008051602061214d833981519152602052604090205460ff166103a8576001600160a01b0316600081815260008051602061214d83398151915260205260408120805460ff1916600117905533919060008051602061218d833981519152906000805160206120ed8339815191529080a4600190565b50600090565b6001600160a01b038116600090815260008051602061216d833981519152602052604090205460ff166103a8576001600160a01b0316600081815260008051602061216d83398151915260205260408120805460ff1916600117905533919060008051602061212d833981519152906000805160206120ed8339815191529080a4600190565b60018101908260005281602052604060002054156000146104a65780546801000000000000000081101561030c576001810180835581101561049057839082600052602060002001555491600052602052604060002055600190565b634e487b7160e01b600052603260045260246000fd5b50505060009056fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a7146112a75750806307b18bde146112275780630c518dce14611189578063105794681461103f5780631593dee114610f5857806321209cfa14610f1d578063248a9ca314610ee8578063280aebcf14610eb15780632a0acc6a14610e765780632a58990814610dcb5780632cc9dfb314610dad5780632f2ff15d14610d4557806336568abe14610ce65780634585e33b146108bd57806347f77bc0146108795780634a84d0211461078e578063581b3ee01461076f5780635affdd4c146107355780636e04ff0d1461049657806376ce5858146104605780639010d07c1461041a57806391d14854146103cc578063a217fddf146103b0578063a3246ad3146102fc578063abf05a1a146102c1578063b12a2d8b146102ae578063bd33b7c8146101d6578063ca15c873146101aa5763d547741f1461015e57600080fd5b346101a55760406003193601126101a5576101a360043561017d61138e565b9061019e61019982600052600060205260016040600020015490565b6115f5565b61163c565b005b600080fd5b346101a55760206003193601126101a55760043560005260016020526020604060002054604051908152f35b346101a55760406003193601126101a5576004356101f261138e565b6101fa611583565b61020381611735565b80830361027c575061021482611882565b919015610267576001600160a01b03169161022f83826119e2565b507f04edbd68b1a49774d0341412ee6173ec25051302eed0d72a0e45571496ccdf7660206001600160a01b03604051944286521693a4005b82631e59ac5160e21b60005260045260246000fd5b90507f352b24610000000000000000000000000000000000000000000000000000000060005260045260245260446000fd5b346101a55760006003193601126101a557005b346101a55760006003193601126101a55760206040517f9792fdc19ab98adfa72ab2fa98d342618c661e01c406979c105b31eda87f5e6f8152f35b346101a55760206003193601126101a5576004356000526001602052604060002060405181548082526020820190819360005260206000209060005b81811061039a575050508161034e9103826113c0565b6040519182916020830190602084525180915260408301919060005b818110610378575050500390f35b82516001600160a01b031684528594506020938401939092019160010161036a565b8254845260209093019260019283019201610338565b346101a55760006003193601126101a557602060405160008152f35b346101a55760406003193601126101a5576103e561138e565b60043560005260006020526001600160a01b0360406000209116600052602052602060ff604060002054166040519015158152f35b346101a55760406003193601126101a557600435600052600160205260206001600160a01b0361045060243560406000206119ff565b90549060031b1c16604051908152f35b346101a55760206003193601126101a557602061048c6004356000526003602052604060002054151590565b6040519015158152f35b346101a55760206003193601126101a55760043567ffffffffffffffff81116101a5576104c79036906004016113ff565b805160a0810361060c575060a0818051810103126101a557602081015160408201519060608301519160a0608085015194015191610512816000526003602052604060002054151590565b156105f8576105209061168d565b919094600094859484811015610593575b505050508215908161058a575b6040519460208601526040850152156060840152151560808301526080825261056860a0836113c0565b61058660405192839215158352604060208401526040830190611469565b0390f35b9250819261053e565b8481039081116105e45710156105db575b6105ae90866117b0565b919082156105d0575b50506105c7575b84808080610531565b600191506105be565b1015905085806105b7565b600194506105a4565b602487634e487b7160e01b81526011600452fd5b631e59ac5160e21b60005260045260246000fd5b6060116106f15760808151106106ad5760a090511061066957606460405162461bcd60e51b815260206004820152600e60248201527f546f6f206d75636820646174612e0000000000000000000000000000000000006044820152fd5b606460405162461bcd60e51b815260206004820152601b60248201527f4d697373696e67206f6666636861696e2074696d657374616d702e00000000006044820152fd5b606460405162461bcd60e51b815260206004820152601760248201527f4d697373696e67206f6666636861696e2070726963652e0000000000000000006044820152fd5b606460405162461bcd60e51b815260206004820152601260248201527f4d697373696e67206665656420646174612e00000000000000000000000000006044820152fd5b346101a55760006003193601126101a55760206040517ef7280a0db925c0d1e88a56cb8ae89369595b41df40ca283519b9b197f5fed08152f35b346101a55760006003193601126101a55760206040516305f5e1008152f35b346101a55760406003193601126101a5576004356107aa61138e565b6107b2611583565b6107bb81611735565b80830361027c57506107cc82611882565b919061084b576001600160a01b0316916107e683826119e2565b506000817f1461e90144abccd369b0962a63908835be724cf6c0e6275e1756bdedf47b51576020604051428152a37f04edbd68b1a49774d0341412ee6173ec25051302eed0d72a0e45571496ccdf7660206001600160a01b03604051944286521693a4005b827fd09bc9e10000000000000000000000000000000000000000000000000000000060005260045260246000fd5b346101a55760006003193601126101a55760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b60206003193601126101a55760043567ffffffffffffffff81116101a557366023820112156101a557806004013567ffffffffffffffff81116101a55781019060248201913683116101a557602090829003126101a55760248101359067ffffffffffffffff82116101a5570190806043830112156101a5576024820135610944816114be565b9261095260405194856113c0565b818452602060248186019360051b83010101918383116101a55760448201905b838210610cb557856040519060006020830152602082526109946040836113c0565b600091825b8251841015610c84576109ac84846114d6565b518051810190608081602084019303126101a55781603f820112156101a5576040516060810181811067ffffffffffffffff821117610c6e5760405260808201908382116101a55760208301905b828210610c5e575050519067ffffffffffffffff82116101a5570181603f820112156101a557602081015190610a2f826113e3565b91610a3d60405193846113c0565b8083526020830193604083830101116101a557836040610a5d9301611446565b6060818051810103126101a557610a8d60606001600160a01b03935192610a8660408201611500565b5001611500565b610a9682611882565b939093169215610c495763ffffffff610aae8361168d565b9290501680821015610c07575050600080610ac988886114d6565b51604051610b4e81610b40610b1060208301957ff3208a50000000000000000000000000000000000000000000000000000000008752604060248501526064840190611469565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc8382030160448401528b611469565b03601f1981018352826113c0565b519082865af1610b5c61148e565b9015610bba57507f9e0b7698b9f11443d38cb8a817dfdc478d23f7beff128684d788ca246a06d99c6020604051428152a36000198114610ba4576001809101935b0192610999565b634e487b7160e01b600052601160045260246000fd5b907f128604bb7ac214246287115a95d0b2e90d8447034bb6634b47ee34fc969dd4ba610bf9600195989493604051918291604083526040830190611469565b4260208301520390a3610b9d565b6060600195989493927fecc3a38fd26d51bc47185041b9eb9e8f456ee5315edd528b927e1681c3675ef5926040519182526020820152426040820152a3610b9d565b50631e59ac5160e21b60005260045260246000fd5b81518152602091820191016109fa565b634e487b7160e01b600052604160045260246000fd5b15610c8b57005b7f4186b1950000000000000000000000000000000000000000000000000000000060005260046000fd5b813567ffffffffffffffff81116101a557602091610cdb878460248195890101016113ff565b815201910190610972565b346101a55760406003193601126101a557610cff61138e565b336001600160a01b03821603610d1b576101a39060043561163c565b7f6697b2320000000000000000000000000000000000000000000000000000000060005260046000fd5b346101a55760406003193601126101a557600435610d6161138e565b610d7c61019983600052600060205260016040600020015490565b610d8681836118b9565b610d8c57005b6101a39160005260016020526001600160a01b036040600020911690611a17565b346101a55760006003193601126101a5576020600254604051908152f35b346101a55760206003193601126101a557600435610de7611583565b610df081611882565b9015610c49579060006001928282526004602052816040812055610e1383611a83565b50827f04edbd68b1a49774d0341412ee6173ec25051302eed0d72a0e45571496ccdf7660206001600160a01b03604051944286521693a47f1461e90144abccd369b0962a63908835be724cf6c0e6275e1756bdedf47b51576020604051428152a3005b346101a55760006003193601126101a55760206040517fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217758152f35b346101a55760206003193601126101a557600435610ece81611882565b9015610c49576020906001600160a01b0360405191168152f35b346101a55760206003193601126101a5576020610f15600435600052600060205260016040600020015490565b604051908152f35b346101a55760006003193601126101a55760206040517fb92d52e77ebaa0cae5c23e882d85609efbcb44029214147dd132daf9ef1018af8152f35b346101a55760606003193601126101a557610f71611378565b602060006001600160a01b03610f8561138e565b93610f8e611511565b16926040516001600160a01b03848201927fa9059cbb000000000000000000000000000000000000000000000000000000008452166024820152604435604482015260448152610fdf6064826113c0565b519082855af115611033576000513d61102a5750803b155b610ffd57005b7f5274afe70000000000000000000000000000000000000000000000000000000060005260045260246000fd5b60011415610ff7565b6040513d6000823e3d90fd5b346101a55760006003193601126101a55760025461105c816114be565b9061106a60405192836113c0565b808252601f19611079826114be565b0160005b8181106111645750506002549060005b8181106110ef578360405180916020820160208352815180915260206040840192019060005b8181106110c1575050500390f35b8251805185526020908101516001600160a01b031681860152869550604090940193909201916001016110b3565b60008382101561115057908060208360026001955220016001600160a01b036040600092549283815260046020522054166040519161112d836113a4565b8252602082015261113e82876114d6565b5261114981866114d6565b500161108d565b80634e487b7160e01b602492526032600452fd5b602090604051611173816113a4565b600081526000838201528282870101520161107d565b346101a55760006003193601126101a55760405160025490818152602081018092600260005260206000209060005b81811061121157505050816111ce9103826113c0565b6040519182916020830190602084525180915260408301919060005b8181106111f8575050500390f35b82518452859450602093840193909201916001016111ea565b82548452602090930192600192830192016111b8565b346101a55760406003193601126101a5576000808080611245611378565b61124d611511565b602435905af161125b61148e565b501561126357005b606460405162461bcd60e51b815260206004820152600f60248201527f5472616e73666572206661696c656400000000000000000000000000000000006044820152fd5b346101a55760206003193601126101a557600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101a557817f5a05180f000000000000000000000000000000000000000000000000000000006020931490811561131b575b5015158152f35b7f7965db0b0000000000000000000000000000000000000000000000000000000081149150811561134e575b5083611314565b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483611347565b600435906001600160a01b03821682036101a557565b602435906001600160a01b03821682036101a557565b6040810190811067ffffffffffffffff821117610c6e57604052565b90601f601f19910116810190811067ffffffffffffffff821117610c6e57604052565b67ffffffffffffffff8111610c6e57601f01601f191660200190565b81601f820112156101a557803590611416826113e3565b9261142460405194856113c0565b828452602083830101116101a557816000926020809301838601378301015290565b60005b8381106114595750506000910152565b8181015183820152602001611449565b90601f19601f60209361148781518092818752878088019101611446565b0116010190565b3d156114b9573d9061149f826113e3565b916114ad60405193846113c0565b82523d6000602084013e565b606090565b67ffffffffffffffff8111610c6e5760051b60200190565b80518210156114ea5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b519063ffffffff821682036101a557565b3360009081527f7d7ffb7a348e1c6a02869081a26547b49160dd3df72d1d75a570eb9b698292ec602052604090205460ff161561154a57565b63e2517d3f60e01b600052336004527fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177560245260446000fd5b3360009081527f88b4af5b933fdc1fcd68c2f9c47ec4f55dd961e785ecbbca61f1df8bed3ceffd602052604090205460ff16156115bc57565b63e2517d3f60e01b600052336004527fb92d52e77ebaa0cae5c23e882d85609efbcb44029214147dd132daf9ef1018af60245260446000fd5b80600052600060205260406000206001600160a01b03331660005260205260ff60406000205416156116245750565b63e2517d3f60e01b6000523360045260245260446000fd5b6116468282611953565b918261165157505090565b6116729160005260016020526001600160a01b036040600020911690611b4c565b5090565b519069ffffffffffffffffffff821682036101a557565b61169681611882565b9190156105f85750600080916040516001600160a01b0360208201917ffeaf968c000000000000000000000000000000000000000000000000000000008352600481526116e46024826113c0565b5192165afa6116f161148e565b906116ff5750600090600090565b9060a0828051810103126101a55761171960208301611676565b50604082015161173060a060808501519401611676565b509190565b60206001600160a01b03916004604051809481937f01d61c49000000000000000000000000000000000000000000000000000000008352165afa90811561103357600091611781575090565b90506020813d6020116117a8575b8161179c602093836113c0565b810103126101a5575190565b3d915061178f565b8015808061187a575b156117c957505050600090600090565b8015611872575b61183b576000811380611868575b8015611853575b61183b57819003600080821261184c5750905b60008082126118455750905b6305f5e1008102906305f5e10082040361183b578115611825570490600090565b634e487b7160e01b600052601260045260246000fd5b5050600090600190565b0390611804565b03906117f8565b506000811280156117e55750600082136117e5565b50600082126117de565b5081156117d0565b5082156117b9565b80600052600460205260406000205480156000146118b157506000526003602052604060002054151590600090565b600192909150565b80600052600060205260406000206001600160a01b03831660005260205260ff604060002054161560001461194c5780600052600060205260406000206001600160a01b0383166000526020526040600020600160ff198254161790556001600160a01b03339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d600080a4600190565b5050600090565b80600052600060205260406000206001600160a01b03831660005260205260ff6040600020541660001461194c5780600052600060205260406000206001600160a01b038316600052602052604060002060ff1981541690556001600160a01b03339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b600080a4600190565b6119fc918160005260046020526040600020556002611a17565b90565b80548210156114ea5760005260206000200190600090565b600082815260018201602052604090205461194c5780549068010000000000000000821015610c6e5782611a6c611a558460018096018555846119ff565b81939154906000199060031b92831b921b19161790565b905580549260005201602052604060002055600190565b600081815260036020526040902054801561194c576000198101818111610ba457600254906000198201918211610ba457818103611b12575b5050506002548015611afc5760001901611ad78160026119ff565b60001982549160031b1b19169055600255600052600360205260006040812055600190565b634e487b7160e01b600052603160045260246000fd5b611b34611b23611a559360026119ff565b90549060031b1c92839260026119ff565b90556000526003602052604060002055388080611abc565b9060018201918160005282602052604060002054801515600014611bff576000198101818111610ba4578254906000198201918211610ba457818103611bc8575b50505080548015611afc576000190190611ba782826119ff565b60001982549160031b1b191690555560005260205260006040812055600190565b611be8611bd8611a5593866119ff565b90549060031b1c928392866119ff565b905560005283602052604060002055388080611b8d565b5050505060009056fea2646970667358221220f4a0cd9b8521f3ffd424bd273c7c0eeff8191fdc51519abbc4678ff38833d3d764736f6c634300081a00332f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0dbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff00f7280a0db925c0d1e88a56cb8ae89369595b41df40ca283519b9b197f5fed07d7ffb7a348e1c6a02869081a26547b49160dd3df72d1d75a570eb9b698292ec93f956adba6c072fd936983f727a6152a8261208a80865e45d1d2b53f6de5fcaa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775000000000000000000000000ec89a5dd6c179c345ea7996aa879e59cb18c8484
Deployed Bytecode
0x608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a7146112a75750806307b18bde146112275780630c518dce14611189578063105794681461103f5780631593dee114610f5857806321209cfa14610f1d578063248a9ca314610ee8578063280aebcf14610eb15780632a0acc6a14610e765780632a58990814610dcb5780632cc9dfb314610dad5780632f2ff15d14610d4557806336568abe14610ce65780634585e33b146108bd57806347f77bc0146108795780634a84d0211461078e578063581b3ee01461076f5780635affdd4c146107355780636e04ff0d1461049657806376ce5858146104605780639010d07c1461041a57806391d14854146103cc578063a217fddf146103b0578063a3246ad3146102fc578063abf05a1a146102c1578063b12a2d8b146102ae578063bd33b7c8146101d6578063ca15c873146101aa5763d547741f1461015e57600080fd5b346101a55760406003193601126101a5576101a360043561017d61138e565b9061019e61019982600052600060205260016040600020015490565b6115f5565b61163c565b005b600080fd5b346101a55760206003193601126101a55760043560005260016020526020604060002054604051908152f35b346101a55760406003193601126101a5576004356101f261138e565b6101fa611583565b61020381611735565b80830361027c575061021482611882565b919015610267576001600160a01b03169161022f83826119e2565b507f04edbd68b1a49774d0341412ee6173ec25051302eed0d72a0e45571496ccdf7660206001600160a01b03604051944286521693a4005b82631e59ac5160e21b60005260045260246000fd5b90507f352b24610000000000000000000000000000000000000000000000000000000060005260045260245260446000fd5b346101a55760006003193601126101a557005b346101a55760006003193601126101a55760206040517f9792fdc19ab98adfa72ab2fa98d342618c661e01c406979c105b31eda87f5e6f8152f35b346101a55760206003193601126101a5576004356000526001602052604060002060405181548082526020820190819360005260206000209060005b81811061039a575050508161034e9103826113c0565b6040519182916020830190602084525180915260408301919060005b818110610378575050500390f35b82516001600160a01b031684528594506020938401939092019160010161036a565b8254845260209093019260019283019201610338565b346101a55760006003193601126101a557602060405160008152f35b346101a55760406003193601126101a5576103e561138e565b60043560005260006020526001600160a01b0360406000209116600052602052602060ff604060002054166040519015158152f35b346101a55760406003193601126101a557600435600052600160205260206001600160a01b0361045060243560406000206119ff565b90549060031b1c16604051908152f35b346101a55760206003193601126101a557602061048c6004356000526003602052604060002054151590565b6040519015158152f35b346101a55760206003193601126101a55760043567ffffffffffffffff81116101a5576104c79036906004016113ff565b805160a0810361060c575060a0818051810103126101a557602081015160408201519060608301519160a0608085015194015191610512816000526003602052604060002054151590565b156105f8576105209061168d565b919094600094859484811015610593575b505050508215908161058a575b6040519460208601526040850152156060840152151560808301526080825261056860a0836113c0565b61058660405192839215158352604060208401526040830190611469565b0390f35b9250819261053e565b8481039081116105e45710156105db575b6105ae90866117b0565b919082156105d0575b50506105c7575b84808080610531565b600191506105be565b1015905085806105b7565b600194506105a4565b602487634e487b7160e01b81526011600452fd5b631e59ac5160e21b60005260045260246000fd5b6060116106f15760808151106106ad5760a090511061066957606460405162461bcd60e51b815260206004820152600e60248201527f546f6f206d75636820646174612e0000000000000000000000000000000000006044820152fd5b606460405162461bcd60e51b815260206004820152601b60248201527f4d697373696e67206f6666636861696e2074696d657374616d702e00000000006044820152fd5b606460405162461bcd60e51b815260206004820152601760248201527f4d697373696e67206f6666636861696e2070726963652e0000000000000000006044820152fd5b606460405162461bcd60e51b815260206004820152601260248201527f4d697373696e67206665656420646174612e00000000000000000000000000006044820152fd5b346101a55760006003193601126101a55760206040517ef7280a0db925c0d1e88a56cb8ae89369595b41df40ca283519b9b197f5fed08152f35b346101a55760006003193601126101a55760206040516305f5e1008152f35b346101a55760406003193601126101a5576004356107aa61138e565b6107b2611583565b6107bb81611735565b80830361027c57506107cc82611882565b919061084b576001600160a01b0316916107e683826119e2565b506000817f1461e90144abccd369b0962a63908835be724cf6c0e6275e1756bdedf47b51576020604051428152a37f04edbd68b1a49774d0341412ee6173ec25051302eed0d72a0e45571496ccdf7660206001600160a01b03604051944286521693a4005b827fd09bc9e10000000000000000000000000000000000000000000000000000000060005260045260246000fd5b346101a55760006003193601126101a55760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b60206003193601126101a55760043567ffffffffffffffff81116101a557366023820112156101a557806004013567ffffffffffffffff81116101a55781019060248201913683116101a557602090829003126101a55760248101359067ffffffffffffffff82116101a5570190806043830112156101a5576024820135610944816114be565b9261095260405194856113c0565b818452602060248186019360051b83010101918383116101a55760448201905b838210610cb557856040519060006020830152602082526109946040836113c0565b600091825b8251841015610c84576109ac84846114d6565b518051810190608081602084019303126101a55781603f820112156101a5576040516060810181811067ffffffffffffffff821117610c6e5760405260808201908382116101a55760208301905b828210610c5e575050519067ffffffffffffffff82116101a5570181603f820112156101a557602081015190610a2f826113e3565b91610a3d60405193846113c0565b8083526020830193604083830101116101a557836040610a5d9301611446565b6060818051810103126101a557610a8d60606001600160a01b03935192610a8660408201611500565b5001611500565b610a9682611882565b939093169215610c495763ffffffff610aae8361168d565b9290501680821015610c07575050600080610ac988886114d6565b51604051610b4e81610b40610b1060208301957ff3208a50000000000000000000000000000000000000000000000000000000008752604060248501526064840190611469565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc8382030160448401528b611469565b03601f1981018352826113c0565b519082865af1610b5c61148e565b9015610bba57507f9e0b7698b9f11443d38cb8a817dfdc478d23f7beff128684d788ca246a06d99c6020604051428152a36000198114610ba4576001809101935b0192610999565b634e487b7160e01b600052601160045260246000fd5b907f128604bb7ac214246287115a95d0b2e90d8447034bb6634b47ee34fc969dd4ba610bf9600195989493604051918291604083526040830190611469565b4260208301520390a3610b9d565b6060600195989493927fecc3a38fd26d51bc47185041b9eb9e8f456ee5315edd528b927e1681c3675ef5926040519182526020820152426040820152a3610b9d565b50631e59ac5160e21b60005260045260246000fd5b81518152602091820191016109fa565b634e487b7160e01b600052604160045260246000fd5b15610c8b57005b7f4186b1950000000000000000000000000000000000000000000000000000000060005260046000fd5b813567ffffffffffffffff81116101a557602091610cdb878460248195890101016113ff565b815201910190610972565b346101a55760406003193601126101a557610cff61138e565b336001600160a01b03821603610d1b576101a39060043561163c565b7f6697b2320000000000000000000000000000000000000000000000000000000060005260046000fd5b346101a55760406003193601126101a557600435610d6161138e565b610d7c61019983600052600060205260016040600020015490565b610d8681836118b9565b610d8c57005b6101a39160005260016020526001600160a01b036040600020911690611a17565b346101a55760006003193601126101a5576020600254604051908152f35b346101a55760206003193601126101a557600435610de7611583565b610df081611882565b9015610c49579060006001928282526004602052816040812055610e1383611a83565b50827f04edbd68b1a49774d0341412ee6173ec25051302eed0d72a0e45571496ccdf7660206001600160a01b03604051944286521693a47f1461e90144abccd369b0962a63908835be724cf6c0e6275e1756bdedf47b51576020604051428152a3005b346101a55760006003193601126101a55760206040517fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217758152f35b346101a55760206003193601126101a557600435610ece81611882565b9015610c49576020906001600160a01b0360405191168152f35b346101a55760206003193601126101a5576020610f15600435600052600060205260016040600020015490565b604051908152f35b346101a55760006003193601126101a55760206040517fb92d52e77ebaa0cae5c23e882d85609efbcb44029214147dd132daf9ef1018af8152f35b346101a55760606003193601126101a557610f71611378565b602060006001600160a01b03610f8561138e565b93610f8e611511565b16926040516001600160a01b03848201927fa9059cbb000000000000000000000000000000000000000000000000000000008452166024820152604435604482015260448152610fdf6064826113c0565b519082855af115611033576000513d61102a5750803b155b610ffd57005b7f5274afe70000000000000000000000000000000000000000000000000000000060005260045260246000fd5b60011415610ff7565b6040513d6000823e3d90fd5b346101a55760006003193601126101a55760025461105c816114be565b9061106a60405192836113c0565b808252601f19611079826114be565b0160005b8181106111645750506002549060005b8181106110ef578360405180916020820160208352815180915260206040840192019060005b8181106110c1575050500390f35b8251805185526020908101516001600160a01b031681860152869550604090940193909201916001016110b3565b60008382101561115057908060208360026001955220016001600160a01b036040600092549283815260046020522054166040519161112d836113a4565b8252602082015261113e82876114d6565b5261114981866114d6565b500161108d565b80634e487b7160e01b602492526032600452fd5b602090604051611173816113a4565b600081526000838201528282870101520161107d565b346101a55760006003193601126101a55760405160025490818152602081018092600260005260206000209060005b81811061121157505050816111ce9103826113c0565b6040519182916020830190602084525180915260408301919060005b8181106111f8575050500390f35b82518452859450602093840193909201916001016111ea565b82548452602090930192600192830192016111b8565b346101a55760406003193601126101a5576000808080611245611378565b61124d611511565b602435905af161125b61148e565b501561126357005b606460405162461bcd60e51b815260206004820152600f60248201527f5472616e73666572206661696c656400000000000000000000000000000000006044820152fd5b346101a55760206003193601126101a557600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101a557817f5a05180f000000000000000000000000000000000000000000000000000000006020931490811561131b575b5015158152f35b7f7965db0b0000000000000000000000000000000000000000000000000000000081149150811561134e575b5083611314565b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483611347565b600435906001600160a01b03821682036101a557565b602435906001600160a01b03821682036101a557565b6040810190811067ffffffffffffffff821117610c6e57604052565b90601f601f19910116810190811067ffffffffffffffff821117610c6e57604052565b67ffffffffffffffff8111610c6e57601f01601f191660200190565b81601f820112156101a557803590611416826113e3565b9261142460405194856113c0565b828452602083830101116101a557816000926020809301838601378301015290565b60005b8381106114595750506000910152565b8181015183820152602001611449565b90601f19601f60209361148781518092818752878088019101611446565b0116010190565b3d156114b9573d9061149f826113e3565b916114ad60405193846113c0565b82523d6000602084013e565b606090565b67ffffffffffffffff8111610c6e5760051b60200190565b80518210156114ea5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b519063ffffffff821682036101a557565b3360009081527f7d7ffb7a348e1c6a02869081a26547b49160dd3df72d1d75a570eb9b698292ec602052604090205460ff161561154a57565b63e2517d3f60e01b600052336004527fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177560245260446000fd5b3360009081527f88b4af5b933fdc1fcd68c2f9c47ec4f55dd961e785ecbbca61f1df8bed3ceffd602052604090205460ff16156115bc57565b63e2517d3f60e01b600052336004527fb92d52e77ebaa0cae5c23e882d85609efbcb44029214147dd132daf9ef1018af60245260446000fd5b80600052600060205260406000206001600160a01b03331660005260205260ff60406000205416156116245750565b63e2517d3f60e01b6000523360045260245260446000fd5b6116468282611953565b918261165157505090565b6116729160005260016020526001600160a01b036040600020911690611b4c565b5090565b519069ffffffffffffffffffff821682036101a557565b61169681611882565b9190156105f85750600080916040516001600160a01b0360208201917ffeaf968c000000000000000000000000000000000000000000000000000000008352600481526116e46024826113c0565b5192165afa6116f161148e565b906116ff5750600090600090565b9060a0828051810103126101a55761171960208301611676565b50604082015161173060a060808501519401611676565b509190565b60206001600160a01b03916004604051809481937f01d61c49000000000000000000000000000000000000000000000000000000008352165afa90811561103357600091611781575090565b90506020813d6020116117a8575b8161179c602093836113c0565b810103126101a5575190565b3d915061178f565b8015808061187a575b156117c957505050600090600090565b8015611872575b61183b576000811380611868575b8015611853575b61183b57819003600080821261184c5750905b60008082126118455750905b6305f5e1008102906305f5e10082040361183b578115611825570490600090565b634e487b7160e01b600052601260045260246000fd5b5050600090600190565b0390611804565b03906117f8565b506000811280156117e55750600082136117e5565b50600082126117de565b5081156117d0565b5082156117b9565b80600052600460205260406000205480156000146118b157506000526003602052604060002054151590600090565b600192909150565b80600052600060205260406000206001600160a01b03831660005260205260ff604060002054161560001461194c5780600052600060205260406000206001600160a01b0383166000526020526040600020600160ff198254161790556001600160a01b03339216907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d600080a4600190565b5050600090565b80600052600060205260406000206001600160a01b03831660005260205260ff6040600020541660001461194c5780600052600060205260406000206001600160a01b038316600052602052604060002060ff1981541690556001600160a01b03339216907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b600080a4600190565b6119fc918160005260046020526040600020556002611a17565b90565b80548210156114ea5760005260206000200190600090565b600082815260018201602052604090205461194c5780549068010000000000000000821015610c6e5782611a6c611a558460018096018555846119ff565b81939154906000199060031b92831b921b19161790565b905580549260005201602052604060002055600190565b600081815260036020526040902054801561194c576000198101818111610ba457600254906000198201918211610ba457818103611b12575b5050506002548015611afc5760001901611ad78160026119ff565b60001982549160031b1b19169055600255600052600360205260006040812055600190565b634e487b7160e01b600052603160045260246000fd5b611b34611b23611a559360026119ff565b90549060031b1c92839260026119ff565b90556000526003602052604060002055388080611abc565b9060018201918160005282602052604060002054801515600014611bff576000198101818111610ba4578254906000198201918211610ba457818103611bc8575b50505080548015611afc576000190190611ba782826119ff565b60001982549160031b1b191690555560005260205260006040812055600190565b611be8611bd8611a5593866119ff565b90549060031b1c928392866119ff565b905560005283602052604060002055388080611b8d565b5050505060009056fea2646970667358221220f4a0cd9b8521f3ffd424bd273c7c0eeff8191fdc51519abbc4678ff38833d3d764736f6c634300081a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ec89a5dd6c179c345ea7996aa879e59cb18c8484
-----Decoded View---------------
Arg [0] : initialAdmin (address): 0xec89a5dd6c179c345EA7996AA879E59cB18c8484
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000ec89a5dd6c179c345ea7996aa879e59cb18c8484
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.