Latest 4 from a total of 4 transactions
View more zero value Internal Transactions in Advanced View mode
Cross-Chain Transactions
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {IReceiver} from "../keystone/interfaces/IReceiver.sol";
import {OwnerIsCreator} from "../shared/access/OwnerIsCreator.sol";
import {ITypeAndVersion} from "../shared/interfaces/ITypeAndVersion.sol";
import {IDataFeedsCache} from "./interfaces/IDataFeedsCache.sol";
import {ITokenRecover} from "./interfaces/ITokenRecover.sol";
import {IERC165} from "../vendor/openzeppelin-solidity/v5.0.2/contracts/interfaces/IERC165.sol";
import {IERC20} from "../vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "../vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/utils/SafeERC20.sol";
contract DataFeedsCache is IDataFeedsCache, IReceiver, ITokenRecover, ITypeAndVersion, OwnerIsCreator {
using SafeERC20 for IERC20;
string public constant override typeAndVersion = "DataFeedsCache 1.0.0";
// solhint-disable-next-line
uint256 public constant override version = 7;
/// Cache State
struct WorkflowMetadata {
address allowedSender; // Address of the sender allowed to send new reports
address allowedWorkflowOwner; // ─╮ Address of the workflow owner
bytes10 allowedWorkflowName; // ──╯ Name of the workflow
}
struct FeedConfig {
uint8[] bundleDecimals; // Only appliciable to Bundle reports - Decimal reports have decimals encoded into the DataId.
string description; // Description of the feed (e.g. "LINK / USD")
WorkflowMetadata[] workflowMetadata; // Metadata for the feed
}
struct ReceivedBundleReport {
bytes32 dataId; // Data ID of the feed from the received report
uint32 timestamp; // Timestamp of the feed from the received report
bytes bundle; // Report data in raw bytes
}
struct ReceivedDecimalReport {
bytes32 dataId; // Data ID of the feed from the received report
uint32 timestamp; // ─╮ Timestamp of the feed from the received report
uint224 answer; // ───╯ Report data in uint224
}
struct StoredBundleReport {
bytes bundle; // The latest bundle report stored for a feed
uint32 timestamp; // The timestamp of the latest bundle report
}
struct StoredDecimalReport {
uint224 answer; // ───╮ The latest decimal report stored for a feed
uint32 timestamp; // ─╯ The timestamp of the latest decimal report
}
/// The message sender determines which feed is being requested, as each proxy has a single associated feed
mapping(address aggProxy => bytes16 dataId) private s_aggregatorProxyToDataId;
/// The latest decimal reports for each decimal feed. This will always equal s_decimalReports[s_dataIdToRoundId[dataId]][dataId]
mapping(bytes16 dataId => StoredDecimalReport) private s_latestDecimalReports;
/// Decimal reports for each feed, per round
mapping(uint256 roundId => mapping(bytes16 dataId => StoredDecimalReport)) private s_decimalReports;
/// The latest bundle reports for each bundle feed
mapping(bytes16 dataId => StoredBundleReport) private s_latestBundleReports;
/// The latest round id for each feed
mapping(bytes16 dataId => uint256 roundId) private s_dataIdToRoundId;
/// Addresses that are permitted to configure all feeds
mapping(address feedAdmin => bool isFeedAdmin) private s_feedAdmins;
mapping(bytes16 dataId => FeedConfig) private s_feedConfigs;
/// Whether a given Sender and Workflow have permission to write feed updates.
/// reportHash is the keccak256 hash of the abi.encoded(dataId, sender, workflowOwner and workflowName)
mapping(bytes32 reportHash => bool) private s_writePermissions;
event BundleReportUpdated(bytes16 indexed dataId, uint256 indexed timestamp, bytes bundle);
event DecimalReportUpdated(
bytes16 indexed dataId, uint256 indexed roundId, uint256 indexed timestamp, uint224 answer
);
event DecimalFeedConfigSet(
bytes16 indexed dataId, uint8 decimals, string description, WorkflowMetadata[] workflowMetadata
);
event BundleFeedConfigSet(
bytes16 indexed dataId, uint8[] decimals, string description, WorkflowMetadata[] workflowMetadata
);
event FeedConfigRemoved(bytes16 indexed dataId);
event TokenRecovered(address indexed token, address indexed to, uint256 amount);
event FeedAdminSet(address indexed feedAdmin, bool indexed isAdmin);
event ProxyDataIdRemoved(address indexed proxy, bytes16 indexed dataId);
event ProxyDataIdUpdated(address indexed proxy, bytes16 indexed dataId);
event InvalidUpdatePermission(bytes16 indexed dataId, address sender, address workflowOwner, bytes10 workflowName);
event StaleDecimalReport(bytes16 indexed dataId, uint256 reportTimestamp, uint256 latestTimestamp);
event StaleBundleReport(bytes16 indexed dataId, uint256 reportTimestamp, uint256 latestTimestamp);
error ArrayLengthMismatch();
error EmptyConfig();
error ErrorSendingNative(address to, uint256 amount, bytes data);
error FeedNotConfigured(bytes16 dataId);
error InsufficientBalance(uint256 balance, uint256 requiredBalance);
error InvalidAddress(address addr);
error InvalidDataId();
error InvalidWorkflowName(bytes10 workflowName);
error UnauthorizedCaller(address caller);
error NoMappingForSender(address proxy);
modifier onlyFeedAdmin() {
if (!s_feedAdmins[msg.sender]) revert UnauthorizedCaller(msg.sender);
_;
}
/// @inheritdoc IERC165
function supportsInterface(
bytes4 interfaceId
) public pure returns (bool) {
return (
interfaceId == type(IDataFeedsCache).interfaceId || interfaceId == type(IERC165).interfaceId
|| interfaceId == type(IReceiver).interfaceId || interfaceId == type(ITokenRecover).interfaceId
|| interfaceId == type(ITypeAndVersion).interfaceId
);
}
/// @notice Get the workflow metadata of a feed
/// @param dataId data ID of the feed
/// @param startIndex The cursor to start fetching the metadata from
/// @param maxCount The number of metadata to fetch
/// @return workflowMetadata The metadata of the feed
function getFeedMetadata(
bytes16 dataId,
uint256 startIndex,
uint256 maxCount
) external view returns (WorkflowMetadata[] memory workflowMetadata) {
FeedConfig storage feedConfig = s_feedConfigs[dataId];
uint256 workflowMetadataLength = feedConfig.workflowMetadata.length;
if (workflowMetadataLength == 0) {
revert FeedNotConfigured(dataId);
}
if (startIndex >= workflowMetadataLength) return new WorkflowMetadata[](0);
uint256 endIndex = startIndex + maxCount;
endIndex = endIndex > workflowMetadataLength || maxCount == 0 ? workflowMetadataLength : endIndex;
workflowMetadata = new WorkflowMetadata[](endIndex - startIndex);
for (uint256 idx; idx < workflowMetadata.length; idx++) {
workflowMetadata[idx] = feedConfig.workflowMetadata[idx + startIndex];
}
return workflowMetadata;
}
/// @notice Checks to see if this data ID, msg.sender, workflow owner, and workflow name are permissioned
/// @param dataId The data ID for the feed
/// @param workflowMetadata workflow metadata
function checkFeedPermission(
bytes16 dataId,
WorkflowMetadata memory workflowMetadata
) external view returns (bool hasPermission) {
bytes32 permission = _createReportHash(
dataId,
workflowMetadata.allowedSender,
workflowMetadata.allowedWorkflowOwner,
workflowMetadata.allowedWorkflowName
);
return s_writePermissions[permission];
}
// ================================================================
// │ Contract Config Interface │
// ================================================================
/// @notice Initializes the config for a decimal feed
/// @param dataIds The data IDs of the feeds to configure
/// @param descriptions The descriptions of the feeds
/// @param workflowMetadata List of workflow metadata (owners, senders, and names) for every feed
function setDecimalFeedConfigs(
bytes16[] calldata dataIds,
string[] calldata descriptions,
WorkflowMetadata[] calldata workflowMetadata
) external onlyFeedAdmin {
if (workflowMetadata.length == 0 || dataIds.length == 0) {
revert EmptyConfig();
}
if (dataIds.length != descriptions.length) {
revert ArrayLengthMismatch();
}
for (uint256 i; i < dataIds.length; ++i) {
bytes16 dataId = dataIds[i];
if (dataId == bytes16(0)) revert InvalidDataId();
FeedConfig storage feedConfig = s_feedConfigs[dataId];
if (feedConfig.workflowMetadata.length > 0) {
// Feed is already configured, remove the previous config
for (uint256 j; j < feedConfig.workflowMetadata.length; ++j) {
WorkflowMetadata memory feedCurrentWorkflowMetadata = feedConfig.workflowMetadata[j];
bytes32 reportHash = _createReportHash(
dataId,
feedCurrentWorkflowMetadata.allowedSender,
feedCurrentWorkflowMetadata.allowedWorkflowOwner,
feedCurrentWorkflowMetadata.allowedWorkflowName
);
delete s_writePermissions[reportHash];
}
delete s_feedConfigs[dataId];
emit FeedConfigRemoved(dataId);
}
for (uint256 j; j < workflowMetadata.length; ++j) {
WorkflowMetadata memory feedWorkflowMetadata = workflowMetadata[j];
// Do those checks only once for the first data id
if (i == 0) {
if (feedWorkflowMetadata.allowedSender == address(0)) {
revert InvalidAddress(feedWorkflowMetadata.allowedSender);
}
if (feedWorkflowMetadata.allowedWorkflowOwner == address(0)) {
revert InvalidAddress(feedWorkflowMetadata.allowedWorkflowOwner);
}
if (feedWorkflowMetadata.allowedWorkflowName == bytes10(0)) {
revert InvalidWorkflowName(feedWorkflowMetadata.allowedWorkflowName);
}
}
bytes32 reportHash = _createReportHash(
dataId,
feedWorkflowMetadata.allowedSender,
feedWorkflowMetadata.allowedWorkflowOwner,
feedWorkflowMetadata.allowedWorkflowName
);
s_writePermissions[reportHash] = true;
feedConfig.workflowMetadata.push(feedWorkflowMetadata);
}
feedConfig.description = descriptions[i];
emit DecimalFeedConfigSet({
dataId: dataId,
decimals: _getDecimals(dataId),
description: descriptions[i],
workflowMetadata: workflowMetadata
});
}
}
/// @notice Initializes the config for a bundle feed
/// @param dataIds The data IDs of the feeds to configure
/// @param descriptions The descriptions of the feeds
/// @param decimalsMatrix The number of decimals for each data point in the bundle for the feed
/// @param workflowMetadata List of workflow metadata (owners, senders, and names) for every feed
function setBundleFeedConfigs(
bytes16[] calldata dataIds,
string[] calldata descriptions,
uint8[][] calldata decimalsMatrix,
WorkflowMetadata[] calldata workflowMetadata
) external onlyFeedAdmin {
if (workflowMetadata.length == 0 || dataIds.length == 0) {
revert EmptyConfig();
}
if (dataIds.length != descriptions.length || dataIds.length != decimalsMatrix.length) {
revert ArrayLengthMismatch();
}
for (uint256 i; i < dataIds.length; ++i) {
bytes16 dataId = dataIds[i];
if (dataId == bytes16(0)) revert InvalidDataId();
FeedConfig storage feedConfig = s_feedConfigs[dataId];
if (feedConfig.workflowMetadata.length > 0) {
// Feed is already configured, remove the previous config
for (uint256 j; j < feedConfig.workflowMetadata.length; ++j) {
WorkflowMetadata memory feedCurrentWorkflowMetadata = feedConfig.workflowMetadata[j];
bytes32 reportHash = _createReportHash(
dataId,
feedCurrentWorkflowMetadata.allowedSender,
feedCurrentWorkflowMetadata.allowedWorkflowOwner,
feedCurrentWorkflowMetadata.allowedWorkflowName
);
delete s_writePermissions[reportHash];
}
delete s_feedConfigs[dataId];
emit FeedConfigRemoved(dataId);
}
for (uint256 j; j < workflowMetadata.length; ++j) {
WorkflowMetadata memory feedWorkflowMetadata = workflowMetadata[j];
// Do those checks only once for the first data id
if (i == 0) {
if (feedWorkflowMetadata.allowedSender == address(0)) {
revert InvalidAddress(feedWorkflowMetadata.allowedSender);
}
if (feedWorkflowMetadata.allowedWorkflowOwner == address(0)) {
revert InvalidAddress(feedWorkflowMetadata.allowedWorkflowOwner);
}
if (feedWorkflowMetadata.allowedWorkflowName == bytes10(0)) {
revert InvalidWorkflowName(feedWorkflowMetadata.allowedWorkflowName);
}
}
bytes32 reportHash = _createReportHash(
dataId,
feedWorkflowMetadata.allowedSender,
feedWorkflowMetadata.allowedWorkflowOwner,
feedWorkflowMetadata.allowedWorkflowName
);
s_writePermissions[reportHash] = true;
feedConfig.workflowMetadata.push(feedWorkflowMetadata);
}
feedConfig.bundleDecimals = decimalsMatrix[i];
feedConfig.description = descriptions[i];
emit BundleFeedConfigSet({
dataId: dataId,
decimals: decimalsMatrix[i],
description: descriptions[i],
workflowMetadata: workflowMetadata
});
}
}
/// @notice Removes feeds and all associated data, for a set of feeds
/// @param dataIds And array of data IDs to delete the data and configs of
function removeFeedConfigs(
bytes16[] calldata dataIds
) external onlyFeedAdmin {
for (uint256 i; i < dataIds.length; ++i) {
bytes16 dataId = dataIds[i];
if (s_feedConfigs[dataId].workflowMetadata.length == 0) revert FeedNotConfigured(dataId);
for (uint256 j; j < s_feedConfigs[dataId].workflowMetadata.length; ++j) {
WorkflowMetadata memory feedWorkflowMetadata = s_feedConfigs[dataId].workflowMetadata[j];
bytes32 reportHash = _createReportHash(
dataId,
feedWorkflowMetadata.allowedSender,
feedWorkflowMetadata.allowedWorkflowOwner,
feedWorkflowMetadata.allowedWorkflowName
);
delete s_writePermissions[reportHash];
}
delete s_feedConfigs[dataId];
emit FeedConfigRemoved(dataId);
}
}
/// @notice Sets a feed admin for all feeds, only callable by the Owner
/// @param feedAdmin The feed admin
function setFeedAdmin(address feedAdmin, bool isAdmin) external onlyOwner {
if (feedAdmin == address(0)) revert InvalidAddress(feedAdmin);
s_feedAdmins[feedAdmin] = isAdmin;
emit FeedAdminSet(feedAdmin, isAdmin);
}
/// @notice Returns a bool is an address has feed admin permission for all feeds
/// @param feedAdmin The feed admin
/// @return isFeedAdmin bool if the address is the feed admin for all feeds
function isFeedAdmin(
address feedAdmin
) external view returns (bool) {
return s_feedAdmins[feedAdmin];
}
/// @inheritdoc IDataFeedsCache
function updateDataIdMappingsForProxies(
address[] calldata proxies,
bytes16[] calldata dataIds
) external onlyFeedAdmin {
uint256 numberOfProxies = proxies.length;
if (numberOfProxies != dataIds.length) revert ArrayLengthMismatch();
for (uint256 i; i < numberOfProxies; i++) {
s_aggregatorProxyToDataId[proxies[i]] = dataIds[i];
emit ProxyDataIdUpdated(proxies[i], dataIds[i]);
}
}
/// @inheritdoc IDataFeedsCache
function getDataIdForProxy(
address proxy
) external view returns (bytes16 dataId) {
return s_aggregatorProxyToDataId[proxy];
}
/// @inheritdoc IDataFeedsCache
function removeDataIdMappingsForProxies(
address[] calldata proxies
) external onlyFeedAdmin {
uint256 numberOfProxies = proxies.length;
for (uint256 i; i < numberOfProxies; i++) {
address proxy = proxies[i];
bytes16 dataId = s_aggregatorProxyToDataId[proxy];
delete s_aggregatorProxyToDataId[proxy];
emit ProxyDataIdRemoved(proxy, dataId);
}
}
// ================================================================
// │ Token Transfer Interface │
// ================================================================
/// @inheritdoc ITokenRecover
function recoverTokens(IERC20 token, address to, uint256 amount) external onlyOwner {
if (address(token) == address(0)) {
if (amount > address(this).balance) {
revert InsufficientBalance(address(this).balance, amount);
}
(bool success, bytes memory data) = to.call{value: amount}("");
if (!success) revert ErrorSendingNative(to, amount, data);
} else {
if (amount > token.balanceOf(address(this))) {
revert InsufficientBalance(token.balanceOf(address(this)), amount);
}
token.safeTransfer(to, amount);
}
emit TokenRecovered(address(token), to, amount);
}
// ================================================================
// │ Cache Update Interface │
// ================================================================
/// @inheritdoc IReceiver
function onReport(bytes calldata metadata, bytes calldata report) external {
(address workflowOwner, bytes10 workflowName) = _getWorkflowMetaData(metadata);
// The first 32 bytes is the offset to the array
// The second 32 bytes is the length of the array
uint256 numReports = uint256(bytes32(report[32:64]));
// Decimal reports contain 96 bytes per report
// The total length should equal to the sum of:
// 32 bytes for the offset
// 32 bytes for the number of reports
// the number of reports times 96
if (report.length == numReports * 96 + 64) {
ReceivedDecimalReport[] memory decodedDecimalReports = abi.decode(report, (ReceivedDecimalReport[]));
for (uint256 i; i < numReports; ++i) {
ReceivedDecimalReport memory decodedDecimalReport = decodedDecimalReports[i];
// single dataId can have multiple permissions, to be updated by multiple Workflows
bytes16 dataId = bytes16(decodedDecimalReport.dataId);
bytes32 permission = _createReportHash(dataId, msg.sender, workflowOwner, workflowName);
if (!s_writePermissions[permission]) {
emit InvalidUpdatePermission(dataId, msg.sender, workflowOwner, workflowName);
continue;
}
if (decodedDecimalReport.timestamp <= s_latestDecimalReports[dataId].timestamp) {
emit StaleDecimalReport(dataId, decodedDecimalReport.timestamp, s_latestDecimalReports[dataId].timestamp);
continue;
}
StoredDecimalReport memory decimalReport =
StoredDecimalReport({answer: decodedDecimalReport.answer, timestamp: decodedDecimalReport.timestamp});
uint256 roundId = ++s_dataIdToRoundId[dataId];
s_latestDecimalReports[dataId] = decimalReport;
s_decimalReports[roundId][dataId] = decimalReport;
emit DecimalReportUpdated(dataId, roundId, decimalReport.timestamp, decimalReport.answer);
// Needed for DF1 backward compatibility
emit NewRound(roundId, address(0), decodedDecimalReport.timestamp);
emit AnswerUpdated(int256(uint256(decodedDecimalReport.answer)), roundId, block.timestamp);
}
}
// Bundle reports contain more bytes for the offsets
// The total length should equal to the sum of:
// 32 bytes for the offset
// 32 bytes for the number of reports
// the number of reports times 224
else {
//For byte reports decode using ReceivedFeedReportBundle struct
ReceivedBundleReport[] memory decodedBundleReports = abi.decode(report, (ReceivedBundleReport[]));
for (uint256 i; i < decodedBundleReports.length; ++i) {
ReceivedBundleReport memory decodedBundleReport = decodedBundleReports[i];
bytes16 dataId = bytes16(decodedBundleReport.dataId);
// same dataId can have multiple permissions
bytes32 permission = _createReportHash(dataId, msg.sender, workflowOwner, workflowName);
if (!s_writePermissions[permission]) {
emit InvalidUpdatePermission(dataId, msg.sender, workflowOwner, workflowName);
continue;
}
if (decodedBundleReport.timestamp <= s_latestBundleReports[dataId].timestamp) {
emit StaleBundleReport(dataId, decodedBundleReport.timestamp, s_latestBundleReports[dataId].timestamp);
continue;
}
StoredBundleReport memory bundleReport =
StoredBundleReport({bundle: decodedBundleReport.bundle, timestamp: decodedBundleReport.timestamp});
s_latestBundleReports[dataId] = bundleReport;
emit BundleReportUpdated(dataId, bundleReport.timestamp, bundleReport.bundle);
}
}
}
// ================================================================
// │ Helper Methods │
// ================================================================
/// @notice Gets the Decimals of the feed from the data Id
/// @param dataId The data ID for the feed
/// @return feedDecimals The number of decimals the feed has
function _getDecimals(
bytes16 dataId
) internal pure returns (uint8 feedDecimals) {
// Get the report type from data id. Report type has index of 7
bytes1 reportType = _getDataType(dataId, 7);
// For decimal reports convert to uint8, then shift
if (reportType >= hex"20" && reportType <= hex"60") {
return uint8(reportType) - 32;
}
// If not decimal type, return 0
return 0;
}
/// @notice Extracts the workflow name and the workflow owner from the metadata parameter of onReport
/// @param metadata The metadata in bytes format
/// @return workflowOwner The owner of the workflow
/// @return workflowName The name of the workflow
function _getWorkflowMetaData(
bytes memory metadata
) internal pure returns (address, bytes10) {
address workflowOwner;
bytes10 workflowName;
// (first 32 bytes contain length of the byte array)
// workflow_cid // offset 32, size 32
// workflow_name // offset 64, size 10
// workflow_owner // offset 74, size 20
// report_name // offset 94, size 2
assembly {
// no shifting needed for bytes10 type
workflowName := mload(add(metadata, 64))
// shift right by 12 bytes to get the actual value
workflowOwner := shr(mul(12, 8), mload(add(metadata, 74)))
}
return (workflowOwner, workflowName);
}
/// @notice Extracts a byte from the data ID, to check data types
/// @param dataId The data ID for the feed
/// @param index The index of the byte to extract from the data Id
/// @return dataType result The keccak256 hash of the abi.encoded inputs
function _getDataType(bytes16 dataId, uint256 index) internal pure returns (bytes1 dataType) {
// Convert bytes16 to bytes
return abi.encodePacked(dataId)[index];
}
/// @notice Creates a report hash used to permission write access
/// @param dataId The data ID for the feed
/// @param sender The msg.sender of the transaction calling into onReport
/// @param workflowOwner The owner of the workflow
/// @param workflowName The name of the workflow
/// @return reportHash The keccak256 hash of the abi.encoded inputs
function _createReportHash(
bytes16 dataId,
address sender,
address workflowOwner,
bytes10 workflowName
) internal pure returns (bytes32) {
return keccak256(abi.encode(dataId, sender, workflowOwner, workflowName));
}
// ================================================================
// │ Data Access Interface │
// ================================================================
/// Bundle Feed Interface
function latestBundle() external view returns (bytes memory bundle) {
bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);
return (s_latestBundleReports[dataId].bundle);
}
function bundleDecimals() external view returns (uint8[] memory bundleFeedDecimals) {
bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);
return s_feedConfigs[dataId].bundleDecimals;
}
function latestBundleTimestamp() external view returns (uint256 timestamp) {
bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);
return s_latestBundleReports[dataId].timestamp;
}
/// AggregatorInterface
function latestAnswer() external view returns (int256 answer) {
bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);
return int256(uint256(s_latestDecimalReports[dataId].answer));
}
function latestTimestamp() external view returns (uint256 timestamp) {
bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);
return s_latestDecimalReports[dataId].timestamp;
}
function latestRound() external view returns (uint256 round) {
bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);
return s_dataIdToRoundId[dataId];
}
function getAnswer(
uint256 roundId
) external view returns (int256 answer) {
bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);
return int256(uint256(s_decimalReports[roundId][dataId].answer));
}
function getTimestamp(
uint256 roundId
) external view returns (uint256 timestamp) {
bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);
return s_decimalReports[roundId][dataId].timestamp;
}
/// AggregatorV3Interface
function decimals() external view returns (uint8 feedDecimals) {
bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);
return _getDecimals(dataId);
}
function description() external view returns (string memory feedDescription) {
bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);
return s_feedConfigs[dataId].description;
}
function getRoundData(
uint80 roundId
) external view returns (uint80 id, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) {
bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);
uint256 timestamp = s_decimalReports[uint256(roundId)][dataId].timestamp;
return (roundId, int256(uint256(s_decimalReports[uint256(roundId)][dataId].answer)), timestamp, timestamp, roundId);
}
function latestRoundData()
external
view
returns (uint80 id, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)
{
bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);
uint80 roundId = uint80(s_dataIdToRoundId[dataId]);
uint256 timestamp = s_latestDecimalReports[dataId].timestamp;
return (roundId, int256(uint256(s_latestDecimalReports[dataId].answer)), timestamp, timestamp, roundId);
}
/// Direct access
function getLatestBundle(
bytes16 dataId
) external view returns (bytes memory bundle) {
if (dataId == bytes16(0)) revert InvalidDataId();
return (s_latestBundleReports[dataId].bundle);
}
function getBundleDecimals(
bytes16 dataId
) external view returns (uint8[] memory bundleFeedDecimals) {
if (dataId == bytes16(0)) revert InvalidDataId();
return s_feedConfigs[dataId].bundleDecimals;
}
function getLatestBundleTimestamp(
bytes16 dataId
) external view returns (uint256 timestamp) {
if (dataId == bytes16(0)) revert InvalidDataId();
return s_latestBundleReports[dataId].timestamp;
}
function getLatestAnswer(
bytes16 dataId
) external view returns (int256 answer) {
if (dataId == bytes16(0)) revert InvalidDataId();
return int256(uint256(s_latestDecimalReports[dataId].answer));
}
function getLatestTimestamp(
bytes16 dataId
) external view returns (uint256 timestamp) {
if (dataId == bytes16(0)) revert InvalidDataId();
return s_latestDecimalReports[dataId].timestamp;
}
function getLatestRoundData(
bytes16 dataId
) external view returns (uint80 id, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) {
if (dataId == bytes16(0)) revert InvalidDataId();
uint80 roundId = uint80(s_dataIdToRoundId[dataId]);
uint256 timestamp = s_latestDecimalReports[dataId].timestamp;
return (roundId, int256(uint256(s_latestDecimalReports[dataId].answer)), timestamp, timestamp, roundId);
}
function getDecimals(
bytes16 dataId
) external pure returns (uint8 feedDecimals) {
if (dataId == bytes16(0)) revert InvalidDataId();
return _getDecimals(dataId);
}
function getDescription(
bytes16 dataId
) external view returns (string memory feedDescription) {
if (dataId == bytes16(0)) revert InvalidDataId();
return s_feedConfigs[dataId].description;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC165} from "../../vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/IERC165.sol";
/// @title IReceiver - receives keystone reports
/// @notice Implementations must support the IReceiver interface through ERC165.
interface IReceiver is IERC165 {
/// @notice Handles incoming keystone reports.
/// @dev If this function call reverts, it can be retried with a higher gas
/// limit. The receiver is responsible for discarding stale reports.
/// @param metadata Report's metadata.
/// @param report Workflow report.
function onReport(bytes calldata metadata, bytes calldata report) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {ConfirmedOwner} from "./ConfirmedOwner.sol";
/// @title The OwnerIsCreator contract
/// @notice A contract with helpers for basic contract ownership.
contract OwnerIsCreator is ConfirmedOwner {
constructor() ConfirmedOwner(msg.sender) {}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ITypeAndVersion {
function typeAndVersion() external pure returns (string memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {IBundleBaseAggregator} from "./IBundleBaseAggregator.sol";
import {ICommonAggregator} from "./ICommonAggregator.sol";
import {IDecimalAggregator} from "./IDecimalAggregator.sol";
/// @notice IDataFeedsCache
/// Responsible for storing data associated with a given data ID and additional request data.
interface IDataFeedsCache is IDecimalAggregator, IBundleBaseAggregator, ICommonAggregator {
/// @notice Remove feed configs.
/// @param dataIds List of data IDs
function removeFeedConfigs(
bytes16[] calldata dataIds
) external;
/// @notice Update mappings for AggregatorProxy -> Data ID
/// @param proxies AggregatorProxy addresses
/// @param dataIds Data IDs
function updateDataIdMappingsForProxies(address[] calldata proxies, bytes16[] calldata dataIds) external;
/// @notice Remove mappings for AggregatorProxy -> Data IDs
/// @param proxies AggregatorProxy addresses to remove
function removeDataIdMappingsForProxies(
address[] calldata proxies
) external;
/// @notice Get the Data ID mapping for a AggregatorProxy
/// @param proxy AggregatorProxy addresses which will be reading feed data
function getDataIdForProxy(
address proxy
) external view returns (bytes16 dataId);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IERC20} from "./../../vendor/openzeppelin-solidity/v5.0.2/contracts/interfaces/IERC20.sol";
/// @notice ITokenRecover
/// Implements the recoverTokens method, enabling the recovery of ERC-20 or native tokens accidentally sent to a
/// contract outside of normal operations.
interface ITokenRecover {
/// @notice Transfer any ERC-20 or native tokens accidentally sent to this contract.
/// @param token Token to transfer
/// @param to Address to send payment to
/// @param amount Amount of token to transfer
function recoverTokens(IERC20 token, address to, uint256 amount) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {ConfirmedOwnerWithProposal} from "./ConfirmedOwnerWithProposal.sol";
/// @title The ConfirmedOwner contract
/// @notice A contract with helpers for basic contract ownership.
contract ConfirmedOwner is ConfirmedOwnerWithProposal {
constructor(address newOwner) ConfirmedOwnerWithProposal(newOwner, address(0)) {}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
interface IBundleBaseAggregator {
function latestBundle() external view returns (bytes memory bundle);
function bundleDecimals() external view returns (uint8[] memory);
function latestBundleTimestamp() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
interface ICommonAggregator {
function description() external view returns (string memory);
function version() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
interface IDecimalAggregator {
function latestAnswer() external view returns (int256);
function latestRound() external view returns (uint256);
function latestTimestamp() external view returns (uint256);
function getAnswer(
uint256 roundId
) external view returns (int256);
function getTimestamp(
uint256 roundId
) external view returns (uint256);
function decimals() external view returns (uint8);
function getRoundData(
uint80 _roundId
) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
function latestRoundData()
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt);
event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @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://consensys.net/diligence/blog/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.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @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 or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* 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.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @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`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IOwnable} from "../interfaces/IOwnable.sol";
/// @title The ConfirmedOwner contract
/// @notice A contract with helpers for basic contract ownership.
contract ConfirmedOwnerWithProposal is IOwnable {
address private s_owner;
address private s_pendingOwner;
event OwnershipTransferRequested(address indexed from, address indexed to);
event OwnershipTransferred(address indexed from, address indexed to);
constructor(address newOwner, address pendingOwner) {
// solhint-disable-next-line gas-custom-errors
require(newOwner != address(0), "Cannot set owner to zero");
s_owner = newOwner;
if (pendingOwner != address(0)) {
_transferOwnership(pendingOwner);
}
}
/// @notice Allows an owner to begin transferring ownership to a new address.
function transferOwnership(address to) public override onlyOwner {
_transferOwnership(to);
}
/// @notice Allows an ownership transfer to be completed by the recipient.
function acceptOwnership() external override {
// solhint-disable-next-line gas-custom-errors
require(msg.sender == s_pendingOwner, "Must be proposed owner");
address oldOwner = s_owner;
s_owner = msg.sender;
s_pendingOwner = address(0);
emit OwnershipTransferred(oldOwner, msg.sender);
}
/// @notice Get the current owner
function owner() public view override returns (address) {
return s_owner;
}
/// @notice validate, transfer ownership, and emit relevant events
function _transferOwnership(address to) private {
// solhint-disable-next-line gas-custom-errors
require(to != msg.sender, "Cannot transfer to self");
s_pendingOwner = to;
emit OwnershipTransferRequested(s_owner, to);
}
/// @notice validate access
function _validateOwnership() internal view {
// solhint-disable-next-line gas-custom-errors
require(msg.sender == s_owner, "Only callable by owner");
}
/// @notice Reverts if called by anyone other than the contract owner.
modifier onlyOwner() {
_validateOwnership();
_;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IOwnable {
function owner() external returns (address);
function transferOwnership(address recipient) external;
function acceptOwnership() external;
}{
"remappings": [
"forge-std/=src/v0.8/vendor/forge-std/src/",
"@openzeppelin/=node_modules/@openzeppelin/",
"@arbitrum/=node_modules/@arbitrum/",
"hardhat/=node_modules/hardhat/",
"@eth-optimism/=node_modules/@eth-optimism/",
"@scroll-tech/=node_modules/@scroll-tech/",
"@zksync/=node_modules/@zksync/",
"@offchainlabs/=node_modules/@offchainlabs/"
],
"optimizer": {
"enabled": true,
"runs": 1000000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"ArrayLengthMismatch","type":"error"},{"inputs":[],"name":"EmptyConfig","type":"error"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"ErrorSendingNative","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"FeedNotConfigured","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"requiredBalance","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidDataId","type":"error"},{"inputs":[{"internalType":"bytes10","name":"workflowName","type":"bytes10"}],"name":"InvalidWorkflowName","type":"error"},{"inputs":[{"internalType":"address","name":"proxy","type":"address"}],"name":"NoMappingForSender","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"UnauthorizedCaller","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"int256","name":"current","type":"int256"},{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"updatedAt","type":"uint256"}],"name":"AnswerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes16","name":"dataId","type":"bytes16"},{"indexed":false,"internalType":"uint8[]","name":"decimals","type":"uint8[]"},{"indexed":false,"internalType":"string","name":"description","type":"string"},{"components":[{"internalType":"address","name":"allowedSender","type":"address"},{"internalType":"address","name":"allowedWorkflowOwner","type":"address"},{"internalType":"bytes10","name":"allowedWorkflowName","type":"bytes10"}],"indexed":false,"internalType":"struct DataFeedsCache.WorkflowMetadata[]","name":"workflowMetadata","type":"tuple[]"}],"name":"BundleFeedConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes16","name":"dataId","type":"bytes16"},{"indexed":true,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"bundle","type":"bytes"}],"name":"BundleReportUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes16","name":"dataId","type":"bytes16"},{"indexed":false,"internalType":"uint8","name":"decimals","type":"uint8"},{"indexed":false,"internalType":"string","name":"description","type":"string"},{"components":[{"internalType":"address","name":"allowedSender","type":"address"},{"internalType":"address","name":"allowedWorkflowOwner","type":"address"},{"internalType":"bytes10","name":"allowedWorkflowName","type":"bytes10"}],"indexed":false,"internalType":"struct DataFeedsCache.WorkflowMetadata[]","name":"workflowMetadata","type":"tuple[]"}],"name":"DecimalFeedConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes16","name":"dataId","type":"bytes16"},{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"uint224","name":"answer","type":"uint224"}],"name":"DecimalReportUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"feedAdmin","type":"address"},{"indexed":true,"internalType":"bool","name":"isAdmin","type":"bool"}],"name":"FeedAdminSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"FeedConfigRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes16","name":"dataId","type":"bytes16"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"workflowOwner","type":"address"},{"indexed":false,"internalType":"bytes10","name":"workflowName","type":"bytes10"}],"name":"InvalidUpdatePermission","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":true,"internalType":"address","name":"startedBy","type":"address"},{"indexed":false,"internalType":"uint256","name":"startedAt","type":"uint256"}],"name":"NewRound","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"proxy","type":"address"},{"indexed":true,"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"ProxyDataIdRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"proxy","type":"address"},{"indexed":true,"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"ProxyDataIdUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes16","name":"dataId","type":"bytes16"},{"indexed":false,"internalType":"uint256","name":"reportTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"latestTimestamp","type":"uint256"}],"name":"StaleBundleReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes16","name":"dataId","type":"bytes16"},{"indexed":false,"internalType":"uint256","name":"reportTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"latestTimestamp","type":"uint256"}],"name":"StaleDecimalReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenRecovered","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bundleDecimals","outputs":[{"internalType":"uint8[]","name":"bundleFeedDecimals","type":"uint8[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"},{"components":[{"internalType":"address","name":"allowedSender","type":"address"},{"internalType":"address","name":"allowedWorkflowOwner","type":"address"},{"internalType":"bytes10","name":"allowedWorkflowName","type":"bytes10"}],"internalType":"struct DataFeedsCache.WorkflowMetadata","name":"workflowMetadata","type":"tuple"}],"name":"checkFeedPermission","outputs":[{"internalType":"bool","name":"hasPermission","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"feedDecimals","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"description","outputs":[{"internalType":"string","name":"feedDescription","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"getAnswer","outputs":[{"internalType":"int256","name":"answer","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"getBundleDecimals","outputs":[{"internalType":"uint8[]","name":"bundleFeedDecimals","type":"uint8[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"proxy","type":"address"}],"name":"getDataIdForProxy","outputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"getDecimals","outputs":[{"internalType":"uint8","name":"feedDecimals","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"getDescription","outputs":[{"internalType":"string","name":"feedDescription","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"},{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"maxCount","type":"uint256"}],"name":"getFeedMetadata","outputs":[{"components":[{"internalType":"address","name":"allowedSender","type":"address"},{"internalType":"address","name":"allowedWorkflowOwner","type":"address"},{"internalType":"bytes10","name":"allowedWorkflowName","type":"bytes10"}],"internalType":"struct DataFeedsCache.WorkflowMetadata[]","name":"workflowMetadata","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"getLatestAnswer","outputs":[{"internalType":"int256","name":"answer","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"getLatestBundle","outputs":[{"internalType":"bytes","name":"bundle","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"getLatestBundleTimestamp","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"getLatestRoundData","outputs":[{"internalType":"uint80","name":"id","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"getLatestTimestamp","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint80","name":"roundId","type":"uint80"}],"name":"getRoundData","outputs":[{"internalType":"uint80","name":"id","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"getTimestamp","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"feedAdmin","type":"address"}],"name":"isFeedAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestAnswer","outputs":[{"internalType":"int256","name":"answer","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestBundle","outputs":[{"internalType":"bytes","name":"bundle","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestBundleTimestamp","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestRound","outputs":[{"internalType":"uint256","name":"round","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestRoundData","outputs":[{"internalType":"uint80","name":"id","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestTimestamp","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"metadata","type":"bytes"},{"internalType":"bytes","name":"report","type":"bytes"}],"name":"onReport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recoverTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"proxies","type":"address[]"}],"name":"removeDataIdMappingsForProxies","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes16[]","name":"dataIds","type":"bytes16[]"}],"name":"removeFeedConfigs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes16[]","name":"dataIds","type":"bytes16[]"},{"internalType":"string[]","name":"descriptions","type":"string[]"},{"internalType":"uint8[][]","name":"decimalsMatrix","type":"uint8[][]"},{"components":[{"internalType":"address","name":"allowedSender","type":"address"},{"internalType":"address","name":"allowedWorkflowOwner","type":"address"},{"internalType":"bytes10","name":"allowedWorkflowName","type":"bytes10"}],"internalType":"struct DataFeedsCache.WorkflowMetadata[]","name":"workflowMetadata","type":"tuple[]"}],"name":"setBundleFeedConfigs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes16[]","name":"dataIds","type":"bytes16[]"},{"internalType":"string[]","name":"descriptions","type":"string[]"},{"components":[{"internalType":"address","name":"allowedSender","type":"address"},{"internalType":"address","name":"allowedWorkflowOwner","type":"address"},{"internalType":"bytes10","name":"allowedWorkflowName","type":"bytes10"}],"internalType":"struct DataFeedsCache.WorkflowMetadata[]","name":"workflowMetadata","type":"tuple[]"}],"name":"setDecimalFeedConfigs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"feedAdmin","type":"address"},{"internalType":"bool","name":"isAdmin","type":"bool"}],"name":"setFeedAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"proxies","type":"address[]"},{"internalType":"bytes16[]","name":"dataIds","type":"bytes16[]"}],"name":"updateDataIdMappingsForProxies","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
608060405234801561000f575f80fd5b5033805f816100655760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b5f80546001600160a01b0319166001600160a01b0384811691909117909155811615610094576100948161009c565b505050610144565b336001600160a01b038216036100f45760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161005c565b600180546001600160a01b0319166001600160a01b038381169182179092555f8054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b615632806101515f395ff3fe608060405234801561000f575f80fd5b5060043610610283575f3560e01c806379ba509711610157578063b5ab58dc116100d2578063ec52b1f511610088578063feaf968c1161006e578063feaf968c146105ff578063feb5d17214610607578063ff25dbc8146106ca575f80fd5b8063ec52b1f5146105d9578063f2fde38b146105ec575f80fd5b8063be4f0a9f116100b8578063be4f0a9f14610593578063cdd25100146105a6578063d143dcd9146105b9575f80fd5b8063b5ab58dc1461056d578063b633620c14610580575f80fd5b80639198274f116101275780639a6fc8f51161010d5780639a6fc8f51461054a5780639d91348d1461055d578063a3d610cc14610565575f80fd5b80639198274f146104d95780639608e18f146104e1575f80fd5b806379ba50971461048f578063805f2132146104975780638205bf6a146104aa5780638da5cb5b146104b2575f80fd5b80634533dc98116102015780635f25452b116101b7578063668a0f021161019d578063668a0f021461046c5780636a36e494146104745780637284e41614610487575f80fd5b80635f25452b1461040f5780635f3e849f14610459575f80fd5b806350d25bcd116101e757806350d25bcd146103ec57806354fd4d50146103f4578063557a33c2146103fc575f80fd5b80634533dc98146103b957806347381b08146103cc575f80fd5b8063297dbf561161025657806335f611221161023c57806335f611221461035b5780633a0449741461036e57806343d5ba50146103a6575f80fd5b8063297dbf561461032c578063313ce56714610341575f80fd5b806301ffc9a71461028757806302ccb3ae146102af578063181f5a77146102cf5780631bb1610c1461030b575b5f80fd5b61029a6102953660046144a9565b6106dd565b60405190151581526020015b60405180910390f35b6102c26102bd36600461451c565b610859565b6040516102a69190614581565b6102c26040518060400160405280601481526020017f446174614665656473436163686520312e302e3000000000000000000000000081525081565b61031e61031936600461451c565b610975565b6040519081526020016102a6565b61033f61033a3660046145db565b610a29565b005b610349610c24565b60405160ff90911681526020016102a6565b61033f610369366004614688565b610ca0565b61029a61037c366004614777565b73ffffffffffffffffffffffffffffffffffffffff165f9081526007602052604090205460ff1690565b6103496103b436600461451c565b61145f565b61033f6103c7366004614792565b6114c2565b6103df6103da36600461451c565b611c26565b6040516102a69190614831565b61031e611d1c565b61031e600781565b61031e61040a36600461451c565b611ddc565b61042261041d36600461451c565b611e88565b6040805169ffffffffffffffffffff968716815260208101959095528401929092526060830152909116608082015260a0016102a6565b61033f610467366004614876565b611f7a565b61031e61226e565b6102c261048236600461451c565b612310565b6102c26123a6565b61033f6124d6565b61033f6104a53660046148f2565b6125d2565b61031e612e45565b5f5460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102a6565b6102c2612f0d565b6105196104ef366004614777565b73ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205460801b90565b6040517fffffffffffffffffffffffffffffffff0000000000000000000000000000000090911681526020016102a6565b610422610558366004614952565b612fb8565b6103df6130cb565b61031e6131d6565b61031e61057b36600461497b565b613281565b61031e61058e36600461497b565b61334e565b61033f6105a1366004614992565b613424565b61033f6105b4366004614992565b613533565b6105cc6105c73660046149d1565b613898565b6040516102a69190614a01565b61033f6105e7366004614aaf565b613b3b565b61033f6105fa366004614777565b613c26565b610422613c3a565b61029a610615366004614c0b565b805160208083015160409384015184517fffffffffffffffffffffffffffffffff00000000000000000000000000000000969096168684015273ffffffffffffffffffffffffffffffffffffffff93841686860152921660608501527fffffffffffffffffffff000000000000000000000000000000000000000000009091166080808501919091528251808503909101815260a090930182528251928101929092205f908152600990925290205460ff1690565b61031e6106d836600461451c565b613d41565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167fcce8054600000000000000000000000000000000000000000000000000000000148061076f57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b806107bb57507fffffffff0000000000000000000000000000000000000000000000000000000082167f805f213200000000000000000000000000000000000000000000000000000000145b8061080757507fffffffff0000000000000000000000000000000000000000000000000000000082167f5f3e849f00000000000000000000000000000000000000000000000000000000145b8061085357507fffffffff0000000000000000000000000000000000000000000000000000000082167f181f5a7700000000000000000000000000000000000000000000000000000000145b92915050565b60607fffffffffffffffffffffffffffffffff0000000000000000000000000000000082166108b4576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f90815260086020526040902060010180546108f290614c3d565b80601f016020809104026020016040519081016040528092919081815260200182805461091e90614c3d565b80156109695780601f1061094057610100808354040283529160200191610969565b820191905f5260205f20905b81548152906001019060200180831161094c57829003601f168201915b50505050509050919050565b5f7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082166109cf576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f908152600360205260409020547c0100000000000000000000000000000000000000000000000000000000900463ffffffff1690565b335f9081526007602052604090205460ff16610a78576040517fd86ad9cf0000000000000000000000000000000000000000000000000000000081523360048201526024015b60405180910390fd5b82818114610ab2576040517fa24a13a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b81811015610c1c57838382818110610ace57610ace614c8e565b9050602002016020810190610ae3919061451c565b60025f888885818110610af857610af8614c8e565b9050602002016020810190610b0d9190614777565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f2080547fffffffffffffffffffffffffffffffff000000000000000000000000000000001660809290921c919091179055838382818110610b7457610b74614c8e565b9050602002016020810190610b89919061451c565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000016868683818110610bbd57610bbd614c8e565b9050602002016020810190610bd29190614777565b73ffffffffffffffffffffffffffffffffffffffff167ff31b9e58190970ef07c23d0ba78c358eb3b416e829ef484b29b9993a6b1b285a60405160405180910390a3600101610ab4565b505050505050565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116610c91576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b610c9a81613dd8565b91505090565b335f9081526007602052604090205460ff16610cea576040517fd86ad9cf000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b801580610cf5575086155b15610d2c576040517f60e8b63a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8685141580610d3b5750868314155b15610d72576040517fa24a13a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b87811015611454575f898983818110610d8f57610d8f614c8e565b9050602002016020810190610da4919061451c565b90507fffffffffffffffffffffffffffffffff000000000000000000000000000000008116610dff576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f908152600860205260409020600281015415611025575f5b6002820154811015610f80575f826002018281548110610e5d57610e5d614c8e565b5f91825260208083206040805160608082018352600295909502909201805473ffffffffffffffffffffffffffffffffffffffff9081168085526001909201549081168486018190527401000000000000000000000000000000000000000090910460b01b7fffffffffffffffffffff000000000000000000000000000000000000000000001684840181905283517fffffffffffffffffffffffffffffffff000000000000000000000000000000008d168188015280850193909352958201526080808201959095528151808203909501855260a0019052825192909101919091209092505f90815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555050600101610e3b565b507fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f90815260086020526040812090610fbc8282614319565b610fc9600183015f61433b565b610fd6600283015f614372565b50506040517fffffffffffffffffffffffffffffffff000000000000000000000000000000008316907f871bcdef10dee59b87f17bab788b72faa8dfe1a9cc5bdc45c3baf4c18fa33910905f90a25b5f5b8481101561133c575f86868381811061104257611042614c8e565b9050606002018036038101906110589190614cbb565b9050845f036111c057805173ffffffffffffffffffffffffffffffffffffffff166110ca5780516040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610a6f565b602081015173ffffffffffffffffffffffffffffffffffffffff166111395760208101516040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610a6f565b60408101517fffffffffffffffffffff00000000000000000000000000000000000000000000166111c05760408082015190517f114988d50000000000000000000000000000000000000000000000000000000081527fffffffffffffffffffff000000000000000000000000000000000000000000009091166004820152602401610a6f565b8051602080830180516040808601805182517fffffffffffffffffffffffffffffffff000000000000000000000000000000008c168188015273ffffffffffffffffffffffffffffffffffffffff9788168185015293871660608501527fffffffffffffffffffff00000000000000000000000000000000000000000000166080808501919091528251808503909101815260a090930182528251928501929092205f9081526009855290812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091556002898101805480840182559084529590922096519490910290950180549385167fffffffffffffffffffffffff000000000000000000000000000000000000000090941693909317835590519184018054915160b01c74010000000000000000000000000000000000000000027fffff000000000000000000000000000000000000000000000000000000000000909216929093169190911717905501611027565b5086868481811061134f5761134f614c8e565b90506020028101906113619190614cd5565b61136c918391614390565b5088888481811061137f5761137f614c8e565b90506020028101906113919190614d39565b60018301916113a1919083614de5565b507fffffffffffffffffffffffffffffffff0000000000000000000000000000000082167fdfebe0878c5611549f54908260ca12271c7ff3f0ebae0c1de47732612403869e8888868181106113f8576113f8614c8e565b905060200281019061140a9190614cd5565b8c8c8881811061141c5761141c614c8e565b905060200281019061142e9190614d39565b8a8a60405161144296959493929190614ff3565b60405180910390a25050600101610d74565b505050505050505050565b5f7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082166114b9576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61085382613dd8565b335f9081526007602052604090205460ff1661150c576040517fd86ad9cf000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b801580611517575084155b1561154e576040517f60e8b63a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b848314611587576040517fa24a13a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b85811015611c1d575f8787838181106115a4576115a4614c8e565b90506020020160208101906115b9919061451c565b90507fffffffffffffffffffffffffffffffff000000000000000000000000000000008116611614576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f90815260086020526040902060028101541561183a575f5b6002820154811015611795575f82600201828154811061167257611672614c8e565b5f91825260208083206040805160608082018352600295909502909201805473ffffffffffffffffffffffffffffffffffffffff9081168085526001909201549081168486018190527401000000000000000000000000000000000000000090910460b01b7fffffffffffffffffffff000000000000000000000000000000000000000000001684840181905283517fffffffffffffffffffffffffffffffff000000000000000000000000000000008d168188015280850193909352958201526080808201959095528151808203909501855260a0019052825192909101919091209092505f90815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555050600101611650565b507fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f908152600860205260408120906117d18282614319565b6117de600183015f61433b565b6117eb600283015f614372565b50506040517fffffffffffffffffffffffffffffffff000000000000000000000000000000008316907f871bcdef10dee59b87f17bab788b72faa8dfe1a9cc5bdc45c3baf4c18fa33910905f90a25b5f5b84811015611b51575f86868381811061185757611857614c8e565b90506060020180360381019061186d9190614cbb565b9050845f036119d557805173ffffffffffffffffffffffffffffffffffffffff166118df5780516040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610a6f565b602081015173ffffffffffffffffffffffffffffffffffffffff1661194e5760208101516040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610a6f565b60408101517fffffffffffffffffffff00000000000000000000000000000000000000000000166119d55760408082015190517f114988d50000000000000000000000000000000000000000000000000000000081527fffffffffffffffffffff000000000000000000000000000000000000000000009091166004820152602401610a6f565b8051602080830180516040808601805182517fffffffffffffffffffffffffffffffff000000000000000000000000000000008c168188015273ffffffffffffffffffffffffffffffffffffffff9788168185015293871660608501527fffffffffffffffffffff00000000000000000000000000000000000000000000166080808501919091528251808503909101815260a090930182528251928501929092205f9081526009855290812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091556002898101805480840182559084529590922096519490910290950180549385167fffffffffffffffffffffffff000000000000000000000000000000000000000090941693909317835590519184018054915160b01c74010000000000000000000000000000000000000000027fffff00000000000000000000000000000000000000000000000000000000000090921692909316919091171790550161183c565b50868684818110611b6457611b64614c8e565b9050602002810190611b769190614d39565b6001830191611b86919083614de5565b507fffffffffffffffffffffffffffffffff0000000000000000000000000000000082167f2dec0e9ffbb18c6499fc8bee8b9c35f765e76d9dbd436f25dd00a80de267ac0d611bd484613dd8565b898987818110611be657611be6614c8e565b9050602002810190611bf89190614d39565b8989604051611c0b95949392919061506a565b60405180910390a25050600101611589565b50505050505050565b60607fffffffffffffffffffffffffffffffff000000000000000000000000000000008216611c81576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f908152600860209081526040918290208054835181840281018401909452808452909183018282801561096957602002820191905f5260205f20905f905b825461010083900a900460ff16815260206001928301818104948501949093039092029101808411611ce3575094979650505050505050565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116611d89576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f908152600360205260409020547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b5f7fffffffffffffffffffffffffffffffff000000000000000000000000000000008216611e36576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f908152600360205260409020547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b5f808080807fffffffffffffffffffffffffffffffff000000000000000000000000000000008616611ee6576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050507fffffffffffffffffffffffffffffffff00000000000000000000000000000000919091165f9081526006602090815260408083205460039092529091205490927bffffffffffffffffffffffffffffffffffffffffffffffffffffffff821692507c010000000000000000000000000000000000000000000000000000000090910463ffffffff169081908490565b611f82613e97565b73ffffffffffffffffffffffffffffffffffffffff83166120855747811115611fe0576040517fcf47918100000000000000000000000000000000000000000000000000000000815247600482015260248101829052604401610a6f565b5f808373ffffffffffffffffffffffffffffffffffffffff16836040515f6040518083038185875af1925050503d805f8114612037576040519150601f19603f3d011682016040523d82523d5f602084013e61203c565b606091505b50915091508161207e578383826040517fc50febed000000000000000000000000000000000000000000000000000000008152600401610a6f939291906150a5565b5050612202565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa1580156120ed573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061211191906150e2565b8111156121e1576040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa158015612180573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121a491906150e2565b6040517fcf479181000000000000000000000000000000000000000000000000000000008152600481019190915260248101829052604401610a6f565b61220273ffffffffffffffffffffffffffffffffffffffff84168383613f19565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f879f92dded0f26b83c3e00b12e0395dc72cfc3077343d1854ed6988edd1f90968360405161226191815260200190565b60405180910390a3505050565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081166122db576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f90815260066020526040902054919050565b60607fffffffffffffffffffffffffffffffff00000000000000000000000000000000821661236b576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f90815260056020526040902080546108f290614c3d565b335f9081526002602052604090205460609060801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116612416576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f908152600860205260409020600101805461245490614c3d565b80601f016020809104026020016040519081016040528092919081815260200182805461248090614c3d565b80156124cb5780601f106124a2576101008083540402835291602001916124cb565b820191905f5260205f20905b8154815290600101906020018083116124ae57829003601f168201915b505050505091505090565b60015473ffffffffffffffffffffffffffffffffffffffff163314612557576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610a6f565b5f8054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b5f8061261286868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250613fa692505050565b90925090505f6126266040602086886150f9565b61262f91615120565b905061263c816060615189565b6126479060406151a0565b8403612aeb575f61265a858701876151e9565b90505f5b82811015612ae4575f82828151811061267957612679614c8e565b6020908102919091018101518051604080517fffffffffffffffffffffffffffffffff00000000000000000000000000000000831681860152338183015273ffffffffffffffffffffffffffffffffffffffff8b1660608201527fffffffffffffffffffff000000000000000000000000000000000000000000008a166080808301919091528251808303909101815260a090910182528051908501205f8181526009909552932054919350919060ff166127d5576040805133815273ffffffffffffffffffffffffffffffffffffffff8a1660208201527fffffffffffffffffffff000000000000000000000000000000000000000000008916918101919091527fffffffffffffffffffffffffffffffff000000000000000000000000000000008316907feeeaa8bf618ff6d960c6cf5935e68384f066abcc8b95d0de91bd773c16ae3ae3906060015b60405180910390a2505050612adc565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f908152600360209081526040909120549084015163ffffffff7c010000000000000000000000000000000000000000000000000000000090920482169116116128d4576020838101517fffffffffffffffffffffffffffffffff0000000000000000000000000000000084165f8181526003845260409081902054815163ffffffff94851681527c010000000000000000000000000000000000000000000000000000000090910490931693830193909352917fcf16f5f704f981fa2279afa1877dd1fdaa462a03a71ec51b9d3b2416a59a013e91016127c5565b604080518082018252848201517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16815260208086015163ffffffff16818301527fffffffffffffffffffffffffffffffff0000000000000000000000000000000085165f908152600690915291822080549192918290612950906152d5565b91829055507fffffffffffffffffffffffffffffffff0000000000000000000000000000000085165f8181526003602090815260408083208751888401805163ffffffff9081167c01000000000000000000000000000000000000000000000000000000009081027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff94851617909455888752600486528487208888528652958490208a519151909616928302911690811790945590519283529394508492917f82584589cd7284d4503ed582275e22b2e8f459f9cf4170a7235844e367f966d5910160405180910390a460208086015160405163ffffffff90911681525f9183917f0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271910160405180910390a38085604001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0559884fd3a460db3073b7fc896cc77986f16e378210ded43186175bf646fc5f42604051612ace91815260200190565b60405180910390a350505050505b60010161265e565b5050611c1d565b5f612af88587018761530c565b90505f5b8151811015611454575f828281518110612b1857612b18614c8e565b6020908102919091018101518051604080517fffffffffffffffffffffffffffffffff00000000000000000000000000000000831681860152338183015273ffffffffffffffffffffffffffffffffffffffff8b1660608201527fffffffffffffffffffff000000000000000000000000000000000000000000008a166080808301919091528251808303909101815260a090910182528051908501205f8181526009909552932054919350919060ff16612c74576040805133815273ffffffffffffffffffffffffffffffffffffffff8a1660208201527fffffffffffffffffffff000000000000000000000000000000000000000000008916918101919091527fffffffffffffffffffffffffffffffff000000000000000000000000000000008316907feeeaa8bf618ff6d960c6cf5935e68384f066abcc8b95d0de91bd773c16ae3ae3906060015b60405180910390a2505050612e3d565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f908152600560209081526040909120600101549084015163ffffffff918216911611612d37576020838101517fffffffffffffffffffffffffffffffff0000000000000000000000000000000084165f8181526005845260409081902060010154815163ffffffff9485168152931693830193909352917f51001b67094834cc084a0c1feb791cf84a481357aa66b924ba205d4cb56fd9819101612c64565b60408051808201825284820151815260208086015163ffffffff16818301527fffffffffffffffffffffffffffffffff0000000000000000000000000000000085165f90815260059091529190912081518291908190612d9790826154b1565b5060209182015160019190910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff92831617905590820151825160405191909216917fffffffffffffffffffffffffffffffff000000000000000000000000000000008616917f1dc1bef0b59d624eab3f0ec044781bb5b8594cd64f0ba09d789f5b51acab161491612e3091614581565b60405180910390a3505050505b600101612afc565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116612eb2576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f908152600360205260409020547c0100000000000000000000000000000000000000000000000000000000900463ffffffff16919050565b335f9081526002602052604090205460609060801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116612f7d576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f908152600560205260409020805461245490614c3d565b335f90815260026020526040812054819081908190819060801b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000811661302d576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b69ffffffffffffffffffff87165f9081526004602090815260408083207fffffffffffffffffffffffffffffffff00000000000000000000000000000000949094168352929052205495967bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8716967c0100000000000000000000000000000000000000000000000000000000900463ffffffff169550859450879350915050565b335f9081526002602052604090205460609060801b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000811661313b576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f90815260086020908152604091829020805483518184028101840190945280845290918301828280156124cb57602002820191905f5260205f20905f905b825461010083900a900460ff1681526020600192830181810494850194909303909202910180841161319d579050505050505091505090565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116613243576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f9081526005602052604090206001015463ffffffff16919050565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081166132ee576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b5f9283526004602090815260408085207fffffffffffffffffffffffffffffffff000000000000000000000000000000009093168552919052909120547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081166133bb576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b5f9283526004602090815260408085207fffffffffffffffffffffffffffffffff0000000000000000000000000000000090931685529190529091205463ffffffff7c010000000000000000000000000000000000000000000000000000000090910416919050565b335f9081526007602052604090205460ff1661346e576040517fd86ad9cf000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b805f5b8181101561352d575f84848381811061348c5761348c614c8e565b90506020020160208101906134a19190614777565b73ffffffffffffffffffffffffffffffffffffffff81165f8181526002602052604080822080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000808216909255915194955060809190911b9390841692917f4200186b7bc2d4f13f7888c5bbe9461d57da88705be86521f3d78be691ad1d2a91a35050600101613471565b50505050565b335f9081526007602052604090205460ff1661357d576040517fd86ad9cf000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b5f5b81811015613893575f83838381811061359a5761359a614c8e565b90506020020160208101906135af919061451c565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f9081526008602052604081206002015491925003613641576040517f8606a85b0000000000000000000000000000000000000000000000000000000081527fffffffffffffffffffffffffffffffff0000000000000000000000000000000082166004820152602401610a6f565b5f5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f908152600860205260409020600201548110156137e6577fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f9081526008602052604081206002018054839081106136c3576136c3614c8e565b5f91825260208083206040805160608082018352600295909502909201805473ffffffffffffffffffffffffffffffffffffffff9081168085526001909201549081168486018190527401000000000000000000000000000000000000000090910460b01b7fffffffffffffffffffff000000000000000000000000000000000000000000001684840181905283517fffffffffffffffffffffffffffffffff000000000000000000000000000000008c168188015280850193909352958201526080808201959095528151808203909501855260a0019052825192909101919091209092505f90815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555050600101613643565b507fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f908152600860205260408120906138228282614319565b61382f600183015f61433b565b61383c600283015f614372565b50506040517fffffffffffffffffffffffffffffffff000000000000000000000000000000008216907f871bcdef10dee59b87f17bab788b72faa8dfe1a9cc5bdc45c3baf4c18fa33910905f90a25060010161357f565b505050565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000083165f908152600860205260408120600281015460609281900361392d576040517f8606a85b0000000000000000000000000000000000000000000000000000000081527fffffffffffffffffffffffffffffffff0000000000000000000000000000000087166004820152602401610a6f565b80851061399d57604080515f8082526020820190925290613993565b604080516060810182525f80825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816139495790505b5092505050613b34565b5f6139a885876151a0565b9050818111806139b6575084155b6139c057806139c2565b815b90506139ce86826155c8565b67ffffffffffffffff8111156139e6576139e6614ae6565b604051908082528060200260200182016040528015613a4e57816020015b604080516060810182525f80825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181613a045790505b5093505f5b8451811015613b2f5760028401613a6a88836151a0565b81548110613a7a57613a7a614c8e565b5f91825260209182902060408051606081018252600293909302909101805473ffffffffffffffffffffffffffffffffffffffff9081168452600190910154908116938301939093527401000000000000000000000000000000000000000090920460b01b7fffffffffffffffffffff0000000000000000000000000000000000000000000016918101919091528551869083908110613b1c57613b1c614c8e565b6020908102919091010152600101613a53565b505050505b9392505050565b613b43613e97565b73ffffffffffffffffffffffffffffffffffffffff8216613ba8576040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401610a6f565b73ffffffffffffffffffffffffffffffffffffffff82165f8181526007602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915590519092917f93a3fa5993d2a54de369386625330cc6d73caee7fece4b3983cf299b264473fd91a35050565b613c2e613e97565b613c3781613fb7565b50565b335f90815260026020526040812054819081908190819060801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116613caf576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f9081526006602090815260408083205460039092529091205490967bffffffffffffffffffffffffffffffffffffffffffffffffffffffff821696507c010000000000000000000000000000000000000000000000000000000090910463ffffffff1694508493508692509050565b5f7fffffffffffffffffffffffffffffffff000000000000000000000000000000008216613d9b576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f9081526005602052604090206001015463ffffffff1690565b5f80613de58360076140ab565b90507f20000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000821610801590613e7b57507f60000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000821611155b15613e8f57613b34602060f883901c6155db565b505f92915050565b5f5473ffffffffffffffffffffffffffffffffffffffff163314613f17576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610a6f565b565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261389390849061412a565b6040810151604a9091015160601c91565b3373ffffffffffffffffffffffffffffffffffffffff821603614036576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610a6f565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182179092555f8054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6040517fffffffffffffffffffffffffffffffff00000000000000000000000000000000831660208201525f9060300160405160208183030381529060405282815181106140fb576140fb614c8e565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016905092915050565b5f61414b73ffffffffffffffffffffffffffffffffffffffff8416836141be565b905080515f1415801561416f57508080602001905181019061416d91906155f4565b155b15613893576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610a6f565b6060613b3483835f845f808573ffffffffffffffffffffffffffffffffffffffff1684866040516141ef919061560f565b5f6040518083038185875af1925050503d805f8114614229576040519150601f19603f3d011682016040523d82523d5f602084013e61422e565b606091505b509150915061423e868383614248565b9695505050505050565b60608261425d57614258826142d7565b613b34565b8151158015614281575073ffffffffffffffffffffffffffffffffffffffff84163b155b156142d0576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610a6f565b5080613b34565b8051156142e75780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5080545f8255601f0160209004905f5260205f2090810190613c379190614434565b50805461434790614c3d565b5f825580601f10614356575050565b601f0160209004905f5260205f2090810190613c379190614434565b5080545f8255600202905f5260205f2090810190613c379190614448565b828054828255905f5260205f2090601f01602090048101928215614424579160200282015f5b838211156143f657833560ff1683826101000a81548160ff021916908360ff16021790555092602001926001016020815f010492830192600103026143b6565b80156144225782816101000a81549060ff02191690556001016020815f010492830192600103026143f6565b505b50614430929150614434565b5090565b5b80821115614430575f8155600101614435565b5b808211156144305780547fffffffffffffffffffffffff00000000000000000000000000000000000000001681556001810180547fffff000000000000000000000000000000000000000000000000000000000000169055600201614449565b5f602082840312156144b9575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114613b34575f80fd5b80357fffffffffffffffffffffffffffffffff0000000000000000000000000000000081168114614517575f80fd5b919050565b5f6020828403121561452c575f80fd5b613b34826144e8565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081525f613b346020830184614535565b5f8083601f8401126145a3575f80fd5b50813567ffffffffffffffff8111156145ba575f80fd5b6020830191508360208260051b85010111156145d4575f80fd5b9250929050565b5f805f80604085870312156145ee575f80fd5b843567ffffffffffffffff811115614604575f80fd5b61461087828801614593565b909550935050602085013567ffffffffffffffff81111561462f575f80fd5b61463b87828801614593565b95989497509550505050565b5f8083601f840112614657575f80fd5b50813567ffffffffffffffff81111561466e575f80fd5b6020830191508360206060830285010111156145d4575f80fd5b5f805f805f805f806080898b03121561469f575f80fd5b883567ffffffffffffffff8111156146b5575f80fd5b6146c18b828c01614593565b909950975050602089013567ffffffffffffffff8111156146e0575f80fd5b6146ec8b828c01614593565b909750955050604089013567ffffffffffffffff81111561470b575f80fd5b6147178b828c01614593565b909550935050606089013567ffffffffffffffff811115614736575f80fd5b6147428b828c01614647565b999c989b5096995094979396929594505050565b73ffffffffffffffffffffffffffffffffffffffff81168114613c37575f80fd5b5f60208284031215614787575f80fd5b8135613b3481614756565b5f805f805f80606087890312156147a7575f80fd5b863567ffffffffffffffff8111156147bd575f80fd5b6147c989828a01614593565b909750955050602087013567ffffffffffffffff8111156147e8575f80fd5b6147f489828a01614593565b909550935050604087013567ffffffffffffffff811115614813575f80fd5b61481f89828a01614647565b979a9699509497509295939492505050565b602080825282518282018190525f918401906040840190835b8181101561486b57835160ff1683526020938401939092019160010161484a565b509095945050505050565b5f805f60608486031215614888575f80fd5b833561489381614756565b925060208401356148a381614756565b929592945050506040919091013590565b5f8083601f8401126148c4575f80fd5b50813567ffffffffffffffff8111156148db575f80fd5b6020830191508360208285010111156145d4575f80fd5b5f805f8060408587031215614905575f80fd5b843567ffffffffffffffff81111561491b575f80fd5b614927878288016148b4565b909550935050602085013567ffffffffffffffff811115614946575f80fd5b61463b878288016148b4565b5f60208284031215614962575f80fd5b813569ffffffffffffffffffff81168114613b34575f80fd5b5f6020828403121561498b575f80fd5b5035919050565b5f80602083850312156149a3575f80fd5b823567ffffffffffffffff8111156149b9575f80fd5b6149c585828601614593565b90969095509350505050565b5f805f606084860312156149e3575f80fd5b6149ec846144e8565b95602085013595506040909401359392505050565b602080825282518282018190525f918401906040840190835b8181101561486b57835173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff60208201511660208501527fffffffffffffffffffff00000000000000000000000000000000000000000000604082015116604085015250606083019250602084019350600181019050614a1a565b8015158114613c37575f80fd5b5f8060408385031215614ac0575f80fd5b8235614acb81614756565b91506020830135614adb81614aa2565b809150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040516060810167ffffffffffffffff81118282101715614b3657614b36614ae6565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614b8357614b83614ae6565b604052919050565b80357fffffffffffffffffffff0000000000000000000000000000000000000000000081168114614517575f80fd5b5f60608284031215614bca575f80fd5b614bd2614b13565b90508135614bdf81614756565b81526020820135614bef81614756565b6020820152614c0060408301614b8b565b604082015292915050565b5f8060808385031215614c1c575f80fd5b614c25836144e8565b9150614c348460208501614bba565b90509250929050565b600181811c90821680614c5157607f821691505b602082108103614c88577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60608284031215614ccb575f80fd5b613b348383614bba565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614d08575f80fd5b83018035915067ffffffffffffffff821115614d22575f80fd5b6020019150600581901b36038213156145d4575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614d6c575f80fd5b83018035915067ffffffffffffffff821115614d86575f80fd5b6020019150368190038213156145d4575f80fd5b601f82111561389357805f5260205f20601f840160051c81016020851015614dbf5750805b601f840160051c820191505b81811015614dde575f8155600101614dcb565b5050505050565b67ffffffffffffffff831115614dfd57614dfd614ae6565b614e1183614e0b8354614c3d565b83614d9a565b5f601f841160018114614e61575f8515614e2b5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614dde565b5f838152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08716915b82811015614eae5786850135825560209485019460019092019101614e8e565b5086821015614ee9577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b8183526020830192505f815f5b84811015614fe9578135614f6281614756565b73ffffffffffffffffffffffffffffffffffffffff1686526020820135614f8881614756565b73ffffffffffffffffffffffffffffffffffffffff1660208701527fffffffffffffffffffff00000000000000000000000000000000000000000000614fd060408401614b8b565b1660408701526060958601959190910190600101614f4f565b5093949350505050565b606080825281018690525f8760808301825b8981101561503357823560ff811680821461501e575f80fd5b83525060209283019290910190600101615005565b50838103602085015261504781888a614efb565b915050828103604084015261505d818587614f42565b9998505050505050505050565b60ff86168152606060208201525f615086606083018688614efb565b8281036040840152615099818587614f42565b98975050505050505050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201525f6150d96060830184614535565b95945050505050565b5f602082840312156150f2575f80fd5b5051919050565b5f8085851115615107575f80fd5b83861115615113575f80fd5b5050820193919092039150565b80356020831015610853577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820281158282048414176108535761085361515c565b808201808211156108535761085361515c565b5f67ffffffffffffffff8211156151cc576151cc614ae6565b5060051b60200190565b803563ffffffff81168114614517575f80fd5b5f602082840312156151f9575f80fd5b813567ffffffffffffffff81111561520f575f80fd5b8201601f8101841361521f575f80fd5b803561523261522d826151b3565b614b3c565b80828252602082019150602060608402850101925086831115615253575f80fd5b6020840193505b8284101561423e5760608488031215615271575f80fd5b615279614b13565b84358152615289602086016151d6565b602082015260408501357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681146152bc575f80fd5b604082015282526060939093019260209091019061525a565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036153055761530561515c565b5060010190565b5f6020828403121561531c575f80fd5b813567ffffffffffffffff811115615332575f80fd5b8201601f81018413615342575f80fd5b803561535061522d826151b3565b8082825260208201915060208360051b850101925086831115615371575f80fd5b602084015b838110156154a657803567ffffffffffffffff811115615394575f80fd5b85016060818a037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00112156153c7575f80fd5b6153cf614b13565b602082013581526153e2604083016151d6565b6020820152606082013567ffffffffffffffff811115615400575f80fd5b60208184010192505089601f830112615417575f80fd5b813567ffffffffffffffff81111561543157615431614ae6565b61546260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614b3c565b8181528b6020838601011115615476575f80fd5b816020850160208301375f6020838301015280604084015250508085525050602083019250602081019050615376565b509695505050505050565b815167ffffffffffffffff8111156154cb576154cb614ae6565b6154df816154d98454614c3d565b84614d9a565b6020601f821160018114615530575f83156154fa5750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b178455614dde565b5f848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b8281101561557d578785015182556020948501946001909201910161555d565b50848210156155b957868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b01905550565b818103818111156108535761085361515c565b60ff82811682821603908111156108535761085361515c565b5f60208284031215615604575f80fd5b8151613b3481614aa2565b5f82518060208501845e5f92019182525091905056fea164736f6c634300081a000a
Deployed Bytecode
0x608060405234801561000f575f80fd5b5060043610610283575f3560e01c806379ba509711610157578063b5ab58dc116100d2578063ec52b1f511610088578063feaf968c1161006e578063feaf968c146105ff578063feb5d17214610607578063ff25dbc8146106ca575f80fd5b8063ec52b1f5146105d9578063f2fde38b146105ec575f80fd5b8063be4f0a9f116100b8578063be4f0a9f14610593578063cdd25100146105a6578063d143dcd9146105b9575f80fd5b8063b5ab58dc1461056d578063b633620c14610580575f80fd5b80639198274f116101275780639a6fc8f51161010d5780639a6fc8f51461054a5780639d91348d1461055d578063a3d610cc14610565575f80fd5b80639198274f146104d95780639608e18f146104e1575f80fd5b806379ba50971461048f578063805f2132146104975780638205bf6a146104aa5780638da5cb5b146104b2575f80fd5b80634533dc98116102015780635f25452b116101b7578063668a0f021161019d578063668a0f021461046c5780636a36e494146104745780637284e41614610487575f80fd5b80635f25452b1461040f5780635f3e849f14610459575f80fd5b806350d25bcd116101e757806350d25bcd146103ec57806354fd4d50146103f4578063557a33c2146103fc575f80fd5b80634533dc98146103b957806347381b08146103cc575f80fd5b8063297dbf561161025657806335f611221161023c57806335f611221461035b5780633a0449741461036e57806343d5ba50146103a6575f80fd5b8063297dbf561461032c578063313ce56714610341575f80fd5b806301ffc9a71461028757806302ccb3ae146102af578063181f5a77146102cf5780631bb1610c1461030b575b5f80fd5b61029a6102953660046144a9565b6106dd565b60405190151581526020015b60405180910390f35b6102c26102bd36600461451c565b610859565b6040516102a69190614581565b6102c26040518060400160405280601481526020017f446174614665656473436163686520312e302e3000000000000000000000000081525081565b61031e61031936600461451c565b610975565b6040519081526020016102a6565b61033f61033a3660046145db565b610a29565b005b610349610c24565b60405160ff90911681526020016102a6565b61033f610369366004614688565b610ca0565b61029a61037c366004614777565b73ffffffffffffffffffffffffffffffffffffffff165f9081526007602052604090205460ff1690565b6103496103b436600461451c565b61145f565b61033f6103c7366004614792565b6114c2565b6103df6103da36600461451c565b611c26565b6040516102a69190614831565b61031e611d1c565b61031e600781565b61031e61040a36600461451c565b611ddc565b61042261041d36600461451c565b611e88565b6040805169ffffffffffffffffffff968716815260208101959095528401929092526060830152909116608082015260a0016102a6565b61033f610467366004614876565b611f7a565b61031e61226e565b6102c261048236600461451c565b612310565b6102c26123a6565b61033f6124d6565b61033f6104a53660046148f2565b6125d2565b61031e612e45565b5f5460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102a6565b6102c2612f0d565b6105196104ef366004614777565b73ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205460801b90565b6040517fffffffffffffffffffffffffffffffff0000000000000000000000000000000090911681526020016102a6565b610422610558366004614952565b612fb8565b6103df6130cb565b61031e6131d6565b61031e61057b36600461497b565b613281565b61031e61058e36600461497b565b61334e565b61033f6105a1366004614992565b613424565b61033f6105b4366004614992565b613533565b6105cc6105c73660046149d1565b613898565b6040516102a69190614a01565b61033f6105e7366004614aaf565b613b3b565b61033f6105fa366004614777565b613c26565b610422613c3a565b61029a610615366004614c0b565b805160208083015160409384015184517fffffffffffffffffffffffffffffffff00000000000000000000000000000000969096168684015273ffffffffffffffffffffffffffffffffffffffff93841686860152921660608501527fffffffffffffffffffff000000000000000000000000000000000000000000009091166080808501919091528251808503909101815260a090930182528251928101929092205f908152600990925290205460ff1690565b61031e6106d836600461451c565b613d41565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167fcce8054600000000000000000000000000000000000000000000000000000000148061076f57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b806107bb57507fffffffff0000000000000000000000000000000000000000000000000000000082167f805f213200000000000000000000000000000000000000000000000000000000145b8061080757507fffffffff0000000000000000000000000000000000000000000000000000000082167f5f3e849f00000000000000000000000000000000000000000000000000000000145b8061085357507fffffffff0000000000000000000000000000000000000000000000000000000082167f181f5a7700000000000000000000000000000000000000000000000000000000145b92915050565b60607fffffffffffffffffffffffffffffffff0000000000000000000000000000000082166108b4576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f90815260086020526040902060010180546108f290614c3d565b80601f016020809104026020016040519081016040528092919081815260200182805461091e90614c3d565b80156109695780601f1061094057610100808354040283529160200191610969565b820191905f5260205f20905b81548152906001019060200180831161094c57829003601f168201915b50505050509050919050565b5f7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082166109cf576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f908152600360205260409020547c0100000000000000000000000000000000000000000000000000000000900463ffffffff1690565b335f9081526007602052604090205460ff16610a78576040517fd86ad9cf0000000000000000000000000000000000000000000000000000000081523360048201526024015b60405180910390fd5b82818114610ab2576040517fa24a13a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b81811015610c1c57838382818110610ace57610ace614c8e565b9050602002016020810190610ae3919061451c565b60025f888885818110610af857610af8614c8e565b9050602002016020810190610b0d9190614777565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f2080547fffffffffffffffffffffffffffffffff000000000000000000000000000000001660809290921c919091179055838382818110610b7457610b74614c8e565b9050602002016020810190610b89919061451c565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000016868683818110610bbd57610bbd614c8e565b9050602002016020810190610bd29190614777565b73ffffffffffffffffffffffffffffffffffffffff167ff31b9e58190970ef07c23d0ba78c358eb3b416e829ef484b29b9993a6b1b285a60405160405180910390a3600101610ab4565b505050505050565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116610c91576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b610c9a81613dd8565b91505090565b335f9081526007602052604090205460ff16610cea576040517fd86ad9cf000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b801580610cf5575086155b15610d2c576040517f60e8b63a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8685141580610d3b5750868314155b15610d72576040517fa24a13a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b87811015611454575f898983818110610d8f57610d8f614c8e565b9050602002016020810190610da4919061451c565b90507fffffffffffffffffffffffffffffffff000000000000000000000000000000008116610dff576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f908152600860205260409020600281015415611025575f5b6002820154811015610f80575f826002018281548110610e5d57610e5d614c8e565b5f91825260208083206040805160608082018352600295909502909201805473ffffffffffffffffffffffffffffffffffffffff9081168085526001909201549081168486018190527401000000000000000000000000000000000000000090910460b01b7fffffffffffffffffffff000000000000000000000000000000000000000000001684840181905283517fffffffffffffffffffffffffffffffff000000000000000000000000000000008d168188015280850193909352958201526080808201959095528151808203909501855260a0019052825192909101919091209092505f90815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555050600101610e3b565b507fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f90815260086020526040812090610fbc8282614319565b610fc9600183015f61433b565b610fd6600283015f614372565b50506040517fffffffffffffffffffffffffffffffff000000000000000000000000000000008316907f871bcdef10dee59b87f17bab788b72faa8dfe1a9cc5bdc45c3baf4c18fa33910905f90a25b5f5b8481101561133c575f86868381811061104257611042614c8e565b9050606002018036038101906110589190614cbb565b9050845f036111c057805173ffffffffffffffffffffffffffffffffffffffff166110ca5780516040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610a6f565b602081015173ffffffffffffffffffffffffffffffffffffffff166111395760208101516040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610a6f565b60408101517fffffffffffffffffffff00000000000000000000000000000000000000000000166111c05760408082015190517f114988d50000000000000000000000000000000000000000000000000000000081527fffffffffffffffffffff000000000000000000000000000000000000000000009091166004820152602401610a6f565b8051602080830180516040808601805182517fffffffffffffffffffffffffffffffff000000000000000000000000000000008c168188015273ffffffffffffffffffffffffffffffffffffffff9788168185015293871660608501527fffffffffffffffffffff00000000000000000000000000000000000000000000166080808501919091528251808503909101815260a090930182528251928501929092205f9081526009855290812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091556002898101805480840182559084529590922096519490910290950180549385167fffffffffffffffffffffffff000000000000000000000000000000000000000090941693909317835590519184018054915160b01c74010000000000000000000000000000000000000000027fffff000000000000000000000000000000000000000000000000000000000000909216929093169190911717905501611027565b5086868481811061134f5761134f614c8e565b90506020028101906113619190614cd5565b61136c918391614390565b5088888481811061137f5761137f614c8e565b90506020028101906113919190614d39565b60018301916113a1919083614de5565b507fffffffffffffffffffffffffffffffff0000000000000000000000000000000082167fdfebe0878c5611549f54908260ca12271c7ff3f0ebae0c1de47732612403869e8888868181106113f8576113f8614c8e565b905060200281019061140a9190614cd5565b8c8c8881811061141c5761141c614c8e565b905060200281019061142e9190614d39565b8a8a60405161144296959493929190614ff3565b60405180910390a25050600101610d74565b505050505050505050565b5f7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082166114b9576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61085382613dd8565b335f9081526007602052604090205460ff1661150c576040517fd86ad9cf000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b801580611517575084155b1561154e576040517f60e8b63a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b848314611587576040517fa24a13a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b85811015611c1d575f8787838181106115a4576115a4614c8e565b90506020020160208101906115b9919061451c565b90507fffffffffffffffffffffffffffffffff000000000000000000000000000000008116611614576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f90815260086020526040902060028101541561183a575f5b6002820154811015611795575f82600201828154811061167257611672614c8e565b5f91825260208083206040805160608082018352600295909502909201805473ffffffffffffffffffffffffffffffffffffffff9081168085526001909201549081168486018190527401000000000000000000000000000000000000000090910460b01b7fffffffffffffffffffff000000000000000000000000000000000000000000001684840181905283517fffffffffffffffffffffffffffffffff000000000000000000000000000000008d168188015280850193909352958201526080808201959095528151808203909501855260a0019052825192909101919091209092505f90815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555050600101611650565b507fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f908152600860205260408120906117d18282614319565b6117de600183015f61433b565b6117eb600283015f614372565b50506040517fffffffffffffffffffffffffffffffff000000000000000000000000000000008316907f871bcdef10dee59b87f17bab788b72faa8dfe1a9cc5bdc45c3baf4c18fa33910905f90a25b5f5b84811015611b51575f86868381811061185757611857614c8e565b90506060020180360381019061186d9190614cbb565b9050845f036119d557805173ffffffffffffffffffffffffffffffffffffffff166118df5780516040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610a6f565b602081015173ffffffffffffffffffffffffffffffffffffffff1661194e5760208101516040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610a6f565b60408101517fffffffffffffffffffff00000000000000000000000000000000000000000000166119d55760408082015190517f114988d50000000000000000000000000000000000000000000000000000000081527fffffffffffffffffffff000000000000000000000000000000000000000000009091166004820152602401610a6f565b8051602080830180516040808601805182517fffffffffffffffffffffffffffffffff000000000000000000000000000000008c168188015273ffffffffffffffffffffffffffffffffffffffff9788168185015293871660608501527fffffffffffffffffffff00000000000000000000000000000000000000000000166080808501919091528251808503909101815260a090930182528251928501929092205f9081526009855290812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091556002898101805480840182559084529590922096519490910290950180549385167fffffffffffffffffffffffff000000000000000000000000000000000000000090941693909317835590519184018054915160b01c74010000000000000000000000000000000000000000027fffff00000000000000000000000000000000000000000000000000000000000090921692909316919091171790550161183c565b50868684818110611b6457611b64614c8e565b9050602002810190611b769190614d39565b6001830191611b86919083614de5565b507fffffffffffffffffffffffffffffffff0000000000000000000000000000000082167f2dec0e9ffbb18c6499fc8bee8b9c35f765e76d9dbd436f25dd00a80de267ac0d611bd484613dd8565b898987818110611be657611be6614c8e565b9050602002810190611bf89190614d39565b8989604051611c0b95949392919061506a565b60405180910390a25050600101611589565b50505050505050565b60607fffffffffffffffffffffffffffffffff000000000000000000000000000000008216611c81576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f908152600860209081526040918290208054835181840281018401909452808452909183018282801561096957602002820191905f5260205f20905f905b825461010083900a900460ff16815260206001928301818104948501949093039092029101808411611ce3575094979650505050505050565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116611d89576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f908152600360205260409020547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b5f7fffffffffffffffffffffffffffffffff000000000000000000000000000000008216611e36576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f908152600360205260409020547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b5f808080807fffffffffffffffffffffffffffffffff000000000000000000000000000000008616611ee6576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050507fffffffffffffffffffffffffffffffff00000000000000000000000000000000919091165f9081526006602090815260408083205460039092529091205490927bffffffffffffffffffffffffffffffffffffffffffffffffffffffff821692507c010000000000000000000000000000000000000000000000000000000090910463ffffffff169081908490565b611f82613e97565b73ffffffffffffffffffffffffffffffffffffffff83166120855747811115611fe0576040517fcf47918100000000000000000000000000000000000000000000000000000000815247600482015260248101829052604401610a6f565b5f808373ffffffffffffffffffffffffffffffffffffffff16836040515f6040518083038185875af1925050503d805f8114612037576040519150601f19603f3d011682016040523d82523d5f602084013e61203c565b606091505b50915091508161207e578383826040517fc50febed000000000000000000000000000000000000000000000000000000008152600401610a6f939291906150a5565b5050612202565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa1580156120ed573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061211191906150e2565b8111156121e1576040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa158015612180573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121a491906150e2565b6040517fcf479181000000000000000000000000000000000000000000000000000000008152600481019190915260248101829052604401610a6f565b61220273ffffffffffffffffffffffffffffffffffffffff84168383613f19565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f879f92dded0f26b83c3e00b12e0395dc72cfc3077343d1854ed6988edd1f90968360405161226191815260200190565b60405180910390a3505050565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081166122db576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f90815260066020526040902054919050565b60607fffffffffffffffffffffffffffffffff00000000000000000000000000000000821661236b576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f90815260056020526040902080546108f290614c3d565b335f9081526002602052604090205460609060801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116612416576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f908152600860205260409020600101805461245490614c3d565b80601f016020809104026020016040519081016040528092919081815260200182805461248090614c3d565b80156124cb5780601f106124a2576101008083540402835291602001916124cb565b820191905f5260205f20905b8154815290600101906020018083116124ae57829003601f168201915b505050505091505090565b60015473ffffffffffffffffffffffffffffffffffffffff163314612557576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610a6f565b5f8054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b5f8061261286868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250613fa692505050565b90925090505f6126266040602086886150f9565b61262f91615120565b905061263c816060615189565b6126479060406151a0565b8403612aeb575f61265a858701876151e9565b90505f5b82811015612ae4575f82828151811061267957612679614c8e565b6020908102919091018101518051604080517fffffffffffffffffffffffffffffffff00000000000000000000000000000000831681860152338183015273ffffffffffffffffffffffffffffffffffffffff8b1660608201527fffffffffffffffffffff000000000000000000000000000000000000000000008a166080808301919091528251808303909101815260a090910182528051908501205f8181526009909552932054919350919060ff166127d5576040805133815273ffffffffffffffffffffffffffffffffffffffff8a1660208201527fffffffffffffffffffff000000000000000000000000000000000000000000008916918101919091527fffffffffffffffffffffffffffffffff000000000000000000000000000000008316907feeeaa8bf618ff6d960c6cf5935e68384f066abcc8b95d0de91bd773c16ae3ae3906060015b60405180910390a2505050612adc565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f908152600360209081526040909120549084015163ffffffff7c010000000000000000000000000000000000000000000000000000000090920482169116116128d4576020838101517fffffffffffffffffffffffffffffffff0000000000000000000000000000000084165f8181526003845260409081902054815163ffffffff94851681527c010000000000000000000000000000000000000000000000000000000090910490931693830193909352917fcf16f5f704f981fa2279afa1877dd1fdaa462a03a71ec51b9d3b2416a59a013e91016127c5565b604080518082018252848201517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16815260208086015163ffffffff16818301527fffffffffffffffffffffffffffffffff0000000000000000000000000000000085165f908152600690915291822080549192918290612950906152d5565b91829055507fffffffffffffffffffffffffffffffff0000000000000000000000000000000085165f8181526003602090815260408083208751888401805163ffffffff9081167c01000000000000000000000000000000000000000000000000000000009081027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff94851617909455888752600486528487208888528652958490208a519151909616928302911690811790945590519283529394508492917f82584589cd7284d4503ed582275e22b2e8f459f9cf4170a7235844e367f966d5910160405180910390a460208086015160405163ffffffff90911681525f9183917f0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271910160405180910390a38085604001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0559884fd3a460db3073b7fc896cc77986f16e378210ded43186175bf646fc5f42604051612ace91815260200190565b60405180910390a350505050505b60010161265e565b5050611c1d565b5f612af88587018761530c565b90505f5b8151811015611454575f828281518110612b1857612b18614c8e565b6020908102919091018101518051604080517fffffffffffffffffffffffffffffffff00000000000000000000000000000000831681860152338183015273ffffffffffffffffffffffffffffffffffffffff8b1660608201527fffffffffffffffffffff000000000000000000000000000000000000000000008a166080808301919091528251808303909101815260a090910182528051908501205f8181526009909552932054919350919060ff16612c74576040805133815273ffffffffffffffffffffffffffffffffffffffff8a1660208201527fffffffffffffffffffff000000000000000000000000000000000000000000008916918101919091527fffffffffffffffffffffffffffffffff000000000000000000000000000000008316907feeeaa8bf618ff6d960c6cf5935e68384f066abcc8b95d0de91bd773c16ae3ae3906060015b60405180910390a2505050612e3d565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f908152600560209081526040909120600101549084015163ffffffff918216911611612d37576020838101517fffffffffffffffffffffffffffffffff0000000000000000000000000000000084165f8181526005845260409081902060010154815163ffffffff9485168152931693830193909352917f51001b67094834cc084a0c1feb791cf84a481357aa66b924ba205d4cb56fd9819101612c64565b60408051808201825284820151815260208086015163ffffffff16818301527fffffffffffffffffffffffffffffffff0000000000000000000000000000000085165f90815260059091529190912081518291908190612d9790826154b1565b5060209182015160019190910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff92831617905590820151825160405191909216917fffffffffffffffffffffffffffffffff000000000000000000000000000000008616917f1dc1bef0b59d624eab3f0ec044781bb5b8594cd64f0ba09d789f5b51acab161491612e3091614581565b60405180910390a3505050505b600101612afc565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116612eb2576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f908152600360205260409020547c0100000000000000000000000000000000000000000000000000000000900463ffffffff16919050565b335f9081526002602052604090205460609060801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116612f7d576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f908152600560205260409020805461245490614c3d565b335f90815260026020526040812054819081908190819060801b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000811661302d576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b69ffffffffffffffffffff87165f9081526004602090815260408083207fffffffffffffffffffffffffffffffff00000000000000000000000000000000949094168352929052205495967bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8716967c0100000000000000000000000000000000000000000000000000000000900463ffffffff169550859450879350915050565b335f9081526002602052604090205460609060801b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000811661313b576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f90815260086020908152604091829020805483518184028101840190945280845290918301828280156124cb57602002820191905f5260205f20905f905b825461010083900a900460ff1681526020600192830181810494850194909303909202910180841161319d579050505050505091505090565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116613243576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f9081526005602052604090206001015463ffffffff16919050565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081166132ee576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b5f9283526004602090815260408085207fffffffffffffffffffffffffffffffff000000000000000000000000000000009093168552919052909120547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081166133bb576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b5f9283526004602090815260408085207fffffffffffffffffffffffffffffffff0000000000000000000000000000000090931685529190529091205463ffffffff7c010000000000000000000000000000000000000000000000000000000090910416919050565b335f9081526007602052604090205460ff1661346e576040517fd86ad9cf000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b805f5b8181101561352d575f84848381811061348c5761348c614c8e565b90506020020160208101906134a19190614777565b73ffffffffffffffffffffffffffffffffffffffff81165f8181526002602052604080822080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000808216909255915194955060809190911b9390841692917f4200186b7bc2d4f13f7888c5bbe9461d57da88705be86521f3d78be691ad1d2a91a35050600101613471565b50505050565b335f9081526007602052604090205460ff1661357d576040517fd86ad9cf000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b5f5b81811015613893575f83838381811061359a5761359a614c8e565b90506020020160208101906135af919061451c565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f9081526008602052604081206002015491925003613641576040517f8606a85b0000000000000000000000000000000000000000000000000000000081527fffffffffffffffffffffffffffffffff0000000000000000000000000000000082166004820152602401610a6f565b5f5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f908152600860205260409020600201548110156137e6577fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f9081526008602052604081206002018054839081106136c3576136c3614c8e565b5f91825260208083206040805160608082018352600295909502909201805473ffffffffffffffffffffffffffffffffffffffff9081168085526001909201549081168486018190527401000000000000000000000000000000000000000090910460b01b7fffffffffffffffffffff000000000000000000000000000000000000000000001684840181905283517fffffffffffffffffffffffffffffffff000000000000000000000000000000008c168188015280850193909352958201526080808201959095528151808203909501855260a0019052825192909101919091209092505f90815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555050600101613643565b507fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f908152600860205260408120906138228282614319565b61382f600183015f61433b565b61383c600283015f614372565b50506040517fffffffffffffffffffffffffffffffff000000000000000000000000000000008216907f871bcdef10dee59b87f17bab788b72faa8dfe1a9cc5bdc45c3baf4c18fa33910905f90a25060010161357f565b505050565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000083165f908152600860205260408120600281015460609281900361392d576040517f8606a85b0000000000000000000000000000000000000000000000000000000081527fffffffffffffffffffffffffffffffff0000000000000000000000000000000087166004820152602401610a6f565b80851061399d57604080515f8082526020820190925290613993565b604080516060810182525f80825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816139495790505b5092505050613b34565b5f6139a885876151a0565b9050818111806139b6575084155b6139c057806139c2565b815b90506139ce86826155c8565b67ffffffffffffffff8111156139e6576139e6614ae6565b604051908082528060200260200182016040528015613a4e57816020015b604080516060810182525f80825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181613a045790505b5093505f5b8451811015613b2f5760028401613a6a88836151a0565b81548110613a7a57613a7a614c8e565b5f91825260209182902060408051606081018252600293909302909101805473ffffffffffffffffffffffffffffffffffffffff9081168452600190910154908116938301939093527401000000000000000000000000000000000000000090920460b01b7fffffffffffffffffffff0000000000000000000000000000000000000000000016918101919091528551869083908110613b1c57613b1c614c8e565b6020908102919091010152600101613a53565b505050505b9392505050565b613b43613e97565b73ffffffffffffffffffffffffffffffffffffffff8216613ba8576040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401610a6f565b73ffffffffffffffffffffffffffffffffffffffff82165f8181526007602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915590519092917f93a3fa5993d2a54de369386625330cc6d73caee7fece4b3983cf299b264473fd91a35050565b613c2e613e97565b613c3781613fb7565b50565b335f90815260026020526040812054819081908190819060801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116613caf576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f9081526006602090815260408083205460039092529091205490967bffffffffffffffffffffffffffffffffffffffffffffffffffffffff821696507c010000000000000000000000000000000000000000000000000000000090910463ffffffff1694508493508692509050565b5f7fffffffffffffffffffffffffffffffff000000000000000000000000000000008216613d9b576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f9081526005602052604090206001015463ffffffff1690565b5f80613de58360076140ab565b90507f20000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000821610801590613e7b57507f60000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000821611155b15613e8f57613b34602060f883901c6155db565b505f92915050565b5f5473ffffffffffffffffffffffffffffffffffffffff163314613f17576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610a6f565b565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261389390849061412a565b6040810151604a9091015160601c91565b3373ffffffffffffffffffffffffffffffffffffffff821603614036576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610a6f565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182179092555f8054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6040517fffffffffffffffffffffffffffffffff00000000000000000000000000000000831660208201525f9060300160405160208183030381529060405282815181106140fb576140fb614c8e565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016905092915050565b5f61414b73ffffffffffffffffffffffffffffffffffffffff8416836141be565b905080515f1415801561416f57508080602001905181019061416d91906155f4565b155b15613893576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610a6f565b6060613b3483835f845f808573ffffffffffffffffffffffffffffffffffffffff1684866040516141ef919061560f565b5f6040518083038185875af1925050503d805f8114614229576040519150601f19603f3d011682016040523d82523d5f602084013e61422e565b606091505b509150915061423e868383614248565b9695505050505050565b60608261425d57614258826142d7565b613b34565b8151158015614281575073ffffffffffffffffffffffffffffffffffffffff84163b155b156142d0576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610a6f565b5080613b34565b8051156142e75780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5080545f8255601f0160209004905f5260205f2090810190613c379190614434565b50805461434790614c3d565b5f825580601f10614356575050565b601f0160209004905f5260205f2090810190613c379190614434565b5080545f8255600202905f5260205f2090810190613c379190614448565b828054828255905f5260205f2090601f01602090048101928215614424579160200282015f5b838211156143f657833560ff1683826101000a81548160ff021916908360ff16021790555092602001926001016020815f010492830192600103026143b6565b80156144225782816101000a81549060ff02191690556001016020815f010492830192600103026143f6565b505b50614430929150614434565b5090565b5b80821115614430575f8155600101614435565b5b808211156144305780547fffffffffffffffffffffffff00000000000000000000000000000000000000001681556001810180547fffff000000000000000000000000000000000000000000000000000000000000169055600201614449565b5f602082840312156144b9575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114613b34575f80fd5b80357fffffffffffffffffffffffffffffffff0000000000000000000000000000000081168114614517575f80fd5b919050565b5f6020828403121561452c575f80fd5b613b34826144e8565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081525f613b346020830184614535565b5f8083601f8401126145a3575f80fd5b50813567ffffffffffffffff8111156145ba575f80fd5b6020830191508360208260051b85010111156145d4575f80fd5b9250929050565b5f805f80604085870312156145ee575f80fd5b843567ffffffffffffffff811115614604575f80fd5b61461087828801614593565b909550935050602085013567ffffffffffffffff81111561462f575f80fd5b61463b87828801614593565b95989497509550505050565b5f8083601f840112614657575f80fd5b50813567ffffffffffffffff81111561466e575f80fd5b6020830191508360206060830285010111156145d4575f80fd5b5f805f805f805f806080898b03121561469f575f80fd5b883567ffffffffffffffff8111156146b5575f80fd5b6146c18b828c01614593565b909950975050602089013567ffffffffffffffff8111156146e0575f80fd5b6146ec8b828c01614593565b909750955050604089013567ffffffffffffffff81111561470b575f80fd5b6147178b828c01614593565b909550935050606089013567ffffffffffffffff811115614736575f80fd5b6147428b828c01614647565b999c989b5096995094979396929594505050565b73ffffffffffffffffffffffffffffffffffffffff81168114613c37575f80fd5b5f60208284031215614787575f80fd5b8135613b3481614756565b5f805f805f80606087890312156147a7575f80fd5b863567ffffffffffffffff8111156147bd575f80fd5b6147c989828a01614593565b909750955050602087013567ffffffffffffffff8111156147e8575f80fd5b6147f489828a01614593565b909550935050604087013567ffffffffffffffff811115614813575f80fd5b61481f89828a01614647565b979a9699509497509295939492505050565b602080825282518282018190525f918401906040840190835b8181101561486b57835160ff1683526020938401939092019160010161484a565b509095945050505050565b5f805f60608486031215614888575f80fd5b833561489381614756565b925060208401356148a381614756565b929592945050506040919091013590565b5f8083601f8401126148c4575f80fd5b50813567ffffffffffffffff8111156148db575f80fd5b6020830191508360208285010111156145d4575f80fd5b5f805f8060408587031215614905575f80fd5b843567ffffffffffffffff81111561491b575f80fd5b614927878288016148b4565b909550935050602085013567ffffffffffffffff811115614946575f80fd5b61463b878288016148b4565b5f60208284031215614962575f80fd5b813569ffffffffffffffffffff81168114613b34575f80fd5b5f6020828403121561498b575f80fd5b5035919050565b5f80602083850312156149a3575f80fd5b823567ffffffffffffffff8111156149b9575f80fd5b6149c585828601614593565b90969095509350505050565b5f805f606084860312156149e3575f80fd5b6149ec846144e8565b95602085013595506040909401359392505050565b602080825282518282018190525f918401906040840190835b8181101561486b57835173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff60208201511660208501527fffffffffffffffffffff00000000000000000000000000000000000000000000604082015116604085015250606083019250602084019350600181019050614a1a565b8015158114613c37575f80fd5b5f8060408385031215614ac0575f80fd5b8235614acb81614756565b91506020830135614adb81614aa2565b809150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040516060810167ffffffffffffffff81118282101715614b3657614b36614ae6565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614b8357614b83614ae6565b604052919050565b80357fffffffffffffffffffff0000000000000000000000000000000000000000000081168114614517575f80fd5b5f60608284031215614bca575f80fd5b614bd2614b13565b90508135614bdf81614756565b81526020820135614bef81614756565b6020820152614c0060408301614b8b565b604082015292915050565b5f8060808385031215614c1c575f80fd5b614c25836144e8565b9150614c348460208501614bba565b90509250929050565b600181811c90821680614c5157607f821691505b602082108103614c88577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60608284031215614ccb575f80fd5b613b348383614bba565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614d08575f80fd5b83018035915067ffffffffffffffff821115614d22575f80fd5b6020019150600581901b36038213156145d4575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614d6c575f80fd5b83018035915067ffffffffffffffff821115614d86575f80fd5b6020019150368190038213156145d4575f80fd5b601f82111561389357805f5260205f20601f840160051c81016020851015614dbf5750805b601f840160051c820191505b81811015614dde575f8155600101614dcb565b5050505050565b67ffffffffffffffff831115614dfd57614dfd614ae6565b614e1183614e0b8354614c3d565b83614d9a565b5f601f841160018114614e61575f8515614e2b5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614dde565b5f838152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08716915b82811015614eae5786850135825560209485019460019092019101614e8e565b5086821015614ee9577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b8183526020830192505f815f5b84811015614fe9578135614f6281614756565b73ffffffffffffffffffffffffffffffffffffffff1686526020820135614f8881614756565b73ffffffffffffffffffffffffffffffffffffffff1660208701527fffffffffffffffffffff00000000000000000000000000000000000000000000614fd060408401614b8b565b1660408701526060958601959190910190600101614f4f565b5093949350505050565b606080825281018690525f8760808301825b8981101561503357823560ff811680821461501e575f80fd5b83525060209283019290910190600101615005565b50838103602085015261504781888a614efb565b915050828103604084015261505d818587614f42565b9998505050505050505050565b60ff86168152606060208201525f615086606083018688614efb565b8281036040840152615099818587614f42565b98975050505050505050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201525f6150d96060830184614535565b95945050505050565b5f602082840312156150f2575f80fd5b5051919050565b5f8085851115615107575f80fd5b83861115615113575f80fd5b5050820193919092039150565b80356020831015610853577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820281158282048414176108535761085361515c565b808201808211156108535761085361515c565b5f67ffffffffffffffff8211156151cc576151cc614ae6565b5060051b60200190565b803563ffffffff81168114614517575f80fd5b5f602082840312156151f9575f80fd5b813567ffffffffffffffff81111561520f575f80fd5b8201601f8101841361521f575f80fd5b803561523261522d826151b3565b614b3c565b80828252602082019150602060608402850101925086831115615253575f80fd5b6020840193505b8284101561423e5760608488031215615271575f80fd5b615279614b13565b84358152615289602086016151d6565b602082015260408501357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681146152bc575f80fd5b604082015282526060939093019260209091019061525a565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036153055761530561515c565b5060010190565b5f6020828403121561531c575f80fd5b813567ffffffffffffffff811115615332575f80fd5b8201601f81018413615342575f80fd5b803561535061522d826151b3565b8082825260208201915060208360051b850101925086831115615371575f80fd5b602084015b838110156154a657803567ffffffffffffffff811115615394575f80fd5b85016060818a037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00112156153c7575f80fd5b6153cf614b13565b602082013581526153e2604083016151d6565b6020820152606082013567ffffffffffffffff811115615400575f80fd5b60208184010192505089601f830112615417575f80fd5b813567ffffffffffffffff81111561543157615431614ae6565b61546260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614b3c565b8181528b6020838601011115615476575f80fd5b816020850160208301375f6020838301015280604084015250508085525050602083019250602081019050615376565b509695505050505050565b815167ffffffffffffffff8111156154cb576154cb614ae6565b6154df816154d98454614c3d565b84614d9a565b6020601f821160018114615530575f83156154fa5750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b178455614dde565b5f848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b8281101561557d578785015182556020948501946001909201910161555d565b50848210156155b957868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b01905550565b818103818111156108535761085361515c565b60ff82811682821603908111156108535761085361515c565b5f60208284031215615604575f80fd5b8151613b3481614aa2565b5f82518060208501845e5f92019182525091905056fea164736f6c634300081a000a
Net Worth in USD
Net Worth in ETH
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.