Contract
0xdc91ea613247c0c9438a6f64cc0e08291198981a
2
Contract Overview
Balance:
0 AVAX
My Name Tag:
Not Available
[ Download CSV Export ]
Latest 25 internal transaction
[ Download CSV Export ]
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
DapiServer
Compiler Version
v0.8.9+commit.e5eed63a
Optimization Enabled:
Yes with 1000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.9; import "../utils/ExtendedMulticall.sol"; import "../whitelist/WhitelistWithManager.sol"; import "../protocol/AirnodeRequester.sol"; import "./Median.sol"; import "./interfaces/IDapiServer.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; /// @title Contract that serves Beacons, Beacon sets and dAPIs based on the /// Airnode protocol /// @notice A Beacon is a live data feed addressed by an ID, which is derived /// from an Airnode address and a template ID. This is suitable where the more /// recent data point is always more favorable, e.g., in the context of an /// asset price data feed. Beacons can also be seen as one-Airnode data feeds /// that can be used individually or combined to build Beacon sets. dAPIs are /// an abstraction layer over Beacons and Beacon sets. /// @dev DapiServer is a PSP requester contract. Unlike RRP, which is /// implemented as a central contract, PSP implementation is built into the /// requester for optimization. Accordingly, the checks that are not required /// are omitted. Some examples: /// - While executing a PSP Beacon update, the condition is not verified /// because Beacon updates where the condition returns `false` (i.e., the /// on-chain value is already close to the actual value) are not harmful, and /// are even desirable. /// - PSP Beacon set update subscription IDs are not verified, as the /// Airnode/relayer cannot be made to "misreport a Beacon set update" by /// spoofing a subscription ID. /// - While executing a PSP Beacon set update, even the signature is not /// checked because this is a purely keeper job that does not require off-chain /// data. Similar to Beacon updates, any Beacon set update is welcome. contract DapiServer is ExtendedMulticall, WhitelistWithManager, AirnodeRequester, Median, IDapiServer { using ECDSA for bytes32; // Airnodes serve their fulfillment data along with timestamps. This // contract casts the reported data to `int224` and the timestamp to // `uint32`, which works until year 2106. struct DataFeed { int224 value; uint32 timestamp; } /// @notice dAPI name setter role description string public constant override DAPI_NAME_SETTER_ROLE_DESCRIPTION = "dAPI name setter"; /// @notice Number that represents 100% /// @dev 10^8 (and not a larger number) is chosen to avoid overflows in /// `calculateUpdateInPercentage()`. Since the reported data needs to fit /// into 224 bits, its multiplication by 10^8 is guaranteed not to /// overflow. uint256 public constant override HUNDRED_PERCENT = 1e8; /// @notice dAPI name setter role bytes32 public immutable override dapiNameSetterRole; /// @notice If an account is an unlimited reader mapping(address => bool) public unlimitedReaderStatus; /// @notice If a sponsor has permitted an account to request RRP-based /// updates at this contract mapping(address => mapping(address => bool)) public override sponsorToRrpBeaconUpdateRequesterToPermissionStatus; /// @notice ID of the Beacon that the subscription is registered to update mapping(bytes32 => bytes32) public override subscriptionIdToBeaconId; mapping(bytes32 => DataFeed) private dataFeeds; mapping(bytes32 => bytes32) private requestIdToBeaconId; mapping(bytes32 => bytes32) private subscriptionIdToHash; mapping(bytes32 => bytes32) private dapiNameHashToDataFeedId; /// @dev Reverts if the sender is not permitted to request an RRP-based /// update with the sponsor and is not the sponsor /// @param sponsor Sponsor address modifier onlyPermittedUpdateRequester(address sponsor) { require( sponsor == msg.sender || sponsorToRrpBeaconUpdateRequesterToPermissionStatus[sponsor][ msg.sender ], "Sender not permitted" ); _; } /// @param _accessControlRegistry AccessControlRegistry contract address /// @param _adminRoleDescription Admin role description /// @param _manager Manager address /// @param _airnodeProtocol AirnodeProtocol contract address constructor( address _accessControlRegistry, string memory _adminRoleDescription, address _manager, address _airnodeProtocol ) WhitelistWithManager( _accessControlRegistry, _adminRoleDescription, _manager ) AirnodeRequester(_airnodeProtocol) { dapiNameSetterRole = _deriveRole( _deriveAdminRole(manager), keccak256(abi.encodePacked(DAPI_NAME_SETTER_ROLE_DESCRIPTION)) ); } /// ~~~RRP Beacon updates~~~ /// @notice Called by the sponsor to set the update request permission /// status of an account /// @param rrpBeaconUpdateRequester RRP-based Beacon update requester /// address /// @param status Permission status function setRrpBeaconUpdatePermissionStatus( address rrpBeaconUpdateRequester, bool status ) external override { require( rrpBeaconUpdateRequester != address(0), "Update requester zero" ); sponsorToRrpBeaconUpdateRequesterToPermissionStatus[msg.sender][ rrpBeaconUpdateRequester ] = status; emit SetRrpBeaconUpdatePermissionStatus( msg.sender, rrpBeaconUpdateRequester, status ); } /// @notice Creates an RRP requests for the Beacon to be updated /// @dev In addition to the sponsor sponsoring this contract (by calling /// `setRrpSponsorshipStatus()`), the sponsor must also give update request /// permission to the sender (by calling /// `setRrpBeaconUpdatePermissionStatus()`) before this method is called. /// The template must specify a single point of data of type `int256` to be /// returned and for it to be small enough to be castable to `int224` /// because this is what `fulfillRrpBeaconUpdate()` expects. /// @param airnode Airnode address /// @param templateId Template ID /// @param sponsor Sponsor address /// @return requestId Request ID function requestRrpBeaconUpdate( address airnode, bytes32 templateId, address sponsor ) external override onlyPermittedUpdateRequester(sponsor) returns (bytes32 requestId) { bytes32 beaconId = deriveBeaconId(airnode, templateId); requestId = IAirnodeProtocol(airnodeProtocol).makeRequest( airnode, templateId, "", sponsor, this.fulfillRrpBeaconUpdate.selector ); requestIdToBeaconId[requestId] = beaconId; emit RequestedRrpBeaconUpdate( beaconId, sponsor, msg.sender, requestId, airnode, templateId ); } /// @notice Creates an RRP requests for the Beacon to be updated by the relayer /// @param airnode Airnode address /// @param templateId Template ID /// @param relayer Relayer address /// @param sponsor Sponsor address /// @return requestId Request ID function requestRrpBeaconUpdateRelayed( address airnode, bytes32 templateId, address relayer, address sponsor ) external override onlyPermittedUpdateRequester(sponsor) returns (bytes32 requestId) { bytes32 beaconId = deriveBeaconId(airnode, templateId); requestId = IAirnodeProtocol(airnodeProtocol).makeRequestRelayed( airnode, templateId, "", relayer, sponsor, this.fulfillRrpBeaconUpdate.selector ); requestIdToBeaconId[requestId] = beaconId; emit RequestedRrpBeaconUpdateRelayed( beaconId, sponsor, msg.sender, requestId, airnode, relayer, templateId ); } /// @notice Called by the Airnode/relayer using the sponsor wallet through /// AirnodeProtocol to fulfill the request /// @param requestId Request ID /// @param timestamp Timestamp used in the signature /// @param data Fulfillment data (an `int256` encoded in contract ABI) function fulfillRrpBeaconUpdate( bytes32 requestId, uint256 timestamp, bytes calldata data ) external override onlyAirnodeProtocol onlyValidTimestamp(timestamp) { bytes32 beaconId = requestIdToBeaconId[requestId]; delete requestIdToBeaconId[requestId]; int256 decodedData = processBeaconUpdate(beaconId, timestamp, data); emit UpdatedBeaconWithRrp(beaconId, requestId, decodedData, timestamp); } /// ~~~PSP Beacon updates~~~ /// @notice Registers the Beacon update subscription /// @dev Similar to how one needs to call `requestRrpBeaconUpdate()` for /// this contract to recognize the incoming RRP fulfillment, this needs to /// be called before the subscription fulfillments. /// In addition to the subscription being registered, the sponsor must use /// `setPspSponsorshipStatus()` to give permission for its sponsor wallet /// to be used for the specific subscription. /// @param airnode Airnode address /// @param templateId Template ID /// @param conditions Conditions under which the subscription is requested /// to be fulfilled /// @param relayer Relayer address /// @param sponsor Sponsor address /// @return subscriptionId Subscription ID function registerBeaconUpdateSubscription( address airnode, bytes32 templateId, bytes memory conditions, address relayer, address sponsor ) external override returns (bytes32 subscriptionId) { require(relayer != address(0), "Relayer address zero"); require(sponsor != address(0), "Sponsor address zero"); subscriptionId = keccak256( abi.encode( block.chainid, airnode, templateId, "", conditions, relayer, sponsor, address(this), this.fulfillPspBeaconUpdate.selector ) ); subscriptionIdToHash[subscriptionId] = keccak256( abi.encodePacked(airnode, relayer, sponsor) ); subscriptionIdToBeaconId[subscriptionId] = deriveBeaconId( airnode, templateId ); emit RegisteredBeaconUpdateSubscription( subscriptionId, airnode, templateId, "", conditions, relayer, sponsor, address(this), this.fulfillPspBeaconUpdate.selector ); } /// @notice Returns if the respective Beacon needs to be updated based on /// the fulfillment data and the condition parameters /// @dev Reverts if not called by a void signer with zero address because /// this method can be used to indirectly read a Beacon. /// `conditionParameters` are specified within the `conditions` field of a /// Subscription. /// @param subscriptionId Subscription ID /// @param data Fulfillment data (an `int256` encoded in contract ABI) /// @param conditionParameters Subscription condition parameters (a /// `uint256` encoded in contract ABI) /// @return If the Beacon update subscription should be fulfilled function conditionPspBeaconUpdate( bytes32 subscriptionId, bytes calldata data, bytes calldata conditionParameters ) external view override returns (bool) { require(msg.sender == address(0), "Sender not zero address"); bytes32 beaconId = subscriptionIdToBeaconId[subscriptionId]; require(beaconId != bytes32(0), "Subscription not registered"); DataFeed storage beacon = dataFeeds[beaconId]; return calculateUpdateInPercentage( beacon.value, decodeFulfillmentData(data) ) >= decodeConditionParameters(conditionParameters) || beacon.timestamp == 0; } /// @notice Called by the Airnode/relayer using the sponsor wallet to /// fulfill the Beacon update subscription /// @dev There is no need to verify that `conditionPspBeaconUpdate()` /// returns `true` because any Beacon update is a good Beacon update /// @param subscriptionId Subscription ID /// @param airnode Airnode address /// @param relayer Relayer address /// @param sponsor Sponsor address /// @param timestamp Timestamp used in the signature /// @param data Fulfillment data (a single `int256` encoded in contract /// ABI) /// @param signature Subscription ID, timestamp, sponsor wallet address /// (and fulfillment data if the relayer is not the Airnode) signed by the /// Airnode wallet function fulfillPspBeaconUpdate( bytes32 subscriptionId, address airnode, address relayer, address sponsor, uint256 timestamp, bytes calldata data, bytes calldata signature ) external override onlyValidTimestamp(timestamp) { require( subscriptionIdToHash[subscriptionId] == keccak256(abi.encodePacked(airnode, relayer, sponsor)), "Subscription not registered" ); if (airnode == relayer) { require( ( keccak256( abi.encodePacked(subscriptionId, timestamp, msg.sender) ).toEthSignedMessageHash() ).recover(signature) == airnode, "Signature mismatch" ); } else { require( ( keccak256( abi.encodePacked( subscriptionId, timestamp, msg.sender, data ) ).toEthSignedMessageHash() ).recover(signature) == airnode, "Signature mismatch" ); } bytes32 beaconId = subscriptionIdToBeaconId[subscriptionId]; // Beacon ID is guaranteed to not be zero because the subscription is // registered int256 decodedData = processBeaconUpdate(beaconId, timestamp, data); emit UpdatedBeaconWithPsp( beaconId, subscriptionId, int224(decodedData), uint32(timestamp) ); } /// ~~~Signed data Beacon updates~~~ /// @notice Updates a Beacon using data signed by the respective Airnode, /// without requiring a request or subscription /// @param airnode Airnode address /// @param templateId Template ID /// @param timestamp Timestamp used in the signature /// @param data Response data (an `int256` encoded in contract ABI) /// @param signature Template ID, a timestamp and the response data signed /// by the Airnode address function updateBeaconWithSignedData( address airnode, bytes32 templateId, uint256 timestamp, bytes calldata data, bytes calldata signature ) external override onlyValidTimestamp(timestamp) { require( ( keccak256(abi.encodePacked(templateId, timestamp, data)) .toEthSignedMessageHash() ).recover(signature) == airnode, "Signature mismatch" ); bytes32 beaconId = deriveBeaconId(airnode, templateId); int256 decodedData = processBeaconUpdate(beaconId, timestamp, data); emit UpdatedBeaconWithSignedData(beaconId, decodedData, timestamp); } /// ~~~PSP Beacon set updates~~~ /// @notice Updates the Beacon set using the current values of its Beacons /// @dev This function still works if some of the IDs in `beaconIds` belong /// to Beacon sets rather than Beacons. However, this is not the intended /// use. /// @param beaconIds Beacon IDs /// @return beaconSetId Beacon set ID function updateBeaconSetWithBeacons(bytes32[] memory beaconIds) public override returns (bytes32 beaconSetId) { uint256 beaconCount = beaconIds.length; require(beaconCount > 1, "Specified less than two Beacons"); int256[] memory values = new int256[](beaconCount); uint256 accumulatedTimestamp = 0; for (uint256 ind = 0; ind < beaconCount; ind++) { DataFeed storage dataFeed = dataFeeds[beaconIds[ind]]; values[ind] = dataFeed.value; accumulatedTimestamp += dataFeed.timestamp; } uint32 updatedTimestamp = uint32(accumulatedTimestamp / beaconCount); beaconSetId = deriveBeaconSetId(beaconIds); require( updatedTimestamp >= dataFeeds[beaconSetId].timestamp, "Updated value outdated" ); int224 updatedValue = int224(median(values)); dataFeeds[beaconSetId] = DataFeed({ value: updatedValue, timestamp: updatedTimestamp }); emit UpdatedBeaconSetWithBeacons( beaconSetId, updatedValue, updatedTimestamp ); } /// @notice Updates the Beacon set using the current values of the Beacons /// and returns if this update was justified according to the deviation /// threshold /// @dev This method does not allow the caller to indirectly read a Beacon /// set, which is why it does not require the sender to be a void signer /// with zero address. This allows the implementation of incentive /// mechanisms that rewards keepers that trigger valid dAPI updates. /// @param beaconIds Beacon IDs /// @param deviationThresholdInPercentage Deviation threshold in percentage /// where 100% is represented as `HUNDRED_PERCENT` function updateBeaconSetWithBeaconsAndReturnCondition( bytes32[] memory beaconIds, uint256 deviationThresholdInPercentage ) public override returns (bool) { bytes32 beaconSetId = deriveBeaconSetId(beaconIds); DataFeed memory initialBeaconSet = dataFeeds[beaconSetId]; updateBeaconSetWithBeacons(beaconIds); DataFeed storage updatedBeaconSet = dataFeeds[beaconSetId]; return calculateUpdateInPercentage( initialBeaconSet.value, updatedBeaconSet.value ) >= deviationThresholdInPercentage || (initialBeaconSet.timestamp == 0 && updatedBeaconSet.timestamp > 0); } /// @notice Returns if the respective Beacon set needs to be updated based /// on the condition parameters /// @dev The template ID used in the respective Subscription is expected to /// be zero, which means the `parameters` field of the Subscription will be /// forwarded to this function as `data`. This field should be the Beacon /// ID array encoded in contract ABI. /// @param subscriptionId Subscription ID /// @param data Fulfillment data (array of Beacon IDs, i.e., `bytes32[]` /// encoded in contract ABI) /// @param conditionParameters Subscription condition parameters (a /// `uint256` encoded in contract ABI) /// @return If the Beacon set update subscription should be fulfilled function conditionPspBeaconSetUpdate( bytes32 subscriptionId, // solhint-disable-line no-unused-vars bytes calldata data, bytes calldata conditionParameters ) external override returns (bool) { require(msg.sender == address(0), "Sender not zero address"); bytes32[] memory beaconIds = abi.decode(data, (bytes32[])); require( keccak256(abi.encode(beaconIds)) == keccak256(data), "Data length not correct" ); return updateBeaconSetWithBeaconsAndReturnCondition( beaconIds, decodeConditionParameters(conditionParameters) ); } /// @notice Called by the Airnode/relayer using the sponsor wallet to /// fulfill the Beacon set update subscription /// @dev Similar to `conditionPspBeaconSetUpdate()`, if `templateId` of the /// Subscription is zero, its `parameters` field will be forwarded to /// `data` here, which is expect to be contract ABI-encoded array of Beacon /// IDs. /// It does not make sense for this subscription to be relayed, as there is /// no external data being delivered. Nevertheless, this is allowed for the /// lack of a reason to prevent it. /// Even though the consistency of the arguments are not being checked, if /// a standard implementation of Airnode is being used, these can be /// expected to be correct. Either way, the assumption is that it does not /// matter for the purposes of a Beacon set update subscription. /// @param subscriptionId Subscription ID /// @param airnode Airnode address /// @param relayer Relayer address /// @param sponsor Sponsor address /// @param timestamp Timestamp used in the signature /// @param data Fulfillment data (an `int256` encoded in contract ABI) /// @param signature Subscription ID, timestamp, sponsor wallet address /// (and fulfillment data if the relayer is not the Airnode) signed by the /// Airnode wallet function fulfillPspBeaconSetUpdate( bytes32 subscriptionId, // solhint-disable-line no-unused-vars address airnode, // solhint-disable-line no-unused-vars address relayer, // solhint-disable-line no-unused-vars address sponsor, // solhint-disable-line no-unused-vars uint256 timestamp, // solhint-disable-line no-unused-vars bytes calldata data, bytes calldata signature // solhint-disable-line no-unused-vars ) external override { require( keccak256(data) == updateBeaconSetWithBeacons(abi.decode(data, (bytes32[]))), "Data length not correct" ); } /// ~~~Signed data Beacon set updates~~~ /// @notice Updates a Beacon set using data signed by the respective /// Airnodes without requiring a request or subscription. The Beacons for /// which the signature is omitted will be read from the storage. /// @param airnodes Airnode addresses /// @param templateIds Template IDs /// @param timestamps Timestamps used in the signatures /// @param data Response data (an `int256` encoded in contract ABI per /// Beacon) /// @param signatures Template ID, a timestamp and the response data signed /// by the respective Airnode address per Beacon /// @return beaconSetId Beacon set ID function updateBeaconSetWithSignedData( address[] memory airnodes, bytes32[] memory templateIds, uint256[] memory timestamps, bytes[] memory data, bytes[] memory signatures ) external override returns (bytes32 beaconSetId) { uint256 beaconCount = airnodes.length; require( beaconCount == templateIds.length && beaconCount == timestamps.length && beaconCount == data.length && beaconCount == signatures.length, "Parameter length mismatch" ); require(beaconCount > 1, "Specified less than two Beacons"); bytes32[] memory beaconIds = new bytes32[](beaconCount); int256[] memory values = new int256[](beaconCount); uint256 accumulatedTimestamp = 0; for (uint256 ind = 0; ind < beaconCount; ind++) { if (signatures[ind].length != 0) { address airnode = airnodes[ind]; uint256 timestamp = timestamps[ind]; require(timestampIsValid(timestamp), "Timestamp not valid"); require( ( keccak256( abi.encodePacked( templateIds[ind], timestamp, data[ind] ) ).toEthSignedMessageHash() ).recover(signatures[ind]) == airnode, "Signature mismatch" ); values[ind] = decodeFulfillmentData(data[ind]); // Timestamp validity is already checked, which means it will // be small enough to be typecast into `uint32` accumulatedTimestamp += timestamp; beaconIds[ind] = deriveBeaconId(airnode, templateIds[ind]); } else { bytes32 beaconId = deriveBeaconId( airnodes[ind], templateIds[ind] ); DataFeed storage dataFeed = dataFeeds[beaconId]; values[ind] = dataFeed.value; accumulatedTimestamp += dataFeed.timestamp; beaconIds[ind] = beaconId; } } beaconSetId = deriveBeaconSetId(beaconIds); uint32 updatedTimestamp = uint32(accumulatedTimestamp / beaconCount); require( updatedTimestamp >= dataFeeds[beaconSetId].timestamp, "Updated value outdated" ); int224 updatedValue = int224(median(values)); dataFeeds[beaconSetId] = DataFeed({ value: updatedValue, timestamp: updatedTimestamp }); emit UpdatedBeaconSetWithSignedData( beaconSetId, updatedValue, updatedTimestamp ); } /// @notice Called by the manager to add the unlimited reader indefinitely /// @dev Since the unlimited reader status cannot be revoked, only /// contracts that are adequately restricted should be given this status /// @param unlimitedReader Unlimited reader address function addUnlimitedReader(address unlimitedReader) external override { require(msg.sender == manager, "Sender not manager"); unlimitedReaderStatus[unlimitedReader] = true; emit AddedUnlimitedReader(unlimitedReader); } /// @notice Sets the data feed ID the dAPI name points to /// @dev While a data feed ID refers to a specific Beacon or Beacon set, /// dAPI names provide a more abstract interface for convenience. This /// means a dAPI name that was pointing to a Beacon can be pointed to a /// Beacon set, then another Beacon set, etc. /// @param dapiName Human-readable dAPI name /// @param dataFeedId Data feed ID the dAPI name will point to function setDapiName(bytes32 dapiName, bytes32 dataFeedId) external override { require(dapiName != bytes32(0), "dAPI name zero"); require( msg.sender == manager || IAccessControlRegistry(accessControlRegistry).hasRole( dapiNameSetterRole, msg.sender ), "Sender cannot set dAPI name" ); dapiNameHashToDataFeedId[ keccak256(abi.encodePacked(dapiName)) ] = dataFeedId; emit SetDapiName(dapiName, dataFeedId, msg.sender); } /// @notice Returns the data feed ID the dAPI name is set to /// @param dapiName dAPI name /// @return Data feed ID function dapiNameToDataFeedId(bytes32 dapiName) external view override returns (bytes32) { return dapiNameHashToDataFeedId[keccak256(abi.encodePacked(dapiName))]; } /// @notice Reads the data feed with ID /// @param dataFeedId Data feed ID /// @return value Data feed value /// @return timestamp Data feed timestamp function readDataFeedWithId(bytes32 dataFeedId) external view override returns (int224 value, uint32 timestamp) { require( readerCanReadDataFeed(dataFeedId, msg.sender), "Sender cannot read" ); DataFeed storage dataFeed = dataFeeds[dataFeedId]; return (dataFeed.value, dataFeed.timestamp); } /// @notice Reads the data feed value with ID /// @param dataFeedId Data feed ID /// @return value Data feed value function readDataFeedValueWithId(bytes32 dataFeedId) external view override returns (int224 value) { require( readerCanReadDataFeed(dataFeedId, msg.sender), "Sender cannot read" ); DataFeed storage dataFeed = dataFeeds[dataFeedId]; require(dataFeed.timestamp != 0, "Data feed does not exist"); return dataFeed.value; } /// @notice Reads the data feed with dAPI name /// @dev The read data feed may belong to a Beacon or dAPI. The reader /// must be whitelisted for the hash of the dAPI name. /// @param dapiName dAPI name /// @return value Data feed value /// @return timestamp Data feed timestamp function readDataFeedWithDapiName(bytes32 dapiName) external view override returns (int224 value, uint32 timestamp) { bytes32 dapiNameHash = keccak256(abi.encodePacked(dapiName)); require( readerCanReadDataFeed(dapiNameHash, msg.sender), "Sender cannot read" ); bytes32 dataFeedId = dapiNameHashToDataFeedId[dapiNameHash]; require(dataFeedId != bytes32(0), "dAPI name not set"); DataFeed storage dataFeed = dataFeeds[dataFeedId]; return (dataFeed.value, dataFeed.timestamp); } /// @notice Reads the data feed value with dAPI name /// @param dapiName dAPI name /// @return value Data feed value function readDataFeedValueWithDapiName(bytes32 dapiName) external view override returns (int224 value) { bytes32 dapiNameHash = keccak256(abi.encodePacked(dapiName)); require( readerCanReadDataFeed(dapiNameHash, msg.sender), "Sender cannot read" ); DataFeed storage dataFeed = dataFeeds[ dapiNameHashToDataFeedId[dapiNameHash] ]; require(dataFeed.timestamp != 0, "Data feed does not exist"); return dataFeed.value; } /// @notice Returns if a reader can read the data feed /// @param dataFeedId Data feed ID (or dAPI name hash) /// @param reader Reader address /// @return If the reader can read the data feed function readerCanReadDataFeed(bytes32 dataFeedId, address reader) public view override returns (bool) { return reader == address(0) || userIsWhitelisted(dataFeedId, reader) || unlimitedReaderStatus[reader]; } /// @notice Returns the detailed whitelist status of the reader for the /// data feed /// @param dataFeedId Data feed ID (or dAPI name hash) /// @param reader Reader address /// @return expirationTimestamp Timestamp at which the whitelisting of the /// reader will expire /// @return indefiniteWhitelistCount Number of times `reader` was /// whitelisted indefinitely for `dataFeedId` function dataFeedIdToReaderToWhitelistStatus( bytes32 dataFeedId, address reader ) external view override returns (uint64 expirationTimestamp, uint192 indefiniteWhitelistCount) { WhitelistStatus storage whitelistStatus = serviceIdToUserToWhitelistStatus[ dataFeedId ][reader]; expirationTimestamp = whitelistStatus.expirationTimestamp; indefiniteWhitelistCount = whitelistStatus.indefiniteWhitelistCount; } /// @notice Returns if an account has indefinitely whitelisted the reader /// for the data feed /// @param dataFeedId Data feed ID (or dAPI name hash) /// @param reader Reader address /// @param setter Address of the account that has potentially whitelisted /// the reader for the data feed indefinitely /// @return indefiniteWhitelistStatus If `setter` has indefinitely /// whitelisted reader for the data feed function dataFeedIdToReaderToSetterToIndefiniteWhitelistStatus( bytes32 dataFeedId, address reader, address setter ) external view override returns (bool indefiniteWhitelistStatus) { indefiniteWhitelistStatus = serviceIdToUserToSetterToIndefiniteWhitelistStatus[ dataFeedId ][reader][setter]; } /// @notice Derives the Beacon ID from the Airnode address and template ID /// @param airnode Airnode address /// @param templateId Template ID /// @return beaconId Beacon ID function deriveBeaconId(address airnode, bytes32 templateId) public pure override returns (bytes32 beaconId) { require(airnode != address(0), "Airnode address zero"); require(templateId != bytes32(0), "Template ID zero"); beaconId = keccak256(abi.encodePacked(airnode, templateId)); } /// @notice Derives the Beacon set ID from the Beacon IDs /// @dev Notice that `abi.encode()` is used over `abi.encodePacked()` /// @param beaconIds Beacon IDs /// @return beaconSetId Beacon set ID function deriveBeaconSetId(bytes32[] memory beaconIds) public pure override returns (bytes32 beaconSetId) { beaconSetId = keccak256(abi.encode(beaconIds)); } /// @notice Called privately to process the Beacon update /// @param beaconId Beacon ID /// @param timestamp Timestamp used in the signature /// @param data Fulfillment data (an `int256` encoded in contract ABI) /// @return updatedBeaconValue Updated Beacon value function processBeaconUpdate( bytes32 beaconId, uint256 timestamp, bytes calldata data ) private returns (int256 updatedBeaconValue) { updatedBeaconValue = decodeFulfillmentData(data); require( timestamp > dataFeeds[beaconId].timestamp, "Fulfillment older than Beacon" ); // Timestamp validity is already checked by `onlyValidTimestamp`, which // means it will be small enough to be typecast into `uint32` dataFeeds[beaconId] = DataFeed({ value: int224(updatedBeaconValue), timestamp: uint32(timestamp) }); } /// @notice Called privately to decode the fulfillment data /// @param data Fulfillment data (an `int256` encoded in contract ABI) /// @return decodedData Decoded fulfillment data function decodeFulfillmentData(bytes memory data) private pure returns (int224) { require(data.length == 32, "Data length not correct"); int256 decodedData = abi.decode(data, (int256)); require( decodedData >= type(int224).min && decodedData <= type(int224).max, "Value typecasting error" ); return int224(decodedData); } /// @notice Called privately to decode the condition parameters /// @param conditionParameters Condition parameters (a `uint256` encoded in /// contract ABI) /// @return deviationThresholdInPercentage Deviation threshold in /// percentage where 100% is represented as `HUNDRED_PERCENT` function decodeConditionParameters(bytes calldata conditionParameters) private pure returns (uint256 deviationThresholdInPercentage) { require(conditionParameters.length == 32, "Incorrect parameter length"); deviationThresholdInPercentage = abi.decode( conditionParameters, (uint256) ); } /// @notice Called privately to calculate the update magnitude in /// percentages where 100% is represented as `HUNDRED_PERCENT` /// @dev The percentage changes will be more pronounced when the first /// value is almost zero, which may trigger updates more frequently than /// wanted. To avoid this, Beacons should be defined in a way that the /// expected values are not small numbers floating around zero, i.e., /// offset and scale. /// @param initialValue Initial value /// @param updatedValue Updated value /// @return updateInPercentage Update in percentage function calculateUpdateInPercentage( int224 initialValue, int224 updatedValue ) private pure returns (uint256 updateInPercentage) { int256 delta = int256(updatedValue) - int256(initialValue); uint256 absoluteDelta = delta > 0 ? uint256(delta) : uint256(-delta); uint256 absoluteInitialValue = initialValue > 0 ? uint256(int256(initialValue)) : uint256(-int256(initialValue)); // Avoid division by 0 if (absoluteInitialValue == 0) { absoluteInitialValue = 1; } updateInPercentage = (absoluteDelta * HUNDRED_PERCENT) / absoluteInitialValue; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/utils/Multicall.sol"; /// @notice Contract that extends the functionality of Multicall to cover the /// retrieval of some globally available variables contract ExtendedMulticall is Multicall { /// @notice Returns the chain ID /// @return Chain ID function getChainId() external view returns (uint256) { return block.chainid; } /// @notice Returns the account balance /// @param account Account address /// @return Account balance function getBalance(address account) external view returns (uint256) { return account.balance; } /// @notice Returns the current block number /// @return Current block number function getBlockNumber() external view returns (uint256) { return block.number; } /// @notice Returns the current block timestamp /// @return Current block timestamp function getBlockTimestamp() external view returns (uint256) { return block.timestamp; } /// @notice Returns the current block basefee /// @return Current block basefee function getBlockBasefee() external view returns (uint256) { return block.basefee; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./Whitelist.sol"; import "./WhitelistRolesWithManager.sol"; import "./interfaces/IWhitelistWithManager.sol"; /// @title Contract to be inherited by Whitelist contracts that are controlled /// by a manager contract WhitelistWithManager is Whitelist, WhitelistRolesWithManager, IWhitelistWithManager { /// @param _accessControlRegistry AccessControlRegistry contract address /// @param _adminRoleDescription Admin role description /// @param _manager Manager address constructor( address _accessControlRegistry, string memory _adminRoleDescription, address _manager ) WhitelistRolesWithManager( _accessControlRegistry, _adminRoleDescription, _manager ) {} /// @notice Extends the expiration of the temporary whitelist of `user` to /// be able to use the service with `serviceId` if the sender has the /// whitelist expiration extender role /// @param serviceId Service ID /// @param user User address /// @param expirationTimestamp Timestamp at which the temporary whitelist /// will expire function extendWhitelistExpiration( bytes32 serviceId, address user, uint64 expirationTimestamp ) external override { require( hasWhitelistExpirationExtenderRoleOrIsManager(msg.sender), "Cannot extend expiration" ); require(serviceId != bytes32(0), "Service ID zero"); require(user != address(0), "User address zero"); _extendWhitelistExpiration(serviceId, user, expirationTimestamp); emit ExtendedWhitelistExpiration( serviceId, user, msg.sender, expirationTimestamp ); } /// @notice Sets the expiration of the temporary whitelist of `user` to be /// able to use the service with `serviceId` if the sender has the /// whitelist expiration setter role /// @param serviceId Service ID /// @param user User address /// @param expirationTimestamp Timestamp at which the temporary whitelist /// will expire function setWhitelistExpiration( bytes32 serviceId, address user, uint64 expirationTimestamp ) external override { require( hasWhitelistExpirationSetterRoleOrIsManager(msg.sender), "Cannot set expiration" ); require(serviceId != bytes32(0), "Service ID zero"); require(user != address(0), "User address zero"); _setWhitelistExpiration(serviceId, user, expirationTimestamp); emit SetWhitelistExpiration( serviceId, user, msg.sender, expirationTimestamp ); } /// @notice Sets the indefinite whitelist status of `user` to be able to /// use the service with `serviceId` if the sender has the indefinite /// whitelister role /// @param serviceId Service ID /// @param user User address /// @param status Indefinite whitelist status function setIndefiniteWhitelistStatus( bytes32 serviceId, address user, bool status ) external override { require( hasIndefiniteWhitelisterRoleOrIsManager(msg.sender), "Cannot set indefinite status" ); require(serviceId != bytes32(0), "Service ID zero"); require(user != address(0), "User address zero"); uint192 indefiniteWhitelistCount = _setIndefiniteWhitelistStatus( serviceId, user, status ); emit SetIndefiniteWhitelistStatus( serviceId, user, msg.sender, status, indefiniteWhitelistCount ); } /// @notice Revokes the indefinite whitelist status granted by a specific /// account that no longer has the indefinite whitelister role /// @param serviceId Service ID /// @param user User address /// @param setter Setter of the indefinite whitelist status function revokeIndefiniteWhitelistStatus( bytes32 serviceId, address user, address setter ) external override { require( !hasIndefiniteWhitelisterRoleOrIsManager(setter), "setter can set indefinite status" ); ( bool revoked, uint192 indefiniteWhitelistCount ) = _revokeIndefiniteWhitelistStatus(serviceId, user, setter); if (revoked) { emit RevokedIndefiniteWhitelistStatus( serviceId, user, setter, msg.sender, indefiniteWhitelistCount ); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./interfaces/IAirnodeProtocol.sol"; import "./interfaces/IAirnodeRequester.sol"; /// @title Contract to be inherited by contracts that will make Airnode /// requests and receive fulfillments contract AirnodeRequester is IAirnodeRequester { /// @notice AirnodeProtocol contract address address public immutable override airnodeProtocol; /// @dev Reverts if the sender is not the AirnodeProtocol contract. Use /// this modifier with methods that are meant to receive RRP fulfillments. modifier onlyAirnodeProtocol() { require( msg.sender == address(airnodeProtocol), "Sender not Airnode protocol" ); _; } /// @dev Reverts if the timestamp is not valid. Use this modifier with /// methods that are meant to receive RRP and PSP fulfillments. /// @param timestamp Timestamp used in the signature modifier onlyValidTimestamp(uint256 timestamp) { require(timestampIsValid(timestamp), "Timestamp not valid"); _; } /// @param _airnodeProtocol AirnodeProtocol contract address constructor(address _airnodeProtocol) { require(_airnodeProtocol != address(0), "AirnodeProtocol address zero"); airnodeProtocol = _airnodeProtocol; } /// @notice Returns if the timestamp used in the signature is valid /// @dev Returns `false` if the timestamp is not at most 1 hour old to /// prevent replays. Returns `false` if the timestamp is not from the past, /// with some leeway to accomodate for some benign time drift. These values /// are appropriate in most cases, but you can adjust them if you are aware /// of the implications. /// @param timestamp Timestamp used in the signature function timestampIsValid(uint256 timestamp) internal view returns (bool) { return timestamp + 1 hours > block.timestamp && timestamp < block.timestamp + 15 minutes; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./Sort.sol"; import "./QuickSelect.sol"; /// @title Contract to be inherited by contracts that will calculate the median /// of an array /// @notice The operation will be in-place, i.e., the array provided as the /// argument will be modified. contract Median is Sort, Quickselect { /// @notice Returns the median of the array /// @dev Uses an unrolled sorting implementation for shorter arrays and /// quickselect for longer arrays for gas cost efficiency /// @param array Array whose median is to be calculated /// @return Median of the array function median(int256[] memory array) internal pure returns (int256) { uint256 arrayLength = array.length; if (arrayLength <= MAX_SORT_LENGTH) { sort(array); if (arrayLength % 2 == 1) { return array[arrayLength / 2]; } else { return (array[arrayLength / 2 - 1] + array[arrayLength / 2]) / 2; } } else { if (arrayLength % 2 == 1) { return array[quickselectK(array, arrayLength / 2)]; } else { (uint256 mid1, uint256 mid2) = quickselectKPlusOne( array, arrayLength / 2 - 1 ); return (array[mid1] + array[mid2]) / 2; } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../../protocol/interfaces/IAirnodeRequester.sol"; interface IDapiServer is IAirnodeRequester { event SetRrpBeaconUpdatePermissionStatus( address indexed sponsor, address indexed rrpBeaconUpdateRequester, bool status ); event RequestedRrpBeaconUpdate( bytes32 indexed beaconId, address indexed sponsor, address indexed requester, bytes32 requestId, address airnode, bytes32 templateId ); event RequestedRrpBeaconUpdateRelayed( bytes32 indexed beaconId, address indexed sponsor, address indexed requester, bytes32 requestId, address airnode, address relayer, bytes32 templateId ); event UpdatedBeaconWithRrp( bytes32 indexed beaconId, bytes32 requestId, int256 value, uint256 timestamp ); event RegisteredBeaconUpdateSubscription( bytes32 indexed subscriptionId, address airnode, bytes32 templateId, bytes parameters, bytes conditions, address relayer, address sponsor, address requester, bytes4 fulfillFunctionId ); event UpdatedBeaconWithPsp( bytes32 indexed beaconId, bytes32 subscriptionId, int224 value, uint32 timestamp ); event UpdatedBeaconWithSignedData( bytes32 indexed beaconId, int256 value, uint256 timestamp ); event UpdatedBeaconSetWithBeacons( bytes32 indexed beaconSetId, int224 value, uint32 timestamp ); event UpdatedBeaconSetWithSignedData( bytes32 indexed dapiId, int224 value, uint32 timestamp ); event AddedUnlimitedReader(address indexed unlimitedReader); event SetDapiName( bytes32 indexed dapiName, bytes32 dataFeedId, address indexed sender ); function setRrpBeaconUpdatePermissionStatus( address rrpBeaconUpdateRequester, bool status ) external; function requestRrpBeaconUpdate( address airnode, bytes32 templateId, address sponsor ) external returns (bytes32 requestId); function requestRrpBeaconUpdateRelayed( address airnode, bytes32 templateId, address relayer, address sponsor ) external returns (bytes32 requestId); function fulfillRrpBeaconUpdate( bytes32 requestId, uint256 timestamp, bytes calldata data ) external; function registerBeaconUpdateSubscription( address airnode, bytes32 templateId, bytes memory conditions, address relayer, address sponsor ) external returns (bytes32 subscriptionId); function conditionPspBeaconUpdate( bytes32 subscriptionId, bytes calldata data, bytes calldata conditionParameters ) external view returns (bool); function fulfillPspBeaconUpdate( bytes32 subscriptionId, address airnode, address relayer, address sponsor, uint256 timestamp, bytes calldata data, bytes calldata signature ) external; function updateBeaconWithSignedData( address airnode, bytes32 beaconId, uint256 timestamp, bytes calldata data, bytes calldata signature ) external; function updateBeaconSetWithBeacons(bytes32[] memory beaconIds) external returns (bytes32 beaconSetId); function updateBeaconSetWithBeaconsAndReturnCondition( bytes32[] memory beaconIds, uint256 updateThresholdInPercentage ) external returns (bool); function conditionPspBeaconSetUpdate( bytes32 subscriptionId, bytes calldata data, bytes calldata conditionParameters ) external returns (bool); function fulfillPspBeaconSetUpdate( bytes32 subscriptionId, address airnode, address relayer, address sponsor, uint256 timestamp, bytes calldata data, bytes calldata signature ) external; function updateBeaconSetWithSignedData( address[] memory airnodes, bytes32[] memory templateIds, uint256[] memory timestamps, bytes[] memory data, bytes[] memory signatures ) external returns (bytes32 beaconSetId); function addUnlimitedReader(address unlimitedReader) external; function setDapiName(bytes32 dapiName, bytes32 dataFeedId) external; function dapiNameToDataFeedId(bytes32 dapiName) external view returns (bytes32); function readDataFeedWithId(bytes32 dataFeedId) external view returns (int224 value, uint32 timestamp); function readDataFeedValueWithId(bytes32 dataFeedId) external view returns (int224 value); function readDataFeedWithDapiName(bytes32 dapiName) external view returns (int224 value, uint32 timestamp); function readDataFeedValueWithDapiName(bytes32 dapiName) external view returns (int224 value); function readerCanReadDataFeed(bytes32 dataFeedId, address reader) external view returns (bool); function dataFeedIdToReaderToWhitelistStatus( bytes32 dataFeedId, address reader ) external view returns (uint64 expirationTimestamp, uint192 indefiniteWhitelistCount); function dataFeedIdToReaderToSetterToIndefiniteWhitelistStatus( bytes32 dataFeedId, address reader, address setter ) external view returns (bool indefiniteWhitelistStatus); function deriveBeaconId(address airnode, bytes32 templateId) external pure returns (bytes32 beaconId); function deriveBeaconSetId(bytes32[] memory beaconIds) external pure returns (bytes32 beaconSetId); // solhint-disable-next-line func-name-mixedcase function DAPI_NAME_SETTER_ROLE_DESCRIPTION() external view returns (string memory); // solhint-disable-next-line func-name-mixedcase function HUNDRED_PERCENT() external view returns (uint256); function dapiNameSetterRole() external view returns (bytes32); function sponsorToRrpBeaconUpdateRequesterToPermissionStatus( address sponsor, address updateRequester ) external view returns (bool); function subscriptionIdToBeaconId(bytes32 subscriptionId) external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } else if (error == RecoverError.InvalidSignatureV) { revert("ECDSA: invalid signature 'v' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { // Check the signature length // - case 65: r,s,v signature (standard) // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._ if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else if (signature.length == 64) { bytes32 r; bytes32 vs; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly { r := mload(add(signature, 0x20)) vs := mload(add(signature, 0x40)) } return tryRecover(hash, r, vs); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s; uint8 v; assembly { s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) v := add(shr(255, vs), 27) } return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } if (v != 27 && v != 28) { return (address(0), RecoverError.InvalidSignatureV); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Multicall.sol) pragma solidity ^0.8.0; import "./Address.sol"; /** * @dev Provides a function to batch together multiple calls in a single external call. * * _Available since v4.1._ */ abstract contract Multicall { /** * @dev Receives and executes a batch of function calls on this contract. */ function multicall(bytes[] calldata data) external returns (bytes[] memory results) { results = new bytes[](data.length); for (uint256 i = 0; i < data.length; i++) { results[i] = Address.functionDelegateCall(address(this), data[i]); } return results; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Address.sol) pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title Contract to be inherited by contracts that need temporary and /// permanent whitelists for services identified by hashes /// @notice This contract implements two kinds of whitelisting: /// (1) Temporary, ends when the expiration timestamp is in the past /// (2) Indefinite, ends when the indefinite whitelist count is zero /// Multiple senders can indefinitely whitelist/unwhitelist independently. The /// user will be considered whitelisted as long as there is at least one active /// indefinite whitelisting. /// @dev The interface of this contract is not implemented. It should be /// inherited and its functions should be exposed with a sort of an /// authorization scheme. contract Whitelist { struct WhitelistStatus { uint64 expirationTimestamp; uint192 indefiniteWhitelistCount; } mapping(bytes32 => mapping(address => WhitelistStatus)) internal serviceIdToUserToWhitelistStatus; mapping(bytes32 => mapping(address => mapping(address => bool))) internal serviceIdToUserToSetterToIndefiniteWhitelistStatus; /// @notice Extends the expiration of the temporary whitelist of the user /// for the service /// @param serviceId Service ID /// @param user User address /// @param expirationTimestamp Timestamp at which the temporary whitelist /// will expire function _extendWhitelistExpiration( bytes32 serviceId, address user, uint64 expirationTimestamp ) internal { require( expirationTimestamp > serviceIdToUserToWhitelistStatus[serviceId][user] .expirationTimestamp, "Does not extend expiration" ); serviceIdToUserToWhitelistStatus[serviceId][user] .expirationTimestamp = expirationTimestamp; } /// @notice Sets the expiration of the temporary whitelist of the user for /// the service /// @dev Unlike `extendWhitelistExpiration()`, this can hasten expiration /// @param serviceId Service ID /// @param user User address /// @param expirationTimestamp Timestamp at which the temporary whitelist /// will expire function _setWhitelistExpiration( bytes32 serviceId, address user, uint64 expirationTimestamp ) internal { serviceIdToUserToWhitelistStatus[serviceId][user] .expirationTimestamp = expirationTimestamp; } /// @notice Sets the indefinite whitelist status of the user for the /// service /// @dev As long as at least there is at least one account that has set the /// indefinite whitelist status of the user for the service as true, the /// user will be considered whitelisted /// @param serviceId Service ID /// @param user User address /// @param status Indefinite whitelist status function _setIndefiniteWhitelistStatus( bytes32 serviceId, address user, bool status ) internal returns (uint192 indefiniteWhitelistCount) { indefiniteWhitelistCount = serviceIdToUserToWhitelistStatus[serviceId][ user ].indefiniteWhitelistCount; if ( status && !serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][ user ][msg.sender] ) { serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][ msg.sender ] = true; indefiniteWhitelistCount++; serviceIdToUserToWhitelistStatus[serviceId][user] .indefiniteWhitelistCount = indefiniteWhitelistCount; } else if ( !status && serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][ msg.sender ] ) { serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][ msg.sender ] = false; indefiniteWhitelistCount--; serviceIdToUserToWhitelistStatus[serviceId][user] .indefiniteWhitelistCount = indefiniteWhitelistCount; } } /// @notice Revokes the indefinite whitelist status granted to the user for /// the service by a specific account /// @param serviceId Service ID /// @param user User address /// @param setter Setter of the indefinite whitelist status function _revokeIndefiniteWhitelistStatus( bytes32 serviceId, address user, address setter ) internal returns (bool revoked, uint192 indefiniteWhitelistCount) { indefiniteWhitelistCount = serviceIdToUserToWhitelistStatus[serviceId][ user ].indefiniteWhitelistCount; if ( serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][ setter ] ) { serviceIdToUserToSetterToIndefiniteWhitelistStatus[serviceId][user][ setter ] = false; indefiniteWhitelistCount--; serviceIdToUserToWhitelistStatus[serviceId][user] .indefiniteWhitelistCount = indefiniteWhitelistCount; revoked = true; } } /// @notice Returns if the user is whitelised to use the service /// @param serviceId Service ID /// @param user User address /// @return isWhitelisted If the user is whitelisted function userIsWhitelisted(bytes32 serviceId, address user) internal view returns (bool isWhitelisted) { WhitelistStatus storage whitelistStatus = serviceIdToUserToWhitelistStatus[ serviceId ][user]; return whitelistStatus.indefiniteWhitelistCount > 0 || whitelistStatus.expirationTimestamp > block.timestamp; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./WhitelistRoles.sol"; import "../access-control-registry/AccessControlRegistryAdminnedWithManager.sol"; import "./interfaces/IWhitelistRolesWithManager.sol"; import "../access-control-registry/interfaces/IAccessControlRegistry.sol"; /// @title Contract to be inherited by Whitelist contracts that will use /// roles where there is a single manager contract WhitelistRolesWithManager is WhitelistRoles, AccessControlRegistryAdminnedWithManager, IWhitelistRolesWithManager { // Since there will be a single manager, we can derive the roles beforehand /// @notice Whitelist expiration extender role bytes32 public immutable override whitelistExpirationExtenderRole; /// @notice Whitelist expiration setter role bytes32 public immutable override whitelistExpirationSetterRole; /// @notice Indefinite whitelister role bytes32 public immutable override indefiniteWhitelisterRole; /// @param _accessControlRegistry AccessControlRegistry contract address /// @param _adminRoleDescription Admin role description /// @param _manager Manager address constructor( address _accessControlRegistry, string memory _adminRoleDescription, address _manager ) AccessControlRegistryAdminnedWithManager( _accessControlRegistry, _adminRoleDescription, _manager ) { whitelistExpirationExtenderRole = _deriveRole( adminRole, WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION_HASH ); whitelistExpirationSetterRole = _deriveRole( adminRole, WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION_HASH ); indefiniteWhitelisterRole = _deriveRole( adminRole, INDEFINITE_WHITELISTER_ROLE_DESCRIPTION_HASH ); } /// @dev Returns if the account has the whitelist expiration extender role /// or is the manager /// @param account Account address /// @return If the account has the whitelist extender role or is the /// manager function hasWhitelistExpirationExtenderRoleOrIsManager(address account) internal view returns (bool) { return manager == account || IAccessControlRegistry(accessControlRegistry).hasRole( whitelistExpirationExtenderRole, account ); } /// @dev Returns if the account has the whitelist expriation setter role or /// is the manager /// @param account Account address /// @return If the account has the whitelist setter role or is the /// manager function hasWhitelistExpirationSetterRoleOrIsManager(address account) internal view returns (bool) { return manager == account || IAccessControlRegistry(accessControlRegistry).hasRole( whitelistExpirationSetterRole, account ); } /// @dev Returns if the account has the indefinite whitelister role or is the /// manager /// @param account Account address /// @return If the account has the indefinite whitelister role or is the /// manager function hasIndefiniteWhitelisterRoleOrIsManager(address account) internal view returns (bool) { return manager == account || IAccessControlRegistry(accessControlRegistry).hasRole( indefiniteWhitelisterRole, account ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IWhitelistRolesWithManager.sol"; interface IWhitelistWithManager is IWhitelistRolesWithManager { event ExtendedWhitelistExpiration( bytes32 indexed serviceId, address indexed user, address indexed sender, uint256 expiration ); event SetWhitelistExpiration( bytes32 indexed serviceId, address indexed user, address indexed sender, uint256 expiration ); event SetIndefiniteWhitelistStatus( bytes32 indexed serviceId, address indexed user, address indexed sender, bool status, uint192 indefiniteWhitelistCount ); event RevokedIndefiniteWhitelistStatus( bytes32 indexed serviceId, address indexed user, address indexed setter, address sender, uint192 indefiniteWhitelistCount ); function extendWhitelistExpiration( bytes32 serviceId, address user, uint64 expirationTimestamp ) external; function setWhitelistExpiration( bytes32 serviceId, address user, uint64 expirationTimestamp ) external; function setIndefiniteWhitelistStatus( bytes32 serviceId, address user, bool status ) external; function revokeIndefiniteWhitelistStatus( bytes32 serviceId, address user, address setter ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./interfaces/IWhitelistRoles.sol"; /// @title Contract to be inherited by Whitelist contracts that will use /// generic AccessControlRegistry roles contract WhitelistRoles is IWhitelistRoles { // There are four roles implemented in this contract: // Root // └── (1) Admin (can grant and revoke the roles below) // ├── (2) Whitelist expiration extender // ├── (3) Whitelist expiration setter // └── (4) Indefinite whitelister // Their IDs are derived from the descriptions below. Refer to // AccessControlRegistry for more information. // To clarify, the root role of the manager is the admin of (1), while (1) // is the admin of (2), (3) and (4). So (1) is more of a "contract admin", // while the `adminRole` used in AccessControl and AccessControlRegistry // refers to a more general adminship relationship between roles. /// @notice Whitelist expiration extender role description string public constant override WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION = "Whitelist expiration extender"; /// @notice Whitelist expiration setter role description string public constant override WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION = "Whitelist expiration setter"; /// @notice Indefinite whitelister role description string public constant override INDEFINITE_WHITELISTER_ROLE_DESCRIPTION = "Indefinite whitelister"; bytes32 internal constant WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION_HASH = keccak256( abi.encodePacked(WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION) ); bytes32 internal constant WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION_HASH = keccak256( abi.encodePacked(WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION) ); bytes32 internal constant INDEFINITE_WHITELISTER_ROLE_DESCRIPTION_HASH = keccak256(abi.encodePacked(INDEFINITE_WHITELISTER_ROLE_DESCRIPTION)); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./AccessControlRegistryAdminned.sol"; import "./interfaces/IAccessControlRegistryAdminnedWithManager.sol"; /// @title Contract to be inherited by contracts with manager whose adminship /// functionality will be implemented using AccessControlRegistry /// @notice The manager address here is expected to belong to an /// AccessControlRegistry user that is a multisig/DAO contract AccessControlRegistryAdminnedWithManager is AccessControlRegistryAdminned, IAccessControlRegistryAdminnedWithManager { /// @notice Address of the manager that manages the related /// AccessControlRegistry roles /// @dev The mutability of the manager role can be implemented by /// designating an OwnableCallForwarder contract as the manager. The /// ownership of this contract can then be transferred, effectively /// transferring managership. address public immutable override manager; /// @notice Admin role /// @dev Since `manager` is immutable, so is `adminRole` bytes32 public immutable override adminRole; /// @param _accessControlRegistry AccessControlRegistry contract address /// @param _adminRoleDescription Admin role description /// @param _manager Manager address constructor( address _accessControlRegistry, string memory _adminRoleDescription, address _manager ) AccessControlRegistryAdminned( _accessControlRegistry, _adminRoleDescription ) { require(_manager != address(0), "Manager address zero"); manager = _manager; adminRole = _deriveAdminRole(_manager); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IWhitelistRoles.sol"; import "../../access-control-registry/interfaces/IAccessControlRegistryAdminnedWithManager.sol"; interface IWhitelistRolesWithManager is IWhitelistRoles, IAccessControlRegistryAdminnedWithManager { function whitelistExpirationExtenderRole() external view returns (bytes32); function whitelistExpirationSetterRole() external view returns (bytes32); function indefiniteWhitelisterRole() external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/access/IAccessControl.sol"; interface IAccessControlRegistry is IAccessControl { event InitializedManager(bytes32 indexed rootRole, address indexed manager); event InitializedRole( bytes32 indexed role, bytes32 indexed adminRole, string description, address sender ); function initializeManager(address manager) external; function initializeRoleAndGrantToSender( bytes32 adminRole, string calldata description ) external returns (bytes32 role); function deriveRootRole(address manager) external pure returns (bytes32 rootRole); function deriveRole(bytes32 adminRole, string calldata description) external pure returns (bytes32 role); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IWhitelistRoles { // solhint-disable-next-line func-name-mixedcase function WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION() external view returns (string memory); // solhint-disable-next-line func-name-mixedcase function WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION() external view returns (string memory); // solhint-disable-next-line func-name-mixedcase function INDEFINITE_WHITELISTER_ROLE_DESCRIPTION() external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/utils/Multicall.sol"; import "./RoleDeriver.sol"; import "./AccessControlRegistryUser.sol"; import "./interfaces/IAccessControlRegistryAdminned.sol"; /// @title Contract to be inherited by contracts whose adminship functionality /// will be implemented using AccessControlRegistry contract AccessControlRegistryAdminned is Multicall, RoleDeriver, AccessControlRegistryUser, IAccessControlRegistryAdminned { /// @notice Admin role description string public override adminRoleDescription; bytes32 internal immutable adminRoleDescriptionHash; /// @dev Contracts deployed with the same admin role descriptions will have /// the same roles, meaning that granting an account a role will authorize /// it in multiple contracts. Unless you want your deployed contract to /// share the role configuration of another contract, use a unique admin /// role description. /// @param _accessControlRegistry AccessControlRegistry contract address /// @param _adminRoleDescription Admin role description constructor( address _accessControlRegistry, string memory _adminRoleDescription ) AccessControlRegistryUser(_accessControlRegistry) { require( bytes(_adminRoleDescription).length > 0, "Admin role description empty" ); adminRoleDescription = _adminRoleDescription; adminRoleDescriptionHash = keccak256( abi.encodePacked(_adminRoleDescription) ); } /// @notice Derives the admin role for the specific manager address /// @param manager Manager address /// @return adminRole Admin role function _deriveAdminRole(address manager) internal view returns (bytes32 adminRole) { adminRole = _deriveRole( _deriveRootRole(manager), adminRoleDescriptionHash ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IAccessControlRegistryAdminned.sol"; interface IAccessControlRegistryAdminnedWithManager is IAccessControlRegistryAdminned { function manager() external view returns (address); function adminRole() external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title Contract to be inherited by contracts that will derive /// AccessControlRegistry roles /// @notice If a contract interfaces with AccessControlRegistry and needs to /// derive roles, it should inherit this contract instead of re-implementing /// the logic contract RoleDeriver { /// @notice Derives the root role of the manager /// @param manager Manager address /// @return rootRole Root role function _deriveRootRole(address manager) internal pure returns (bytes32 rootRole) { rootRole = keccak256(abi.encodePacked(manager)); } /// @notice Derives the role using its admin role and description /// @dev This implies that roles adminned by the same role cannot have the /// same description /// @param adminRole Admin role /// @param description Human-readable description of the role /// @return role Role function _deriveRole(bytes32 adminRole, string memory description) internal pure returns (bytes32 role) { role = _deriveRole(adminRole, keccak256(abi.encodePacked(description))); } /// @notice Derives the role using its admin role and description hash /// @dev This implies that roles adminned by the same role cannot have the /// same description /// @param adminRole Admin role /// @param descriptionHash Hash of the human-readable description of the /// role /// @return role Role function _deriveRole(bytes32 adminRole, bytes32 descriptionHash) internal pure returns (bytes32 role) { role = keccak256(abi.encodePacked(adminRole, descriptionHash)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./interfaces/IAccessControlRegistry.sol"; import "./interfaces/IAccessControlRegistryUser.sol"; /// @title Contract to be inherited by contracts that will interact with /// AccessControlRegistry contract AccessControlRegistryUser is IAccessControlRegistryUser { /// @notice AccessControlRegistry contract address address public immutable override accessControlRegistry; /// @param _accessControlRegistry AccessControlRegistry contract address constructor(address _accessControlRegistry) { require(_accessControlRegistry != address(0), "ACR address zero"); accessControlRegistry = _accessControlRegistry; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IAccessControlRegistryUser.sol"; interface IAccessControlRegistryAdminned is IAccessControlRegistryUser { function adminRoleDescription() external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IAccessControlRegistryUser { function accessControlRegistry() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IStorageUtils.sol"; import "./ISponsorshipUtils.sol"; import "./IWithdrawalUtils.sol"; interface IAirnodeProtocol is IStorageUtils, ISponsorshipUtils, IWithdrawalUtils { event MadeRequest( address indexed airnode, bytes32 indexed requestId, address requester, uint256 requesterRequestCount, bytes32 templateId, bytes parameters, address sponsor, bytes4 fulfillFunctionId ); event FulfilledRequest( address indexed airnode, bytes32 indexed requestId, uint256 timestamp, bytes data ); event FailedRequest( address indexed airnode, bytes32 indexed requestId, uint256 timestamp, string errorMessage ); event MadeRequestRelayed( address indexed relayer, bytes32 indexed requestId, address indexed airnode, address requester, uint256 requesterRequestCount, bytes32 templateId, bytes parameters, address sponsor, bytes4 fulfillFunctionId ); event FulfilledRequestRelayed( address indexed relayer, bytes32 indexed requestId, address indexed airnode, uint256 timestamp, bytes data ); event FailedRequestRelayed( address indexed relayer, bytes32 indexed requestId, address indexed airnode, uint256 timestamp, string errorMessage ); function makeRequest( address airnode, bytes32 templateId, bytes calldata parameters, address sponsor, bytes4 fulfillFunctionId ) external returns (bytes32 requestId); function fulfillRequest( bytes32 requestId, address airnode, address requester, bytes4 fulfillFunctionId, uint256 timestamp, bytes calldata data, bytes calldata signature ) external returns (bool callSuccess, bytes memory callData); function failRequest( bytes32 requestId, address airnode, address requester, bytes4 fulfillFunctionId, uint256 timestamp, string calldata errorMessage, bytes calldata signature ) external; function makeRequestRelayed( address airnode, bytes32 templateId, bytes calldata parameters, address relayer, address sponsor, bytes4 fulfillFunctionId ) external returns (bytes32 requestId); function fulfillRequestRelayed( bytes32 requestId, address airnode, address requester, address relayer, bytes4 fulfillFunctionId, uint256 timestamp, bytes calldata data, bytes calldata signature ) external returns (bool callSuccess, bytes memory callData); function failRequestRelayed( bytes32 requestId, address airnode, address requester, address relayer, bytes4 fulfillFunctionId, uint256 timestamp, string calldata errorMessage, bytes calldata signature ) external; function requestIsAwaitingFulfillment(bytes32 requestId) external view returns (bool); function requesterToRequestCount(address requester) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IAirnodeRequester { function airnodeProtocol() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IStorageUtils { event StoredTemplate( bytes32 indexed templateId, bytes32 endpointId, bytes parameters ); event StoredSubscription( bytes32 indexed subscriptionId, uint256 chainId, address airnode, bytes32 templateId, bytes parameters, bytes conditions, address relayer, address sponsor, address requester, bytes4 fulfillFunctionId ); function storeTemplate(bytes32 endpointId, bytes calldata parameters) external returns (bytes32 templateId); function storeSubscription( uint256 chainId, address airnode, bytes32 templateId, bytes calldata parameters, bytes calldata conditions, address relayer, address sponsor, address requester, bytes4 fulfillFunctionId ) external returns (bytes32 subscriptionId); // solhint-disable-next-line func-name-mixedcase function MAXIMUM_PARAMETER_LENGTH() external view returns (uint256); function templates(bytes32 templateId) external view returns (bytes32 endpointId, bytes memory parameters); function subscriptions(bytes32 subscriptionId) external view returns ( uint256 chainId, address airnode, bytes32 templateId, bytes memory parameters, bytes memory conditions, address relayer, address sponsor, address requester, bytes4 fulfillFunctionId ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface ISponsorshipUtils { event SetRrpSponsorshipStatus( address indexed sponsor, address indexed requester, bool status ); event SetPspSponsorshipStatus( address indexed sponsor, bytes32 indexed subscriptionId, bool status ); function setRrpSponsorshipStatus(address requester, bool status) external; function setPspSponsorshipStatus(bytes32 subscriptionId, bool status) external; function sponsorToRequesterToRrpSponsorshipStatus( address sponsor, address requester ) external view returns (bool status); function sponsorToSubscriptionIdToPspSponsorshipStatus( address sponsor, bytes32 subscriptionId ) external view returns (bool status); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IWithdrawalUtils { event RequestedWithdrawal( address indexed airnodeOrRelayer, address indexed sponsor, bytes32 indexed withdrawalRequestId, uint256 protocolId ); event FulfilledWithdrawal( address indexed airnodeOrRelayer, address indexed sponsor, bytes32 indexed withdrawalRequestId, uint256 protocolId, address sponsorWallet, uint256 amount ); event ClaimedBalance(address indexed sponsor, uint256 amount); function requestWithdrawal(address airnodeOrRelayer, uint256 protocolId) external; function fulfillWithdrawal( bytes32 withdrawalRequestId, address airnodeOrRelayer, uint256 protocolId, address sponsor, uint256 timestamp, bytes calldata signature ) external payable; function claimBalance() external; function withdrawalRequestIsAwaitingFulfillment(bytes32 withdrawalRequestId) external view returns (bool); function sponsorToBalance(address sponsor) external view returns (uint256); function sponsorToWithdrawalRequestCount(address sponsor) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title Contract to be inherited by contracts that will sort an array using /// an unrolled implementation /// @notice The operation will be in-place, i.e., the array provided as the /// argument will be modified. contract Sort { uint256 internal constant MAX_SORT_LENGTH = 9; /// @notice Sorts the array /// @param array Array to be sorted function sort(int256[] memory array) internal pure { uint256 arrayLength = array.length; require(arrayLength <= MAX_SORT_LENGTH, "Array too long to sort"); // Do a binary search if (arrayLength < 6) { // Possible lengths: 1, 2, 3, 4, 5 if (arrayLength < 4) { // Possible lengths: 1, 2, 3 if (arrayLength == 3) { // Length: 3 swapIfFirstIsLarger(array, 0, 1); swapIfFirstIsLarger(array, 1, 2); swapIfFirstIsLarger(array, 0, 1); } else if (arrayLength == 2) { // Length: 2 swapIfFirstIsLarger(array, 0, 1); } // Do nothing for Length: 1 } else { // Possible lengths: 4, 5 if (arrayLength == 5) { // Length: 5 swapIfFirstIsLarger(array, 1, 2); swapIfFirstIsLarger(array, 3, 4); swapIfFirstIsLarger(array, 1, 3); swapIfFirstIsLarger(array, 0, 2); swapIfFirstIsLarger(array, 2, 4); swapIfFirstIsLarger(array, 0, 3); swapIfFirstIsLarger(array, 0, 1); swapIfFirstIsLarger(array, 2, 3); swapIfFirstIsLarger(array, 1, 2); } else { // Length: 4 swapIfFirstIsLarger(array, 0, 1); swapIfFirstIsLarger(array, 2, 3); swapIfFirstIsLarger(array, 1, 3); swapIfFirstIsLarger(array, 0, 2); swapIfFirstIsLarger(array, 1, 2); } } } else { // Possible lengths: 6, 7, 8, 9 if (arrayLength < 8) { // Possible lengths: 6, 7 if (arrayLength == 7) { // Length: 7 swapIfFirstIsLarger(array, 1, 2); swapIfFirstIsLarger(array, 3, 4); swapIfFirstIsLarger(array, 5, 6); swapIfFirstIsLarger(array, 0, 2); swapIfFirstIsLarger(array, 4, 6); swapIfFirstIsLarger(array, 3, 5); swapIfFirstIsLarger(array, 2, 6); swapIfFirstIsLarger(array, 1, 5); swapIfFirstIsLarger(array, 0, 4); swapIfFirstIsLarger(array, 2, 5); swapIfFirstIsLarger(array, 0, 3); swapIfFirstIsLarger(array, 2, 4); swapIfFirstIsLarger(array, 1, 3); swapIfFirstIsLarger(array, 0, 1); swapIfFirstIsLarger(array, 2, 3); swapIfFirstIsLarger(array, 4, 5); } else { // Length: 6 swapIfFirstIsLarger(array, 0, 1); swapIfFirstIsLarger(array, 2, 3); swapIfFirstIsLarger(array, 4, 5); swapIfFirstIsLarger(array, 1, 3); swapIfFirstIsLarger(array, 3, 5); swapIfFirstIsLarger(array, 1, 3); swapIfFirstIsLarger(array, 2, 4); swapIfFirstIsLarger(array, 0, 2); swapIfFirstIsLarger(array, 2, 4); swapIfFirstIsLarger(array, 3, 4); swapIfFirstIsLarger(array, 1, 2); swapIfFirstIsLarger(array, 2, 3); } } else { // Possible lengths: 8, 9 if (arrayLength == 9) { // Length: 9 swapIfFirstIsLarger(array, 1, 8); swapIfFirstIsLarger(array, 2, 7); swapIfFirstIsLarger(array, 3, 6); swapIfFirstIsLarger(array, 4, 5); swapIfFirstIsLarger(array, 1, 4); swapIfFirstIsLarger(array, 5, 8); swapIfFirstIsLarger(array, 0, 2); swapIfFirstIsLarger(array, 6, 7); swapIfFirstIsLarger(array, 2, 6); swapIfFirstIsLarger(array, 7, 8); swapIfFirstIsLarger(array, 0, 3); swapIfFirstIsLarger(array, 4, 5); swapIfFirstIsLarger(array, 0, 1); swapIfFirstIsLarger(array, 3, 5); swapIfFirstIsLarger(array, 6, 7); swapIfFirstIsLarger(array, 2, 4); swapIfFirstIsLarger(array, 1, 3); swapIfFirstIsLarger(array, 5, 7); swapIfFirstIsLarger(array, 4, 6); swapIfFirstIsLarger(array, 1, 2); swapIfFirstIsLarger(array, 3, 4); swapIfFirstIsLarger(array, 5, 6); swapIfFirstIsLarger(array, 7, 8); swapIfFirstIsLarger(array, 2, 3); swapIfFirstIsLarger(array, 4, 5); } else { // Length: 8 swapIfFirstIsLarger(array, 0, 7); swapIfFirstIsLarger(array, 1, 6); swapIfFirstIsLarger(array, 2, 5); swapIfFirstIsLarger(array, 3, 4); swapIfFirstIsLarger(array, 0, 3); swapIfFirstIsLarger(array, 4, 7); swapIfFirstIsLarger(array, 1, 2); swapIfFirstIsLarger(array, 5, 6); swapIfFirstIsLarger(array, 0, 1); swapIfFirstIsLarger(array, 2, 3); swapIfFirstIsLarger(array, 4, 5); swapIfFirstIsLarger(array, 6, 7); swapIfFirstIsLarger(array, 3, 5); swapIfFirstIsLarger(array, 2, 4); swapIfFirstIsLarger(array, 1, 2); swapIfFirstIsLarger(array, 3, 4); swapIfFirstIsLarger(array, 5, 6); swapIfFirstIsLarger(array, 2, 3); swapIfFirstIsLarger(array, 4, 5); swapIfFirstIsLarger(array, 3, 4); } } } } /// @notice Swaps two elements of an array if the first element is greater /// than the second /// @param array Array whose elements are to be swapped /// @param ind1 Index of the first element /// @param ind2 Index of the second element function swapIfFirstIsLarger( int256[] memory array, uint256 ind1, uint256 ind2 ) private pure { if (array[ind1] > array[ind2]) { (array[ind1], array[ind2]) = (array[ind2], array[ind1]); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title Contract to be inherited by contracts that will calculate the index /// of the k-th and optionally (k+1)-th largest elements in the array /// @notice Uses quickselect, which operates in-place, i.e., the array provided /// as the argument will be modified. contract Quickselect { /// @notice Returns the index of the k-th largest element in the array /// @param array Array in which k-th largest element will be searched /// @param k K /// @return indK Index of the k-th largest element function quickselectK(int256[] memory array, uint256 k) internal pure returns (uint256 indK) { (indK, ) = quickselect(array, 0, array.length - 1, k, false); } /// @notice Returns the index of the k-th and (k+1)-th largest elements in /// the array /// @param array Array in which k-th and (k+1)-th largest elements will be /// searched /// @param k K /// @return indK Index of the k-th largest element /// @return indKPlusOne Index of the (k+1)-th largest element function quickselectKPlusOne(int256[] memory array, uint256 k) internal pure returns (uint256 indK, uint256 indKPlusOne) { uint256 arrayLength = array.length; require(arrayLength > 1, "Array too short to select k+1"); return quickselect(array, 0, arrayLength - 1, k, true); } /// @notice Returns the index of the k-th largest element in the specified /// section of the (potentially unsorted) array /// @param array Array in which K will be searched for /// @param lo Starting index of the section of the array that K will be /// searched in /// @param hi Last index of the section of the array that K will be /// searched in /// @param k K /// @param selectKPlusOne If the index of the (k+1)-th largest element is /// to be returned /// @return indK Index of the k-th largest element /// @return indKPlusOne Index of the (k+1)-th largest element (only set if /// `selectKPlusOne` is `true`) function quickselect( int256[] memory array, uint256 lo, uint256 hi, uint256 k, bool selectKPlusOne ) private pure returns (uint256 indK, uint256 indKPlusOne) { if (lo == hi) { return (k, 0); } uint256 indPivot = partition(array, lo, hi); if (k < indPivot) { (indK, ) = quickselect(array, lo, indPivot - 1, k, false); } else if (k > indPivot) { (indK, ) = quickselect(array, indPivot + 1, hi, k, false); } else { indK = indPivot; } // Since Quickselect ends in the array being partitioned around the // k-th largest element, we can continue searching towards right for // the (k+1)-th largest element, which is useful in calculating the // median of an array with even length if (selectKPlusOne) { indKPlusOne = indK + 1; for (uint256 i = indKPlusOne + 1; i < array.length; i++) { if (array[i] < array[indKPlusOne]) { indKPlusOne = i; } } } } /// @notice Partitions the array into two around a pivot /// @param array Array that will be partitioned /// @param lo Starting index of the section of the array that will be /// partitioned /// @param hi Last index of the section of the array that will be /// partitioned /// @return pivotInd Pivot index function partition( int256[] memory array, uint256 lo, uint256 hi ) private pure returns (uint256 pivotInd) { if (lo == hi) { return lo; } int256 pivot = array[lo]; uint256 i = lo; pivotInd = hi + 1; while (true) { do { i++; } while (i < array.length && array[i] < pivot); do { pivotInd--; } while (array[pivotInd] > pivot); if (i >= pivotInd) { (array[lo], array[pivotInd]) = (array[pivotInd], array[lo]); return pivotInd; } (array[i], array[pivotInd]) = (array[pivotInd], array[i]); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } }
{ "optimizer": { "enabled": true, "runs": 1000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
[{"inputs":[{"internalType":"address","name":"_accessControlRegistry","type":"address"},{"internalType":"string","name":"_adminRoleDescription","type":"string"},{"internalType":"address","name":"_manager","type":"address"},{"internalType":"address","name":"_airnodeProtocol","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"unlimitedReader","type":"address"}],"name":"AddedUnlimitedReader","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"serviceId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"expiration","type":"uint256"}],"name":"ExtendedWhitelistExpiration","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"subscriptionId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"airnode","type":"address"},{"indexed":false,"internalType":"bytes32","name":"templateId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"parameters","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"conditions","type":"bytes"},{"indexed":false,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"address","name":"sponsor","type":"address"},{"indexed":false,"internalType":"address","name":"requester","type":"address"},{"indexed":false,"internalType":"bytes4","name":"fulfillFunctionId","type":"bytes4"}],"name":"RegisteredBeaconUpdateSubscription","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"beaconId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sponsor","type":"address"},{"indexed":true,"internalType":"address","name":"requester","type":"address"},{"indexed":false,"internalType":"bytes32","name":"requestId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"airnode","type":"address"},{"indexed":false,"internalType":"bytes32","name":"templateId","type":"bytes32"}],"name":"RequestedRrpBeaconUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"beaconId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sponsor","type":"address"},{"indexed":true,"internalType":"address","name":"requester","type":"address"},{"indexed":false,"internalType":"bytes32","name":"requestId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"airnode","type":"address"},{"indexed":false,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"templateId","type":"bytes32"}],"name":"RequestedRrpBeaconUpdateRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"serviceId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"setter","type":"address"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint192","name":"indefiniteWhitelistCount","type":"uint192"}],"name":"RevokedIndefiniteWhitelistStatus","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"dapiName","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"dataFeedId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"SetDapiName","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"serviceId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"},{"indexed":false,"internalType":"uint192","name":"indefiniteWhitelistCount","type":"uint192"}],"name":"SetIndefiniteWhitelistStatus","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sponsor","type":"address"},{"indexed":true,"internalType":"address","name":"rrpBeaconUpdateRequester","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"SetRrpBeaconUpdatePermissionStatus","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"serviceId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"expiration","type":"uint256"}],"name":"SetWhitelistExpiration","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"beaconSetId","type":"bytes32"},{"indexed":false,"internalType":"int224","name":"value","type":"int224"},{"indexed":false,"internalType":"uint32","name":"timestamp","type":"uint32"}],"name":"UpdatedBeaconSetWithBeacons","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"dapiId","type":"bytes32"},{"indexed":false,"internalType":"int224","name":"value","type":"int224"},{"indexed":false,"internalType":"uint32","name":"timestamp","type":"uint32"}],"name":"UpdatedBeaconSetWithSignedData","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"beaconId","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"subscriptionId","type":"bytes32"},{"indexed":false,"internalType":"int224","name":"value","type":"int224"},{"indexed":false,"internalType":"uint32","name":"timestamp","type":"uint32"}],"name":"UpdatedBeaconWithPsp","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"beaconId","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"requestId","type":"bytes32"},{"indexed":false,"internalType":"int256","name":"value","type":"int256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"UpdatedBeaconWithRrp","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"beaconId","type":"bytes32"},{"indexed":false,"internalType":"int256","name":"value","type":"int256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"UpdatedBeaconWithSignedData","type":"event"},{"inputs":[],"name":"DAPI_NAME_SETTER_ROLE_DESCRIPTION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"HUNDRED_PERCENT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INDEFINITE_WHITELISTER_ROLE_DESCRIPTION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WHITELIST_EXPIRATION_EXTENDER_ROLE_DESCRIPTION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WHITELIST_EXPIRATION_SETTER_ROLE_DESCRIPTION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accessControlRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"unlimitedReader","type":"address"}],"name":"addUnlimitedReader","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"adminRole","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"adminRoleDescription","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"airnodeProtocol","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"subscriptionId","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"conditionParameters","type":"bytes"}],"name":"conditionPspBeaconSetUpdate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"subscriptionId","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"conditionParameters","type":"bytes"}],"name":"conditionPspBeaconUpdate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dapiNameSetterRole","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dapiName","type":"bytes32"}],"name":"dapiNameToDataFeedId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dataFeedId","type":"bytes32"},{"internalType":"address","name":"reader","type":"address"},{"internalType":"address","name":"setter","type":"address"}],"name":"dataFeedIdToReaderToSetterToIndefiniteWhitelistStatus","outputs":[{"internalType":"bool","name":"indefiniteWhitelistStatus","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dataFeedId","type":"bytes32"},{"internalType":"address","name":"reader","type":"address"}],"name":"dataFeedIdToReaderToWhitelistStatus","outputs":[{"internalType":"uint64","name":"expirationTimestamp","type":"uint64"},{"internalType":"uint192","name":"indefiniteWhitelistCount","type":"uint192"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"airnode","type":"address"},{"internalType":"bytes32","name":"templateId","type":"bytes32"}],"name":"deriveBeaconId","outputs":[{"internalType":"bytes32","name":"beaconId","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"beaconIds","type":"bytes32[]"}],"name":"deriveBeaconSetId","outputs":[{"internalType":"bytes32","name":"beaconSetId","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"serviceId","type":"bytes32"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint64","name":"expirationTimestamp","type":"uint64"}],"name":"extendWhitelistExpiration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"subscriptionId","type":"bytes32"},{"internalType":"address","name":"airnode","type":"address"},{"internalType":"address","name":"relayer","type":"address"},{"internalType":"address","name":"sponsor","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"fulfillPspBeaconSetUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"subscriptionId","type":"bytes32"},{"internalType":"address","name":"airnode","type":"address"},{"internalType":"address","name":"relayer","type":"address"},{"internalType":"address","name":"sponsor","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"fulfillPspBeaconUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"fulfillRrpBeaconUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBlockBasefee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBlockTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getChainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"indefiniteWhitelisterRole","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"manager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dapiName","type":"bytes32"}],"name":"readDataFeedValueWithDapiName","outputs":[{"internalType":"int224","name":"value","type":"int224"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dataFeedId","type":"bytes32"}],"name":"readDataFeedValueWithId","outputs":[{"internalType":"int224","name":"value","type":"int224"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dapiName","type":"bytes32"}],"name":"readDataFeedWithDapiName","outputs":[{"internalType":"int224","name":"value","type":"int224"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dataFeedId","type":"bytes32"}],"name":"readDataFeedWithId","outputs":[{"internalType":"int224","name":"value","type":"int224"},{"internalType":"uint32","name":"timestamp","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dataFeedId","type":"bytes32"},{"internalType":"address","name":"reader","type":"address"}],"name":"readerCanReadDataFeed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"airnode","type":"address"},{"internalType":"bytes32","name":"templateId","type":"bytes32"},{"internalType":"bytes","name":"conditions","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"},{"internalType":"address","name":"sponsor","type":"address"}],"name":"registerBeaconUpdateSubscription","outputs":[{"internalType":"bytes32","name":"subscriptionId","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"airnode","type":"address"},{"internalType":"bytes32","name":"templateId","type":"bytes32"},{"internalType":"address","name":"sponsor","type":"address"}],"name":"requestRrpBeaconUpdate","outputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"airnode","type":"address"},{"internalType":"bytes32","name":"templateId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"},{"internalType":"address","name":"sponsor","type":"address"}],"name":"requestRrpBeaconUpdateRelayed","outputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"serviceId","type":"bytes32"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"setter","type":"address"}],"name":"revokeIndefiniteWhitelistStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dapiName","type":"bytes32"},{"internalType":"bytes32","name":"dataFeedId","type":"bytes32"}],"name":"setDapiName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"serviceId","type":"bytes32"},{"internalType":"address","name":"user","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"setIndefiniteWhitelistStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"rrpBeaconUpdateRequester","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"setRrpBeaconUpdatePermissionStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"serviceId","type":"bytes32"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint64","name":"expirationTimestamp","type":"uint64"}],"name":"setWhitelistExpiration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"sponsorToRrpBeaconUpdateRequesterToPermissionStatus","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"subscriptionIdToBeaconId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"unlimitedReaderStatus","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"beaconIds","type":"bytes32[]"}],"name":"updateBeaconSetWithBeacons","outputs":[{"internalType":"bytes32","name":"beaconSetId","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"beaconIds","type":"bytes32[]"},{"internalType":"uint256","name":"deviationThresholdInPercentage","type":"uint256"}],"name":"updateBeaconSetWithBeaconsAndReturnCondition","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"airnodes","type":"address[]"},{"internalType":"bytes32[]","name":"templateIds","type":"bytes32[]"},{"internalType":"uint256[]","name":"timestamps","type":"uint256[]"},{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bytes[]","name":"signatures","type":"bytes[]"}],"name":"updateBeaconSetWithSignedData","outputs":[{"internalType":"bytes32","name":"beaconSetId","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"airnode","type":"address"},{"internalType":"bytes32","name":"templateId","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"updateBeaconWithSignedData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"whitelistExpirationExtenderRole","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"whitelistExpirationSetterRole","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6101a06040523480156200001257600080fd5b5060405162005d7938038062005d7983398101604081905262000035916200054d565b808484848282828282828282816001600160a01b038116620000915760405162461bcd60e51b815260206004820152601060248201526f4143522061646472657373207a65726f60801b60448201526064015b60405180910390fd5b6001600160a01b03166080528051620000ed5760405162461bcd60e51b815260206004820152601c60248201527f41646d696e20726f6c65206465736372697074696f6e20656d70747900000000604482015260640162000088565b80516200010290600290602084019062000441565b508060405160200162000116919062000640565b60408051601f19818403018152919052805160209091012060a05250506001600160a01b0381166200018b5760405162461bcd60e51b815260206004820152601460248201527f4d616e616765722061646472657373207a65726f000000000000000000000000604482015260640162000088565b6001600160a01b03811660c052620001a3816200039b565b60e081815250505050506200021e60e0516040518060400160405280601d81526020017f57686974656c6973742065787069726174696f6e20657874656e646572000000815250604051602001620001fc919062000640565b604051602081830303815290604052805190602001206200041560201b60201c565b61010081815250506200027560e0516040518060400160405280601b81526020017f57686974656c6973742065787069726174696f6e207365747465720000000000815250604051602001620001fc919062000640565b6101208181525050620002cc60e0516040518060400160405280601681526020017f496e646566696e6974652077686974656c697374657200000000000000000000815250604051602001620001fc919062000640565b6101405250505050506001600160a01b03821615159050620003315760405162461bcd60e51b815260206004820152601c60248201527f4169726e6f646550726f746f636f6c2061646472657373207a65726f00000000604482015260640162000088565b6001600160a01b03166101605260c0516200038c9062000351906200039b565b6040518060400160405280601081526020016f3220a824903730b6b29039b2ba3a32b960811b815250604051602001620001fc919062000640565b61018052506200069b92505050565b60006200040f620003e0836040516001600160601b0319606083901b166020820152600090603401604051602081830303815290604052805190602001209050919050565b60a051604080516020808201949094528082019290925280518083038201815260609092019052805191012090565b92915050565b604080516020808201949094528082019290925280518083038201815260609092019052805191012090565b8280546200044f906200065e565b90600052602060002090601f016020900481019282620004735760008555620004be565b82601f106200048e57805160ff1916838001178555620004be565b82800160010185558215620004be579182015b82811115620004be578251825591602001919060010190620004a1565b50620004cc929150620004d0565b5090565b5b80821115620004cc5760008155600101620004d1565b80516001600160a01b0381168114620004ff57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620005375781810151838201526020016200051d565b8381111562000547576000848401525b50505050565b600080600080608085870312156200056457600080fd5b6200056f85620004e7565b60208601519094506001600160401b03808211156200058d57600080fd5b818701915087601f830112620005a257600080fd5b815181811115620005b757620005b762000504565b604051601f8201601f19908116603f01168101908382118183101715620005e257620005e262000504565b816040528281528a6020848701011115620005fc57600080fd5b6200060f8360208301602088016200051a565b80975050505050506200062560408601620004e7565b91506200063560608601620004e7565b905092959194509250565b60008251620006548184602087016200051a565b9190910192915050565b600181811c908216806200067357607f821691505b602082108114156200069557634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a05160c05160e051610100516101205161014051610160516101805161560062000779600039600081816105b6015261207401526000818161076a015281816116cd015281816122f00152612bb001526000818161089201526132f101526000818161065301526131b10152600081816105f601526137c1015260006103540152600081816104920152818161203e015281816129f501528181613173015281816132b30152613783015260005050600081816103c9015281816120a0015281816131e70152818161332701526137f701526156006000f3fe608060405234801561001057600080fd5b506004361061034a5760003560e01c80638e85afe0116101bd578063bcb5daec116100f9578063e18de857116100a2578063f60e45d31161007c578063f60e45d3146108da578063f8b2cb4f1461091b578063fc3c1f8b14610936578063fce90be81461094957600080fd5b8063e18de8571461088d578063e406f3b2146108b4578063e705882e146108c757600080fd5b8063d55a42dd116100d3578063d55a42dd1461082b578063d7c0b87914610867578063dc96acc81461087a57600080fd5b8063bcb5daec1461078c578063c4f95dd51461079f578063d39c8968146107b257600080fd5b80639e14caa811610166578063a6b1b9a211610140578063a6b1b9a21461070f578063ac9650d814610722578063b605bbcd14610742578063b76f3c151461076557600080fd5b80639e14caa8146106c9578063a026658f146106dc578063a5fc076f146106fc57600080fd5b806391eed0851161019757806391eed085146106755780639421240514610688578063977cae011461069b57600080fd5b80638e85afe0146106185780638fca9ab91461063b5780638fe47dd81461064e57600080fd5b80634c8f1d8d1161028c5780636db798f9116102355780637512449b1161020f5780637512449b146105b1578063776bcbd2146105d8578063796b89b9146105eb5780637c706738146105f157600080fd5b80636db798f9146105575780636ed93dd01461059357806370c927ca1461059e57600080fd5b80635bc8a5c8116102665780635bc8a5c8146104f557806365101054146105085780636bd2bdd01461051b57600080fd5b80634c8f1d8d146104b45780634dcc19fe146104c957806358c55edd146104cf57600080fd5b8063206b48f4116102f95780633408e470116102d35780633408e4701461044f5780633af1dbfd1461045557806342cbb15c14610487578063481c6a751461048d57600080fd5b8063206b48f4146104165780632ce010e3146104295780633376e7c21461043c57600080fd5b80631a0a0b3e1161032a5780631a0a0b3e146103af5780631ce9ae07146103c45780631d36cf5c1461040357600080fd5b80629f2f3c1461034f578062aae33f1461038957806304dd3cee1461039c575b600080fd5b6103767f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b6103766103973660046147a4565b610985565b6103766103aa3660046147f5565b610be1565b6103c26103bd366004614861565b610cca565b005b6103eb7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610380565b6103c26104113660046148f5565b610e46565b6103c2610424366004614942565b610fb1565b6103c2610437366004614942565b6112ad565b6103c261044a366004614a07565b61132c565b46610376565b610468610463366004614a3c565b611472565b60408051601b9390930b835263ffffffff909116602083015201610380565b43610376565b6103eb7f000000000000000000000000000000000000000000000000000000000000000081565b6104bc611574565b6040516103809190614ab1565b48610376565b6104e26104dd366004614a3c565b611602565b604051601b9190910b8152602001610380565b6103c2610503366004614ac4565b6116c2565b610376610516366004614c69565b6117f6565b6104bc6040518060400160405280601b81526020017f57686974656c6973742065787069726174696f6e20736574746572000000000081525081565b6104bc6040518060400160405280601d81526020017f57686974656c6973742065787069726174696f6e20657874656e64657200000081525081565b6103766305f5e10081565b6104e26105ac366004614a3c565b611d3b565b6103767f000000000000000000000000000000000000000000000000000000000000000081565b6103c26105e6366004614d3b565b611e35565b42610376565b6103767f000000000000000000000000000000000000000000000000000000000000000081565b61062b610626366004614d77565b611efe565b6040519015158152602001610380565b610376610649366004614a3c565b611fa1565b6103767f000000000000000000000000000000000000000000000000000000000000000081565b6103c2610683366004614dbc565b611fe6565b610376610696366004614dde565b6121f6565b61062b6106a9366004614e11565b600460209081526000928352604080842090915290825290205460ff1681565b6103c26106d7366004614e44565b6123e0565b6103766106ea366004614a3c565b60056020526000908152604090205481565b61046861070a366004614a3c565b61249b565b6103c261071d3660046148f5565b612511565b610735610730366004614e7b565b612643565b6040516103809190614ef0565b61062b610750366004614f52565b60036020526000908152604090205460ff1681565b6103eb7f000000000000000000000000000000000000000000000000000000000000000081565b61062b61079a366004614f6d565b612738565b6103766107ad3660046147a4565b61277f565b6108036107c0366004614f6d565b6000918252602082815260408084206001600160a01b0393909316845291905290205467ffffffffffffffff811691600160401b9091046001600160c01b031690565b6040805167ffffffffffffffff90931683526001600160c01b03909116602083015201610380565b6104bc6040518060400160405280601681526020017f496e646566696e6974652077686974656c69737465720000000000000000000081525081565b61062b610875366004614f90565b6127af565b61062b610888366004614f90565b6128b4565b6103767f000000000000000000000000000000000000000000000000000000000000000081565b6103c26108c2366004614f52565b6129ea565b6103766108d536600461500a565b612aae565b61062b6108e8366004614d3b565b60009283526001602090815260408085206001600160a01b03948516865282528085209290931684525290205460ff1690565b610376610929366004614f52565b6001600160a01b03163190565b610376610944366004615057565b612cb9565b6104bc6040518060400160405280601081526020017f64415049206e616d65207365747465720000000000000000000000000000000081525081565b8051600090600181116109df5760405162461bcd60e51b815260206004820152601f60248201527f537065636966696564206c657373207468616e2074776f20426561636f6e730060448201526064015b60405180910390fd5b60008167ffffffffffffffff8111156109fa576109fa6146ce565b604051908082528060200260200182016040528015610a23578160200160208202803683370190505b5090506000805b83811015610abb57600060066000888481518110610a4a57610a4a6150d0565b602090810291909101810151825281019190915260400160002080548551919250601b0b90859084908110610a8157610a816150d0565b60209081029190910101528054610aa590600160e01b900463ffffffff16846150fc565b9250508080610ab390615114565b915050610a2a565b506000610ac88483615145565b9050610ad38661277f565b60008181526006602052604090205490955063ffffffff600160e01b90910481169082161015610b455760405162461bcd60e51b815260206004820152601660248201527f557064617465642076616c7565206f757464617465640000000000000000000060448201526064016109d6565b6000610b5084612e6d565b604080518082018252601b83900b80825263ffffffff868116602080850182815260008e81526006835287902095519051909316600160e01b026001600160e01b0390931692909217909355835191825281019190915291925087917fb7712be6248d021e8c56ac9613c09491354a4d0f4ad0b7db1a664b35be4b2349910160405180910390a25050505050919050565b60006001600160a01b038316610c395760405162461bcd60e51b815260206004820152601460248201527f4169726e6f64652061646472657373207a65726f00000000000000000000000060448201526064016109d6565b81610c865760405162461bcd60e51b815260206004820152601060248201527f54656d706c617465204944207a65726f0000000000000000000000000000000060448201526064016109d6565b6040516bffffffffffffffffffffffff19606085901b1660208201526034810183905260540160405160208183030381529060405280519060200120905092915050565b84610cd481612fd5565b610d165760405162461bcd60e51b8152602060048201526013602482015272151a5b595cdd185b5c081b9bdd081d985b1a59606a1b60448201526064016109d6565b876001600160a01b0316610d9584848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604051610d8f9250610d7491508c908c908c908c90602001615159565b60405160208183030381529060405280519060200120613001565b9061303c565b6001600160a01b031614610de05760405162461bcd60e51b81526020600482015260126024820152710a6d2cedcc2e8eae4ca40dad2e6dac2e8c6d60731b60448201526064016109d6565b6000610dec8989610be1565b90506000610dfc82898989613060565b60408051828152602081018b905291925083917f403078446dab7471f481ca4bffac706bd84a6dba118980d267676c096f2ba924910160405180910390a250505050505050505050565b610e4f33613165565b610e9b5760405162461bcd60e51b815260206004820152601560248201527f43616e6e6f74207365742065787069726174696f6e000000000000000000000060448201526064016109d6565b82610eda5760405162461bcd60e51b815260206004820152600f60248201526e53657276696365204944207a65726f60881b60448201526064016109d6565b6001600160a01b038216610f245760405162461bcd60e51b8152602060048201526011602482015270557365722061646472657373207a65726f60781b60448201526064016109d6565b6000838152602081815260408083206001600160a01b03861684529091529020805467ffffffffffffffff191667ffffffffffffffff831617905560405167ffffffffffffffff8216815233906001600160a01b0384169085907fd19e89b7d547ccf349211588a9a1d29461e2ce984b1b1cdbe7150976528b86f1906020015b60405180910390a4505050565b84610fbb81612fd5565b610ffd5760405162461bcd60e51b8152602060048201526013602482015272151a5b595cdd185b5c081b9bdd081d985b1a59606a1b60448201526064016109d6565b6040516bffffffffffffffffffffffff1960608b811b821660208401528a811b8216603484015289901b166048820152605c0160408051601f19818403018152918152815160209283012060008d81526008909352912054146110a25760405162461bcd60e51b815260206004820152601b60248201527f537562736372697074696f6e206e6f742072656769737465726564000000000060448201526064016109d6565b876001600160a01b0316896001600160a01b0316141561118b57886001600160a01b031661113b84848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604051610d8f9250610d7491508f908c903390602001928352602083019190915260601b6bffffffffffffffffffffffff1916604082015260540190565b6001600160a01b0316146111865760405162461bcd60e51b81526020600482015260126024820152710a6d2cedcc2e8eae4ca40dad2e6dac2e8c6d60731b60448201526064016109d6565b611236565b886001600160a01b03166111eb84848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604051610d8f9250610d7491508f908c9033908d908d9060200161517a565b6001600160a01b0316146112365760405162461bcd60e51b81526020600482015260126024820152710a6d2cedcc2e8eae4ca40dad2e6dac2e8c6d60731b60448201526064016109d6565b60008a8152600560205260408120549061125282898989613060565b604080518e8152601b83900b602082015263ffffffff8b1681830152905191925083917f2b85d71813342fd0091d4573a5f78e244c2133755e470943c33a6dbf3cf9c15d9181900360600190a2505050505050505050505050565b6112bc610397848601866147a4565b84846040516112cc9291906151b4565b6040518091039020146113215760405162461bcd60e51b815260206004820152601760248201527f44617461206c656e677468206e6f7420636f727265637400000000000000000060448201526064016109d6565b505050505050505050565b611335336132a5565b6113815760405162461bcd60e51b815260206004820152601c60248201527f43616e6e6f742073657420696e646566696e697465207374617475730000000060448201526064016109d6565b826113c05760405162461bcd60e51b815260206004820152600f60248201526e53657276696365204944207a65726f60881b60448201526064016109d6565b6001600160a01b03821661140a5760405162461bcd60e51b8152602060048201526011602482015270557365722061646472657373207a65726f60781b60448201526064016109d6565b6000611417848484613356565b6040805184151581526001600160c01b038316602082015291925033916001600160a01b0386169187917f2fa93828cf3f001b9a9f0a7365db04ea068b9db7bcb7a38d289f0cf8aa9ce374910160405180910390a450505050565b60008060008360405160200161148a91815260200190565b6040516020818303038152906040528051906020012090506114ac8133612738565b6114ed5760405162461bcd60e51b815260206004820152601260248201527114d95b99195c8818d85b9b9bdd081c99585960721b60448201526064016109d6565b600081815260096020526040902054806115495760405162461bcd60e51b815260206004820152601160248201527f64415049206e616d65206e6f742073657400000000000000000000000000000060448201526064016109d6565b600090815260066020526040902054601b81900b95600160e01b90910463ffffffff16945092505050565b60028054611581906151c4565b80601f01602080910402602001604051908101604052809291908181526020018280546115ad906151c4565b80156115fa5780601f106115cf576101008083540402835291602001916115fa565b820191906000526020600020905b8154815290600101906020018083116115dd57829003601f168201915b505050505081565b600061160e8233612738565b61164f5760405162461bcd60e51b815260206004820152601260248201527114d95b99195c8818d85b9b9bdd081c99585960721b60448201526064016109d6565b60008281526006602052604090208054600160e01b900463ffffffff166116b85760405162461bcd60e51b815260206004820152601860248201527f44617461206665656420646f6573206e6f74206578697374000000000000000060448201526064016109d6565b54601b0b92915050565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461173a5760405162461bcd60e51b815260206004820152601b60248201527f53656e646572206e6f74204169726e6f64652070726f746f636f6c000000000060448201526064016109d6565b8261174481612fd5565b6117865760405162461bcd60e51b8152602060048201526013602482015272151a5b595cdd185b5c081b9bdd081d985b1a59606a1b60448201526064016109d6565b6000858152600760205260408120805490829055906117a782878787613060565b604080518981526020810183905290810188905290915082907f7c88b543c4cda65df046e87397c3152c27098419cb22a90a5e37db30ef621b269060600160405180910390a250505050505050565b84518451600091908114801561180c5750845181145b80156118185750835181145b80156118245750825181145b6118705760405162461bcd60e51b815260206004820152601960248201527f506172616d65746572206c656e677468206d69736d617463680000000000000060448201526064016109d6565b600181116118c05760405162461bcd60e51b815260206004820152601f60248201527f537065636966696564206c657373207468616e2074776f20426561636f6e730060448201526064016109d6565b60008167ffffffffffffffff8111156118db576118db6146ce565b604051908082528060200260200182016040528015611904578160200160208202803683370190505b50905060008267ffffffffffffffff811115611922576119226146ce565b60405190808252806020026020018201604052801561194b578160200160208202803683370190505b5090506000805b84811015611c105786818151811061196c5761196c6150d0565b602002602001015151600014611b555760008b8281518110611990576119906150d0565b6020026020010151905060008a83815181106119ae576119ae6150d0565b602002602001015190506119c181612fd5565b611a035760405162461bcd60e51b8152602060048201526013602482015272151a5b595cdd185b5c081b9bdd081d985b1a59606a1b60448201526064016109d6565b816001600160a01b0316611a748a8581518110611a2257611a226150d0565b6020026020010151610d8f8f8781518110611a3f57611a3f6150d0565b6020026020010151858f8981518110611a5a57611a5a6150d0565b6020026020010151604051602001610d74939291906151f9565b6001600160a01b031614611abf5760405162461bcd60e51b81526020600482015260126024820152710a6d2cedcc2e8eae4ca40dad2e6dac2e8c6d60731b60448201526064016109d6565b611ae18a8481518110611ad457611ad46150d0565b602002602001015161350e565b601b0b858481518110611af657611af66150d0565b6020908102919091010152611b0b81856150fc565b9350611b30828d8581518110611b2357611b236150d0565b6020026020010151610be1565b868481518110611b4257611b426150d0565b6020026020010181815250505050611bfe565b6000611b868c8381518110611b6c57611b6c6150d0565b60200260200101518c8481518110611b2357611b236150d0565b6000818152600660205260409020805486519293509091601b9190910b90869085908110611bb657611bb66150d0565b60209081029190910101528054611bda90600160e01b900463ffffffff16856150fc565b935081868481518110611bef57611bef6150d0565b60200260200101818152505050505b80611c0881615114565b915050611952565b50611c1a8361277f565b94506000611c288583615145565b60008781526006602052604090205490915063ffffffff600160e01b90910481169082161015611c9a5760405162461bcd60e51b815260206004820152601660248201527f557064617465642076616c7565206f757464617465640000000000000000000060448201526064016109d6565b6000611ca584612e6d565b604080518082018252601b83900b80825263ffffffff868116602080850182815260008f81526006835287902095519051909316600160e01b026001600160e01b0390931692909217909355835191825281019190915291925088917fb34747dc40d9c985b4857c2955fec7a8f34d88bc06da72f43319795758800407910160405180910390a250505050505095945050505050565b60008082604051602001611d5191815260200190565b604051602081830303815290604052805190602001209050611d738133612738565b611db45760405162461bcd60e51b815260206004820152601260248201527114d95b99195c8818d85b9b9bdd081c99585960721b60448201526064016109d6565b6000818152600960209081526040808320548352600690915290208054600160e01b900463ffffffff16611e2a5760405162461bcd60e51b815260206004820152601860248201527f44617461206665656420646f6573206e6f74206578697374000000000000000060448201526064016109d6565b54601b0b9392505050565b611e3e816132a5565b15611e8b5760405162461bcd60e51b815260206004820181905260248201527f7365747465722063616e2073657420696e646566696e6974652073746174757360448201526064016109d6565b600080611e99858585613611565b915091508115611ef757604080513381526001600160c01b03831660208201526001600160a01b03808616929087169188917f29c394c1d92801cab93215bf9cd50ae38d23341be6540f27d80ee2bc8a541237910160405180910390a45b5050505050565b600080611f0a8461277f565b600081815260066020908152604091829020825180840190935254601b81900b8352600160e01b900463ffffffff1690820152909150611f4985610985565b506000828152600660205260409020815181548691611f6a91601b0b6136fc565b101580611f975750602082015163ffffffff16158015611f9757508054600160e01b900463ffffffff1615155b9695505050505050565b60006009600083604051602001611fba91815260200190565b604051602081830303815290604052805190602001208152602001908152602001600020549050919050565b816120335760405162461bcd60e51b815260206004820152600e60248201527f64415049206e616d65207a65726f00000000000000000000000000000000000060448201526064016109d6565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806121225750604051632474521560e21b81527f000000000000000000000000000000000000000000000000000000000000000060048201523360248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906391d148549060440160206040518083038186803b1580156120ea57600080fd5b505afa1580156120fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121229190615226565b61216e5760405162461bcd60e51b815260206004820152601b60248201527f53656e6465722063616e6e6f74207365742064415049206e616d65000000000060448201526064016109d6565b80600960008460405160200161218691815260200190565b60405160208183030381529060405280519060200120815260200190815260200160002081905550336001600160a01b0316827ff3a9aac9b6ac0f842cb5d9b3491cd5fc1b6a6778d97fd9529f587339865294f5836040516121ea91815260200190565b60405180910390a35050565b6000816001600160a01b03811633148061223357506001600160a01b038116600090815260046020908152604080832033845290915290205460ff165b61227f5760405162461bcd60e51b815260206004820152601460248201527f53656e646572206e6f74207065726d697474656400000000000000000000000060448201526064016109d6565b600061228b8686610be1565b6040517feebecf690000000000000000000000000000000000000000000000000000000081526001600160a01b0388811660048301526024820188905260a06044830152600060a48301528681166064830152630b7914b960e31b60848301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063eebecf699060c401602060405180830381600087803b15801561233657600080fd5b505af115801561234a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061236e9190615243565b60008181526007602090815260409182902084905581518381526001600160a01b038a811692820192909252918201889052919450339186169083907fc0e8c8735457dd46668d6c01832656e0803b41b1e61ba12354a24f11e114eab39060600160405180910390a450509392505050565b6001600160a01b0382166124365760405162461bcd60e51b815260206004820152601560248201527f55706461746520726571756573746572207a65726f000000000000000000000060448201526064016109d6565b3360008181526004602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917fba239f737a4075f5efb0d649e16cd7d2b1978690876b079dab642f077050b27991016121ea565b6000806124a88333612738565b6124e95760405162461bcd60e51b815260206004820152601260248201527114d95b99195c8818d85b9b9bdd081c99585960721b60448201526064016109d6565b5050600090815260066020526040902054601b81900b91600160e01b90910463ffffffff1690565b61251a33613775565b6125665760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420657874656e642065787069726174696f6e000000000000000060448201526064016109d6565b826125a55760405162461bcd60e51b815260206004820152600f60248201526e53657276696365204944207a65726f60881b60448201526064016109d6565b6001600160a01b0382166125ef5760405162461bcd60e51b8152602060048201526011602482015270557365722061646472657373207a65726f60781b60448201526064016109d6565b6125fa838383613826565b60405167ffffffffffffffff8216815233906001600160a01b0384169085907fa9e0c89b898eb7a904617915dc5b5510d539c899810042e9248569b54b9cc2ed90602001610fa4565b60608167ffffffffffffffff81111561265e5761265e6146ce565b60405190808252806020026020018201604052801561269157816020015b606081526020019060019003908161267c5790505b50905060005b8281101561273157612701308585848181106126b5576126b56150d0565b90506020028101906126c7919061525c565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506138a392505050565b828281518110612713576127136150d0565b6020026020010181905250808061272990615114565b915050612697565b5092915050565b60006001600160a01b0382161580612755575061275583836138c8565b8061277857506001600160a01b03821660009081526003602052604090205460ff165b9392505050565b60008160405160200161279291906152a3565b604051602081830303815290604052805190602001209050919050565b600033156127ff5760405162461bcd60e51b815260206004820152601760248201527f53656e646572206e6f74207a65726f206164647265737300000000000000000060448201526064016109d6565b600061280d858701876147a4565b9050858560405161281f9291906151b4565b60405180910390208160405160200161283891906152a3565b604051602081830303815290604052805190602001201461289b5760405162461bcd60e51b815260206004820152601760248201527f44617461206c656e677468206e6f7420636f727265637400000000000000000060448201526064016109d6565b6128a981610626868661391b565b979650505050505050565b600033156129045760405162461bcd60e51b815260206004820152601760248201527f53656e646572206e6f74207a65726f206164647265737300000000000000000060448201526064016109d6565b600086815260056020526040902054806129605760405162461bcd60e51b815260206004820152601b60248201527f537562736372697074696f6e206e6f742072656769737465726564000000000060448201526064016109d6565b6000818152600660205260409020612978858561391b565b8154604080516020601f8b018190048102820181019092528981526129c592601b0b916129c091908c908c908190840183828082843760009201919091525061350e92505050565b6136fc565b1015806129de57508054600160e01b900463ffffffff16155b98975050505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612a625760405162461bcd60e51b815260206004820152601260248201527f53656e646572206e6f74206d616e61676572000000000000000000000000000060448201526064016109d6565b6001600160a01b038116600081815260036020526040808220805460ff19166001179055517f6d71fde11d6c56eaf0154d464b51df0b26dcdac118703056ea3da805fc9e1cd79190a250565b6000816001600160a01b038116331480612aeb57506001600160a01b038116600090815260046020908152604080832033845290915290205460ff165b612b375760405162461bcd60e51b815260206004820152601460248201527f53656e646572206e6f74207065726d697474656400000000000000000000000060448201526064016109d6565b6000612b438787610be1565b6040517fa7e0c85e0000000000000000000000000000000000000000000000000000000081526001600160a01b0389811660048301526024820189905260c06044830152600060c483015287811660648301528681166084830152630b7914b960e31b60a48301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a7e0c85e9060e401602060405180830381600087803b158015612bf657600080fd5b505af1158015612c0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c2e9190615243565b600081815260076020526040908190208390555190935033906001600160a01b0386169083907faeef85c84fba3ef952ca2738d951d30f5093595cb5eb9830764f5b49a39442a390612ca79088908d908c908e909384526001600160a01b03928316602085015291166040830152606082015260800190565b60405180910390a45050949350505050565b60006001600160a01b038316612d115760405162461bcd60e51b815260206004820152601460248201527f52656c617965722061646472657373207a65726f00000000000000000000000060448201526064016109d6565b6001600160a01b038216612d675760405162461bcd60e51b815260206004820152601460248201527f53706f6e736f722061646472657373207a65726f00000000000000000000000060448201526064016109d6565b604051612d8d90469088908890889088908890309063081ad23d60e21b906020016152e7565b60408051601f1981840301815282825280516020918201206bffffffffffffffffffffffff1960608b811b82168487015288811b8216603487015287901b1660488501528251808503603c018152605c909401835283519382019390932060008481526008909252919020559050612e058686610be1565b60008281526005602052604090819020919091555181907f82b139c5e690a3a4a9c2f68133d2ab1f7724bf8a69ad3fe1cd9f5a4923cf41b290612e5c9089908990899089908990309063081ad23d60e21b90615376565b60405180910390a295945050505050565b805160009060098111612f2d57612e8383613979565b612e8e6002826153fd565b60011415612ec25782612ea2600283615145565b81518110612eb257612eb26150d0565b6020026020010151915050919050565b600283612ecf8284615145565b81518110612edf57612edf6150d0565b6020026020010151846001600285612ef79190615145565b612f019190615411565b81518110612f1157612f116150d0565b6020026020010151612f239190615428565b6127789190615467565b612f386002826153fd565b60011415612f555782612ea281612f50600285615145565b613e90565b600080612f78856001612f69600287615145565b612f739190615411565b613eae565b915091506002858281518110612f9057612f906150d0565b6020026020010151868481518110612faa57612faa6150d0565b6020026020010151612fbc9190615428565b612fc69190615467565b95945050505050565b50919050565b600042612fe483610e106150fc565b118015612ffb5750612ff8426103846150fc565b82105b92915050565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01612792565b600080600061304b8585613f2b565b9150915061305881613f98565b509392505050565b60006130a183838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061350e92505050565b600086815260066020526040902054601b9190910b9150600160e01b900463ffffffff1684116131135760405162461bcd60e51b815260206004820152601d60248201527f46756c66696c6c6d656e74206f6c646572207468616e20426561636f6e00000060448201526064016109d6565b604080518082018252601b83900b815263ffffffff95861660208083019182526000988952600690529190962095519051909416600160e01b026001600160e01b039094169390931790935550919050565b6000816001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161480612ffb5750604051632474521560e21b81527f000000000000000000000000000000000000000000000000000000000000000060048201526001600160a01b0383811660248301527f000000000000000000000000000000000000000000000000000000000000000016906391d14854906044015b60206040518083038186803b15801561322a57600080fd5b505afa15801561323e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ffb9190615226565b6000928352602083815260408085206001600160a01b039490941685529290529120805467ffffffffffffffff191667ffffffffffffffff909216919091179055565b6000816001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161480612ffb5750604051632474521560e21b81527f000000000000000000000000000000000000000000000000000000000000000060048201526001600160a01b0383811660248301527f000000000000000000000000000000000000000000000000000000000000000016906391d1485490604401613212565b6000838152602081815260408083206001600160a01b0386168452909152902054600160401b90046001600160c01b03168180156133bf575060008481526001602090815260408083206001600160a01b0387168452825280832033845290915290205460ff16155b1561344c5760008481526001602081815260408084206001600160a01b03881685528252808420338552909152909120805460ff191690911790558061340481615495565b6000868152602081815260408083206001600160a01b03891684529091529020805467ffffffffffffffff16600160401b6001600160c01b0384160217905591506127789050565b81158015613484575060008481526001602090815260408083206001600160a01b0387168452825280832033845290915290205460ff165b156127785760008481526001602090815260408083206001600160a01b038716845282528083203384529091529020805460ff19169055806134c5816154bc565b6000868152602081815260408083206001600160a01b03891684529091529020805467ffffffffffffffff16600160401b6001600160c01b038416021790559150509392505050565b600081516020146135615760405162461bcd60e51b815260206004820152601760248201527f44617461206c656e677468206e6f7420636f727265637400000000000000000060448201526064016109d6565b6000828060200190518101906135779190615243565b90507fffffffff8000000000000000000000000000000000000000000000000000000081128015906135c557507b7fffffffffffffffffffffffffffffffffffffffffffffffffffffff8113155b612ffb5760405162461bcd60e51b815260206004820152601760248201527f56616c7565207479706563617374696e67206572726f7200000000000000000060448201526064016109d6565b6000838152602081815260408083206001600160a01b0386811680865291845282852054888652600185528386209286529184528285209086168552909252822054600160401b9091046001600160c01b03169060ff16156136f45760008581526001602090815260408083206001600160a01b03808916855290835281842090871684529091529020805460ff19169055806136ad816154bc565b6000878152602081815260408083206001600160a01b038a1684529091529020805467ffffffffffffffff16600160401b6001600160c01b03841602179055600193509150505b935093915050565b60008083601b0b83601b0b61371191906154df565b9050600080821361372a576137258261551e565b61372c565b815b905060008086601b0b1361374c5785601b0b6137479061551e565b613751565b85601b0b5b90508061375c575060015b8061376b6305f5e1008461553b565b611f979190615145565b6000816001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161480612ffb5750604051632474521560e21b81527f000000000000000000000000000000000000000000000000000000000000000060048201526001600160a01b0383811660248301527f000000000000000000000000000000000000000000000000000000000000000016906391d1485490604401613212565b6000838152602081815260408083206001600160a01b038616845290915290205467ffffffffffffffff908116908216116132625760405162461bcd60e51b815260206004820152601a60248201527f446f6573206e6f7420657874656e642065787069726174696f6e00000000000060448201526064016109d6565b606061277883836040518060600160405280602781526020016155a460279139614156565b6000828152602081815260408083206001600160a01b038516845290915281208054600160401b90046001600160c01b0316151580613913575080544267ffffffffffffffff909116115b949350505050565b60006020821461396d5760405162461bcd60e51b815260206004820152601a60248201527f496e636f727265637420706172616d65746572206c656e67746800000000000060448201526064016109d6565b61277882840184614a3c565b805160098111156139cc5760405162461bcd60e51b815260206004820152601660248201527f417272617920746f6f206c6f6e6720746f20736f72740000000000000000000060448201526064016109d6565b6006811015613ada576004811015613a28578060031415613a12576139f48260006001614237565b613a018260016002614237565b613a0e8260006001614237565b5050565b8060021415613a0e57613a0e8260006001614237565b8060051415613aa657613a3e8260016002614237565b613a4b8260036004614237565b613a588260016003614237565b613a658260006002614237565b613a728260026004614237565b613a7f8260006003614237565b613a8c8260006001614237565b613a998260026003614237565b613a0e8260016002614237565b613ab38260006001614237565b613ac08260026003614237565b613acd8260016003614237565b613a998260006002614237565b6008811015613c58578060071415613bbc57613af98260016002614237565b613b068260036004614237565b613b138260056006614237565b613b208260006002614237565b613b2d8260046006614237565b613b3a8260036005614237565b613b478260026006614237565b613b548260016005614237565b613b618260006004614237565b613b6e8260026005614237565b613b7b8260006003614237565b613b888260026004614237565b613b958260016003614237565b613ba28260006001614237565b613baf8260026003614237565b613a0e8260046005614237565b613bc98260006001614237565b613bd68260026003614237565b613be38260046005614237565b613bf08260016003614237565b613bfd8260036005614237565b613c0a8260016003614237565b613c178260026004614237565b613c248260006002614237565b613c318260026004614237565b613c3e8260036004614237565b613c4b8260016002614237565b613a0e8260026003614237565b8060091415613d8c57613c6e8260016008614237565b613c7b8260026007614237565b613c888260036006614237565b613c958260046005614237565b613ca28260016004614237565b613caf8260056008614237565b613cbc8260006002614237565b613cc98260066007614237565b613cd68260026006614237565b613ce38260076008614237565b613cf08260006003614237565b613cfd8260046005614237565b613d0a8260006001614237565b613d178260036005614237565b613d248260066007614237565b613d318260026004614237565b613d3e8260016003614237565b613d4b8260056007614237565b613d588260046006614237565b613d658260016002614237565b613d728260036004614237565b613d7f8260056006614237565b613ba28260076008614237565b613d998260006007614237565b613da68260016006614237565b613db38260026005614237565b613dc08260036004614237565b613dcd8260006003614237565b613dda8260046007614237565b613de78260016002614237565b613df48260056006614237565b613e018260006001614237565b613e0e8260026003614237565b613e1b8260046005614237565b613e288260066007614237565b613e358260036005614237565b613e428260026004614237565b613e4f8260016002614237565b613e5c8260036004614237565b613e698260056006614237565b613e768260026003614237565b613e838260046005614237565b613a0e8260036004614237565b600061305883600060018651613ea69190615411565b8560006142e5565b8151600090819060018111613f055760405162461bcd60e51b815260206004820152601d60248201527f417272617920746f6f2073686f727420746f2073656c656374206b2b3100000060448201526064016109d6565b613f1e856000613f16600185615411565b8760016142e5565b92509250505b9250929050565b600080825160411415613f625760208301516040840151606085015160001a613f56878285856143e0565b94509450505050613f24565b825160401415613f8c5760208301516040840151613f818683836144cd565b935093505050613f24565b50600090506002613f24565b6000816004811115613fac57613fac61555a565b1415613fb55750565b6001816004811115613fc957613fc961555a565b14156140175760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016109d6565b600281600481111561402b5761402b61555a565b14156140795760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016109d6565b600381600481111561408d5761408d61555a565b14156140e65760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016109d6565b60048160048111156140fa576140fa61555a565b14156141535760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b60648201526084016109d6565b50565b6060833b6141cc5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e7472616374000000000000000000000000000000000000000000000000000060648201526084016109d6565b600080856001600160a01b0316856040516141e79190615570565b600060405180830381855af49150503d8060008114614222576040519150601f19603f3d011682016040523d82523d6000602084013e614227565b606091505b5091509150611f978282866144fc565b828181518110614249576142496150d0565b6020026020010151838381518110614263576142636150d0565b602002602001015113156142e057828181518110614283576142836150d0565b602002602001015183838151811061429d5761429d6150d0565b60200260200101518484815181106142b7576142b76150d0565b602002602001018584815181106142d0576142d06150d0565b6020908102919091010191909152525b505050565b600080848614156142fb575082905060006143d6565b6000614308888888614535565b9050808510156143325761432a8888614322600185615411565b8860006142e5565b509250614356565b808511156143525761432a886143498360016150fc565b888860006142e5565b8092505b83156143d4576143678360016150fc565b915060006143768360016150fc565b90505b88518110156143d257888381518110614394576143946150d0565b60200260200101518982815181106143ae576143ae6150d0565b602002602001015112156143c0578092505b806143ca81615114565b915050614379565b505b505b9550959350505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561441757506000905060036144c4565b8460ff16601b1415801561442f57508460ff16601c14155b1561444057506000905060046144c4565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614494573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166144bd576000600192509250506144c4565b9150600090505b94509492505050565b6000806001600160ff1b03831660ff84901c601b016144ee878288856143e0565b935093505050935093915050565b6060831561450b575081612778565b82511561451b5782518084602001fd5b8160405162461bcd60e51b81526004016109d69190614ab1565b600081831415614546575081612778565b600084848151811061455a5761455a6150d0565b60209081029190910101519050836145738460016150fc565b92505b8061458081615114565b9150508551811080156145ab5750818682815181106145a1576145a16150d0565b6020026020010151125b614576575b826145ba8161558c565b935050818684815181106145d0576145d06150d0565b6020026020010151136145b05782811061465b578583815181106145f6576145f66150d0565b6020026020010151868681518110614610576146106150d0565b602002602001015187878151811061462a5761462a6150d0565b60200260200101888681518110614643576146436150d0565b60200260200101828152508281525050505050612778565b85838151811061466d5761466d6150d0565b6020026020010151868281518110614687576146876150d0565b60200260200101518783815181106146a1576146a16150d0565b602002602001018886815181106146ba576146ba6150d0565b602090810291909101019190915252614576565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561470d5761470d6146ce565b604052919050565b600067ffffffffffffffff82111561472f5761472f6146ce565b5060051b60200190565b600082601f83011261474a57600080fd5b8135602061475f61475a83614715565b6146e4565b82815260059290921b8401810191818101908684111561477e57600080fd5b8286015b848110156147995780358352918301918301614782565b509695505050505050565b6000602082840312156147b657600080fd5b813567ffffffffffffffff8111156147cd57600080fd5b61391384828501614739565b80356001600160a01b03811681146147f057600080fd5b919050565b6000806040838503121561480857600080fd5b614811836147d9565b946020939093013593505050565b60008083601f84011261483157600080fd5b50813567ffffffffffffffff81111561484957600080fd5b602083019150836020828501011115613f2457600080fd5b600080600080600080600060a0888a03121561487c57600080fd5b614885886147d9565b96506020880135955060408801359450606088013567ffffffffffffffff808211156148b057600080fd5b6148bc8b838c0161481f565b909650945060808a01359150808211156148d557600080fd5b506148e28a828b0161481f565b989b979a50959850939692959293505050565b60008060006060848603121561490a57600080fd5b8335925061491a602085016147d9565b9150604084013567ffffffffffffffff8116811461493757600080fd5b809150509250925092565b600080600080600080600080600060e08a8c03121561496057600080fd5b8935985061497060208b016147d9565b975061497e60408b016147d9565b965061498c60608b016147d9565b955060808a0135945060a08a013567ffffffffffffffff808211156149b057600080fd5b6149bc8d838e0161481f565b909650945060c08c01359150808211156149d557600080fd5b506149e28c828d0161481f565b915080935050809150509295985092959850929598565b801515811461415357600080fd5b600080600060608486031215614a1c57600080fd5b83359250614a2c602085016147d9565b91506040840135614937816149f9565b600060208284031215614a4e57600080fd5b5035919050565b60005b83811015614a70578181015183820152602001614a58565b83811115614a7f576000848401525b50505050565b60008151808452614a9d816020860160208601614a55565b601f01601f19169290920160200192915050565b6020815260006127786020830184614a85565b60008060008060608587031215614ada57600080fd5b8435935060208501359250604085013567ffffffffffffffff811115614aff57600080fd5b614b0b8782880161481f565b95989497509550505050565b600082601f830112614b2857600080fd5b81356020614b3861475a83614715565b82815260059290921b84018101918181019086841115614b5757600080fd5b8286015b8481101561479957614b6c816147d9565b8352918301918301614b5b565b600082601f830112614b8a57600080fd5b813567ffffffffffffffff811115614ba457614ba46146ce565b614bb7601f8201601f19166020016146e4565b818152846020838601011115614bcc57600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f830112614bfa57600080fd5b81356020614c0a61475a83614715565b82815260059290921b84018101918181019086841115614c2957600080fd5b8286015b8481101561479957803567ffffffffffffffff811115614c4d5760008081fd5b614c5b8986838b0101614b79565b845250918301918301614c2d565b600080600080600060a08688031215614c8157600080fd5b853567ffffffffffffffff80821115614c9957600080fd5b614ca589838a01614b17565b96506020880135915080821115614cbb57600080fd5b614cc789838a01614739565b95506040880135915080821115614cdd57600080fd5b614ce989838a01614739565b94506060880135915080821115614cff57600080fd5b614d0b89838a01614be9565b93506080880135915080821115614d2157600080fd5b50614d2e88828901614be9565b9150509295509295909350565b600080600060608486031215614d5057600080fd5b83359250614d60602085016147d9565b9150614d6e604085016147d9565b90509250925092565b60008060408385031215614d8a57600080fd5b823567ffffffffffffffff811115614da157600080fd5b614dad85828601614739565b95602094909401359450505050565b60008060408385031215614dcf57600080fd5b50508035926020909101359150565b600080600060608486031215614df357600080fd5b614dfc846147d9565b925060208401359150614d6e604085016147d9565b60008060408385031215614e2457600080fd5b614e2d836147d9565b9150614e3b602084016147d9565b90509250929050565b60008060408385031215614e5757600080fd5b614e60836147d9565b91506020830135614e70816149f9565b809150509250929050565b60008060208385031215614e8e57600080fd5b823567ffffffffffffffff80821115614ea657600080fd5b818501915085601f830112614eba57600080fd5b813581811115614ec957600080fd5b8660208260051b8501011115614ede57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614f4557603f19888603018452614f33858351614a85565b94509285019290850190600101614f17565b5092979650505050505050565b600060208284031215614f6457600080fd5b612778826147d9565b60008060408385031215614f8057600080fd5b82359150614e3b602084016147d9565b600080600080600060608688031215614fa857600080fd5b85359450602086013567ffffffffffffffff80821115614fc757600080fd5b614fd389838a0161481f565b90965094506040880135915080821115614fec57600080fd5b50614ff98882890161481f565b969995985093965092949392505050565b6000806000806080858703121561502057600080fd5b615029856147d9565b93506020850135925061503e604086016147d9565b915061504c606086016147d9565b905092959194509250565b600080600080600060a0868803121561506f57600080fd5b615078866147d9565b945060208601359350604086013567ffffffffffffffff81111561509b57600080fd5b6150a788828901614b79565b9350506150b6606087016147d9565b91506150c4608087016147d9565b90509295509295909350565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000821982111561510f5761510f6150e6565b500190565b6000600019821415615128576151286150e6565b5060010190565b634e487b7160e01b600052601260045260246000fd5b6000826151545761515461512f565b500490565b84815283602082015281836040830137600091016040019081529392505050565b8581528460208201526bffffffffffffffffffffffff198460601b1660408201528183605483013760009101605401908152949350505050565b8183823760009101908152919050565b600181811c908216806151d857607f821691505b60208210811415612fcf57634e487b7160e01b600052602260045260246000fd5b83815282602082015260008251615217816040850160208701614a55565b91909101604001949350505050565b60006020828403121561523857600080fd5b8151612778816149f9565b60006020828403121561525557600080fd5b5051919050565b6000808335601e1984360301811261527357600080fd5b83018035915067ffffffffffffffff82111561528e57600080fd5b602001915036819003821315613f2457600080fd5b6020808252825182820181905260009190848201906040850190845b818110156152db578351835292840192918401916001016152bf565b50909695505050505050565b60006101208a83526001600160a01b03808b16602085015289604085015281606085015260008285015261014091508160808501526153288285018a614a85565b97811660a085015295861660c084015250509190921660e08201527fffffffff0000000000000000000000000000000000000000000000000000000090911661010090910152949350505050565b60006101006001600160a01b03808b16845289602085015281604085015260008285015261012091508160608501526153b18285018a614a85565b978116608085015295861660a084015250509190921660c08201527fffffffff0000000000000000000000000000000000000000000000000000000090911660e0909101529392505050565b60008261540c5761540c61512f565b500690565b600082821015615423576154236150e6565b500390565b6000808212826001600160ff1b0303841381151615615449576154496150e6565b82600160ff1b038412811615615461576154616150e6565b50500190565b6000826154765761547661512f565b600160ff1b821460001984141615615490576154906150e6565b500590565b60006001600160c01b03808316818114156154b2576154b26150e6565b6001019392505050565b60006001600160c01b038216806154d5576154d56150e6565b6000190192915050565b600080831283600160ff1b018312811516156154fd576154fd6150e6565b836001600160ff1b03018313811615615518576155186150e6565b50500390565b6000600160ff1b821415615534576155346150e6565b5060000390565b6000816000190483118215151615615555576155556150e6565b500290565b634e487b7160e01b600052602160045260246000fd5b60008251615582818460208701614a55565b9190910192915050565b60008161559b5761559b6150e6565b50600019019056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220aaf5f98df755a777bf2ab38bf5b0d2b2f9740cb9c1a1c935964c5d11caec024864736f6c634300080900330000000000000000000000005997c09be60196b7de9de73c88dd7776f28754010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000c3e76d8829259f2a34541746de2f8a0509dc1987000000000000000000000000ccc843194f02ef93b8ee9a9f7b5f9273604acd120000000000000000000000000000000000000000000000000000000000000010446170695365727665722061646d696e00000000000000000000000000000000
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000005997c09be60196b7de9de73c88dd7776f28754010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000c3e76d8829259f2a34541746de2f8a0509dc1987000000000000000000000000ccc843194f02ef93b8ee9a9f7b5f9273604acd120000000000000000000000000000000000000000000000000000000000000010446170695365727665722061646d696e00000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _accessControlRegistry (address): 0x5997c09be60196b7de9de73c88dd7776f2875401
Arg [1] : _adminRoleDescription (string): DapiServer admin
Arg [2] : _manager (address): 0xc3e76d8829259f2a34541746de2f8a0509dc1987
Arg [3] : _airnodeProtocol (address): 0xccc843194f02ef93b8ee9a9f7b5f9273604acd12
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000005997c09be60196b7de9de73c88dd7776f2875401
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [2] : 000000000000000000000000c3e76d8829259f2a34541746de2f8a0509dc1987
Arg [3] : 000000000000000000000000ccc843194f02ef93b8ee9a9f7b5f9273604acd12
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [5] : 446170695365727665722061646d696e00000000000000000000000000000000
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|