More Info
Private Name Tags
ContractCreator
Sponsored
Latest 25 from a total of 117 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Transmit | 117928832 | 198 days ago | IN | 0 ETH | 0.000062461682 | ||||
Transmit | 117922421 | 198 days ago | IN | 0 ETH | 0.000024874348 | ||||
Transmit | 117917020 | 198 days ago | IN | 0 ETH | 0.000023292071 | ||||
Transmit | 117911620 | 198 days ago | IN | 0 ETH | 0.00002140013 | ||||
Transmit | 117906219 | 199 days ago | IN | 0 ETH | 0.000024706449 | ||||
Transmit | 117900820 | 199 days ago | IN | 0 ETH | 0.000021234143 | ||||
Transmit | 117895421 | 199 days ago | IN | 0 ETH | 0.000025137423 | ||||
Transmit | 117890019 | 199 days ago | IN | 0 ETH | 0.000024960819 | ||||
Transmit | 117884619 | 199 days ago | IN | 0 ETH | 0.000009029243 | ||||
Transmit | 117879219 | 199 days ago | IN | 0 ETH | 0.000009591058 | ||||
Transmit | 117873820 | 199 days ago | IN | 0 ETH | 0.000005988523 | ||||
Transmit | 117868422 | 199 days ago | IN | 0 ETH | 0.000007414103 | ||||
Transmit | 117863020 | 200 days ago | IN | 0 ETH | 0.000005147118 | ||||
Transmit | 117857619 | 200 days ago | IN | 0 ETH | 0.000007960728 | ||||
Transmit | 117852234 | 200 days ago | IN | 0 ETH | 0.000005400901 | ||||
Transmit | 117846822 | 200 days ago | IN | 0 ETH | 0.000005777064 | ||||
Transmit | 117841421 | 200 days ago | IN | 0 ETH | 0.000005859871 | ||||
Transmit | 117836021 | 200 days ago | IN | 0 ETH | 0.000006212154 | ||||
Transmit | 117830623 | 200 days ago | IN | 0 ETH | 0.000005094403 | ||||
Transmit | 117825222 | 200 days ago | IN | 0 ETH | 0.000005607633 | ||||
Transmit | 117819822 | 201 days ago | IN | 0 ETH | 0.000008151542 | ||||
Transmit | 117814421 | 201 days ago | IN | 0 ETH | 0.000005040045 | ||||
Transmit | 117809021 | 201 days ago | IN | 0 ETH | 0.000005599804 | ||||
Transmit | 117803622 | 201 days ago | IN | 0 ETH | 0.000005535697 | ||||
Transmit | 117798235 | 201 days ago | IN | 0 ETH | 0.000005543136 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
FunctionsCoordinator
Compiler Version
v0.8.19+commit.7dd6d404
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {IFunctionsCoordinator} from "./interfaces/IFunctionsCoordinator.sol"; import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; import {FunctionsBilling, FunctionsBillingConfig} from "./FunctionsBilling.sol"; import {OCR2Base} from "./ocr/OCR2Base.sol"; import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; /// @title Functions Coordinator contract /// @notice Contract that nodes of a Decentralized Oracle Network (DON) interact with contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilling { using FunctionsResponse for FunctionsResponse.RequestMeta; using FunctionsResponse for FunctionsResponse.Commitment; using FunctionsResponse for FunctionsResponse.FulfillResult; /// @inheritdoc ITypeAndVersion // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "Functions Coordinator v1.3.0"; event OracleRequest( bytes32 indexed requestId, address indexed requestingContract, address requestInitiator, uint64 subscriptionId, address subscriptionOwner, bytes data, uint16 dataVersion, bytes32 flags, uint64 callbackGasLimit, FunctionsResponse.Commitment commitment ); event OracleResponse(bytes32 indexed requestId, address transmitter); error InconsistentReportData(); error EmptyPublicKey(); error UnauthorizedPublicKeyChange(); bytes private s_donPublicKey; bytes private s_thresholdPublicKey; constructor( address router, FunctionsBillingConfig memory config, address linkToNativeFeed, address linkToUsdFeed ) OCR2Base() FunctionsBilling(router, config, linkToNativeFeed, linkToUsdFeed) {} /// @inheritdoc IFunctionsCoordinator function getThresholdPublicKey() external view override returns (bytes memory) { if (s_thresholdPublicKey.length == 0) { revert EmptyPublicKey(); } return s_thresholdPublicKey; } /// @inheritdoc IFunctionsCoordinator function setThresholdPublicKey(bytes calldata thresholdPublicKey) external override onlyOwner { if (thresholdPublicKey.length == 0) { revert EmptyPublicKey(); } s_thresholdPublicKey = thresholdPublicKey; } /// @inheritdoc IFunctionsCoordinator function getDONPublicKey() external view override returns (bytes memory) { if (s_donPublicKey.length == 0) { revert EmptyPublicKey(); } return s_donPublicKey; } /// @inheritdoc IFunctionsCoordinator function setDONPublicKey(bytes calldata donPublicKey) external override onlyOwner { if (donPublicKey.length == 0) { revert EmptyPublicKey(); } s_donPublicKey = donPublicKey; } /// @dev check if node is in current transmitter list function _isTransmitter(address node) internal view returns (bool) { // Bounded by "maxNumOracles" on OCR2Abstract.sol for (uint256 i = 0; i < s_transmitters.length; ++i) { if (s_transmitters[i] == node) { return true; } } return false; } /// @inheritdoc IFunctionsCoordinator function startRequest( FunctionsResponse.RequestMeta calldata request ) external override onlyRouter returns (FunctionsResponse.Commitment memory commitment) { uint72 operationFee; (commitment, operationFee) = _startBilling(request); emit OracleRequest( commitment.requestId, request.requestingContract, // solhint-disable-next-line avoid-tx-origin tx.origin, request.subscriptionId, request.subscriptionOwner, request.data, request.dataVersion, request.flags, request.callbackGasLimit, FunctionsResponse.Commitment({ coordinator: commitment.coordinator, client: commitment.client, subscriptionId: commitment.subscriptionId, callbackGasLimit: commitment.callbackGasLimit, estimatedTotalCostJuels: commitment.estimatedTotalCostJuels, timeoutTimestamp: commitment.timeoutTimestamp, requestId: commitment.requestId, donFee: commitment.donFee, gasOverheadBeforeCallback: commitment.gasOverheadBeforeCallback, gasOverheadAfterCallback: commitment.gasOverheadAfterCallback, // The following line is done to use the Coordinator's operationFee in place of the Router's operation fee // With this in place the Router.adminFee must be set to 0 in the Router. adminFee: operationFee }) ); return commitment; } /// @dev DON fees are pooled together. If the OCR configuration is going to change, these need to be distributed. function _beforeSetConfig(uint8 /* _f */, bytes memory /* _onchainConfig */) internal override { if (_getTransmitters().length > 0) { _disperseFeePool(); } } /// @dev Used by FunctionsBilling.sol function _getTransmitters() internal view override returns (address[] memory) { return s_transmitters; } function _beforeTransmit( bytes calldata report ) internal view override returns (bool shouldStop, DecodedReport memory decodedReport) { ( bytes32[] memory requestIds, bytes[] memory results, bytes[] memory errors, bytes[] memory onchainMetadata, bytes[] memory offchainMetadata ) = abi.decode(report, (bytes32[], bytes[], bytes[], bytes[], bytes[])); uint256 numberOfFulfillments = uint8(requestIds.length); if ( numberOfFulfillments == 0 || numberOfFulfillments != results.length || numberOfFulfillments != errors.length || numberOfFulfillments != onchainMetadata.length || numberOfFulfillments != offchainMetadata.length ) { revert ReportInvalid("Fields must be equal length"); } for (uint256 i = 0; i < numberOfFulfillments; ++i) { if (_isExistingRequest(requestIds[i])) { // If there is an existing request, validate report // Leave shouldStop to default, false break; } if (i == numberOfFulfillments - 1) { // If the last fulfillment on the report does not exist, then all are duplicates // Indicate that it's safe to stop to save on the gas of validating the report shouldStop = true; } } return ( shouldStop, DecodedReport({ requestIds: requestIds, results: results, errors: errors, onchainMetadata: onchainMetadata, offchainMetadata: offchainMetadata }) ); } /// @dev Report hook called within OCR2Base.sol function _report(DecodedReport memory decodedReport) internal override { uint256 numberOfFulfillments = uint8(decodedReport.requestIds.length); // Bounded by "MaxRequestBatchSize" on the Job's ReportingPluginConfig for (uint256 i = 0; i < numberOfFulfillments; ++i) { FunctionsResponse.FulfillResult result = FunctionsResponse.FulfillResult( _fulfillAndBill( decodedReport.requestIds[i], decodedReport.results[i], decodedReport.errors[i], decodedReport.onchainMetadata[i], decodedReport.offchainMetadata[i], uint8(numberOfFulfillments) // will not exceed "MaxRequestBatchSize" on the Job's ReportingPluginConfig ) ); // Emit on successfully processing the fulfillment // In these two fulfillment results the user has been charged // Otherwise, the DON will re-try if ( result == FunctionsResponse.FulfillResult.FULFILLED || result == FunctionsResponse.FulfillResult.USER_CALLBACK_ERROR ) { emit OracleResponse(decodedReport.requestIds[i], msg.sender); } } } /// @dev Used in FunctionsBilling.sol function _onlyOwner() internal view override { _validateOwnership(); } /// @dev Used in FunctionsBilling.sol function _owner() internal view override returns (address owner) { return this.owner(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {IFunctionsSubscriptions} from "./interfaces/IFunctionsSubscriptions.sol"; import {AggregatorV3Interface} from "../../../shared/interfaces/AggregatorV3Interface.sol"; import {IFunctionsBilling, FunctionsBillingConfig} from "./interfaces/IFunctionsBilling.sol"; import {Routable} from "./Routable.sol"; import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol"; import {ChainSpecificUtil} from "./libraries/ChainSpecificUtil.sol"; /// @title Functions Billing contract /// @notice Contract that calculates payment from users to the nodes of the Decentralized Oracle Network (DON). abstract contract FunctionsBilling is Routable, IFunctionsBilling { using FunctionsResponse for FunctionsResponse.RequestMeta; using FunctionsResponse for FunctionsResponse.Commitment; using FunctionsResponse for FunctionsResponse.FulfillResult; uint256 private constant REASONABLE_GAS_PRICE_CEILING = 1_000_000_000_000_000; // 1 million gwei event RequestBilled( bytes32 indexed requestId, uint96 juelsPerGas, uint256 l1FeeShareWei, uint96 callbackCostJuels, uint72 donFeeJuels, uint72 adminFeeJuels, uint72 operationFeeJuels ); // ================================================================ // | Request Commitment state | // ================================================================ mapping(bytes32 requestId => bytes32 commitmentHash) private s_requestCommitments; event CommitmentDeleted(bytes32 requestId); FunctionsBillingConfig private s_config; event ConfigUpdated(FunctionsBillingConfig config); error UnsupportedRequestDataVersion(); error InsufficientBalance(); error InvalidSubscription(); error UnauthorizedSender(); error MustBeSubOwner(address owner); error InvalidLinkWeiPrice(int256 linkWei); error InvalidUsdLinkPrice(int256 usdLink); error PaymentTooLarge(); error NoTransmittersSet(); error InvalidCalldata(); // ================================================================ // | Balance state | // ================================================================ mapping(address transmitter => uint96 balanceJuelsLink) private s_withdrawableTokens; // Pool together collected DON fees // Disperse them on withdrawal or change in OCR configuration uint96 internal s_feePool; AggregatorV3Interface private s_linkToNativeFeed; AggregatorV3Interface private s_linkToUsdFeed; // ================================================================ // | Initialization | // ================================================================ constructor( address router, FunctionsBillingConfig memory config, address linkToNativeFeed, address linkToUsdFeed ) Routable(router) { s_linkToNativeFeed = AggregatorV3Interface(linkToNativeFeed); s_linkToUsdFeed = AggregatorV3Interface(linkToUsdFeed); updateConfig(config); } // ================================================================ // | Configuration | // ================================================================ /// @notice Gets the Chainlink Coordinator's billing configuration /// @return config function getConfig() external view returns (FunctionsBillingConfig memory) { return s_config; } /// @notice Sets the Chainlink Coordinator's billing configuration /// @param config - See the contents of the FunctionsBillingConfig struct in IFunctionsBilling.sol for more information function updateConfig(FunctionsBillingConfig memory config) public { _onlyOwner(); s_config = config; emit ConfigUpdated(config); } // ================================================================ // | Fee Calculation | // ================================================================ /// @inheritdoc IFunctionsBilling function getDONFeeJuels(bytes memory /* requestData */) public view override returns (uint72) { // s_config.donFee is in cents of USD. Get Juel amount then convert to dollars. return SafeCast.toUint72(_getJuelsFromUsd(s_config.donFeeCentsUsd) / 100); } /// @inheritdoc IFunctionsBilling function getOperationFeeJuels() public view override returns (uint72) { // s_config.donFee is in cents of USD. Get Juel amount then convert to dollars. return SafeCast.toUint72(_getJuelsFromUsd(s_config.operationFeeCentsUsd) / 100); } /// @inheritdoc IFunctionsBilling function getAdminFeeJuels() public view override returns (uint72) { return _getRouter().getAdminFee(); } /// @inheritdoc IFunctionsBilling function getWeiPerUnitLink() public view returns (uint256) { (, int256 weiPerUnitLink, , uint256 timestamp, ) = s_linkToNativeFeed.latestRoundData(); // solhint-disable-next-line not-rely-on-time if (s_config.feedStalenessSeconds < block.timestamp - timestamp && s_config.feedStalenessSeconds > 0) { return s_config.fallbackNativePerUnitLink; } if (weiPerUnitLink <= 0) { revert InvalidLinkWeiPrice(weiPerUnitLink); } return uint256(weiPerUnitLink); } function _getJuelsFromWei(uint256 amountWei) private view returns (uint96) { // (1e18 juels/link) * wei / (wei/link) = juels // There are only 1e9*1e18 = 1e27 juels in existence, should not exceed uint96 (2^96 ~ 7e28) return SafeCast.toUint96((1e18 * amountWei) / getWeiPerUnitLink()); } /// @inheritdoc IFunctionsBilling function getUsdPerUnitLink() public view returns (uint256, uint8) { (, int256 usdPerUnitLink, , uint256 timestamp, ) = s_linkToUsdFeed.latestRoundData(); // solhint-disable-next-line not-rely-on-time if (s_config.feedStalenessSeconds < block.timestamp - timestamp && s_config.feedStalenessSeconds > 0) { return (s_config.fallbackUsdPerUnitLink, s_config.fallbackUsdPerUnitLinkDecimals); } if (usdPerUnitLink <= 0) { revert InvalidUsdLinkPrice(usdPerUnitLink); } return (uint256(usdPerUnitLink), s_linkToUsdFeed.decimals()); } function _getJuelsFromUsd(uint256 amountUsd) private view returns (uint96) { (uint256 usdPerLink, uint8 decimals) = getUsdPerUnitLink(); // (usd) * (10**18 juels/link) * (10**decimals) / (link / usd) = juels // There are only 1e9*1e18 = 1e27 juels in existence, should not exceed uint96 (2^96 ~ 7e28) return SafeCast.toUint96((amountUsd * 10 ** (18 + decimals)) / usdPerLink); } // ================================================================ // | Cost Estimation | // ================================================================ /// @inheritdoc IFunctionsBilling function estimateCost( uint64 subscriptionId, bytes calldata data, uint32 callbackGasLimit, uint256 gasPriceWei ) external view override returns (uint96) { _getRouter().isValidCallbackGasLimit(subscriptionId, callbackGasLimit); // Reasonable ceilings to prevent integer overflows if (gasPriceWei > REASONABLE_GAS_PRICE_CEILING) { revert InvalidCalldata(); } uint72 adminFee = getAdminFeeJuels(); uint72 donFee = getDONFeeJuels(data); uint72 operationFee = getOperationFeeJuels(); return _calculateCostEstimate(callbackGasLimit, gasPriceWei, donFee, adminFee, operationFee); } /// @notice Estimate the cost in Juels of LINK // that will be charged to a subscription to fulfill a Functions request // Gas Price can be overestimated to account for flucuations between request and response time function _calculateCostEstimate( uint32 callbackGasLimit, uint256 gasPriceWei, uint72 donFeeJuels, uint72 adminFeeJuels, uint72 operationFeeJuels ) internal view returns (uint96) { // If gas price is less than the minimum fulfillment gas price, override to using the minimum if (gasPriceWei < s_config.minimumEstimateGasPriceWei) { gasPriceWei = s_config.minimumEstimateGasPriceWei; } uint256 gasPriceWithOverestimation = gasPriceWei + ((gasPriceWei * s_config.fulfillmentGasPriceOverEstimationBP) / 10_000); /// @NOTE: Basis Points are 1/100th of 1%, divide by 10_000 to bring back to original units uint256 executionGas = s_config.gasOverheadBeforeCallback + s_config.gasOverheadAfterCallback + callbackGasLimit; uint256 l1FeeWei = ChainSpecificUtil._getCurrentTxL1GasFees(msg.data); uint96 estimatedGasReimbursementJuels = _getJuelsFromWei((gasPriceWithOverestimation * executionGas) + l1FeeWei); uint96 feesJuels = uint96(donFeeJuels) + uint96(adminFeeJuels) + uint96(operationFeeJuels); return estimatedGasReimbursementJuels + feesJuels; } // ================================================================ // | Billing | // ================================================================ /// @notice Initiate the billing process for an Functions request /// @dev Only callable by the Functions Router /// @param request - Chainlink Functions request data, see FunctionsResponse.RequestMeta for the structure /// @return commitment - The parameters of the request that must be held consistent at response time function _startBilling( FunctionsResponse.RequestMeta memory request ) internal returns (FunctionsResponse.Commitment memory commitment, uint72 operationFee) { // Nodes should support all past versions of the structure if (request.dataVersion > s_config.maxSupportedRequestDataVersion) { revert UnsupportedRequestDataVersion(); } uint72 donFee = getDONFeeJuels(request.data); operationFee = getOperationFeeJuels(); uint96 estimatedTotalCostJuels = _calculateCostEstimate( request.callbackGasLimit, tx.gasprice, donFee, request.adminFee, operationFee ); // Check that subscription can afford the estimated cost if ((request.availableBalance) < estimatedTotalCostJuels) { revert InsufficientBalance(); } uint32 timeoutTimestamp = uint32(block.timestamp + s_config.requestTimeoutSeconds); bytes32 requestId = keccak256( abi.encode( address(this), request.requestingContract, request.subscriptionId, request.initiatedRequests + 1, keccak256(request.data), request.dataVersion, request.callbackGasLimit, estimatedTotalCostJuels, timeoutTimestamp, // solhint-disable-next-line avoid-tx-origin tx.origin ) ); commitment = FunctionsResponse.Commitment({ adminFee: request.adminFee, coordinator: address(this), client: request.requestingContract, subscriptionId: request.subscriptionId, callbackGasLimit: request.callbackGasLimit, estimatedTotalCostJuels: estimatedTotalCostJuels, timeoutTimestamp: timeoutTimestamp, requestId: requestId, donFee: donFee, gasOverheadBeforeCallback: s_config.gasOverheadBeforeCallback, gasOverheadAfterCallback: s_config.gasOverheadAfterCallback }); s_requestCommitments[requestId] = keccak256(abi.encode(commitment)); return (commitment, operationFee); } /// @notice Finalize billing process for an Functions request by sending a callback to the Client contract and then charging the subscription /// @param requestId identifier for the request that was generated by the Registry in the beginBilling commitment /// @param response response data from DON consensus /// @param err error from DON consensus /// @param reportBatchSize the number of fulfillments in the transmitter's report /// @return result fulfillment result /// @dev Only callable by a node that has been approved on the Coordinator /// @dev simulated offchain to determine if sufficient balance is present to fulfill the request function _fulfillAndBill( bytes32 requestId, bytes memory response, bytes memory err, bytes memory onchainMetadata, bytes memory /* offchainMetadata TODO: use in getDonFee() for dynamic billing */, uint8 reportBatchSize ) internal returns (FunctionsResponse.FulfillResult) { FunctionsResponse.Commitment memory commitment = abi.decode(onchainMetadata, (FunctionsResponse.Commitment)); uint256 gasOverheadWei = (commitment.gasOverheadBeforeCallback + commitment.gasOverheadAfterCallback) * tx.gasprice; uint256 l1FeeShareWei = ChainSpecificUtil._getCurrentTxL1GasFees(msg.data) / reportBatchSize; // Gas overhead without callback uint96 gasOverheadJuels = _getJuelsFromWei(gasOverheadWei + l1FeeShareWei); uint96 juelsPerGas = _getJuelsFromWei(tx.gasprice); // The Functions Router will perform the callback to the client contract (FunctionsResponse.FulfillResult resultCode, uint96 callbackCostJuels) = _getRouter().fulfill( response, err, juelsPerGas, // The following line represents: "cost without callback or admin fee, those will be added by the Router" // But because the _offchain_ Commitment is using operation fee in the place of the admin fee, this now adds admin fee (actually operation fee) // Admin fee is configured to 0 in the Router gasOverheadJuels + commitment.donFee + commitment.adminFee, msg.sender, FunctionsResponse.Commitment({ adminFee: 0, // The Router should have adminFee set to 0. If it does not this will cause fulfillments to fail with INVALID_COMMITMENT instead of carrying out incorrect bookkeeping. coordinator: commitment.coordinator, client: commitment.client, subscriptionId: commitment.subscriptionId, callbackGasLimit: commitment.callbackGasLimit, estimatedTotalCostJuels: commitment.estimatedTotalCostJuels, timeoutTimestamp: commitment.timeoutTimestamp, requestId: commitment.requestId, donFee: commitment.donFee, gasOverheadBeforeCallback: commitment.gasOverheadBeforeCallback, gasOverheadAfterCallback: commitment.gasOverheadAfterCallback }) ); // The router will only pay the DON on successfully processing the fulfillment // In these two fulfillment results the user has been charged // Otherwise, the Coordinator should hold on to the request commitment if ( resultCode == FunctionsResponse.FulfillResult.FULFILLED || resultCode == FunctionsResponse.FulfillResult.USER_CALLBACK_ERROR ) { delete s_requestCommitments[requestId]; // Reimburse the transmitter for the fulfillment gas cost s_withdrawableTokens[msg.sender] += gasOverheadJuels + callbackCostJuels; // Put donFee into the pool of fees, to be split later // Saves on storage writes that would otherwise be charged to the user s_feePool += commitment.donFee; // Pay the operation fee to the Coordinator owner s_withdrawableTokens[_owner()] += commitment.adminFee; // OperationFee is used in the slot for Admin Fee in the Offchain Commitment. Admin Fee is set to 0 in the Router (enforced by line 316 in FunctionsBilling.sol). emit RequestBilled({ requestId: requestId, juelsPerGas: juelsPerGas, l1FeeShareWei: l1FeeShareWei, callbackCostJuels: callbackCostJuels, donFeeJuels: commitment.donFee, // The following two lines are because of OperationFee being used in the Offchain Commitment adminFeeJuels: 0, operationFeeJuels: commitment.adminFee }); } return resultCode; } // ================================================================ // | Request Timeout | // ================================================================ /// @inheritdoc IFunctionsBilling /// @dev Only callable by the Router /// @dev Used by FunctionsRouter.sol during timeout of a request function deleteCommitment(bytes32 requestId) external override onlyRouter { // Delete commitment delete s_requestCommitments[requestId]; emit CommitmentDeleted(requestId); } // ================================================================ // | Fund withdrawal | // ================================================================ /// @inheritdoc IFunctionsBilling function oracleWithdraw(address recipient, uint96 amount) external { _disperseFeePool(); if (amount == 0) { amount = s_withdrawableTokens[msg.sender]; } else if (s_withdrawableTokens[msg.sender] < amount) { revert InsufficientBalance(); } s_withdrawableTokens[msg.sender] -= amount; IFunctionsSubscriptions(address(_getRouter())).oracleWithdraw(recipient, amount); } /// @inheritdoc IFunctionsBilling /// @dev Only callable by the Coordinator owner function oracleWithdrawAll() external { _onlyOwner(); _disperseFeePool(); address[] memory transmitters = _getTransmitters(); // Bounded by "maxNumOracles" on OCR2Abstract.sol for (uint256 i = 0; i < transmitters.length; ++i) { uint96 balance = s_withdrawableTokens[transmitters[i]]; if (balance > 0) { s_withdrawableTokens[transmitters[i]] = 0; IFunctionsSubscriptions(address(_getRouter())).oracleWithdraw(transmitters[i], balance); } } } // Overriden in FunctionsCoordinator, which has visibility into transmitters function _getTransmitters() internal view virtual returns (address[] memory); // DON fees are collected into a pool s_feePool // When OCR configuration changes, or any oracle withdraws, this must be dispersed function _disperseFeePool() internal { if (s_feePool == 0) { return; } // All transmitters are assumed to also be observers // Pay out the DON fee to all transmitters address[] memory transmitters = _getTransmitters(); uint256 numberOfTransmitters = transmitters.length; if (numberOfTransmitters == 0) { revert NoTransmittersSet(); } uint96 feePoolShare = s_feePool / uint96(numberOfTransmitters); // Bounded by "maxNumOracles" on OCR2Abstract.sol for (uint256 i = 0; i < numberOfTransmitters; ++i) { s_withdrawableTokens[transmitters[i]] += feePoolShare; } s_feePool -= feePoolShare * uint96(numberOfTransmitters); } // Overriden in FunctionsCoordinator.sol function _onlyOwner() internal view virtual; // Used in FunctionsCoordinator.sol function _isExistingRequest(bytes32 requestId) internal view returns (bool) { return s_requestCommitments[requestId] != bytes32(0); } // Overriden in FunctionsCoordinator.sol function _owner() internal view virtual returns (address owner); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {IFunctionsRouter} from "./interfaces/IFunctionsRouter.sol"; import {IFunctionsClient} from "./interfaces/IFunctionsClient.sol"; import {FunctionsRequest} from "./libraries/FunctionsRequest.sol"; /// @title The Chainlink Functions client contract /// @notice Contract developers can inherit this contract in order to make Chainlink Functions requests abstract contract FunctionsClient is IFunctionsClient { using FunctionsRequest for FunctionsRequest.Request; IFunctionsRouter internal immutable i_functionsRouter; event RequestSent(bytes32 indexed id); event RequestFulfilled(bytes32 indexed id); error OnlyRouterCanFulfill(); constructor(address router) { i_functionsRouter = IFunctionsRouter(router); } /// @notice Sends a Chainlink Functions request /// @param data The CBOR encoded bytes data for a Functions request /// @param subscriptionId The subscription ID that will be charged to service the request /// @param callbackGasLimit the amount of gas that will be available for the fulfillment callback /// @return requestId The generated request ID for this request function _sendRequest( bytes memory data, uint64 subscriptionId, uint32 callbackGasLimit, bytes32 donId ) internal returns (bytes32) { bytes32 requestId = i_functionsRouter.sendRequest( subscriptionId, data, FunctionsRequest.REQUEST_DATA_VERSION, callbackGasLimit, donId ); emit RequestSent(requestId); return requestId; } /// @notice User defined function to handle a response from the DON /// @param requestId The request ID, returned by sendRequest() /// @param response Aggregated response from the execution of the user's source code /// @param err Aggregated error from the execution of the user code or from the execution pipeline /// @dev Either response or error parameter will be set, but never both function _fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal virtual; /// @inheritdoc IFunctionsClient function handleOracleFulfillment(bytes32 requestId, bytes memory response, bytes memory err) external override { if (msg.sender != address(i_functionsRouter)) { revert OnlyRouterCanFulfill(); } _fulfillRequest(requestId, response, err); emit RequestFulfilled(requestId); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; import {IFunctionsRouter} from "./interfaces/IFunctionsRouter.sol"; import {IFunctionsCoordinator} from "./interfaces/IFunctionsCoordinator.sol"; import {IAccessController} from "../../../shared/interfaces/IAccessController.sol"; import {FunctionsSubscriptions} from "./FunctionsSubscriptions.sol"; import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol"; import {Pausable} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/security/Pausable.sol"; contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, ITypeAndVersion, ConfirmedOwner { using FunctionsResponse for FunctionsResponse.RequestMeta; using FunctionsResponse for FunctionsResponse.Commitment; using FunctionsResponse for FunctionsResponse.FulfillResult; // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "Functions Router v1.0.0"; // We limit return data to a selector plus 4 words. This is to avoid // malicious contracts from returning large amounts of data and causing // repeated out-of-gas scenarios. uint16 public constant MAX_CALLBACK_RETURN_BYTES = 4 + 4 * 32; uint8 private constant MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX = 0; event RequestStart( bytes32 indexed requestId, bytes32 indexed donId, uint64 indexed subscriptionId, address subscriptionOwner, address requestingContract, address requestInitiator, bytes data, uint16 dataVersion, uint32 callbackGasLimit, uint96 estimatedTotalCostJuels ); event RequestProcessed( bytes32 indexed requestId, uint64 indexed subscriptionId, uint96 totalCostJuels, address transmitter, FunctionsResponse.FulfillResult resultCode, bytes response, bytes err, bytes callbackReturnData ); event RequestNotProcessed( bytes32 indexed requestId, address coordinator, address transmitter, FunctionsResponse.FulfillResult resultCode ); error EmptyRequestData(); error OnlyCallableFromCoordinator(); error SenderMustAcceptTermsOfService(address sender); error InvalidGasFlagValue(uint8 value); error GasLimitTooBig(uint32 limit); error DuplicateRequestId(bytes32 requestId); struct CallbackResult { bool success; // ══════╸ Whether the callback succeeded or not uint256 gasUsed; // ═══╸ The amount of gas consumed during the callback bytes returnData; // ══╸ The return of the callback function } // ================================================================ // | Route state | // ================================================================ mapping(bytes32 id => address routableContract) private s_route; error RouteNotFound(bytes32 id); // Identifier for the route to the Terms of Service Allow List bytes32 private s_allowListId; // ================================================================ // | Configuration state | // ================================================================ struct Config { uint16 maxConsumersPerSubscription; // ═════════╗ Maximum number of consumers which can be added to a single subscription. This bound ensures we are able to loop over all subscription consumers as needed, without exceeding gas limits. Should a user require more consumers, they can use multiple subscriptions. uint72 adminFee; // ║ Flat fee (in Juels of LINK) that will be paid to the Router owner for operation of the network bytes4 handleOracleFulfillmentSelector; // ║ The function selector that is used when calling back to the Client contract uint16 gasForCallExactCheck; // ════════════════╝ Used during calling back to the client. Ensures we have at least enough gas to be able to revert if gasAmount > 63//64*gas available. uint32[] maxCallbackGasLimits; // ══════════════╸ List of max callback gas limits used by flag with MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX uint16 subscriptionDepositMinimumRequests; //═══╗ Amount of requests that must be completed before the full subscription balance will be released when closing a subscription account. uint72 subscriptionDepositJuels; // ════════════╝ Amount of subscription funds that are held as a deposit until Config.subscriptionDepositMinimumRequests are made using the subscription. } Config private s_config; event ConfigUpdated(Config); // ================================================================ // | Proposal state | // ================================================================ uint8 private constant MAX_PROPOSAL_SET_LENGTH = 8; struct ContractProposalSet { bytes32[] ids; // ══╸ The IDs that key into the routes that will be modified if the update is applied address[] to; // ═══╸ The address of the contracts that the route will point to if the updated is applied } ContractProposalSet private s_proposedContractSet; event ContractProposed( bytes32 proposedContractSetId, address proposedContractSetFromAddress, address proposedContractSetToAddress ); event ContractUpdated(bytes32 id, address from, address to); error InvalidProposal(); error IdentifierIsReserved(bytes32 id); // ================================================================ // | Initialization | // ================================================================ constructor( address linkToken, Config memory config ) FunctionsSubscriptions(linkToken) ConfirmedOwner(msg.sender) Pausable() { // Set the intial configuration updateConfig(config); } // ================================================================ // | Configuration | // ================================================================ /// @notice The identifier of the route to retrieve the address of the access control contract // The access control contract controls which accounts can manage subscriptions /// @return id - bytes32 id that can be passed to the "getContractById" of the Router function getConfig() external view returns (Config memory) { return s_config; } /// @notice The router configuration function updateConfig(Config memory config) public onlyOwner { s_config = config; emit ConfigUpdated(config); } /// @inheritdoc IFunctionsRouter function isValidCallbackGasLimit(uint64 subscriptionId, uint32 callbackGasLimit) public view { uint8 callbackGasLimitsIndexSelector = uint8(getFlags(subscriptionId)[MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX]); if (callbackGasLimitsIndexSelector >= s_config.maxCallbackGasLimits.length) { revert InvalidGasFlagValue(callbackGasLimitsIndexSelector); } uint32 maxCallbackGasLimit = s_config.maxCallbackGasLimits[callbackGasLimitsIndexSelector]; if (callbackGasLimit > maxCallbackGasLimit) { revert GasLimitTooBig(maxCallbackGasLimit); } } /// @inheritdoc IFunctionsRouter function getAdminFee() external view override returns (uint72) { return s_config.adminFee; } /// @inheritdoc IFunctionsRouter function getAllowListId() external view override returns (bytes32) { return s_allowListId; } /// @inheritdoc IFunctionsRouter function setAllowListId(bytes32 allowListId) external override onlyOwner { s_allowListId = allowListId; } /// @dev Used within FunctionsSubscriptions.sol function _getMaxConsumers() internal view override returns (uint16) { return s_config.maxConsumersPerSubscription; } /// @dev Used within FunctionsSubscriptions.sol function _getSubscriptionDepositDetails() internal view override returns (uint16, uint72) { return (s_config.subscriptionDepositMinimumRequests, s_config.subscriptionDepositJuels); } // ================================================================ // | Requests | // ================================================================ /// @inheritdoc IFunctionsRouter function sendRequest( uint64 subscriptionId, bytes calldata data, uint16 dataVersion, uint32 callbackGasLimit, bytes32 donId ) external override returns (bytes32) { IFunctionsCoordinator coordinator = IFunctionsCoordinator(getContractById(donId)); return _sendRequest(donId, coordinator, subscriptionId, data, dataVersion, callbackGasLimit); } /// @inheritdoc IFunctionsRouter function sendRequestToProposed( uint64 subscriptionId, bytes calldata data, uint16 dataVersion, uint32 callbackGasLimit, bytes32 donId ) external override returns (bytes32) { IFunctionsCoordinator coordinator = IFunctionsCoordinator(getProposedContractById(donId)); return _sendRequest(donId, coordinator, subscriptionId, data, dataVersion, callbackGasLimit); } function _sendRequest( bytes32 donId, IFunctionsCoordinator coordinator, uint64 subscriptionId, bytes memory data, uint16 dataVersion, uint32 callbackGasLimit ) private returns (bytes32) { _whenNotPaused(); _isExistingSubscription(subscriptionId); _isAllowedConsumer(msg.sender, subscriptionId); isValidCallbackGasLimit(subscriptionId, callbackGasLimit); if (data.length == 0) { revert EmptyRequestData(); } Subscription memory subscription = getSubscription(subscriptionId); Consumer memory consumer = getConsumer(msg.sender, subscriptionId); uint72 adminFee = s_config.adminFee; // Forward request to DON FunctionsResponse.Commitment memory commitment = coordinator.startRequest( FunctionsResponse.RequestMeta({ requestingContract: msg.sender, data: data, subscriptionId: subscriptionId, dataVersion: dataVersion, flags: getFlags(subscriptionId), callbackGasLimit: callbackGasLimit, adminFee: adminFee, initiatedRequests: consumer.initiatedRequests, completedRequests: consumer.completedRequests, availableBalance: subscription.balance - subscription.blockedBalance, subscriptionOwner: subscription.owner }) ); // Do not allow setting a comittment for a requestId that already exists if (s_requestCommitments[commitment.requestId] != bytes32(0)) { revert DuplicateRequestId(commitment.requestId); } // Store a commitment about the request s_requestCommitments[commitment.requestId] = keccak256( abi.encode( FunctionsResponse.Commitment({ adminFee: adminFee, coordinator: address(coordinator), client: msg.sender, subscriptionId: subscriptionId, callbackGasLimit: callbackGasLimit, estimatedTotalCostJuels: commitment.estimatedTotalCostJuels, timeoutTimestamp: commitment.timeoutTimestamp, requestId: commitment.requestId, donFee: commitment.donFee, gasOverheadBeforeCallback: commitment.gasOverheadBeforeCallback, gasOverheadAfterCallback: commitment.gasOverheadAfterCallback }) ) ); _markRequestInFlight(msg.sender, subscriptionId, commitment.estimatedTotalCostJuels); emit RequestStart({ requestId: commitment.requestId, donId: donId, subscriptionId: subscriptionId, subscriptionOwner: subscription.owner, requestingContract: msg.sender, // solhint-disable-next-line avoid-tx-origin requestInitiator: tx.origin, data: data, dataVersion: dataVersion, callbackGasLimit: callbackGasLimit, estimatedTotalCostJuels: commitment.estimatedTotalCostJuels }); return commitment.requestId; } // ================================================================ // | Responses | // ================================================================ /// @inheritdoc IFunctionsRouter function fulfill( bytes memory response, bytes memory err, uint96 juelsPerGas, uint96 costWithoutFulfillment, address transmitter, FunctionsResponse.Commitment memory commitment ) external override returns (FunctionsResponse.FulfillResult resultCode, uint96) { _whenNotPaused(); if (msg.sender != commitment.coordinator) { revert OnlyCallableFromCoordinator(); } { bytes32 commitmentHash = s_requestCommitments[commitment.requestId]; if (commitmentHash == bytes32(0)) { resultCode = FunctionsResponse.FulfillResult.INVALID_REQUEST_ID; emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); return (resultCode, 0); } if (keccak256(abi.encode(commitment)) != commitmentHash) { resultCode = FunctionsResponse.FulfillResult.INVALID_COMMITMENT; emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); return (resultCode, 0); } // Check that the transmitter has supplied enough gas for the callback to succeed if (gasleft() < commitment.callbackGasLimit + commitment.gasOverheadAfterCallback) { resultCode = FunctionsResponse.FulfillResult.INSUFFICIENT_GAS_PROVIDED; emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); return (resultCode, 0); } } { uint96 callbackCost = juelsPerGas * SafeCast.toUint96(commitment.callbackGasLimit); uint96 totalCostJuels = commitment.adminFee + costWithoutFulfillment + callbackCost; // Check that the subscription can still afford to fulfill the request if (totalCostJuels > getSubscription(commitment.subscriptionId).balance) { resultCode = FunctionsResponse.FulfillResult.SUBSCRIPTION_BALANCE_INVARIANT_VIOLATION; emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); return (resultCode, 0); } // Check that the cost has not exceeded the quoted cost if (totalCostJuels > commitment.estimatedTotalCostJuels) { resultCode = FunctionsResponse.FulfillResult.COST_EXCEEDS_COMMITMENT; emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); return (resultCode, 0); } } delete s_requestCommitments[commitment.requestId]; CallbackResult memory result = _callback( commitment.requestId, response, err, commitment.callbackGasLimit, commitment.client ); resultCode = result.success ? FunctionsResponse.FulfillResult.FULFILLED : FunctionsResponse.FulfillResult.USER_CALLBACK_ERROR; Receipt memory receipt = _pay( commitment.subscriptionId, commitment.estimatedTotalCostJuels, commitment.client, commitment.adminFee, juelsPerGas, SafeCast.toUint96(result.gasUsed), costWithoutFulfillment ); emit RequestProcessed({ requestId: commitment.requestId, subscriptionId: commitment.subscriptionId, totalCostJuels: receipt.totalCostJuels, transmitter: transmitter, resultCode: resultCode, response: response, err: err, callbackReturnData: result.returnData }); return (resultCode, receipt.callbackGasCostJuels); } function _callback( bytes32 requestId, bytes memory response, bytes memory err, uint32 callbackGasLimit, address client ) private returns (CallbackResult memory) { bool destinationNoLongerExists; assembly { // solidity calls check that a contract actually exists at the destination, so we do the same destinationNoLongerExists := iszero(extcodesize(client)) } if (destinationNoLongerExists) { // Return without attempting callback // The subscription will still be charged to reimburse transmitter's gas overhead return CallbackResult({success: false, gasUsed: 0, returnData: new bytes(0)}); } bytes memory encodedCallback = abi.encodeWithSelector( s_config.handleOracleFulfillmentSelector, requestId, response, err ); uint16 gasForCallExactCheck = s_config.gasForCallExactCheck; // Call with explicitly the amount of callback gas requested // Important to not let them exhaust the gas budget and avoid payment. // NOTE: that callWithExactGas will revert if we do not have sufficient gas // to give the callee their requested amount. bool success; uint256 gasUsed; // allocate return data memory ahead of time bytes memory returnData = new bytes(MAX_CALLBACK_RETURN_BYTES); assembly { let g := gas() // Compute g -= gasForCallExactCheck and check for underflow // The gas actually passed to the callee is _min(gasAmount, 63//64*gas available). // We want to ensure that we revert if gasAmount > 63//64*gas available // as we do not want to provide them with less, however that check itself costs // gas. gasForCallExactCheck ensures we have at least enough gas to be able // to revert if gasAmount > 63//64*gas available. if lt(g, gasForCallExactCheck) { revert(0, 0) } g := sub(g, gasForCallExactCheck) // if g - g//64 <= gasAmount, revert // (we subtract g//64 because of EIP-150) if iszero(gt(sub(g, div(g, 64)), callbackGasLimit)) { revert(0, 0) } // call and report whether we succeeded // call(gas,addr,value,argsOffset,argsLength,retOffset,retLength) let gasBeforeCall := gas() success := call(callbackGasLimit, client, 0, add(encodedCallback, 0x20), mload(encodedCallback), 0, 0) gasUsed := sub(gasBeforeCall, gas()) // limit our copy to MAX_CALLBACK_RETURN_BYTES bytes let toCopy := returndatasize() if gt(toCopy, MAX_CALLBACK_RETURN_BYTES) { toCopy := MAX_CALLBACK_RETURN_BYTES } // Store the length of the copied bytes mstore(returnData, toCopy) // copy the bytes from returnData[0:_toCopy] returndatacopy(add(returnData, 0x20), 0, toCopy) } return CallbackResult({success: success, gasUsed: gasUsed, returnData: returnData}); } // ================================================================ // | Route methods | // ================================================================ /// @inheritdoc IFunctionsRouter function getContractById(bytes32 id) public view override returns (address) { address currentImplementation = s_route[id]; if (currentImplementation == address(0)) { revert RouteNotFound(id); } return currentImplementation; } /// @inheritdoc IFunctionsRouter function getProposedContractById(bytes32 id) public view override returns (address) { // Iterations will not exceed MAX_PROPOSAL_SET_LENGTH for (uint8 i = 0; i < s_proposedContractSet.ids.length; ++i) { if (id == s_proposedContractSet.ids[i]) { return s_proposedContractSet.to[i]; } } revert RouteNotFound(id); } // ================================================================ // | Contract Proposal methods | // ================================================================ /// @inheritdoc IFunctionsRouter function getProposedContractSet() external view override returns (bytes32[] memory, address[] memory) { return (s_proposedContractSet.ids, s_proposedContractSet.to); } /// @inheritdoc IFunctionsRouter function proposeContractsUpdate( bytes32[] memory proposedContractSetIds, address[] memory proposedContractSetAddresses ) external override onlyOwner { // IDs and addresses arrays must be of equal length and must not exceed the max proposal length uint256 idsArrayLength = proposedContractSetIds.length; if (idsArrayLength != proposedContractSetAddresses.length || idsArrayLength > MAX_PROPOSAL_SET_LENGTH) { revert InvalidProposal(); } // NOTE: iterations of this loop will not exceed MAX_PROPOSAL_SET_LENGTH for (uint256 i = 0; i < idsArrayLength; ++i) { bytes32 id = proposedContractSetIds[i]; address proposedContract = proposedContractSetAddresses[i]; if ( proposedContract == address(0) || // The Proposed address must be a valid address s_route[id] == proposedContract // The Proposed address must point to a different address than what is currently set ) { revert InvalidProposal(); } emit ContractProposed({ proposedContractSetId: id, proposedContractSetFromAddress: s_route[id], proposedContractSetToAddress: proposedContract }); } s_proposedContractSet = ContractProposalSet({ids: proposedContractSetIds, to: proposedContractSetAddresses}); } /// @inheritdoc IFunctionsRouter function updateContracts() external override onlyOwner { // Iterations will not exceed MAX_PROPOSAL_SET_LENGTH for (uint256 i = 0; i < s_proposedContractSet.ids.length; ++i) { bytes32 id = s_proposedContractSet.ids[i]; address to = s_proposedContractSet.to[i]; emit ContractUpdated({id: id, from: s_route[id], to: to}); s_route[id] = to; } delete s_proposedContractSet; } // ================================================================ // | Modifiers | // ================================================================ // Favoring internal functions over actual modifiers to reduce contract size /// @dev Used within FunctionsSubscriptions.sol function _whenNotPaused() internal view override { _requireNotPaused(); } /// @dev Used within FunctionsSubscriptions.sol function _onlyRouterOwner() internal view override { _validateOwnership(); } /// @dev Used within FunctionsSubscriptions.sol function _onlySenderThatAcceptedToS() internal view override { address currentImplementation = s_route[s_allowListId]; if (currentImplementation == address(0)) { // If not set, ignore this check, allow all access return; } if (!IAccessController(currentImplementation).hasAccess(msg.sender, new bytes(0))) { revert SenderMustAcceptTermsOfService(msg.sender); } } /// @inheritdoc IFunctionsRouter function pause() external override onlyOwner { _pause(); } /// @inheritdoc IFunctionsRouter function unpause() external override onlyOwner { _unpause(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {IFunctionsSubscriptions} from "./interfaces/IFunctionsSubscriptions.sol"; import {IERC677Receiver} from "../../../shared/interfaces/IERC677Receiver.sol"; import {IFunctionsBilling} from "./interfaces/IFunctionsBilling.sol"; import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; /// @title Functions Subscriptions contract /// @notice Contract that coordinates payment from users to the nodes of the Decentralized Oracle Network (DON). abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Receiver { using SafeERC20 for IERC20; using FunctionsResponse for FunctionsResponse.Commitment; // ================================================================ // | Balance state | // ================================================================ // link token address IERC20 internal immutable i_linkToken; // s_totalLinkBalance tracks the total LINK sent to/from // this contract through onTokenTransfer, cancelSubscription and oracleWithdraw. // A discrepancy with this contract's LINK balance indicates that someone // sent tokens using transfer and so we may need to use recoverFunds. uint96 private s_totalLinkBalance; /// @dev NOP balances are held as a single amount. The breakdown is held by the Coordinator. mapping(address coordinator => uint96 balanceJuelsLink) private s_withdrawableTokens; // ================================================================ // | Subscription state | // ================================================================ // Keep a count of the number of subscriptions so that its possible to // loop through all the current subscriptions via .getSubscription(). uint64 private s_currentSubscriptionId; mapping(uint64 subscriptionId => Subscription) private s_subscriptions; // Maintains the list of keys in s_consumers. // We do this for 2 reasons: // 1. To be able to clean up all keys from s_consumers when canceling a subscription. // 2. To be able to return the list of all consumers in getSubscription. // Note that we need the s_consumers map to be able to directly check if a // consumer is valid without reading all the consumers from storage. mapping(address consumer => mapping(uint64 subscriptionId => Consumer)) private s_consumers; event SubscriptionCreated(uint64 indexed subscriptionId, address owner); event SubscriptionFunded(uint64 indexed subscriptionId, uint256 oldBalance, uint256 newBalance); event SubscriptionConsumerAdded(uint64 indexed subscriptionId, address consumer); event SubscriptionConsumerRemoved(uint64 indexed subscriptionId, address consumer); event SubscriptionCanceled(uint64 indexed subscriptionId, address fundsRecipient, uint256 fundsAmount); event SubscriptionOwnerTransferRequested(uint64 indexed subscriptionId, address from, address to); event SubscriptionOwnerTransferred(uint64 indexed subscriptionId, address from, address to); error TooManyConsumers(uint16 maximumConsumers); error InsufficientBalance(uint96 currentBalanceJuels); error InvalidConsumer(); error CannotRemoveWithPendingRequests(); error InvalidSubscription(); error OnlyCallableFromLink(); error InvalidCalldata(); error MustBeSubscriptionOwner(); error TimeoutNotExceeded(); error MustBeProposedOwner(address proposedOwner); event FundsRecovered(address to, uint256 amount); // ================================================================ // | Request state | // ================================================================ mapping(bytes32 requestId => bytes32 commitmentHash) internal s_requestCommitments; struct Receipt { uint96 callbackGasCostJuels; uint96 totalCostJuels; } event RequestTimedOut(bytes32 indexed requestId); // ================================================================ // | Initialization | // ================================================================ constructor(address link) { i_linkToken = IERC20(link); } // ================================================================ // | Request/Response | // ================================================================ /// @notice Sets a request as in-flight /// @dev Only callable within the Router function _markRequestInFlight(address client, uint64 subscriptionId, uint96 estimatedTotalCostJuels) internal { // Earmark subscription funds s_subscriptions[subscriptionId].blockedBalance += estimatedTotalCostJuels; // Increment sent requests s_consumers[client][subscriptionId].initiatedRequests += 1; } /// @notice Moves funds from one subscription account to another. /// @dev Only callable by the Coordinator contract that is saved in the request commitment function _pay( uint64 subscriptionId, uint96 estimatedTotalCostJuels, address client, uint96 adminFee, uint96 juelsPerGas, uint96 gasUsed, uint96 costWithoutCallbackJuels ) internal returns (Receipt memory) { uint96 callbackGasCostJuels = juelsPerGas * gasUsed; uint96 totalCostJuels = costWithoutCallbackJuels + adminFee + callbackGasCostJuels; if ( s_subscriptions[subscriptionId].balance < totalCostJuels || s_subscriptions[subscriptionId].blockedBalance < estimatedTotalCostJuels ) { revert InsufficientBalance(s_subscriptions[subscriptionId].balance); } // Charge the subscription s_subscriptions[subscriptionId].balance -= totalCostJuels; // Unblock earmarked funds s_subscriptions[subscriptionId].blockedBalance -= estimatedTotalCostJuels; // Pay the DON's fees and gas reimbursement s_withdrawableTokens[msg.sender] += costWithoutCallbackJuels + callbackGasCostJuels; // Pay out the administration fee s_withdrawableTokens[address(this)] += adminFee; // Increment finished requests s_consumers[client][subscriptionId].completedRequests += 1; return Receipt({callbackGasCostJuels: callbackGasCostJuels, totalCostJuels: totalCostJuels}); } // ================================================================ // | Owner methods | // ================================================================ /// @inheritdoc IFunctionsSubscriptions function ownerCancelSubscription(uint64 subscriptionId) external override { _onlyRouterOwner(); _isExistingSubscription(subscriptionId); _cancelSubscriptionHelper(subscriptionId, s_subscriptions[subscriptionId].owner, false); } /// @inheritdoc IFunctionsSubscriptions function recoverFunds(address to) external override { _onlyRouterOwner(); uint256 externalBalance = i_linkToken.balanceOf(address(this)); uint256 internalBalance = uint256(s_totalLinkBalance); if (internalBalance < externalBalance) { uint256 amount = externalBalance - internalBalance; i_linkToken.safeTransfer(to, amount); emit FundsRecovered(to, amount); } // If the balances are equal, nothing to be done. } // ================================================================ // | Fund withdrawal | // ================================================================ /// @inheritdoc IFunctionsSubscriptions function oracleWithdraw(address recipient, uint96 amount) external override { _whenNotPaused(); if (amount == 0) { revert InvalidCalldata(); } uint96 currentBalance = s_withdrawableTokens[msg.sender]; if (currentBalance < amount) { revert InsufficientBalance(currentBalance); } s_withdrawableTokens[msg.sender] -= amount; s_totalLinkBalance -= amount; i_linkToken.safeTransfer(recipient, amount); } /// @notice Owner withdraw LINK earned through admin fees /// @notice If amount is 0 the full balance will be withdrawn /// @param recipient where to send the funds /// @param amount amount to withdraw function ownerWithdraw(address recipient, uint96 amount) external { _onlyRouterOwner(); if (amount == 0) { amount = s_withdrawableTokens[address(this)]; } uint96 currentBalance = s_withdrawableTokens[address(this)]; if (currentBalance < amount) { revert InsufficientBalance(currentBalance); } s_withdrawableTokens[address(this)] -= amount; s_totalLinkBalance -= amount; i_linkToken.safeTransfer(recipient, amount); } // ================================================================ // | TransferAndCall Deposit helper | // ================================================================ // This function is to be invoked when using LINK.transferAndCall /// @dev Note to fund the subscription, use transferAndCall. For example /// @dev LINKTOKEN.transferAndCall( /// @dev address(ROUTER), /// @dev amount, /// @dev abi.encode(subscriptionId)); function onTokenTransfer(address /* sender */, uint256 amount, bytes calldata data) external override { _whenNotPaused(); if (msg.sender != address(i_linkToken)) { revert OnlyCallableFromLink(); } if (data.length != 32) { revert InvalidCalldata(); } uint64 subscriptionId = abi.decode(data, (uint64)); if (s_subscriptions[subscriptionId].owner == address(0)) { revert InvalidSubscription(); } // We do not check that the msg.sender is the subscription owner, // anyone can fund a subscription. uint256 oldBalance = s_subscriptions[subscriptionId].balance; s_subscriptions[subscriptionId].balance += uint96(amount); s_totalLinkBalance += uint96(amount); emit SubscriptionFunded(subscriptionId, oldBalance, oldBalance + amount); } // ================================================================ // | Subscription management | // ================================================================ /// @inheritdoc IFunctionsSubscriptions function getTotalBalance() external view override returns (uint96) { return s_totalLinkBalance; } /// @inheritdoc IFunctionsSubscriptions function getSubscriptionCount() external view override returns (uint64) { return s_currentSubscriptionId; } /// @inheritdoc IFunctionsSubscriptions function getSubscription(uint64 subscriptionId) public view override returns (Subscription memory) { _isExistingSubscription(subscriptionId); return s_subscriptions[subscriptionId]; } /// @inheritdoc IFunctionsSubscriptions function getSubscriptionsInRange( uint64 subscriptionIdStart, uint64 subscriptionIdEnd ) external view override returns (Subscription[] memory subscriptions) { if ( subscriptionIdStart > subscriptionIdEnd || subscriptionIdEnd > s_currentSubscriptionId || s_currentSubscriptionId == 0 ) { revert InvalidCalldata(); } subscriptions = new Subscription[]((subscriptionIdEnd - subscriptionIdStart) + 1); for (uint256 i = 0; i <= subscriptionIdEnd - subscriptionIdStart; ++i) { subscriptions[i] = s_subscriptions[uint64(subscriptionIdStart + i)]; } return subscriptions; } /// @inheritdoc IFunctionsSubscriptions function getConsumer(address client, uint64 subscriptionId) public view override returns (Consumer memory) { return s_consumers[client][subscriptionId]; } /// @dev Used within this file & FunctionsRouter.sol function _isExistingSubscription(uint64 subscriptionId) internal view { if (s_subscriptions[subscriptionId].owner == address(0)) { revert InvalidSubscription(); } } /// @dev Used within FunctionsRouter.sol function _isAllowedConsumer(address client, uint64 subscriptionId) internal view { if (!s_consumers[client][subscriptionId].allowed) { revert InvalidConsumer(); } } /// @inheritdoc IFunctionsSubscriptions function createSubscription() external override returns (uint64 subscriptionId) { _whenNotPaused(); _onlySenderThatAcceptedToS(); subscriptionId = ++s_currentSubscriptionId; s_subscriptions[subscriptionId] = Subscription({ balance: 0, blockedBalance: 0, owner: msg.sender, proposedOwner: address(0), consumers: new address[](0), flags: bytes32(0) }); emit SubscriptionCreated(subscriptionId, msg.sender); return subscriptionId; } /// @inheritdoc IFunctionsSubscriptions function createSubscriptionWithConsumer(address consumer) external override returns (uint64 subscriptionId) { _whenNotPaused(); _onlySenderThatAcceptedToS(); subscriptionId = ++s_currentSubscriptionId; s_subscriptions[subscriptionId] = Subscription({ balance: 0, blockedBalance: 0, owner: msg.sender, proposedOwner: address(0), consumers: new address[](0), flags: bytes32(0) }); s_subscriptions[subscriptionId].consumers.push(consumer); s_consumers[consumer][subscriptionId].allowed = true; emit SubscriptionCreated(subscriptionId, msg.sender); emit SubscriptionConsumerAdded(subscriptionId, consumer); return subscriptionId; } /// @inheritdoc IFunctionsSubscriptions function proposeSubscriptionOwnerTransfer(uint64 subscriptionId, address newOwner) external override { _whenNotPaused(); _onlySubscriptionOwner(subscriptionId); _onlySenderThatAcceptedToS(); if (newOwner == address(0) || s_subscriptions[subscriptionId].proposedOwner == newOwner) { revert InvalidCalldata(); } s_subscriptions[subscriptionId].proposedOwner = newOwner; emit SubscriptionOwnerTransferRequested(subscriptionId, msg.sender, newOwner); } /// @inheritdoc IFunctionsSubscriptions function acceptSubscriptionOwnerTransfer(uint64 subscriptionId) external override { _whenNotPaused(); _onlySenderThatAcceptedToS(); address previousOwner = s_subscriptions[subscriptionId].owner; address proposedOwner = s_subscriptions[subscriptionId].proposedOwner; if (proposedOwner != msg.sender) { revert MustBeProposedOwner(proposedOwner); } s_subscriptions[subscriptionId].owner = msg.sender; s_subscriptions[subscriptionId].proposedOwner = address(0); emit SubscriptionOwnerTransferred(subscriptionId, previousOwner, msg.sender); } /// @inheritdoc IFunctionsSubscriptions function removeConsumer(uint64 subscriptionId, address consumer) external override { _whenNotPaused(); _onlySubscriptionOwner(subscriptionId); _onlySenderThatAcceptedToS(); Consumer memory consumerData = s_consumers[consumer][subscriptionId]; _isAllowedConsumer(consumer, subscriptionId); if (consumerData.initiatedRequests != consumerData.completedRequests) { revert CannotRemoveWithPendingRequests(); } // Note bounded by config.maxConsumers address[] memory consumers = s_subscriptions[subscriptionId].consumers; for (uint256 i = 0; i < consumers.length; ++i) { if (consumers[i] == consumer) { // Storage write to preserve last element s_subscriptions[subscriptionId].consumers[i] = consumers[consumers.length - 1]; // Storage remove last element s_subscriptions[subscriptionId].consumers.pop(); break; } } delete s_consumers[consumer][subscriptionId]; emit SubscriptionConsumerRemoved(subscriptionId, consumer); } /// @dev Overriden in FunctionsRouter.sol function _getMaxConsumers() internal view virtual returns (uint16); /// @inheritdoc IFunctionsSubscriptions function addConsumer(uint64 subscriptionId, address consumer) external override { _whenNotPaused(); _onlySubscriptionOwner(subscriptionId); _onlySenderThatAcceptedToS(); // Already maxed, cannot add any more consumers. uint16 maximumConsumers = _getMaxConsumers(); if (s_subscriptions[subscriptionId].consumers.length >= maximumConsumers) { revert TooManyConsumers(maximumConsumers); } if (s_consumers[consumer][subscriptionId].allowed) { // Idempotence - do nothing if already added. // Ensures uniqueness in s_subscriptions[subscriptionId].consumers. return; } s_consumers[consumer][subscriptionId].allowed = true; s_subscriptions[subscriptionId].consumers.push(consumer); emit SubscriptionConsumerAdded(subscriptionId, consumer); } /// @dev Overriden in FunctionsRouter.sol function _getSubscriptionDepositDetails() internal virtual returns (uint16, uint72); function _cancelSubscriptionHelper(uint64 subscriptionId, address toAddress, bool checkDepositRefundability) private { Subscription memory subscription = s_subscriptions[subscriptionId]; uint96 balance = subscription.balance; uint64 completedRequests = 0; // NOTE: loop iterations are bounded by config.maxConsumers // If no consumers, does nothing. for (uint256 i = 0; i < subscription.consumers.length; ++i) { address consumer = subscription.consumers[i]; completedRequests += s_consumers[consumer][subscriptionId].completedRequests; delete s_consumers[consumer][subscriptionId]; } delete s_subscriptions[subscriptionId]; (uint16 subscriptionDepositMinimumRequests, uint72 subscriptionDepositJuels) = _getSubscriptionDepositDetails(); // If subscription has not made enough requests, deposit will be forfeited if (checkDepositRefundability && completedRequests < subscriptionDepositMinimumRequests) { uint96 deposit = subscriptionDepositJuels > balance ? balance : subscriptionDepositJuels; if (deposit > 0) { s_withdrawableTokens[address(this)] += deposit; balance -= deposit; } } if (balance > 0) { s_totalLinkBalance -= balance; i_linkToken.safeTransfer(toAddress, uint256(balance)); } emit SubscriptionCanceled(subscriptionId, toAddress, balance); } /// @inheritdoc IFunctionsSubscriptions function cancelSubscription(uint64 subscriptionId, address to) external override { _whenNotPaused(); _onlySubscriptionOwner(subscriptionId); _onlySenderThatAcceptedToS(); if (pendingRequestExists(subscriptionId)) { revert CannotRemoveWithPendingRequests(); } _cancelSubscriptionHelper(subscriptionId, to, true); } /// @inheritdoc IFunctionsSubscriptions function pendingRequestExists(uint64 subscriptionId) public view override returns (bool) { address[] memory consumers = s_subscriptions[subscriptionId].consumers; // NOTE: loop iterations are bounded by config.maxConsumers for (uint256 i = 0; i < consumers.length; ++i) { Consumer memory consumer = s_consumers[consumers[i]][subscriptionId]; if (consumer.initiatedRequests != consumer.completedRequests) { return true; } } return false; } /// @inheritdoc IFunctionsSubscriptions function setFlags(uint64 subscriptionId, bytes32 flags) external override { _onlyRouterOwner(); _isExistingSubscription(subscriptionId); s_subscriptions[subscriptionId].flags = flags; } /// @inheritdoc IFunctionsSubscriptions function getFlags(uint64 subscriptionId) public view returns (bytes32) { return s_subscriptions[subscriptionId].flags; } // ================================================================ // | Request Timeout | // ================================================================ /// @inheritdoc IFunctionsSubscriptions function timeoutRequests(FunctionsResponse.Commitment[] calldata requestsToTimeoutByCommitment) external override { _whenNotPaused(); for (uint256 i = 0; i < requestsToTimeoutByCommitment.length; ++i) { FunctionsResponse.Commitment memory request = requestsToTimeoutByCommitment[i]; bytes32 requestId = request.requestId; uint64 subscriptionId = request.subscriptionId; // Check that request ID is valid if (keccak256(abi.encode(request)) != s_requestCommitments[requestId]) { revert InvalidCalldata(); } // Check that request has exceeded allowed request time if (block.timestamp < request.timeoutTimestamp) { revert TimeoutNotExceeded(); } // Notify the Coordinator that the request should no longer be fulfilled IFunctionsBilling(request.coordinator).deleteCommitment(requestId); // Release the subscription's balance that had been earmarked for the request s_subscriptions[subscriptionId].blockedBalance -= request.estimatedTotalCostJuels; s_consumers[request.client][subscriptionId].completedRequests += 1; // Delete commitment within Router state delete s_requestCommitments[requestId]; emit RequestTimedOut(requestId); } } // ================================================================ // | Modifiers | // ================================================================ function _onlySubscriptionOwner(uint64 subscriptionId) internal view { address owner = s_subscriptions[subscriptionId].owner; if (owner == address(0)) { revert InvalidSubscription(); } if (msg.sender != owner) { revert MustBeSubscriptionOwner(); } } /// @dev Overriden in FunctionsRouter.sol function _onlySenderThatAcceptedToS() internal virtual; /// @dev Overriden in FunctionsRouter.sol function _onlyRouterOwner() internal virtual; /// @dev Overriden in FunctionsRouter.sol function _whenNotPaused() internal virtual; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; import {IOwnableFunctionsRouter} from "./interfaces/IOwnableFunctionsRouter.sol"; /// @title This abstract should be inherited by contracts that will be used /// as the destinations to a route (id=>contract) on the Router. /// It provides a Router getter and modifiers. abstract contract Routable is ITypeAndVersion { IOwnableFunctionsRouter private immutable i_functionsRouter; error RouterMustBeSet(); error OnlyCallableByRouter(); error OnlyCallableByRouterOwner(); /// @dev Initializes the contract. constructor(address router) { if (router == address(0)) { revert RouterMustBeSet(); } i_functionsRouter = IOwnableFunctionsRouter(router); } /// @notice Return the Router function _getRouter() internal view returns (IOwnableFunctionsRouter router) { return i_functionsRouter; } /// @notice Reverts if called by anyone other than the router. modifier onlyRouter() { if (msg.sender != address(i_functionsRouter)) { revert OnlyCallableByRouter(); } _; } /// @notice Reverts if called by anyone other than the router owner. modifier onlyRouterOwner() { if (msg.sender != i_functionsRouter.owner()) { revert OnlyCallableByRouterOwner(); } _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {ITermsOfServiceAllowList, TermsOfServiceAllowListConfig} from "./interfaces/ITermsOfServiceAllowList.sol"; import {IAccessController} from "../../../../shared/interfaces/IAccessController.sol"; import {ITypeAndVersion} from "../../../../shared/interfaces/ITypeAndVersion.sol"; import {ConfirmedOwner} from "../../../../shared/access/ConfirmedOwner.sol"; import {Address} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/Address.sol"; import {EnumerableSet} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol"; /// @notice A contract to handle access control of subscription management dependent on signing a Terms of Service contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, ITypeAndVersion, ConfirmedOwner { using Address for address; using EnumerableSet for EnumerableSet.AddressSet; /// @inheritdoc ITypeAndVersion // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "Functions Terms of Service Allow List v1.1.0"; EnumerableSet.AddressSet private s_allowedSenders; EnumerableSet.AddressSet private s_blockedSenders; event AddedAccess(address user); event BlockedAccess(address user); event UnblockedAccess(address user); error InvalidSignature(); error InvalidUsage(); error RecipientIsBlocked(); error InvalidCalldata(); TermsOfServiceAllowListConfig private s_config; event ConfigUpdated(TermsOfServiceAllowListConfig config); // ================================================================ // | Initialization | // ================================================================ constructor( TermsOfServiceAllowListConfig memory config, address[] memory initialAllowedSenders, address[] memory initialBlockedSenders ) ConfirmedOwner(msg.sender) { updateConfig(config); for (uint256 i = 0; i < initialAllowedSenders.length; ++i) { s_allowedSenders.add(initialAllowedSenders[i]); } for (uint256 j = 0; j < initialBlockedSenders.length; ++j) { if (s_allowedSenders.contains(initialBlockedSenders[j])) { // Allowed senders cannot also be blocked revert InvalidCalldata(); } s_blockedSenders.add(initialBlockedSenders[j]); } } // ================================================================ // | Configuration | // ================================================================ /// @notice Gets the contracts's configuration /// @return config function getConfig() external view returns (TermsOfServiceAllowListConfig memory) { return s_config; } /// @notice Sets the contracts's configuration /// @param config - See the contents of the TermsOfServiceAllowListConfig struct in ITermsOfServiceAllowList.sol for more information function updateConfig(TermsOfServiceAllowListConfig memory config) public onlyOwner { s_config = config; emit ConfigUpdated(config); } // ================================================================ // | Allow methods | // ================================================================ /// @inheritdoc ITermsOfServiceAllowList function getMessage(address acceptor, address recipient) public pure override returns (bytes32) { return keccak256(abi.encodePacked(acceptor, recipient)); } /// @inheritdoc ITermsOfServiceAllowList function acceptTermsOfService(address acceptor, address recipient, bytes32 r, bytes32 s, uint8 v) external override { if (s_blockedSenders.contains(recipient)) { revert RecipientIsBlocked(); } // Validate that the signature is correct and the correct data has been signed bytes32 prefixedMessage = keccak256( abi.encodePacked("\x19Ethereum Signed Message:\n32", getMessage(acceptor, recipient)) ); if (ecrecover(prefixedMessage, v, r, s) != s_config.signerPublicKey) { revert InvalidSignature(); } // If contract, validate that msg.sender == recipient // This is to prevent EoAs from claiming contracts that they are not in control of // If EoA, validate that msg.sender == acceptor == recipient // This is to prevent EoAs from accepting for other EoAs if (msg.sender != recipient || (msg.sender != acceptor && !msg.sender.isContract())) { revert InvalidUsage(); } // Add recipient to the allow list if (s_allowedSenders.add(recipient)) { emit AddedAccess(recipient); } } /// @inheritdoc ITermsOfServiceAllowList function getAllAllowedSenders() external view override returns (address[] memory) { return s_allowedSenders.values(); } /// @inheritdoc ITermsOfServiceAllowList function getAllowedSendersCount() external view override returns (uint64) { return uint64(s_allowedSenders.length()); } /// @inheritdoc ITermsOfServiceAllowList function getAllowedSendersInRange( uint64 allowedSenderIdxStart, uint64 allowedSenderIdxEnd ) external view override returns (address[] memory allowedSenders) { if ( allowedSenderIdxStart > allowedSenderIdxEnd || allowedSenderIdxEnd >= s_allowedSenders.length() || s_allowedSenders.length() == 0 ) { revert InvalidCalldata(); } allowedSenders = new address[]((allowedSenderIdxEnd - allowedSenderIdxStart) + 1); for (uint256 i = 0; i <= allowedSenderIdxEnd - allowedSenderIdxStart; ++i) { allowedSenders[i] = s_allowedSenders.at(uint256(allowedSenderIdxStart + i)); } return allowedSenders; } /// @inheritdoc IAccessController function hasAccess(address user, bytes calldata /* data */) external view override returns (bool) { if (!s_config.enabled) { return true; } return s_allowedSenders.contains(user); } // ================================================================ // | Block methods | // ================================================================ /// @inheritdoc ITermsOfServiceAllowList function isBlockedSender(address sender) external view override returns (bool) { if (!s_config.enabled) { return false; } return s_blockedSenders.contains(sender); } /// @inheritdoc ITermsOfServiceAllowList function blockSender(address sender) external override onlyOwner { s_allowedSenders.remove(sender); s_blockedSenders.add(sender); emit BlockedAccess(sender); } /// @inheritdoc ITermsOfServiceAllowList function unblockSender(address sender) external override onlyOwner { s_blockedSenders.remove(sender); emit UnblockedAccess(sender); } /// @inheritdoc ITermsOfServiceAllowList function getBlockedSendersCount() external view override returns (uint64) { return uint64(s_blockedSenders.length()); } /// @inheritdoc ITermsOfServiceAllowList function getBlockedSendersInRange( uint64 blockedSenderIdxStart, uint64 blockedSenderIdxEnd ) external view override returns (address[] memory blockedSenders) { if ( blockedSenderIdxStart > blockedSenderIdxEnd || blockedSenderIdxEnd >= s_blockedSenders.length() || s_blockedSenders.length() == 0 ) { revert InvalidCalldata(); } blockedSenders = new address[]((blockedSenderIdxEnd - blockedSenderIdxStart) + 1); for (uint256 i = 0; i <= blockedSenderIdxEnd - blockedSenderIdxStart; ++i) { blockedSenders[i] = s_blockedSenders.at(uint256(blockedSenderIdxStart + i)); } return blockedSenders; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; /// @notice A contract to handle access control of subscription management dependent on signing a Terms of Service interface ITermsOfServiceAllowList { /// @notice Return the message data for the proof given to accept the Terms of Service /// @param acceptor - The wallet address that has accepted the Terms of Service on the UI /// @param recipient - The recipient address that the acceptor is taking responsibility for /// @return Hash of the message data function getMessage(address acceptor, address recipient) external pure returns (bytes32); /// @notice Check if the address is blocked for usage /// @param sender The transaction sender's address /// @return True or false function isBlockedSender(address sender) external returns (bool); /// @notice Get a list of all allowed senders /// @dev WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed /// to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that /// this function has an unbounded cost, and using it as part of a state-changing function may render the function /// uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. /// @return addresses - all allowed addresses function getAllAllowedSenders() external view returns (address[] memory); /// @notice Get details about the total number of allowed senders /// @return count - total number of allowed senders in the system function getAllowedSendersCount() external view returns (uint64); /// @notice Retrieve a list of allowed senders using an inclusive range /// @dev WARNING: getAllowedSendersInRange uses EnumerableSet .length() and .at() methods to iterate over the list /// without the need for an extra mapping. These method can not guarantee the ordering when new elements are added. /// Evaluate if eventual consistency will satisfy your usecase before using it. /// @param allowedSenderIdxStart - index of the allowed sender to start the range at /// @param allowedSenderIdxEnd - index of the allowed sender to end the range at /// @return allowedSenders - allowed addresses in the range provided function getAllowedSendersInRange( uint64 allowedSenderIdxStart, uint64 allowedSenderIdxEnd ) external view returns (address[] memory allowedSenders); /// @notice Allows access to the sender based on acceptance of the Terms of Service /// @param acceptor - The wallet address that has accepted the Terms of Service on the UI /// @param recipient - The recipient address that the acceptor is taking responsibility for /// @param r - ECDSA signature r data produced by the Chainlink Functions Subscription UI /// @param s - ECDSA signature s produced by the Chainlink Functions Subscription UI /// @param v - ECDSA signature v produced by the Chainlink Functions Subscription UI function acceptTermsOfService(address acceptor, address recipient, bytes32 r, bytes32 s, uint8 v) external; /// @notice Removes a sender's access if already authorized, and disallows re-accepting the Terms of Service /// @param sender - Address of the sender to block function blockSender(address sender) external; /// @notice Re-allows a previously blocked sender to accept the Terms of Service /// @param sender - Address of the sender to unblock function unblockSender(address sender) external; /// @notice Get details about the total number of blocked senders /// @return count - total number of blocked senders in the system function getBlockedSendersCount() external view returns (uint64); /// @notice Retrieve a list of blocked senders using an inclusive range /// @dev WARNING: getBlockedSendersInRange uses EnumerableSet .length() and .at() methods to iterate over the list /// without the need for an extra mapping. These method can not guarantee the ordering when new elements are added. /// Evaluate if eventual consistency will satisfy your usecase before using it. /// @param blockedSenderIdxStart - index of the blocked sender to start the range at /// @param blockedSenderIdxEnd - index of the blocked sender to end the range at /// @return blockedSenders - blocked addresses in the range provided function getBlockedSendersInRange( uint64 blockedSenderIdxStart, uint64 blockedSenderIdxEnd ) external view returns (address[] memory blockedSenders); } // ================================================================ // | Configuration state | // ================================================================ struct TermsOfServiceAllowListConfig { bool enabled; // ═════════════╗ When enabled, access will be checked against s_allowedSenders. When disabled, all access will be allowed. address signerPublicKey; // ══╝ The key pair that needs to sign the acceptance data }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {FunctionsClient} from "../FunctionsClient.sol"; import {ConfirmedOwner} from "../../../../shared/access/ConfirmedOwner.sol"; import {FunctionsRequest} from "../libraries/FunctionsRequest.sol"; /// @title Chainlink Functions example Client contract implementation contract FunctionsClientExample is FunctionsClient, ConfirmedOwner { using FunctionsRequest for FunctionsRequest.Request; uint32 public constant MAX_CALLBACK_GAS = 70_000; bytes32 public s_lastRequestId; bytes32 public s_lastResponse; bytes32 public s_lastError; uint32 public s_lastResponseLength; uint32 public s_lastErrorLength; error UnexpectedRequestID(bytes32 requestId); constructor(address router) FunctionsClient(router) ConfirmedOwner(msg.sender) {} /// @notice Send a simple request /// @param source JavaScript source code /// @param encryptedSecretsReferences Encrypted secrets payload /// @param args List of arguments accessible from within the source code /// @param subscriptionId Billing ID function sendRequest( string calldata source, bytes calldata encryptedSecretsReferences, string[] calldata args, uint64 subscriptionId, bytes32 jobId ) external onlyOwner { FunctionsRequest.Request memory req; req._initializeRequestForInlineJavaScript(source); if (encryptedSecretsReferences.length > 0) req._addSecretsReference(encryptedSecretsReferences); if (args.length > 0) req._setArgs(args); s_lastRequestId = _sendRequest(req._encodeCBOR(), subscriptionId, MAX_CALLBACK_GAS, jobId); } /// @notice Store latest result/error /// @param requestId The request ID, returned by sendRequest() /// @param response Aggregated response from the user code /// @param err Aggregated error from the user code or from the execution pipeline /// @dev Either response or error parameter will be set, but never both function _fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal override { if (s_lastRequestId != requestId) { revert UnexpectedRequestID(requestId); } // Save only the first 32 bytes of response/error to always fit within MAX_CALLBACK_GAS s_lastResponse = _bytesToBytes32(response); s_lastResponseLength = uint32(response.length); s_lastError = _bytesToBytes32(err); s_lastErrorLength = uint32(err.length); } function _bytesToBytes32(bytes memory b) private pure returns (bytes32 out) { uint256 maxLen = 32; if (b.length < 32) { maxLen = b.length; } for (uint256 i = 0; i < maxLen; ++i) { out |= bytes32(b[i]) >> (i * 8); } return out; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; /// @title Chainlink Functions DON billing interface. interface IFunctionsBilling { /// @notice Return the current conversion from WEI of ETH to LINK from the configured Chainlink data feed /// @return weiPerUnitLink - The amount of WEI in one LINK function getWeiPerUnitLink() external view returns (uint256); /// @notice Return the current conversion from LINK to USD from the configured Chainlink data feed /// @return weiPerUnitLink - The amount of USD that one LINK is worth /// @return decimals - The number of decimals that should be represented in the price feed's response function getUsdPerUnitLink() external view returns (uint256, uint8); /// @notice Determine the fee that will be split between Node Operators for servicing a request /// @param requestCBOR - CBOR encoded Chainlink Functions request data, use FunctionsRequest library to encode a request /// @return fee - Cost in Juels (1e18) of LINK function getDONFeeJuels(bytes memory requestCBOR) external view returns (uint72); /// @notice Determine the fee that will be paid to the Coordinator owner for operating the network /// @return fee - Cost in Juels (1e18) of LINK function getOperationFeeJuels() external view returns (uint72); /// @notice Determine the fee that will be paid to the Router owner for operating the network /// @return fee - Cost in Juels (1e18) of LINK function getAdminFeeJuels() external view returns (uint72); /// @notice Estimate the total cost that will be charged to a subscription to make a request: transmitter gas re-reimbursement, plus DON fee, plus Registry fee /// @param - subscriptionId An identifier of the billing account /// @param - data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request /// @param - callbackGasLimit Gas limit for the fulfillment callback /// @param - gasPriceWei The blockchain's gas price to estimate with /// @return - billedCost Cost in Juels (1e18) of LINK function estimateCost( uint64 subscriptionId, bytes calldata data, uint32 callbackGasLimit, uint256 gasPriceWei ) external view returns (uint96); /// @notice Remove a request commitment that the Router has determined to be stale /// @param requestId - The request ID to remove function deleteCommitment(bytes32 requestId) external; /// @notice Oracle withdraw LINK earned through fulfilling requests /// @notice If amount is 0 the full balance will be withdrawn /// @param recipient where to send the funds /// @param amount amount to withdraw function oracleWithdraw(address recipient, uint96 amount) external; /// @notice Withdraw all LINK earned by Oracles through fulfilling requests /// @dev transmitter addresses must support LINK tokens to avoid tokens from getting stuck as oracleWithdrawAll() calls will forward tokens directly to transmitters function oracleWithdrawAll() external; } // ================================================================ // | Configuration state | // ================================================================ struct FunctionsBillingConfig { uint32 fulfillmentGasPriceOverEstimationBP; // ══╗ Percentage of gas price overestimation to account for changes in gas price between request and response. Held as basis points (one hundredth of 1 percentage point) uint32 feedStalenessSeconds; // ║ How long before we consider the feed price to be stale and fallback to fallbackNativePerUnitLink. uint32 gasOverheadBeforeCallback; // ║ Represents the average gas execution cost before the fulfillment callback. This amount is always billed for every request. uint32 gasOverheadAfterCallback; // ║ Represents the average gas execution cost after the fulfillment callback. This amount is always billed for every request. uint40 minimumEstimateGasPriceWei; // ║ The lowest amount of wei that will be used as the tx.gasprice when estimating the cost to fulfill the request uint16 maxSupportedRequestDataVersion; // ║ The highest support request data version supported by the node. All lower versions should also be supported. uint64 fallbackUsdPerUnitLink; // ║ Fallback LINK / USD conversion rate if the data feed is stale uint8 fallbackUsdPerUnitLinkDecimals; // ════════╝ Fallback LINK / USD conversion rate decimal places if the data feed is stale uint224 fallbackNativePerUnitLink; // ═══════════╗ Fallback NATIVE CURRENCY / LINK conversion rate if the data feed is stale uint32 requestTimeoutSeconds; // ════════════════╝ How many seconds it takes before we consider a request to be timed out uint16 donFeeCentsUsd; // ═══════════════════════════════╗ Additional flat fee (denominated in cents of USD, paid as LINK) that will be split between Node Operators. uint16 operationFeeCentsUsd; // ═════════════════════════╝ Additional flat fee (denominated in cents of USD, paid as LINK) that will be paid to the owner of the Coordinator contract. }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; /// @title Chainlink Functions client interface. interface IFunctionsClient { /// @notice Chainlink Functions response handler called by the Functions Router /// during fullilment from the designated transmitter node in an OCR round. /// @param requestId The requestId returned by FunctionsClient.sendRequest(). /// @param response Aggregated response from the request's source code. /// @param err Aggregated error either from the request's source code or from the execution pipeline. /// @dev Either response or error parameter will be set, but never both. function handleOracleFulfillment(bytes32 requestId, bytes memory response, bytes memory err) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {FunctionsResponse} from "../libraries/FunctionsResponse.sol"; /// @title Chainlink Functions DON Coordinator interface. interface IFunctionsCoordinator { /// @notice Returns the DON's threshold encryption public key used to encrypt secrets /// @dev All nodes on the DON have separate key shares of the threshold decryption key /// and nodes must participate in a threshold decryption OCR round to decrypt secrets /// @return thresholdPublicKey the DON's threshold encryption public key function getThresholdPublicKey() external view returns (bytes memory); /// @notice Sets the DON's threshold encryption public key used to encrypt secrets /// @dev Used to rotate the key /// @param thresholdPublicKey The new public key function setThresholdPublicKey(bytes calldata thresholdPublicKey) external; /// @notice Returns the DON's secp256k1 public key that is used to encrypt secrets /// @dev All nodes on the DON have the corresponding private key /// needed to decrypt the secrets encrypted with the public key /// @return publicKey the DON's public key function getDONPublicKey() external view returns (bytes memory); /// @notice Sets DON's secp256k1 public key used to encrypt secrets /// @dev Used to rotate the key /// @param donPublicKey The new public key function setDONPublicKey(bytes calldata donPublicKey) external; /// @notice Receives a request to be emitted to the DON for processing /// @param request The request metadata /// @dev see the struct for field descriptions /// @return commitment - The parameters of the request that must be held consistent at response time function startRequest( FunctionsResponse.RequestMeta calldata request ) external returns (FunctionsResponse.Commitment memory commitment); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {FunctionsResponse} from "../libraries/FunctionsResponse.sol"; /// @title Chainlink Functions Router interface. interface IFunctionsRouter { /// @notice The identifier of the route to retrieve the address of the access control contract /// The access control contract controls which accounts can manage subscriptions /// @return id - bytes32 id that can be passed to the "getContractById" of the Router function getAllowListId() external view returns (bytes32); /// @notice Set the identifier of the route to retrieve the address of the access control contract /// The access control contract controls which accounts can manage subscriptions function setAllowListId(bytes32 allowListId) external; /// @notice Get the flat fee (in Juels of LINK) that will be paid to the Router owner for operation of the network /// @return adminFee function getAdminFee() external view returns (uint72 adminFee); /// @notice Sends a request using the provided subscriptionId /// @param subscriptionId - A unique subscription ID allocated by billing system, /// a client can make requests from different contracts referencing the same subscription /// @param data - CBOR encoded Chainlink Functions request data, use FunctionsClient API to encode a request /// @param dataVersion - Gas limit for the fulfillment callback /// @param callbackGasLimit - Gas limit for the fulfillment callback /// @param donId - An identifier used to determine which route to send the request along /// @return requestId - A unique request identifier function sendRequest( uint64 subscriptionId, bytes calldata data, uint16 dataVersion, uint32 callbackGasLimit, bytes32 donId ) external returns (bytes32); /// @notice Sends a request to the proposed contracts /// @param subscriptionId - A unique subscription ID allocated by billing system, /// a client can make requests from different contracts referencing the same subscription /// @param data - CBOR encoded Chainlink Functions request data, use FunctionsClient API to encode a request /// @param dataVersion - Gas limit for the fulfillment callback /// @param callbackGasLimit - Gas limit for the fulfillment callback /// @param donId - An identifier used to determine which route to send the request along /// @return requestId - A unique request identifier function sendRequestToProposed( uint64 subscriptionId, bytes calldata data, uint16 dataVersion, uint32 callbackGasLimit, bytes32 donId ) external returns (bytes32); /// @notice Fulfill the request by: /// - calling back the data that the Oracle returned to the client contract /// - pay the DON for processing the request /// @dev Only callable by the Coordinator contract that is saved in the commitment /// @param response response data from DON consensus /// @param err error from DON consensus /// @param juelsPerGas - current rate of juels/gas /// @param costWithoutFulfillment - The cost of processing the request (in Juels of LINK ), without fulfillment /// @param transmitter - The Node that transmitted the OCR report /// @param commitment - The parameters of the request that must be held consistent between request and response time /// @return fulfillResult - /// @return callbackGasCostJuels - function fulfill( bytes memory response, bytes memory err, uint96 juelsPerGas, uint96 costWithoutFulfillment, address transmitter, FunctionsResponse.Commitment memory commitment ) external returns (FunctionsResponse.FulfillResult, uint96); /// @notice Validate requested gas limit is below the subscription max. /// @param subscriptionId subscription ID /// @param callbackGasLimit desired callback gas limit function isValidCallbackGasLimit(uint64 subscriptionId, uint32 callbackGasLimit) external view; /// @notice Get the current contract given an ID /// @param id A bytes32 identifier for the route /// @return contract The current contract address function getContractById(bytes32 id) external view returns (address); /// @notice Get the proposed next contract given an ID /// @param id A bytes32 identifier for the route /// @return contract The current or proposed contract address function getProposedContractById(bytes32 id) external view returns (address); /// @notice Return the latest proprosal set /// @return ids The identifiers of the contracts to update /// @return to The addresses of the contracts that will be updated to function getProposedContractSet() external view returns (bytes32[] memory, address[] memory); /// @notice Proposes one or more updates to the contract routes /// @dev Only callable by owner function proposeContractsUpdate(bytes32[] memory proposalSetIds, address[] memory proposalSetAddresses) external; /// @notice Updates the current contract routes to the proposed contracts /// @dev Only callable by owner function updateContracts() external; /// @dev Puts the system into an emergency stopped state. /// @dev Only callable by owner function pause() external; /// @dev Takes the system out of an emergency stopped state. /// @dev Only callable by owner function unpause() external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {FunctionsResponse} from "../libraries/FunctionsResponse.sol"; /// @title Chainlink Functions Subscription interface. interface IFunctionsSubscriptions { struct Subscription { uint96 balance; // ═════════╗ Common LINK balance that is controlled by the Router to be used for all consumer requests. address owner; // ══════════╝ The owner can fund/withdraw/cancel the subscription. uint96 blockedBalance; // ══╗ LINK balance that is reserved to pay for pending consumer requests. address proposedOwner; // ══╝ For safely transferring sub ownership. address[] consumers; // ════╸ Client contracts that can use the subscription bytes32 flags; // ══════════╸ Per-subscription flags } struct Consumer { bool allowed; // ══════════════╗ Owner can fund/withdraw/cancel the sub. uint64 initiatedRequests; // ║ The number of requests that have been started uint64 completedRequests; // ══╝ The number of requests that have successfully completed or timed out } /// @notice Get details about a subscription. /// @param subscriptionId - the ID of the subscription /// @return subscription - see IFunctionsSubscriptions.Subscription for more information on the structure function getSubscription(uint64 subscriptionId) external view returns (Subscription memory); /// @notice Retrieve details about multiple subscriptions using an inclusive range /// @param subscriptionIdStart - the ID of the subscription to start the range at /// @param subscriptionIdEnd - the ID of the subscription to end the range at /// @return subscriptions - see IFunctionsSubscriptions.Subscription for more information on the structure function getSubscriptionsInRange( uint64 subscriptionIdStart, uint64 subscriptionIdEnd ) external view returns (Subscription[] memory); /// @notice Get details about a consumer of a subscription. /// @param client - the consumer contract address /// @param subscriptionId - the ID of the subscription /// @return consumer - see IFunctionsSubscriptions.Consumer for more information on the structure function getConsumer(address client, uint64 subscriptionId) external view returns (Consumer memory); /// @notice Get details about the total amount of LINK within the system /// @return totalBalance - total Juels of LINK held by the contract function getTotalBalance() external view returns (uint96); /// @notice Get details about the total number of subscription accounts /// @return count - total number of subscriptions in the system function getSubscriptionCount() external view returns (uint64); /// @notice Time out all expired requests: unlocks funds and removes the ability for the request to be fulfilled /// @param requestsToTimeoutByCommitment - A list of request commitments to time out /// @dev The commitment can be found on the "OracleRequest" event created when sending the request. function timeoutRequests(FunctionsResponse.Commitment[] calldata requestsToTimeoutByCommitment) external; /// @notice Oracle withdraw LINK earned through fulfilling requests /// @notice If amount is 0 the full balance will be withdrawn /// @notice Both signing and transmitting wallets will have a balance to withdraw /// @param recipient where to send the funds /// @param amount amount to withdraw function oracleWithdraw(address recipient, uint96 amount) external; /// @notice Owner cancel subscription, sends remaining link directly to the subscription owner. /// @dev Only callable by the Router Owner /// @param subscriptionId subscription id /// @dev notably can be called even if there are pending requests, outstanding ones may fail onchain function ownerCancelSubscription(uint64 subscriptionId) external; /// @notice Recover link sent with transfer instead of transferAndCall. /// @dev Only callable by the Router Owner /// @param to address to send link to function recoverFunds(address to) external; /// @notice Create a new subscription. /// @return subscriptionId - A unique subscription id. /// @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. /// @dev Note to fund the subscription, use transferAndCall. For example /// @dev LINKTOKEN.transferAndCall( /// @dev address(ROUTER), /// @dev amount, /// @dev abi.encode(subscriptionId)); function createSubscription() external returns (uint64); /// @notice Create a new subscription and add a consumer. /// @return subscriptionId - A unique subscription id. /// @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. /// @dev Note to fund the subscription, use transferAndCall. For example /// @dev LINKTOKEN.transferAndCall( /// @dev address(ROUTER), /// @dev amount, /// @dev abi.encode(subscriptionId)); function createSubscriptionWithConsumer(address consumer) external returns (uint64 subscriptionId); /// @notice Propose a new owner for a subscription. /// @dev Only callable by the Subscription's owner /// @param subscriptionId - ID of the subscription /// @param newOwner - proposed new owner of the subscription function proposeSubscriptionOwnerTransfer(uint64 subscriptionId, address newOwner) external; /// @notice Accept an ownership transfer. /// @param subscriptionId - ID of the subscription /// @dev will revert if original owner of subscriptionId has not requested that msg.sender become the new owner. function acceptSubscriptionOwnerTransfer(uint64 subscriptionId) external; /// @notice Remove a consumer from a Chainlink Functions subscription. /// @dev Only callable by the Subscription's owner /// @param subscriptionId - ID of the subscription /// @param consumer - Consumer to remove from the subscription function removeConsumer(uint64 subscriptionId, address consumer) external; /// @notice Add a consumer to a Chainlink Functions subscription. /// @dev Only callable by the Subscription's owner /// @param subscriptionId - ID of the subscription /// @param consumer - New consumer which can use the subscription function addConsumer(uint64 subscriptionId, address consumer) external; /// @notice Cancel a subscription /// @dev Only callable by the Subscription's owner /// @param subscriptionId - ID of the subscription /// @param to - Where to send the remaining LINK to function cancelSubscription(uint64 subscriptionId, address to) external; /// @notice Check to see if there exists a request commitment for all consumers for a given sub. /// @param subscriptionId - ID of the subscription /// @return true if there exists at least one unfulfilled request for the subscription, false otherwise. /// @dev Looping is bounded to MAX_CONSUMERS*(number of DONs). /// @dev Used to disable subscription canceling while outstanding request are present. function pendingRequestExists(uint64 subscriptionId) external view returns (bool); /// @notice Set subscription specific flags for a subscription. /// Each byte of the flag is used to represent a resource tier that the subscription can utilize. /// @param subscriptionId - ID of the subscription /// @param flags - desired flag values function setFlags(uint64 subscriptionId, bytes32 flags) external; /// @notice Get flags for a given subscription. /// @param subscriptionId - ID of the subscription /// @return flags - current flag values function getFlags(uint64 subscriptionId) external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {IFunctionsRouter} from "./IFunctionsRouter.sol"; import {IOwnable} from "../../../../shared/interfaces/IOwnable.sol"; /// @title Chainlink Functions Router interface with Ownability. interface IOwnableFunctionsRouter is IOwnable, IFunctionsRouter {}
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {ArbGasInfo} from "../../../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbGasInfo.sol"; import {GasPriceOracle} from "../../../../vendor/@eth-optimism/contracts-bedrock/v0.16.2/src/L2/GasPriceOracle.sol"; /// @dev A library that abstracts out opcodes that behave differently across chains. /// @dev The methods below return values that are pertinent to the given chain. library ChainSpecificUtil { // ------------ Start Arbitrum Constants ------------ /// @dev ARBGAS_ADDR is the address of the ArbGasInfo precompile on Arbitrum. /// @dev reference: https://github.com/OffchainLabs/nitro/blob/v2.0.14/contracts/src/precompiles/ArbGasInfo.sol#L10 address private constant ARBGAS_ADDR = address(0x000000000000000000000000000000000000006C); ArbGasInfo private constant ARBGAS = ArbGasInfo(ARBGAS_ADDR); uint256 private constant ARB_MAINNET_CHAIN_ID = 42161; uint256 private constant ARB_GOERLI_TESTNET_CHAIN_ID = 421613; uint256 private constant ARB_SEPOLIA_TESTNET_CHAIN_ID = 421614; // ------------ End Arbitrum Constants ------------ // ------------ Start Optimism Constants ------------ /// @dev L1_FEE_DATA_PADDING includes 35 bytes for L1 data padding for Optimism bytes internal constant L1_FEE_DATA_PADDING = "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; /// @dev OVM_GASPRICEORACLE_ADDR is the address of the GasPriceOracle precompile on Optimism. /// @dev reference: https://community.optimism.io/docs/developers/build/transaction-fees/#estimating-the-l1-data-fee address private constant OVM_GASPRICEORACLE_ADDR = address(0x420000000000000000000000000000000000000F); GasPriceOracle private constant OVM_GASPRICEORACLE = GasPriceOracle(OVM_GASPRICEORACLE_ADDR); uint256 private constant OP_MAINNET_CHAIN_ID = 10; uint256 private constant OP_GOERLI_CHAIN_ID = 420; uint256 private constant OP_SEPOLIA_CHAIN_ID = 11155420; /// @dev Base is a OP stack based rollup and follows the same L1 pricing logic as Optimism. uint256 private constant BASE_MAINNET_CHAIN_ID = 8453; uint256 private constant BASE_GOERLI_CHAIN_ID = 84531; uint256 private constant BASE_SEPOLIA_CHAIN_ID = 84532; // ------------ End Optimism Constants ------------ /// @notice Returns the L1 fees in wei that will be paid for the current transaction, given any calldata /// @notice for the current transaction. /// @notice When on a known Arbitrum chain, it uses ArbGas.getCurrentTxL1GasFees to get the fees. /// @notice On Arbitrum, the provided calldata is not used to calculate the fees. /// @notice On Optimism, the provided calldata is passed to the GasPriceOracle predeploy /// @notice and getL1Fee is called to get the fees. function _getCurrentTxL1GasFees(bytes memory txCallData) internal view returns (uint256 l1FeeWei) { uint256 chainid = block.chainid; if (_isArbitrumChainId(chainid)) { return ARBGAS.getCurrentTxL1GasFees(); } else if (_isOptimismChainId(chainid)) { return OVM_GASPRICEORACLE.getL1Fee(bytes.concat(txCallData, L1_FEE_DATA_PADDING)); } return 0; } /// @notice Return true if and only if the provided chain ID is an Arbitrum chain ID. function _isArbitrumChainId(uint256 chainId) internal pure returns (bool) { return chainId == ARB_MAINNET_CHAIN_ID || chainId == ARB_GOERLI_TESTNET_CHAIN_ID || chainId == ARB_SEPOLIA_TESTNET_CHAIN_ID; } /// @notice Return true if and only if the provided chain ID is an Optimism (or Base) chain ID. /// @notice Note that optimism chain id's are also OP stack chain id's. function _isOptimismChainId(uint256 chainId) internal pure returns (bool) { return chainId == OP_MAINNET_CHAIN_ID || chainId == OP_GOERLI_CHAIN_ID || chainId == OP_SEPOLIA_CHAIN_ID || chainId == BASE_MAINNET_CHAIN_ID || chainId == BASE_GOERLI_CHAIN_ID || chainId == BASE_SEPOLIA_CHAIN_ID; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {CBOR} from "../../../../vendor/solidity-cborutils/v2.0.0/CBOR.sol"; /// @title Library for encoding the input data of a Functions request into CBOR library FunctionsRequest { using CBOR for CBOR.CBORBuffer; uint16 public constant REQUEST_DATA_VERSION = 1; uint256 internal constant DEFAULT_BUFFER_SIZE = 256; enum Location { Inline, // Provided within the Request Remote, // Hosted through remote location that can be accessed through a provided URL DONHosted // Hosted on the DON's storage } enum CodeLanguage { JavaScript // In future version we may add other languages } struct Request { Location codeLocation; // ════════════╸ The location of the source code that will be executed on each node in the DON Location secretsLocation; // ═════════╸ The location of secrets that will be passed into the source code. *Only Remote secrets are supported CodeLanguage language; // ════════════╸ The coding language that the source code is written in string source; // ════════════════════╸ Raw source code for Request.codeLocation of Location.Inline, URL for Request.codeLocation of Location.Remote, or slot decimal number for Request.codeLocation of Location.DONHosted bytes encryptedSecretsReference; // ══╸ Encrypted URLs for Request.secretsLocation of Location.Remote (use addSecretsReference()), or CBOR encoded slotid+version for Request.secretsLocation of Location.DONHosted (use addDONHostedSecrets()) string[] args; // ════════════════════╸ String arguments that will be passed into the source code bytes[] bytesArgs; // ════════════════╸ Bytes arguments that will be passed into the source code } error EmptySource(); error EmptySecrets(); error EmptyArgs(); error NoInlineSecrets(); /// @notice Encodes a Request to CBOR encoded bytes /// @param self The request to encode /// @return CBOR encoded bytes function _encodeCBOR(Request memory self) internal pure returns (bytes memory) { CBOR.CBORBuffer memory buffer = CBOR.create(DEFAULT_BUFFER_SIZE); buffer.writeString("codeLocation"); buffer.writeUInt256(uint256(self.codeLocation)); buffer.writeString("language"); buffer.writeUInt256(uint256(self.language)); buffer.writeString("source"); buffer.writeString(self.source); if (self.args.length > 0) { buffer.writeString("args"); buffer.startArray(); for (uint256 i = 0; i < self.args.length; ++i) { buffer.writeString(self.args[i]); } buffer.endSequence(); } if (self.encryptedSecretsReference.length > 0) { if (self.secretsLocation == Location.Inline) { revert NoInlineSecrets(); } buffer.writeString("secretsLocation"); buffer.writeUInt256(uint256(self.secretsLocation)); buffer.writeString("secrets"); buffer.writeBytes(self.encryptedSecretsReference); } if (self.bytesArgs.length > 0) { buffer.writeString("bytesArgs"); buffer.startArray(); for (uint256 i = 0; i < self.bytesArgs.length; ++i) { buffer.writeBytes(self.bytesArgs[i]); } buffer.endSequence(); } return buffer.buf.buf; } /// @notice Initializes a Chainlink Functions Request /// @dev Sets the codeLocation and code on the request /// @param self The uninitialized request /// @param codeLocation The user provided source code location /// @param language The programming language of the user code /// @param source The user provided source code or a url function _initializeRequest( Request memory self, Location codeLocation, CodeLanguage language, string memory source ) internal pure { if (bytes(source).length == 0) revert EmptySource(); self.codeLocation = codeLocation; self.language = language; self.source = source; } /// @notice Initializes a Chainlink Functions Request /// @dev Simplified version of initializeRequest for PoC /// @param self The uninitialized request /// @param javaScriptSource The user provided JS code (must not be empty) function _initializeRequestForInlineJavaScript(Request memory self, string memory javaScriptSource) internal pure { _initializeRequest(self, Location.Inline, CodeLanguage.JavaScript, javaScriptSource); } /// @notice Adds Remote user encrypted secrets to a Request /// @param self The initialized request /// @param encryptedSecretsReference Encrypted comma-separated string of URLs pointing to off-chain secrets function _addSecretsReference(Request memory self, bytes memory encryptedSecretsReference) internal pure { if (encryptedSecretsReference.length == 0) revert EmptySecrets(); self.secretsLocation = Location.Remote; self.encryptedSecretsReference = encryptedSecretsReference; } /// @notice Adds DON-hosted secrets reference to a Request /// @param self The initialized request /// @param slotID Slot ID of the user's secrets hosted on DON /// @param version User data version (for the slotID) function _addDONHostedSecrets(Request memory self, uint8 slotID, uint64 version) internal pure { CBOR.CBORBuffer memory buffer = CBOR.create(DEFAULT_BUFFER_SIZE); buffer.writeString("slotID"); buffer.writeUInt64(slotID); buffer.writeString("version"); buffer.writeUInt64(version); self.secretsLocation = Location.DONHosted; self.encryptedSecretsReference = buffer.buf.buf; } /// @notice Sets args for the user run function /// @param self The initialized request /// @param args The array of string args (must not be empty) function _setArgs(Request memory self, string[] memory args) internal pure { if (args.length == 0) revert EmptyArgs(); self.args = args; } /// @notice Sets bytes args for the user run function /// @param self The initialized request /// @param args The array of bytes args (must not be empty) function _setBytesArgs(Request memory self, bytes[] memory args) internal pure { if (args.length == 0) revert EmptyArgs(); self.bytesArgs = args; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; /// @title Library of types that are used for fulfillment of a Functions request library FunctionsResponse { // Used to send request information from the Router to the Coordinator struct RequestMeta { bytes data; // ══════════════════╸ CBOR encoded Chainlink Functions request data, use FunctionsRequest library to encode a request bytes32 flags; // ═══════════════╸ Per-subscription flags address requestingContract; // ══╗ The client contract that is sending the request uint96 availableBalance; // ═════╝ Common LINK balance of the subscription that is controlled by the Router to be used for all consumer requests. uint72 adminFee; // ═════════════╗ Flat fee (in Juels of LINK) that will be paid to the Router Owner for operation of the network uint64 subscriptionId; // ║ Identifier of the billing subscription that will be charged for the request uint64 initiatedRequests; // ║ The number of requests that have been started uint32 callbackGasLimit; // ║ The amount of gas that the callback to the consuming contract will be given uint16 dataVersion; // ══════════╝ The version of the structure of the CBOR encoded request data uint64 completedRequests; // ════╗ The number of requests that have successfully completed or timed out address subscriptionOwner; // ═══╝ The owner of the billing subscription } enum FulfillResult { FULFILLED, // 0 USER_CALLBACK_ERROR, // 1 INVALID_REQUEST_ID, // 2 COST_EXCEEDS_COMMITMENT, // 3 INSUFFICIENT_GAS_PROVIDED, // 4 SUBSCRIPTION_BALANCE_INVARIANT_VIOLATION, // 5 INVALID_COMMITMENT // 6 } struct Commitment { bytes32 requestId; // ═════════════════╸ A unique identifier for a Chainlink Functions request address coordinator; // ═══════════════╗ The Coordinator contract that manages the DON that is servicing a request uint96 estimatedTotalCostJuels; // ════╝ The maximum cost in Juels (1e18) of LINK that will be charged to fulfill a request address client; // ════════════════════╗ The client contract that sent the request uint64 subscriptionId; // ║ Identifier of the billing subscription that will be charged for the request uint32 callbackGasLimit; // ═══════════╝ The amount of gas that the callback to the consuming contract will be given uint72 adminFee; // ═══════════════════╗ Flat fee (in Juels of LINK) that will be paid to the Router Owner for operation of the network uint72 donFee; // ║ Fee (in Juels of LINK) that will be split between Node Operators for servicing a request uint40 gasOverheadBeforeCallback; // ║ Represents the average gas execution cost before the fulfillment callback. uint40 gasOverheadAfterCallback; // ║ Represents the average gas execution cost after the fulfillment callback. uint32 timeoutTimestamp; // ═══════════╝ The timestamp at which a request will be eligible to be timed out } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; contract FunctionsV1EventsMock { struct Config { uint16 maxConsumersPerSubscription; uint72 adminFee; bytes4 handleOracleFulfillmentSelector; uint16 gasForCallExactCheck; uint32[] maxCallbackGasLimits; } event ConfigUpdated(Config param1); event ContractProposed( bytes32 proposedContractSetId, address proposedContractSetFromAddress, address proposedContractSetToAddress ); event ContractUpdated(bytes32 id, address from, address to); event FundsRecovered(address to, uint256 amount); event OwnershipTransferRequested(address indexed from, address indexed to); event OwnershipTransferred(address indexed from, address indexed to); event Paused(address account); event RequestNotProcessed(bytes32 indexed requestId, address coordinator, address transmitter, uint8 resultCode); event RequestProcessed( bytes32 indexed requestId, uint64 indexed subscriptionId, uint96 totalCostJuels, address transmitter, uint8 resultCode, bytes response, bytes err, bytes callbackReturnData ); event RequestStart( bytes32 indexed requestId, bytes32 indexed donId, uint64 indexed subscriptionId, address subscriptionOwner, address requestingContract, address requestInitiator, bytes data, uint16 dataVersion, uint32 callbackGasLimit, uint96 estimatedTotalCostJuels ); event RequestTimedOut(bytes32 indexed requestId); event SubscriptionCanceled(uint64 indexed subscriptionId, address fundsRecipient, uint256 fundsAmount); event SubscriptionConsumerAdded(uint64 indexed subscriptionId, address consumer); event SubscriptionConsumerRemoved(uint64 indexed subscriptionId, address consumer); event SubscriptionCreated(uint64 indexed subscriptionId, address owner); event SubscriptionFunded(uint64 indexed subscriptionId, uint256 oldBalance, uint256 newBalance); event SubscriptionOwnerTransferRequested(uint64 indexed subscriptionId, address from, address to); event SubscriptionOwnerTransferred(uint64 indexed subscriptionId, address from, address to); event Unpaused(address account); function emitConfigUpdated(Config memory param1) public { emit ConfigUpdated(param1); } function emitContractProposed( bytes32 proposedContractSetId, address proposedContractSetFromAddress, address proposedContractSetToAddress ) public { emit ContractProposed(proposedContractSetId, proposedContractSetFromAddress, proposedContractSetToAddress); } function emitContractUpdated(bytes32 id, address from, address to) public { emit ContractUpdated(id, from, to); } function emitFundsRecovered(address to, uint256 amount) public { emit FundsRecovered(to, amount); } function emitOwnershipTransferRequested(address from, address to) public { emit OwnershipTransferRequested(from, to); } function emitOwnershipTransferred(address from, address to) public { emit OwnershipTransferred(from, to); } function emitPaused(address account) public { emit Paused(account); } function emitRequestNotProcessed( bytes32 requestId, address coordinator, address transmitter, uint8 resultCode ) public { emit RequestNotProcessed(requestId, coordinator, transmitter, resultCode); } function emitRequestProcessed( bytes32 requestId, uint64 subscriptionId, uint96 totalCostJuels, address transmitter, uint8 resultCode, bytes memory response, bytes memory err, bytes memory callbackReturnData ) public { emit RequestProcessed( requestId, subscriptionId, totalCostJuels, transmitter, resultCode, response, err, callbackReturnData ); } function emitRequestStart( bytes32 requestId, bytes32 donId, uint64 subscriptionId, address subscriptionOwner, address requestingContract, address requestInitiator, bytes memory data, uint16 dataVersion, uint32 callbackGasLimit, uint96 estimatedTotalCostJuels ) public { emit RequestStart( requestId, donId, subscriptionId, subscriptionOwner, requestingContract, requestInitiator, data, dataVersion, callbackGasLimit, estimatedTotalCostJuels ); } function emitRequestTimedOut(bytes32 requestId) public { emit RequestTimedOut(requestId); } function emitSubscriptionCanceled(uint64 subscriptionId, address fundsRecipient, uint256 fundsAmount) public { emit SubscriptionCanceled(subscriptionId, fundsRecipient, fundsAmount); } function emitSubscriptionConsumerAdded(uint64 subscriptionId, address consumer) public { emit SubscriptionConsumerAdded(subscriptionId, consumer); } function emitSubscriptionConsumerRemoved(uint64 subscriptionId, address consumer) public { emit SubscriptionConsumerRemoved(subscriptionId, consumer); } function emitSubscriptionCreated(uint64 subscriptionId, address owner) public { emit SubscriptionCreated(subscriptionId, owner); } function emitSubscriptionFunded(uint64 subscriptionId, uint256 oldBalance, uint256 newBalance) public { emit SubscriptionFunded(subscriptionId, oldBalance, newBalance); } function emitSubscriptionOwnerTransferRequested(uint64 subscriptionId, address from, address to) public { emit SubscriptionOwnerTransferRequested(subscriptionId, from, to); } function emitSubscriptionOwnerTransferred(uint64 subscriptionId, address from, address to) public { emit SubscriptionOwnerTransferred(subscriptionId, from, to); } function emitUnpaused(address account) public { emit Unpaused(account); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {ITypeAndVersion} from "../../../../shared/interfaces/ITypeAndVersion.sol"; abstract contract OCR2Abstract is ITypeAndVersion { // Maximum number of oracles the offchain reporting protocol is designed for uint256 internal constant MAX_NUM_ORACLES = 31; /** * @notice triggers a new run of the offchain reporting protocol * @param previousConfigBlockNumber block in which the previous config was set, to simplify historic analysis * @param configDigest configDigest of this configuration * @param configCount ordinal number of this config setting among all config settings over the life of this contract * @param signers ith element is address ith oracle uses to sign a report * @param transmitters ith element is address ith oracle uses to transmit a report via the transmit method * @param f maximum number of faulty/dishonest oracles the protocol can tolerate while still working correctly * @param onchainConfig serialized configuration used by the contract (and possibly oracles) * @param offchainConfigVersion version of the serialization format used for "offchainConfig" parameter * @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract */ event ConfigSet( uint32 previousConfigBlockNumber, bytes32 configDigest, uint64 configCount, address[] signers, address[] transmitters, uint8 f, bytes onchainConfig, uint64 offchainConfigVersion, bytes offchainConfig ); /** * @notice sets offchain reporting protocol configuration incl. participating oracles * @param signers addresses with which oracles sign the reports * @param transmitters addresses oracles use to transmit the reports * @param f number of faulty oracles the system can tolerate * @param onchainConfig serialized configuration used by the contract (and possibly oracles) * @param offchainConfigVersion version number for offchainEncoding schema * @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract */ function setConfig( address[] memory signers, address[] memory transmitters, uint8 f, bytes memory onchainConfig, uint64 offchainConfigVersion, bytes memory offchainConfig ) external virtual; /** * @notice information about current offchain reporting protocol configuration * @return configCount ordinal number of current config, out of all configs applied to this contract so far * @return blockNumber block at which this config was set * @return configDigest domain-separation tag for current config (see _configDigestFromConfigData) */ function latestConfigDetails() external view virtual returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest); /** * @notice optionally emited to indicate the latest configDigest and epoch for which a report was successfully transmited. Alternatively, the contract may use latestConfigDigestAndEpoch with scanLogs set to false. */ event Transmitted(bytes32 configDigest, uint32 epoch); /** * @notice optionally returns the latest configDigest and epoch for which a report was successfully transmitted. Alternatively, the contract may return scanLogs set to true and use Transmitted events to provide this information to offchain watchers. * @return scanLogs indicates whether to rely on the configDigest and epoch returned or whether to scan logs for the Transmitted event instead. * @return configDigest * @return epoch */ function latestConfigDigestAndEpoch() external view virtual returns (bool scanLogs, bytes32 configDigest, uint32 epoch); /** * @notice transmit is called to post a new report to the contract * @param report serialized report, which the signatures are signing. * @param rs ith element is the R components of the ith signature on report. Must have at most maxNumOracles entries * @param ss ith element is the S components of the ith signature on report. Must have at most maxNumOracles entries * @param rawVs ith element is the the V component of the ith signature */ function transmit( // NOTE: If these parameters are changed, expectedMsgDataLength and/or // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly bytes32[3] calldata reportContext, bytes calldata report, bytes32[] calldata rs, bytes32[] calldata ss, bytes32 rawVs // signatures ) external virtual; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {ConfirmedOwner} from "../../../../shared/access/ConfirmedOwner.sol"; import {OCR2Abstract} from "./OCR2Abstract.sol"; /** * @notice Onchain verification of reports from the offchain reporting protocol * @dev For details on its operation, see the offchain reporting protocol design * doc, which refers to this contract as simply the "contract". */ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { error ReportInvalid(string message); error InvalidConfig(string message); constructor() ConfirmedOwner(msg.sender) {} // incremented each time a new config is posted. This count is incorporated // into the config digest, to prevent replay attacks. uint32 internal s_configCount; uint32 internal s_latestConfigBlockNumber; // makes it easier for offchain systems // to extract config from logs. // Storing these fields used on the hot path in a ConfigInfo variable reduces the // retrieval of all of them to a single SLOAD. If any further fields are // added, make sure that storage of the struct still takes at most 32 bytes. struct ConfigInfo { bytes32 latestConfigDigest; uint8 f; // TODO: could be optimized by squeezing into one slot uint8 n; } ConfigInfo internal s_configInfo; // Used for s_oracles[a].role, where a is an address, to track the purpose // of the address, or to indicate that the address is unset. enum Role { // No oracle role has been set for address a Unset, // Signing address for the s_oracles[a].index'th oracle. I.e., report // signatures from this oracle should ecrecover back to address a. Signer, // Transmission address for the s_oracles[a].index'th oracle. I.e., if a // report is received by OCR2Aggregator.transmit in which msg.sender is // a, it is attributed to the s_oracles[a].index'th oracle. Transmitter } struct Oracle { uint8 index; // Index of oracle in s_signers/s_transmitters Role role; // Role of the address which mapped to this struct } mapping(address signerOrTransmitter => Oracle) internal s_oracles; // s_signers contains the signing address of each oracle address[] internal s_signers; // s_transmitters contains the transmission address of each oracle, // i.e. the address the oracle actually sends transactions to the contract from address[] internal s_transmitters; struct DecodedReport { bytes32[] requestIds; bytes[] results; bytes[] errors; bytes[] onchainMetadata; bytes[] offchainMetadata; } /* * Config logic */ // Reverts transaction if config args are invalid modifier checkConfigValid( uint256 numSigners, uint256 numTransmitters, uint256 f ) { if (numSigners > MAX_NUM_ORACLES) revert InvalidConfig("too many signers"); if (f == 0) revert InvalidConfig("f must be positive"); if (numSigners != numTransmitters) revert InvalidConfig("oracle addresses out of registration"); if (numSigners <= 3 * f) revert InvalidConfig("faulty-oracle f too high"); _; } struct SetConfigArgs { address[] signers; address[] transmitters; uint8 f; bytes onchainConfig; uint64 offchainConfigVersion; bytes offchainConfig; } /// @inheritdoc OCR2Abstract function latestConfigDigestAndEpoch() external view virtual override returns (bool scanLogs, bytes32 configDigest, uint32 epoch) { return (true, bytes32(0), uint32(0)); } /** * @notice sets offchain reporting protocol configuration incl. participating oracles * @param _signers addresses with which oracles sign the reports * @param _transmitters addresses oracles use to transmit the reports * @param _f number of faulty oracles the system can tolerate * @param _onchainConfig encoded on-chain contract configuration * @param _offchainConfigVersion version number for offchainEncoding schema * @param _offchainConfig encoded off-chain oracle configuration */ function setConfig( address[] memory _signers, address[] memory _transmitters, uint8 _f, bytes memory _onchainConfig, uint64 _offchainConfigVersion, bytes memory _offchainConfig ) external override checkConfigValid(_signers.length, _transmitters.length, _f) onlyOwner { SetConfigArgs memory args = SetConfigArgs({ signers: _signers, transmitters: _transmitters, f: _f, onchainConfig: _onchainConfig, offchainConfigVersion: _offchainConfigVersion, offchainConfig: _offchainConfig }); _beforeSetConfig(args.f, args.onchainConfig); while (s_signers.length != 0) { // remove any old signer/transmitter addresses uint256 lastIdx = s_signers.length - 1; address signer = s_signers[lastIdx]; address transmitter = s_transmitters[lastIdx]; delete s_oracles[signer]; delete s_oracles[transmitter]; s_signers.pop(); s_transmitters.pop(); } // Bounded by MAX_NUM_ORACLES in OCR2Abstract.sol for (uint256 i = 0; i < args.signers.length; i++) { if (args.signers[i] == address(0)) revert InvalidConfig("signer must not be empty"); if (args.transmitters[i] == address(0)) revert InvalidConfig("transmitter must not be empty"); // add new signer/transmitter addresses if (s_oracles[args.signers[i]].role != Role.Unset) revert InvalidConfig("repeated signer address"); s_oracles[args.signers[i]] = Oracle(uint8(i), Role.Signer); if (s_oracles[args.transmitters[i]].role != Role.Unset) revert InvalidConfig("repeated transmitter address"); s_oracles[args.transmitters[i]] = Oracle(uint8(i), Role.Transmitter); s_signers.push(args.signers[i]); s_transmitters.push(args.transmitters[i]); } s_configInfo.f = args.f; uint32 previousConfigBlockNumber = s_latestConfigBlockNumber; s_latestConfigBlockNumber = uint32(block.number); s_configCount += 1; { s_configInfo.latestConfigDigest = _configDigestFromConfigData( block.chainid, address(this), s_configCount, args.signers, args.transmitters, args.f, args.onchainConfig, args.offchainConfigVersion, args.offchainConfig ); } s_configInfo.n = uint8(args.signers.length); emit ConfigSet( previousConfigBlockNumber, s_configInfo.latestConfigDigest, s_configCount, args.signers, args.transmitters, args.f, args.onchainConfig, args.offchainConfigVersion, args.offchainConfig ); } function _configDigestFromConfigData( uint256 _chainId, address _contractAddress, uint64 _configCount, address[] memory _signers, address[] memory _transmitters, uint8 _f, bytes memory _onchainConfig, uint64 _encodedConfigVersion, bytes memory _encodedConfig ) internal pure returns (bytes32) { uint256 h = uint256( keccak256( abi.encode( _chainId, _contractAddress, _configCount, _signers, _transmitters, _f, _onchainConfig, _encodedConfigVersion, _encodedConfig ) ) ); uint256 prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00 uint256 prefix = 0x0001 << (256 - 16); // 0x000100..00 return bytes32((prefix & prefixMask) | (h & ~prefixMask)); } /** * @notice information about current offchain reporting protocol configuration * @return configCount ordinal number of current config, out of all configs applied to this contract so far * @return blockNumber block at which this config was set * @return configDigest domain-separation tag for current config (see __configDigestFromConfigData) */ function latestConfigDetails() external view override returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest) { return (s_configCount, s_latestConfigBlockNumber, s_configInfo.latestConfigDigest); } /** * @return list of addresses permitted to transmit reports to this contract * @dev The list will match the order used to specify the transmitter during setConfig */ function transmitters() external view returns (address[] memory) { return s_transmitters; } function _beforeSetConfig(uint8 _f, bytes memory _onchainConfig) internal virtual; /** * @dev hook called after the report has been fully validated * for the extending contract to handle additional logic, such as oracle payment * @param decodedReport decodedReport */ function _report(DecodedReport memory decodedReport) internal virtual; // The constant-length components of the msg.data sent to transmit. // See the "If we wanted to call sam" example on for example reasoning // https://solidity.readthedocs.io/en/v0.7.2/abi-spec.html uint16 private constant TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT = 4 + // function selector 32 * 3 + // 3 words containing reportContext 32 + // word containing start location of abiencoded report value 32 + // word containing location start of abiencoded rs value 32 + // word containing start location of abiencoded ss value 32 + // rawVs value 32 + // word containing length of report 32 + // word containing length rs 32 + // word containing length of ss 0; // placeholder function _requireExpectedMsgDataLength( bytes calldata report, bytes32[] calldata rs, bytes32[] calldata ss ) private pure { // calldata will never be big enough to make this overflow uint256 expected = uint256(TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT) + report.length + // one byte pure entry in _report rs.length * 32 + // 32 bytes per entry in _rs ss.length * 32 + // 32 bytes per entry in _ss 0; // placeholder if (msg.data.length != expected) revert ReportInvalid("calldata length mismatch"); } function _beforeTransmit( bytes calldata report ) internal virtual returns (bool shouldStop, DecodedReport memory decodedReport); /** * @notice transmit is called to post a new report to the contract * @param report serialized report, which the signatures are signing. * @param rs ith element is the R components of the ith signature on report. Must have at most maxNumOracles entries * @param ss ith element is the S components of the ith signature on report. Must have at most maxNumOracles entries * @param rawVs ith element is the the V component of the ith signature */ function transmit( // NOTE: If these parameters are changed, expectedMsgDataLength and/or // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly bytes32[3] calldata reportContext, bytes calldata report, bytes32[] calldata rs, bytes32[] calldata ss, bytes32 rawVs // signatures ) external override { (bool shouldStop, DecodedReport memory decodedReport) = _beforeTransmit(report); if (shouldStop) { return; } { // reportContext consists of: // reportContext[0]: ConfigDigest // reportContext[1]: 27 byte padding, 4-byte epoch and 1-byte round // reportContext[2]: ExtraHash bytes32 configDigest = reportContext[0]; uint32 epochAndRound = uint32(uint256(reportContext[1])); emit Transmitted(configDigest, uint32(epochAndRound >> 8)); // The following check is disabled to allow both current and proposed routes to submit reports using the same OCR config digest // Chainlink Functions uses globally unique request IDs. Metadata about the request is stored and checked in the Coordinator and Router // require(configInfo.latestConfigDigest == configDigest, "configDigest mismatch"); _requireExpectedMsgDataLength(report, rs, ss); uint256 expectedNumSignatures = (s_configInfo.n + s_configInfo.f) / 2 + 1; if (rs.length != expectedNumSignatures) revert ReportInvalid("wrong number of signatures"); if (rs.length != ss.length) revert ReportInvalid("report rs and ss must be of equal length"); Oracle memory transmitter = s_oracles[msg.sender]; if (transmitter.role != Role.Transmitter && msg.sender != s_transmitters[transmitter.index]) revert ReportInvalid("unauthorized transmitter"); } address[MAX_NUM_ORACLES] memory signed; { // Verify signatures attached to report bytes32 h = keccak256(abi.encodePacked(keccak256(report), reportContext)); Oracle memory o; // Bounded by MAX_NUM_ORACLES in OCR2Abstract.sol for (uint256 i = 0; i < rs.length; ++i) { address signer = ecrecover(h, uint8(rawVs[i]) + 27, rs[i], ss[i]); o = s_oracles[signer]; if (o.role != Role.Signer) revert ReportInvalid("address not authorized to sign"); if (signed[o.index] != address(0)) revert ReportInvalid("non-unique signature"); signed[o.index] = signer; } } _report(decodedReport); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {FunctionsRequest} from "../../../dev/v1_X/libraries/FunctionsRequest.sol"; import {FunctionsClient} from "../../../dev/v1_X/FunctionsClient.sol"; import {ConfirmedOwner} from "../../../../shared/access/ConfirmedOwner.sol"; contract FunctionsClientUpgradeHelper is FunctionsClient, ConfirmedOwner { using FunctionsRequest for FunctionsRequest.Request; constructor(address router) FunctionsClient(router) ConfirmedOwner(msg.sender) {} event ResponseReceived(bytes32 indexed requestId, bytes result, bytes err); /** * @notice Send a simple request * * @param donId DON ID * @param source JavaScript source code * @param secrets Encrypted secrets payload * @param args List of arguments accessible from within the source code * @param subscriptionId Funtions billing subscription ID * @param callbackGasLimit Maximum amount of gas used to call the client contract's `handleOracleFulfillment` function * @return Functions request ID */ function sendRequest( bytes32 donId, string calldata source, bytes calldata secrets, string[] calldata args, bytes[] memory bytesArgs, uint64 subscriptionId, uint32 callbackGasLimit ) public onlyOwner returns (bytes32) { FunctionsRequest.Request memory req; req._initializeRequestForInlineJavaScript(source); if (secrets.length > 0) req._addSecretsReference(secrets); if (args.length > 0) req._setArgs(args); if (bytesArgs.length > 0) req._setBytesArgs(bytesArgs); return _sendRequest(FunctionsRequest._encodeCBOR(req), subscriptionId, callbackGasLimit, donId); } function sendRequestBytes( bytes memory data, uint64 subscriptionId, uint32 callbackGasLimit, bytes32 donId ) public returns (bytes32 requestId) { return _sendRequest(data, subscriptionId, callbackGasLimit, donId); } /** * @notice Same as sendRequest but for DONHosted secrets */ function sendRequestWithDONHostedSecrets( bytes32 donId, string calldata source, uint8 slotId, uint64 slotVersion, string[] calldata args, uint64 subscriptionId, uint32 callbackGasLimit ) public onlyOwner returns (bytes32) { FunctionsRequest.Request memory req; req._initializeRequestForInlineJavaScript(source); req._addDONHostedSecrets(slotId, slotVersion); if (args.length > 0) req._setArgs(args); return _sendRequest(FunctionsRequest._encodeCBOR(req), subscriptionId, callbackGasLimit, donId); } // @notice Sends a Chainlink Functions request // @param data The CBOR encoded bytes data for a Functions request // @param subscriptionId The subscription ID that will be charged to service the request // @param callbackGasLimit the amount of gas that will be available for the fulfillment callback // @return requestId The generated request ID for this request function _sendRequestToProposed( bytes memory data, uint64 subscriptionId, uint32 callbackGasLimit, bytes32 donId ) internal returns (bytes32) { bytes32 requestId = i_functionsRouter.sendRequestToProposed( subscriptionId, data, FunctionsRequest.REQUEST_DATA_VERSION, callbackGasLimit, donId ); emit RequestSent(requestId); return requestId; } /** * @notice Send a simple request to the proposed contract * * @param donId DON ID * @param source JavaScript source code * @param secrets Encrypted secrets payload * @param args List of arguments accessible from within the source code * @param subscriptionId Funtions billing subscription ID * @param callbackGasLimit Maximum amount of gas used to call the client contract's `handleOracleFulfillment` function * @return Functions request ID */ function sendRequestToProposed( bytes32 donId, string calldata source, bytes calldata secrets, string[] calldata args, bytes[] memory bytesArgs, uint64 subscriptionId, uint32 callbackGasLimit ) public onlyOwner returns (bytes32) { FunctionsRequest.Request memory req; req._initializeRequestForInlineJavaScript(source); if (secrets.length > 0) req._addSecretsReference(secrets); if (args.length > 0) req._setArgs(args); if (bytesArgs.length > 0) req._setBytesArgs(bytesArgs); return _sendRequestToProposed(FunctionsRequest._encodeCBOR(req), subscriptionId, callbackGasLimit, donId); } /** * @notice Same as sendRequestToProposed but for DONHosted secrets */ function sendRequestToProposedWithDONHostedSecrets( bytes32 donId, string calldata source, uint8 slotId, uint64 slotVersion, string[] calldata args, uint64 subscriptionId, uint32 callbackGasLimit ) public onlyOwner returns (bytes32) { FunctionsRequest.Request memory req; req._initializeRequestForInlineJavaScript(source); req._addDONHostedSecrets(slotId, slotVersion); if (args.length > 0) req._setArgs(args); return _sendRequestToProposed(FunctionsRequest._encodeCBOR(req), subscriptionId, callbackGasLimit, donId); } /** * @notice Callback that is invoked once the DON has resolved the request or hit an error * * @param requestId The request ID, returned by sendRequest() * @param response Aggregated response from the user code * @param err Aggregated error from the user code or from the execution pipeline * Either response or error parameter will be set, but never both */ function _fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal override { emit ResponseReceived(requestId, response, err); } }
// 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.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 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 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 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 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 AggregatorV3Interface { function decimals() external view returns (uint8); function description() external view returns (string memory); function version() external view returns (uint256); function getRoundData( uint80 _roundId ) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound); function latestRoundData() external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IAccessController { function hasAccess(address user, bytes calldata data) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.6; interface IERC677Receiver { function onTokenTransfer(address sender, uint256 amount, bytes calldata data) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IOwnable { function owner() external returns (address); function transferOwnership(address recipient) external; function acceptOwnership() external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface ITypeAndVersion { function typeAndVersion() external pure returns (string memory); }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.4.21 <0.9.0; interface ArbGasInfo { // return gas prices in wei, assuming the specified aggregator is used // ( // per L2 tx, // per L1 calldata unit, (zero byte = 4 units, nonzero byte = 16 units) // per storage allocation, // per ArbGas base, // per ArbGas congestion, // per ArbGas total // ) function getPricesInWeiWithAggregator(address aggregator) external view returns (uint, uint, uint, uint, uint, uint); // return gas prices in wei, as described above, assuming the caller's preferred aggregator is used // if the caller hasn't specified a preferred aggregator, the default aggregator is assumed function getPricesInWei() external view returns (uint, uint, uint, uint, uint, uint); // return prices in ArbGas (per L2 tx, per L1 calldata unit, per storage allocation), // assuming the specified aggregator is used function getPricesInArbGasWithAggregator(address aggregator) external view returns (uint, uint, uint); // return gas prices in ArbGas, as described above, assuming the caller's preferred aggregator is used // if the caller hasn't specified a preferred aggregator, the default aggregator is assumed function getPricesInArbGas() external view returns (uint, uint, uint); // return gas accounting parameters (speedLimitPerSecond, gasPoolMax, maxTxGasLimit) function getGasAccountingParams() external view returns (uint, uint, uint); // get ArbOS's estimate of the L1 gas price in wei function getL1GasPriceEstimate() external view returns(uint); // set ArbOS's estimate of the L1 gas price in wei // reverts unless called by chain owner or designated gas oracle (if any) function setL1GasPriceEstimate(uint priceInWei) external; // get L1 gas fees paid by the current transaction (txBaseFeeWei, calldataFeeWei) function getCurrentTxL1GasFees() external view returns(uint); }
// SPDX-License-Identifier: BSD-2-Clause pragma solidity ^0.8.4; /** * @dev A library for working with mutable byte buffers in Solidity. * * Byte buffers are mutable and expandable, and provide a variety of primitives * for appending to them. At any time you can fetch a bytes object containing the * current contents of the buffer. The bytes object should not be stored between * operations, as it may change due to resizing of the buffer. */ library Buffer { /** * @dev Represents a mutable buffer. Buffers have a current value (buf) and * a capacity. The capacity may be longer than the current value, in * which case it can be extended without the need to allocate more memory. */ struct buffer { bytes buf; uint capacity; } /** * @dev Initializes a buffer with an initial capacity. * @param buf The buffer to initialize. * @param capacity The number of bytes of space to allocate the buffer. * @return The buffer, for chaining. */ function init(buffer memory buf, uint capacity) internal pure returns(buffer memory) { if (capacity % 32 != 0) { capacity += 32 - (capacity % 32); } // Allocate space for the buffer data buf.capacity = capacity; assembly { let ptr := mload(0x40) mstore(buf, ptr) mstore(ptr, 0) let fpm := add(32, add(ptr, capacity)) if lt(fpm, ptr) { revert(0, 0) } mstore(0x40, fpm) } return buf; } /** * @dev Initializes a new buffer from an existing bytes object. * Changes to the buffer may mutate the original value. * @param b The bytes object to initialize the buffer with. * @return A new buffer. */ function fromBytes(bytes memory b) internal pure returns(buffer memory) { buffer memory buf; buf.buf = b; buf.capacity = b.length; return buf; } function resize(buffer memory buf, uint capacity) private pure { bytes memory oldbuf = buf.buf; init(buf, capacity); append(buf, oldbuf); } /** * @dev Sets buffer length to 0. * @param buf The buffer to truncate. * @return The original buffer, for chaining.. */ function truncate(buffer memory buf) internal pure returns (buffer memory) { assembly { let bufptr := mload(buf) mstore(bufptr, 0) } return buf; } /** * @dev Appends len bytes of a byte string to a buffer. Resizes if doing so would exceed * the capacity of the buffer. * @param buf The buffer to append to. * @param data The data to append. * @param len The number of bytes to copy. * @return The original buffer, for chaining. */ function append(buffer memory buf, bytes memory data, uint len) internal pure returns(buffer memory) { require(len <= data.length); uint off = buf.buf.length; uint newCapacity = off + len; if (newCapacity > buf.capacity) { resize(buf, newCapacity * 2); } uint dest; uint src; assembly { // Memory address of the buffer data let bufptr := mload(buf) // Length of existing buffer data let buflen := mload(bufptr) // Start address = buffer address + offset + sizeof(buffer length) dest := add(add(bufptr, 32), off) // Update buffer length if we're extending it if gt(newCapacity, buflen) { mstore(bufptr, newCapacity) } src := add(data, 32) } // Copy word-length chunks while possible for (; len >= 32; len -= 32) { assembly { mstore(dest, mload(src)) } dest += 32; src += 32; } // Copy remaining bytes unchecked { uint mask = (256 ** (32 - len)) - 1; assembly { let srcpart := and(mload(src), not(mask)) let destpart := and(mload(dest), mask) mstore(dest, or(destpart, srcpart)) } } return buf; } /** * @dev Appends a byte string to a buffer. Resizes if doing so would exceed * the capacity of the buffer. * @param buf The buffer to append to. * @param data The data to append. * @return The original buffer, for chaining. */ function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) { return append(buf, data, data.length); } /** * @dev Appends a byte to the buffer. Resizes if doing so would exceed the * capacity of the buffer. * @param buf The buffer to append to. * @param data The data to append. * @return The original buffer, for chaining. */ function appendUint8(buffer memory buf, uint8 data) internal pure returns(buffer memory) { uint off = buf.buf.length; uint offPlusOne = off + 1; if (off >= buf.capacity) { resize(buf, offPlusOne * 2); } assembly { // Memory address of the buffer data let bufptr := mload(buf) // Address = buffer address + sizeof(buffer length) + off let dest := add(add(bufptr, off), 32) mstore8(dest, data) // Update buffer length if we extended it if gt(offPlusOne, mload(bufptr)) { mstore(bufptr, offPlusOne) } } return buf; } /** * @dev Appends len bytes of bytes32 to a buffer. Resizes if doing so would * exceed the capacity of the buffer. * @param buf The buffer to append to. * @param data The data to append. * @param len The number of bytes to write (left-aligned). * @return The original buffer, for chaining. */ function append(buffer memory buf, bytes32 data, uint len) private pure returns(buffer memory) { uint off = buf.buf.length; uint newCapacity = len + off; if (newCapacity > buf.capacity) { resize(buf, newCapacity * 2); } unchecked { uint mask = (256 ** len) - 1; // Right-align data data = data >> (8 * (32 - len)); assembly { // Memory address of the buffer data let bufptr := mload(buf) // Address = buffer address + sizeof(buffer length) + newCapacity let dest := add(bufptr, newCapacity) mstore(dest, or(and(mload(dest), not(mask)), data)) // Update buffer length if we extended it if gt(newCapacity, mload(bufptr)) { mstore(bufptr, newCapacity) } } } return buf; } /** * @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed * the capacity of the buffer. * @param buf The buffer to append to. * @param data The data to append. * @return The original buffer, for chhaining. */ function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) { return append(buf, bytes32(data), 20); } /** * @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed * the capacity of the buffer. * @param buf The buffer to append to. * @param data The data to append. * @return The original buffer, for chaining. */ function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) { return append(buf, data, 32); } /** * @dev Appends a byte to the end of the buffer. Resizes if doing so would * exceed the capacity of the buffer. * @param buf The buffer to append to. * @param data The data to append. * @param len The number of bytes to write (right-aligned). * @return The original buffer. */ function appendInt(buffer memory buf, uint data, uint len) internal pure returns(buffer memory) { uint off = buf.buf.length; uint newCapacity = len + off; if (newCapacity > buf.capacity) { resize(buf, newCapacity * 2); } uint mask = (256 ** len) - 1; assembly { // Memory address of the buffer data let bufptr := mload(buf) // Address = buffer address + sizeof(buffer length) + newCapacity let dest := add(bufptr, newCapacity) mstore(dest, or(and(mload(dest), not(mask)), data)) // Update buffer length if we extended it if gt(newCapacity, mload(bufptr)) { mstore(bufptr, newCapacity) } } return buf; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.15; import { ISemver } from "../universal/ISemver.sol"; import { Predeploys } from "../libraries/Predeploys.sol"; import { L1Block } from "./L1Block.sol"; /// @custom:proxied /// @custom:predeploy 0x420000000000000000000000000000000000000F /// @title GasPriceOracle /// @notice This contract maintains the variables responsible for computing the L1 portion of the /// total fee charged on L2. Before Bedrock, this contract held variables in state that were /// read during the state transition function to compute the L1 portion of the transaction /// fee. After Bedrock, this contract now simply proxies the L1Block contract, which has /// the values used to compute the L1 portion of the fee in its state. /// /// The contract exposes an API that is useful for knowing how large the L1 portion of the /// transaction fee will be. The following events were deprecated with Bedrock: /// - event OverheadUpdated(uint256 overhead); /// - event ScalarUpdated(uint256 scalar); /// - event DecimalsUpdated(uint256 decimals); contract GasPriceOracle is ISemver { /// @notice Number of decimals used in the scalar. uint256 public constant DECIMALS = 6; /// @notice Semantic version. /// @custom:semver 1.1.0 string public constant version = "1.1.0"; /// @notice Computes the L1 portion of the fee based on the size of the rlp encoded input /// transaction, the current L1 base fee, and the various dynamic parameters. /// @param _data Unsigned fully RLP-encoded transaction to get the L1 fee for. /// @return L1 fee that should be paid for the tx function getL1Fee(bytes memory _data) external view returns (uint256) { uint256 l1GasUsed = getL1GasUsed(_data); uint256 l1Fee = l1GasUsed * l1BaseFee(); uint256 divisor = 10 ** DECIMALS; uint256 unscaled = l1Fee * scalar(); uint256 scaled = unscaled / divisor; return scaled; } /// @notice Retrieves the current gas price (base fee). /// @return Current L2 gas price (base fee). function gasPrice() public view returns (uint256) { return block.basefee; } /// @notice Retrieves the current base fee. /// @return Current L2 base fee. function baseFee() public view returns (uint256) { return block.basefee; } /// @notice Retrieves the current fee overhead. /// @return Current fee overhead. function overhead() public view returns (uint256) { return L1Block(Predeploys.L1_BLOCK_ATTRIBUTES).l1FeeOverhead(); } /// @notice Retrieves the current fee scalar. /// @return Current fee scalar. function scalar() public view returns (uint256) { return L1Block(Predeploys.L1_BLOCK_ATTRIBUTES).l1FeeScalar(); } /// @notice Retrieves the latest known L1 base fee. /// @return Latest known L1 base fee. function l1BaseFee() public view returns (uint256) { return L1Block(Predeploys.L1_BLOCK_ATTRIBUTES).basefee(); } /// @custom:legacy /// @notice Retrieves the number of decimals used in the scalar. /// @return Number of decimals used in the scalar. function decimals() public pure returns (uint256) { return DECIMALS; } /// @notice Computes the amount of L1 gas used for a transaction. Adds the overhead which /// represents the per-transaction gas overhead of posting the transaction and state /// roots to L1. Adds 68 bytes of padding to account for the fact that the input does /// not have a signature. /// @param _data Unsigned fully RLP-encoded transaction to get the L1 gas for. /// @return Amount of L1 gas used to publish the transaction. function getL1GasUsed(bytes memory _data) public view returns (uint256) { uint256 total = 0; uint256 length = _data.length; for (uint256 i = 0; i < length; i++) { if (_data[i] == 0) { total += 4; } else { total += 16; } } uint256 unsigned = total + overhead(); return unsigned + (68 * 16); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.15; import { ISemver } from "../universal/ISemver.sol"; /// @custom:proxied /// @custom:predeploy 0x4200000000000000000000000000000000000015 /// @title L1Block /// @notice The L1Block predeploy gives users access to information about the last known L1 block. /// Values within this contract are updated once per epoch (every L1 block) and can only be /// set by the "depositor" account, a special system address. Depositor account transactions /// are created by the protocol whenever we move to a new epoch. contract L1Block is ISemver { /// @notice Address of the special depositor account. address public constant DEPOSITOR_ACCOUNT = 0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001; /// @notice The latest L1 block number known by the L2 system. uint64 public number; /// @notice The latest L1 timestamp known by the L2 system. uint64 public timestamp; /// @notice The latest L1 basefee. uint256 public basefee; /// @notice The latest L1 blockhash. bytes32 public hash; /// @notice The number of L2 blocks in the same epoch. uint64 public sequenceNumber; /// @notice The versioned hash to authenticate the batcher by. bytes32 public batcherHash; /// @notice The overhead value applied to the L1 portion of the transaction fee. uint256 public l1FeeOverhead; /// @notice The scalar value applied to the L1 portion of the transaction fee. uint256 public l1FeeScalar; /// @custom:semver 1.1.0 string public constant version = "1.1.0"; /// @notice Updates the L1 block values. /// @param _number L1 blocknumber. /// @param _timestamp L1 timestamp. /// @param _basefee L1 basefee. /// @param _hash L1 blockhash. /// @param _sequenceNumber Number of L2 blocks since epoch start. /// @param _batcherHash Versioned hash to authenticate batcher by. /// @param _l1FeeOverhead L1 fee overhead. /// @param _l1FeeScalar L1 fee scalar. function setL1BlockValues( uint64 _number, uint64 _timestamp, uint256 _basefee, bytes32 _hash, uint64 _sequenceNumber, bytes32 _batcherHash, uint256 _l1FeeOverhead, uint256 _l1FeeScalar ) external { require(msg.sender == DEPOSITOR_ACCOUNT, "L1Block: only the depositor account can set L1 block values"); number = _number; timestamp = _timestamp; basefee = _basefee; hash = _hash; sequenceNumber = _sequenceNumber; batcherHash = _batcherHash; l1FeeOverhead = _l1FeeOverhead; l1FeeScalar = _l1FeeScalar; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title Predeploys /// @notice Contains constant addresses for contracts that are pre-deployed to the L2 system. library Predeploys { /// @notice Address of the L2ToL1MessagePasser predeploy. address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000016; /// @notice Address of the L2CrossDomainMessenger predeploy. address internal constant L2_CROSS_DOMAIN_MESSENGER = 0x4200000000000000000000000000000000000007; /// @notice Address of the L2StandardBridge predeploy. address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010; /// @notice Address of the L2ERC721Bridge predeploy. address internal constant L2_ERC721_BRIDGE = 0x4200000000000000000000000000000000000014; //// @notice Address of the SequencerFeeWallet predeploy. address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011; /// @notice Address of the OptimismMintableERC20Factory predeploy. address internal constant OPTIMISM_MINTABLE_ERC20_FACTORY = 0x4200000000000000000000000000000000000012; /// @notice Address of the OptimismMintableERC721Factory predeploy. address internal constant OPTIMISM_MINTABLE_ERC721_FACTORY = 0x4200000000000000000000000000000000000017; /// @notice Address of the L1Block predeploy. address internal constant L1_BLOCK_ATTRIBUTES = 0x4200000000000000000000000000000000000015; /// @notice Address of the GasPriceOracle predeploy. Includes fee information /// and helpers for computing the L1 portion of the transaction fee. address internal constant GAS_PRICE_ORACLE = 0x420000000000000000000000000000000000000F; /// @custom:legacy /// @notice Address of the L1MessageSender predeploy. Deprecated. Use L2CrossDomainMessenger /// or access tx.origin (or msg.sender) in a L1 to L2 transaction instead. address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001; /// @custom:legacy /// @notice Address of the DeployerWhitelist predeploy. No longer active. address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002; /// @custom:legacy /// @notice Address of the LegacyERC20ETH predeploy. Deprecated. Balances are migrated to the /// state trie as of the Bedrock upgrade. Contract has been locked and write functions /// can no longer be accessed. address internal constant LEGACY_ERC20_ETH = 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000; /// @custom:legacy /// @notice Address of the L1BlockNumber predeploy. Deprecated. Use the L1Block predeploy /// instead, which exposes more information about the L1 state. address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013; /// @custom:legacy /// @notice Address of the LegacyMessagePasser predeploy. Deprecate. Use the updated /// L2ToL1MessagePasser contract instead. address internal constant LEGACY_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000; /// @notice Address of the ProxyAdmin predeploy. address internal constant PROXY_ADMIN = 0x4200000000000000000000000000000000000018; /// @notice Address of the BaseFeeVault predeploy. address internal constant BASE_FEE_VAULT = 0x4200000000000000000000000000000000000019; /// @notice Address of the L1FeeVault predeploy. address internal constant L1_FEE_VAULT = 0x420000000000000000000000000000000000001A; /// @notice Address of the GovernanceToken predeploy. address internal constant GOVERNANCE_TOKEN = 0x4200000000000000000000000000000000000042; /// @notice Address of the SchemaRegistry predeploy. address internal constant SCHEMA_REGISTRY = 0x4200000000000000000000000000000000000020; /// @notice Address of the EAS predeploy. address internal constant EAS = 0x4200000000000000000000000000000000000021; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title ISemver /// @notice ISemver is a simple contract for ensuring that contracts are /// versioned using semantic versioning. interface ISemver { /// @notice Getter for the semantic version of the contract. This is not /// meant to be used onchain but instead meant to be used by offchain /// tooling. /// @return Semver contract version as a string. function version() external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.0; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafeCast { /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toUint248(uint256 value) internal pure returns (uint248) { require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits"); return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toUint240(uint256 value) internal pure returns (uint240) { require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits"); return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toUint232(uint256 value) internal pure returns (uint232) { require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits"); return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.2._ */ function toUint224(uint256 value) internal pure returns (uint224) { require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits"); return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toUint216(uint256 value) internal pure returns (uint216) { require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits"); return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toUint208(uint256 value) internal pure returns (uint208) { require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits"); return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toUint200(uint256 value) internal pure returns (uint200) { require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits"); return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toUint192(uint256 value) internal pure returns (uint192) { require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits"); return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toUint184(uint256 value) internal pure returns (uint184) { require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits"); return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toUint176(uint256 value) internal pure returns (uint176) { require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits"); return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toUint168(uint256 value) internal pure returns (uint168) { require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits"); return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toUint160(uint256 value) internal pure returns (uint160) { require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits"); return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toUint152(uint256 value) internal pure returns (uint152) { require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits"); return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toUint144(uint256 value) internal pure returns (uint144) { require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits"); return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toUint136(uint256 value) internal pure returns (uint136) { require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits"); return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v2.5._ */ function toUint128(uint256 value) internal pure returns (uint128) { require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toUint120(uint256 value) internal pure returns (uint120) { require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits"); return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toUint112(uint256 value) internal pure returns (uint112) { require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits"); return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toUint104(uint256 value) internal pure returns (uint104) { require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits"); return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.2._ */ function toUint96(uint256 value) internal pure returns (uint96) { require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits"); return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toUint88(uint256 value) internal pure returns (uint88) { require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits"); return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toUint80(uint256 value) internal pure returns (uint80) { require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits"); return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toUint72(uint256 value) internal pure returns (uint72) { require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits"); return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v2.5._ */ function toUint64(uint256 value) internal pure returns (uint64) { require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toUint56(uint256 value) internal pure returns (uint56) { require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits"); return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toUint48(uint256 value) internal pure returns (uint48) { require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits"); return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toUint40(uint256 value) internal pure returns (uint40) { require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits"); return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v2.5._ */ function toUint32(uint256 value) internal pure returns (uint32) { require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toUint24(uint256 value) internal pure returns (uint24) { require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits"); return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v2.5._ */ function toUint16(uint256 value) internal pure returns (uint16) { require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v2.5._ */ function toUint8(uint256 value) internal pure returns (uint8) { require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits"); return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. * * _Available since v3.0._ */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); require(downcasted == value, "SafeCast: value doesn't fit in 248 bits"); } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); require(downcasted == value, "SafeCast: value doesn't fit in 240 bits"); } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); require(downcasted == value, "SafeCast: value doesn't fit in 232 bits"); } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.7._ */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); require(downcasted == value, "SafeCast: value doesn't fit in 224 bits"); } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); require(downcasted == value, "SafeCast: value doesn't fit in 216 bits"); } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); require(downcasted == value, "SafeCast: value doesn't fit in 208 bits"); } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); require(downcasted == value, "SafeCast: value doesn't fit in 200 bits"); } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); require(downcasted == value, "SafeCast: value doesn't fit in 192 bits"); } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); require(downcasted == value, "SafeCast: value doesn't fit in 184 bits"); } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); require(downcasted == value, "SafeCast: value doesn't fit in 176 bits"); } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); require(downcasted == value, "SafeCast: value doesn't fit in 168 bits"); } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); require(downcasted == value, "SafeCast: value doesn't fit in 160 bits"); } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); require(downcasted == value, "SafeCast: value doesn't fit in 152 bits"); } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); require(downcasted == value, "SafeCast: value doesn't fit in 144 bits"); } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); require(downcasted == value, "SafeCast: value doesn't fit in 136 bits"); } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v3.1._ */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); require(downcasted == value, "SafeCast: value doesn't fit in 128 bits"); } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); require(downcasted == value, "SafeCast: value doesn't fit in 120 bits"); } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); require(downcasted == value, "SafeCast: value doesn't fit in 112 bits"); } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); require(downcasted == value, "SafeCast: value doesn't fit in 104 bits"); } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.7._ */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); require(downcasted == value, "SafeCast: value doesn't fit in 96 bits"); } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); require(downcasted == value, "SafeCast: value doesn't fit in 88 bits"); } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); require(downcasted == value, "SafeCast: value doesn't fit in 80 bits"); } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); require(downcasted == value, "SafeCast: value doesn't fit in 72 bits"); } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v3.1._ */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); require(downcasted == value, "SafeCast: value doesn't fit in 64 bits"); } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); require(downcasted == value, "SafeCast: value doesn't fit in 56 bits"); } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); require(downcasted == value, "SafeCast: value doesn't fit in 48 bits"); } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); require(downcasted == value, "SafeCast: value doesn't fit in 40 bits"); } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v3.1._ */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); require(downcasted == value, "SafeCast: value doesn't fit in 32 bits"); } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); require(downcasted == value, "SafeCast: value doesn't fit in 24 bits"); } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v3.1._ */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); require(downcasted == value, "SafeCast: value doesn't fit in 16 bits"); } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v3.1._ */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); require(downcasted == value, "SafeCast: value doesn't fit in 8 bits"); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. * * _Available since v3.0._ */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256"); return int256(value); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "../../@ensdomains/buffer/v0.1.0/Buffer.sol"; /** * @dev A library for populating CBOR encoded payload in Solidity. * * https://datatracker.ietf.org/doc/html/rfc7049 * * The library offers various write* and start* methods to encode values of different types. * The resulted buffer can be obtained with data() method. * Encoding of primitive types is staightforward, whereas encoding of sequences can result * in an invalid CBOR if start/write/end flow is violated. * For the purpose of gas saving, the library does not verify start/write/end flow internally, * except for nested start/end pairs. */ library CBOR { using Buffer for Buffer.buffer; struct CBORBuffer { Buffer.buffer buf; uint256 depth; } uint8 private constant MAJOR_TYPE_INT = 0; uint8 private constant MAJOR_TYPE_NEGATIVE_INT = 1; uint8 private constant MAJOR_TYPE_BYTES = 2; uint8 private constant MAJOR_TYPE_STRING = 3; uint8 private constant MAJOR_TYPE_ARRAY = 4; uint8 private constant MAJOR_TYPE_MAP = 5; uint8 private constant MAJOR_TYPE_TAG = 6; uint8 private constant MAJOR_TYPE_CONTENT_FREE = 7; uint8 private constant TAG_TYPE_BIGNUM = 2; uint8 private constant TAG_TYPE_NEGATIVE_BIGNUM = 3; uint8 private constant CBOR_FALSE = 20; uint8 private constant CBOR_TRUE = 21; uint8 private constant CBOR_NULL = 22; uint8 private constant CBOR_UNDEFINED = 23; function create(uint256 capacity) internal pure returns(CBORBuffer memory cbor) { Buffer.init(cbor.buf, capacity); cbor.depth = 0; return cbor; } function data(CBORBuffer memory buf) internal pure returns(bytes memory) { require(buf.depth == 0, "Invalid CBOR"); return buf.buf.buf; } function writeUInt256(CBORBuffer memory buf, uint256 value) internal pure { buf.buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_BIGNUM)); writeBytes(buf, abi.encode(value)); } function writeInt256(CBORBuffer memory buf, int256 value) internal pure { if (value < 0) { buf.buf.appendUint8( uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_NEGATIVE_BIGNUM) ); writeBytes(buf, abi.encode(uint256(-1 - value))); } else { writeUInt256(buf, uint256(value)); } } function writeUInt64(CBORBuffer memory buf, uint64 value) internal pure { writeFixedNumeric(buf, MAJOR_TYPE_INT, value); } function writeInt64(CBORBuffer memory buf, int64 value) internal pure { if(value >= 0) { writeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(value)); } else{ writeFixedNumeric(buf, MAJOR_TYPE_NEGATIVE_INT, uint64(-1 - value)); } } function writeBytes(CBORBuffer memory buf, bytes memory value) internal pure { writeFixedNumeric(buf, MAJOR_TYPE_BYTES, uint64(value.length)); buf.buf.append(value); } function writeString(CBORBuffer memory buf, string memory value) internal pure { writeFixedNumeric(buf, MAJOR_TYPE_STRING, uint64(bytes(value).length)); buf.buf.append(bytes(value)); } function writeBool(CBORBuffer memory buf, bool value) internal pure { writeContentFree(buf, value ? CBOR_TRUE : CBOR_FALSE); } function writeNull(CBORBuffer memory buf) internal pure { writeContentFree(buf, CBOR_NULL); } function writeUndefined(CBORBuffer memory buf) internal pure { writeContentFree(buf, CBOR_UNDEFINED); } function startArray(CBORBuffer memory buf) internal pure { writeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY); buf.depth += 1; } function startFixedArray(CBORBuffer memory buf, uint64 length) internal pure { writeDefiniteLengthType(buf, MAJOR_TYPE_ARRAY, length); } function startMap(CBORBuffer memory buf) internal pure { writeIndefiniteLengthType(buf, MAJOR_TYPE_MAP); buf.depth += 1; } function startFixedMap(CBORBuffer memory buf, uint64 length) internal pure { writeDefiniteLengthType(buf, MAJOR_TYPE_MAP, length); } function endSequence(CBORBuffer memory buf) internal pure { writeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE); buf.depth -= 1; } function writeKVString(CBORBuffer memory buf, string memory key, string memory value) internal pure { writeString(buf, key); writeString(buf, value); } function writeKVBytes(CBORBuffer memory buf, string memory key, bytes memory value) internal pure { writeString(buf, key); writeBytes(buf, value); } function writeKVUInt256(CBORBuffer memory buf, string memory key, uint256 value) internal pure { writeString(buf, key); writeUInt256(buf, value); } function writeKVInt256(CBORBuffer memory buf, string memory key, int256 value) internal pure { writeString(buf, key); writeInt256(buf, value); } function writeKVUInt64(CBORBuffer memory buf, string memory key, uint64 value) internal pure { writeString(buf, key); writeUInt64(buf, value); } function writeKVInt64(CBORBuffer memory buf, string memory key, int64 value) internal pure { writeString(buf, key); writeInt64(buf, value); } function writeKVBool(CBORBuffer memory buf, string memory key, bool value) internal pure { writeString(buf, key); writeBool(buf, value); } function writeKVNull(CBORBuffer memory buf, string memory key) internal pure { writeString(buf, key); writeNull(buf); } function writeKVUndefined(CBORBuffer memory buf, string memory key) internal pure { writeString(buf, key); writeUndefined(buf); } function writeKVMap(CBORBuffer memory buf, string memory key) internal pure { writeString(buf, key); startMap(buf); } function writeKVArray(CBORBuffer memory buf, string memory key) internal pure { writeString(buf, key); startArray(buf); } function writeFixedNumeric( CBORBuffer memory buf, uint8 major, uint64 value ) private pure { if (value <= 23) { buf.buf.appendUint8(uint8((major << 5) | value)); } else if (value <= 0xFF) { buf.buf.appendUint8(uint8((major << 5) | 24)); buf.buf.appendInt(value, 1); } else if (value <= 0xFFFF) { buf.buf.appendUint8(uint8((major << 5) | 25)); buf.buf.appendInt(value, 2); } else if (value <= 0xFFFFFFFF) { buf.buf.appendUint8(uint8((major << 5) | 26)); buf.buf.appendInt(value, 4); } else { buf.buf.appendUint8(uint8((major << 5) | 27)); buf.buf.appendInt(value, 8); } } function writeIndefiniteLengthType(CBORBuffer memory buf, uint8 major) private pure { buf.buf.appendUint8(uint8((major << 5) | 31)); } function writeDefiniteLengthType(CBORBuffer memory buf, uint8 major, uint64 length) private pure { writeFixedNumeric(buf, major, length); } function writeContentFree(CBORBuffer memory buf, uint8 value) private pure { buf.buf.appendUint8(uint8((MAJOR_TYPE_CONTENT_FREE << 5) | value)); } }
{ "remappings": [ "ds-test/=foundry-lib/forge-std/lib/ds-test/src/", "forge-std/=foundry-lib/forge-std/src/", "@openzeppelin/=node_modules/@openzeppelin/", "hardhat/=node_modules/hardhat/", "@eth-optimism/=node_modules/@eth-optimism/", "@scroll-tech/=node_modules/@scroll-tech/" ], "optimizer": { "enabled": true, "runs": 1000000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"router","type":"address"},{"components":[{"internalType":"uint32","name":"fulfillmentGasPriceOverEstimationBP","type":"uint32"},{"internalType":"uint32","name":"feedStalenessSeconds","type":"uint32"},{"internalType":"uint32","name":"gasOverheadBeforeCallback","type":"uint32"},{"internalType":"uint32","name":"gasOverheadAfterCallback","type":"uint32"},{"internalType":"uint40","name":"minimumEstimateGasPriceWei","type":"uint40"},{"internalType":"uint16","name":"maxSupportedRequestDataVersion","type":"uint16"},{"internalType":"uint64","name":"fallbackUsdPerUnitLink","type":"uint64"},{"internalType":"uint8","name":"fallbackUsdPerUnitLinkDecimals","type":"uint8"},{"internalType":"uint224","name":"fallbackNativePerUnitLink","type":"uint224"},{"internalType":"uint32","name":"requestTimeoutSeconds","type":"uint32"},{"internalType":"uint16","name":"donFeeCentsUsd","type":"uint16"},{"internalType":"uint16","name":"operationFeeCentsUsd","type":"uint16"}],"internalType":"struct FunctionsBillingConfig","name":"config","type":"tuple"},{"internalType":"address","name":"linkToNativeFeed","type":"address"},{"internalType":"address","name":"linkToUsdFeed","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"EmptyPublicKey","type":"error"},{"inputs":[],"name":"InconsistentReportData","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidCalldata","type":"error"},{"inputs":[{"internalType":"string","name":"message","type":"string"}],"name":"InvalidConfig","type":"error"},{"inputs":[{"internalType":"int256","name":"linkWei","type":"int256"}],"name":"InvalidLinkWeiPrice","type":"error"},{"inputs":[],"name":"InvalidSubscription","type":"error"},{"inputs":[{"internalType":"int256","name":"usdLink","type":"int256"}],"name":"InvalidUsdLinkPrice","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"MustBeSubOwner","type":"error"},{"inputs":[],"name":"NoTransmittersSet","type":"error"},{"inputs":[],"name":"OnlyCallableByRouter","type":"error"},{"inputs":[],"name":"OnlyCallableByRouterOwner","type":"error"},{"inputs":[],"name":"PaymentTooLarge","type":"error"},{"inputs":[{"internalType":"string","name":"message","type":"string"}],"name":"ReportInvalid","type":"error"},{"inputs":[],"name":"RouterMustBeSet","type":"error"},{"inputs":[],"name":"UnauthorizedPublicKeyChange","type":"error"},{"inputs":[],"name":"UnauthorizedSender","type":"error"},{"inputs":[],"name":"UnsupportedRequestDataVersion","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"requestId","type":"bytes32"}],"name":"CommitmentDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"previousConfigBlockNumber","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"configCount","type":"uint64"},{"indexed":false,"internalType":"address[]","name":"signers","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"transmitters","type":"address[]"},{"indexed":false,"internalType":"uint8","name":"f","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"onchainConfig","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"ConfigSet","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint32","name":"fulfillmentGasPriceOverEstimationBP","type":"uint32"},{"internalType":"uint32","name":"feedStalenessSeconds","type":"uint32"},{"internalType":"uint32","name":"gasOverheadBeforeCallback","type":"uint32"},{"internalType":"uint32","name":"gasOverheadAfterCallback","type":"uint32"},{"internalType":"uint40","name":"minimumEstimateGasPriceWei","type":"uint40"},{"internalType":"uint16","name":"maxSupportedRequestDataVersion","type":"uint16"},{"internalType":"uint64","name":"fallbackUsdPerUnitLink","type":"uint64"},{"internalType":"uint8","name":"fallbackUsdPerUnitLinkDecimals","type":"uint8"},{"internalType":"uint224","name":"fallbackNativePerUnitLink","type":"uint224"},{"internalType":"uint32","name":"requestTimeoutSeconds","type":"uint32"},{"internalType":"uint16","name":"donFeeCentsUsd","type":"uint16"},{"internalType":"uint16","name":"operationFeeCentsUsd","type":"uint16"}],"indexed":false,"internalType":"struct FunctionsBillingConfig","name":"config","type":"tuple"}],"name":"ConfigUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"requestId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"requestingContract","type":"address"},{"indexed":false,"internalType":"address","name":"requestInitiator","type":"address"},{"indexed":false,"internalType":"uint64","name":"subscriptionId","type":"uint64"},{"indexed":false,"internalType":"address","name":"subscriptionOwner","type":"address"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"uint16","name":"dataVersion","type":"uint16"},{"indexed":false,"internalType":"bytes32","name":"flags","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"callbackGasLimit","type":"uint64"},{"components":[{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"address","name":"coordinator","type":"address"},{"internalType":"uint96","name":"estimatedTotalCostJuels","type":"uint96"},{"internalType":"address","name":"client","type":"address"},{"internalType":"uint64","name":"subscriptionId","type":"uint64"},{"internalType":"uint32","name":"callbackGasLimit","type":"uint32"},{"internalType":"uint72","name":"adminFee","type":"uint72"},{"internalType":"uint72","name":"donFee","type":"uint72"},{"internalType":"uint40","name":"gasOverheadBeforeCallback","type":"uint40"},{"internalType":"uint40","name":"gasOverheadAfterCallback","type":"uint40"},{"internalType":"uint32","name":"timeoutTimestamp","type":"uint32"}],"indexed":false,"internalType":"struct FunctionsResponse.Commitment","name":"commitment","type":"tuple"}],"name":"OracleRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"requestId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"transmitter","type":"address"}],"name":"OracleResponse","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":"bytes32","name":"requestId","type":"bytes32"},{"indexed":false,"internalType":"uint96","name":"juelsPerGas","type":"uint96"},{"indexed":false,"internalType":"uint256","name":"l1FeeShareWei","type":"uint256"},{"indexed":false,"internalType":"uint96","name":"callbackCostJuels","type":"uint96"},{"indexed":false,"internalType":"uint72","name":"donFeeJuels","type":"uint72"},{"indexed":false,"internalType":"uint72","name":"adminFeeJuels","type":"uint72"},{"indexed":false,"internalType":"uint72","name":"operationFeeJuels","type":"uint72"}],"name":"RequestBilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"epoch","type":"uint32"}],"name":"Transmitted","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32"}],"name":"deleteCommitment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"subscriptionId","type":"uint64"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint32","name":"callbackGasLimit","type":"uint32"},{"internalType":"uint256","name":"gasPriceWei","type":"uint256"}],"name":"estimateCost","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAdminFeeJuels","outputs":[{"internalType":"uint72","name":"","type":"uint72"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getConfig","outputs":[{"components":[{"internalType":"uint32","name":"fulfillmentGasPriceOverEstimationBP","type":"uint32"},{"internalType":"uint32","name":"feedStalenessSeconds","type":"uint32"},{"internalType":"uint32","name":"gasOverheadBeforeCallback","type":"uint32"},{"internalType":"uint32","name":"gasOverheadAfterCallback","type":"uint32"},{"internalType":"uint40","name":"minimumEstimateGasPriceWei","type":"uint40"},{"internalType":"uint16","name":"maxSupportedRequestDataVersion","type":"uint16"},{"internalType":"uint64","name":"fallbackUsdPerUnitLink","type":"uint64"},{"internalType":"uint8","name":"fallbackUsdPerUnitLinkDecimals","type":"uint8"},{"internalType":"uint224","name":"fallbackNativePerUnitLink","type":"uint224"},{"internalType":"uint32","name":"requestTimeoutSeconds","type":"uint32"},{"internalType":"uint16","name":"donFeeCentsUsd","type":"uint16"},{"internalType":"uint16","name":"operationFeeCentsUsd","type":"uint16"}],"internalType":"struct FunctionsBillingConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"getDONFeeJuels","outputs":[{"internalType":"uint72","name":"","type":"uint72"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDONPublicKey","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOperationFeeJuels","outputs":[{"internalType":"uint72","name":"","type":"uint72"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getThresholdPublicKey","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUsdPerUnitLink","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWeiPerUnitLink","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestConfigDetails","outputs":[{"internalType":"uint32","name":"configCount","type":"uint32"},{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestConfigDigestAndEpoch","outputs":[{"internalType":"bool","name":"scanLogs","type":"bool"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"internalType":"uint32","name":"epoch","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint96","name":"amount","type":"uint96"}],"name":"oracleWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"oracleWithdrawAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_signers","type":"address[]"},{"internalType":"address[]","name":"_transmitters","type":"address[]"},{"internalType":"uint8","name":"_f","type":"uint8"},{"internalType":"bytes","name":"_onchainConfig","type":"bytes"},{"internalType":"uint64","name":"_offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"_offchainConfig","type":"bytes"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"donPublicKey","type":"bytes"}],"name":"setDONPublicKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"thresholdPublicKey","type":"bytes"}],"name":"setThresholdPublicKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes32","name":"flags","type":"bytes32"},{"internalType":"address","name":"requestingContract","type":"address"},{"internalType":"uint96","name":"availableBalance","type":"uint96"},{"internalType":"uint72","name":"adminFee","type":"uint72"},{"internalType":"uint64","name":"subscriptionId","type":"uint64"},{"internalType":"uint64","name":"initiatedRequests","type":"uint64"},{"internalType":"uint32","name":"callbackGasLimit","type":"uint32"},{"internalType":"uint16","name":"dataVersion","type":"uint16"},{"internalType":"uint64","name":"completedRequests","type":"uint64"},{"internalType":"address","name":"subscriptionOwner","type":"address"}],"internalType":"struct FunctionsResponse.RequestMeta","name":"request","type":"tuple"}],"name":"startRequest","outputs":[{"components":[{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"address","name":"coordinator","type":"address"},{"internalType":"uint96","name":"estimatedTotalCostJuels","type":"uint96"},{"internalType":"address","name":"client","type":"address"},{"internalType":"uint64","name":"subscriptionId","type":"uint64"},{"internalType":"uint32","name":"callbackGasLimit","type":"uint32"},{"internalType":"uint72","name":"adminFee","type":"uint72"},{"internalType":"uint72","name":"donFee","type":"uint72"},{"internalType":"uint40","name":"gasOverheadBeforeCallback","type":"uint40"},{"internalType":"uint40","name":"gasOverheadAfterCallback","type":"uint40"},{"internalType":"uint32","name":"timeoutTimestamp","type":"uint32"}],"internalType":"struct FunctionsResponse.Commitment","name":"commitment","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[3]","name":"reportContext","type":"bytes32[3]"},{"internalType":"bytes","name":"report","type":"bytes"},{"internalType":"bytes32[]","name":"rs","type":"bytes32[]"},{"internalType":"bytes32[]","name":"ss","type":"bytes32[]"},{"internalType":"bytes32","name":"rawVs","type":"bytes32"}],"name":"transmit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"transmitters","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"fulfillmentGasPriceOverEstimationBP","type":"uint32"},{"internalType":"uint32","name":"feedStalenessSeconds","type":"uint32"},{"internalType":"uint32","name":"gasOverheadBeforeCallback","type":"uint32"},{"internalType":"uint32","name":"gasOverheadAfterCallback","type":"uint32"},{"internalType":"uint40","name":"minimumEstimateGasPriceWei","type":"uint40"},{"internalType":"uint16","name":"maxSupportedRequestDataVersion","type":"uint16"},{"internalType":"uint64","name":"fallbackUsdPerUnitLink","type":"uint64"},{"internalType":"uint8","name":"fallbackUsdPerUnitLinkDecimals","type":"uint8"},{"internalType":"uint224","name":"fallbackNativePerUnitLink","type":"uint224"},{"internalType":"uint32","name":"requestTimeoutSeconds","type":"uint32"},{"internalType":"uint16","name":"donFeeCentsUsd","type":"uint16"},{"internalType":"uint16","name":"operationFeeCentsUsd","type":"uint16"}],"internalType":"struct FunctionsBillingConfig","name":"config","type":"tuple"}],"name":"updateConfig","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a06040523480156200001157600080fd5b506040516200601f3803806200601f8339810160408190526200003491620004db565b83838383833380600081620000905760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c357620000c3816200014e565b5050506001600160a01b038116620000ee57604051632530e88560e11b815260040160405180910390fd5b6001600160a01b03908116608052600c80546001600160601b03166c0100000000000000000000000085841602179055600d80546001600160a01b0319169183169190911790556200014083620001f9565b505050505050505062000742565b336001600160a01b03821603620001a85760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000087565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620002036200039e565b80516008805460208401516040808601516060870151608088015160a089015160c08a015160e08b015160ff16600160f81b026001600160f81b036001600160401b03909216600160b81b02919091166001600160b81b0361ffff938416600160a81b0261ffff60a81b1964ffffffffff909616600160801b029590951666ffffffffffffff60801b1963ffffffff9788166c010000000000000000000000000263ffffffff60601b19998916680100000000000000000299909916600160401b600160801b03199b8916640100000000026001600160401b0319909d169e89169e909e179b909b17999099169b909b1795909517979097169590951717969096161792909217909255610100840151610120850151909316600160e01b026001600160e01b0390931692909217600955610140830151600a80546101608601518416620100000263ffffffff19919091169290931691909117919091179055517f2e2c8535dcc25459d519f2300c114d2d2128bf6399722d04eca078461a3bf33a906200039390839062000639565b60405180910390a150565b620003a8620003aa565b565b6000546001600160a01b03163314620003a85760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000087565b80516001600160a01b03811681146200041e57600080fd5b919050565b60405161018081016001600160401b03811182821017156200045557634e487b7160e01b600052604160045260246000fd5b60405290565b805163ffffffff811681146200041e57600080fd5b805164ffffffffff811681146200041e57600080fd5b805161ffff811681146200041e57600080fd5b80516001600160401b03811681146200041e57600080fd5b805160ff811681146200041e57600080fd5b80516001600160e01b03811681146200041e57600080fd5b6000806000808486036101e0811215620004f457600080fd5b620004ff8662000406565b945061018080601f19830112156200051657600080fd5b6200052062000423565b915062000530602088016200045b565b825262000540604088016200045b565b602083015262000553606088016200045b565b604083015262000566608088016200045b565b60608301526200057960a0880162000470565b60808301526200058c60c0880162000486565b60a08301526200059f60e0880162000499565b60c0830152610100620005b4818901620004b1565b60e0840152610120620005c9818a01620004c3565b828501526101409150620005df828a016200045b565b90840152610160620005f389820162000486565b8285015262000604838a0162000486565b90840152509093506200061d90506101a0860162000406565b91506200062e6101c0860162000406565b905092959194509250565b815163ffffffff1681526101808101602083015162000660602084018263ffffffff169052565b50604083015162000679604084018263ffffffff169052565b50606083015162000692606084018263ffffffff169052565b506080830151620006ac608084018264ffffffffff169052565b5060a0830151620006c360a084018261ffff169052565b5060c0830151620006df60c08401826001600160401b03169052565b5060e0830151620006f560e084018260ff169052565b50610100838101516001600160e01b0316908301526101208084015163ffffffff16908301526101408084015161ffff908116918401919091526101609384015116929091019190915290565b608051615897620007886000396000818161079c01528181610c7d01528181610f110152818161102701528181611b2d015281816129eb015261396901526158976000f3fe608060405234801561001057600080fd5b50600436106101a35760003560e01c80638da5cb5b116100ee578063d227d24511610097578063e4ddcea611610071578063e4ddcea6146105d5578063f2f22ef1146105eb578063f2fde38b146105f3578063f6ea41f61461060657600080fd5b8063d227d2451461058a578063d328a91e146105ba578063e3d0e712146105c257600080fd5b8063b1dc65a4116100c8578063b1dc65a414610396578063ba9c924d146103a9578063c3f909d4146103bc57600080fd5b80638da5cb5b1461032e578063a631571e14610356578063afcb95d71461037657600080fd5b80637d4807871161015057806381f1b9381161012a57806381f1b938146102a657806381ff7048146102ae57806385b214cf1461031b57600080fd5b80637d480787146102765780637f15e1661461027e578063814118341461029157600080fd5b806366316d8d1161018157806366316d8d1461023c5780637212762f1461024f57806379ba50971461026e57600080fd5b8063083a5466146101a8578063181f5a77146101bd578063626f458c1461020f575b600080fd5b6101bb6101b6366004614010565b61060e565b005b6101f96040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e332e300000000081525081565b60405161020691906140c0565b60405180910390f35b61022261021d36600461422d565b610663565b60405168ffffffffffffffffff9091168152602001610206565b6101bb61024a3660046142b4565b6106a0565b610257610859565b6040805192835260ff909116602083015201610206565b6101bb610a6c565b6101bb610b69565b6101bb61028c366004614010565b610d69565b610299610db9565b604051610206919061433e565b6101f9610e28565b6102f860015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610206565b6101bb610329366004614351565b610ef9565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610206565b61036961036436600461436a565b610fb6565b60405161020691906144bf565b604080516001815260006020820181905291810191909152606001610206565b6101bb6103a4366004614513565b611247565b6101bb6103b736600461467e565b61185e565b61057d6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915250604080516101808101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c01000000000000000000000000810483166060830152700100000000000000000000000000000000810464ffffffffff1660808301527501000000000000000000000000000000000000000000810461ffff90811660a084015277010000000000000000000000000000000000000000000000820467ffffffffffffffff1660c08401527f010000000000000000000000000000000000000000000000000000000000000090910460ff1660e08301526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81166101008401527c01000000000000000000000000000000000000000000000000000000009004909216610120820152600a5480831661014083015262010000900490911661016082015290565b604051610206919061476a565b61059d610598366004614887565b611b29565b6040516bffffffffffffffffffffffff9091168152602001610206565b6101f9611c97565b6101bb6105d036600461498f565b611cee565b6105dd61286a565b604051908152602001610206565b6102226129ae565b6101bb610601366004614a5c565b6129d3565b6102226129e7565b610616612a78565b6000819003610651576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f61065e828483614b0c565b505050565b600a5460009061069a9060649061067d9061ffff16612afb565b6106879190614c85565b6bffffffffffffffffffffffff16612b48565b92915050565b6106a8612be7565b806bffffffffffffffffffffffff166000036106e25750336000908152600b60205260409020546bffffffffffffffffffffffff1661073c565b336000908152600b60205260409020546bffffffffffffffffffffffff8083169116101561073c576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b6020526040812080548392906107699084906bffffffffffffffffffffffff16614cb0565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506107be7f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b15801561083d57600080fd5b505af1158015610851573d6000803e3d6000fd5b505050505050565b600080600080600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156108cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f09190614cf6565b5093505092505080426109039190614d46565b600854640100000000900463ffffffff161080156109305750600854640100000000900463ffffffff1615155b1561098d57505060085477010000000000000000000000000000000000000000000000810467ffffffffffffffff16937f010000000000000000000000000000000000000000000000000000000000000090910460ff1692509050565b600082136109cf576040517f56b22ab8000000000000000000000000000000000000000000000000000000008152600481018390526024015b60405180910390fd5b600d54604080517f313ce5670000000000000000000000000000000000000000000000000000000081529051849273ffffffffffffffffffffffffffffffffffffffff169163313ce5679160048083019260209291908290030181865afa158015610a3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a629190614d59565b9350935050509091565b60015473ffffffffffffffffffffffffffffffffffffffff163314610aed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016109c6565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b71612d93565b610b79612be7565b6000610b83610db9565b905060005b8151811015610d65576000600b6000848481518110610ba957610ba9614d76565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610d54576000600b6000858581518110610c0857610c08614d76565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610c9f7f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610ccc57610ccc614d76565b6020026020010151836040518363ffffffff1660e01b8152600401610d2192919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610d3b57600080fd5b505af1158015610d4f573d6000803e3d6000fd5b505050505b50610d5e81614da5565b9050610b88565b5050565b610d71612a78565b6000819003610dac576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e61065e828483614b0c565b60606006805480602002602001604051908101604052809291908181526020018280548015610e1e57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610df3575b5050505050905090565b6060600f8054610e3790614a79565b9050600003610e72576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f8054610e7f90614a79565b80601f0160208091040260200160405190810160405280929190818152602001828054610eab90614a79565b8015610e1e5780601f10610ecd57610100808354040283529160200191610e1e565b820191906000526020600020905b815481529060010190602001808311610edb57509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f68576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f41690610fab9083815260200190565b60405180910390a150565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461107e576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061109161108c84614dff565b612d9b565b90925090506110a66060840160408501614a5c565b825173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff326110f460c0880160a08901614eec565b61110661016089016101408a01614a5c565b6111108980614f09565b6111226101208c016101008d01614f6e565b60208c01356111386101008e0160e08f01614f89565b6040518061016001604052808e6000015181526020018e6020015173ffffffffffffffffffffffffffffffffffffffff1681526020018e604001516bffffffffffffffffffffffff1681526020018e6060015173ffffffffffffffffffffffffffffffffffffffff1681526020018e6080015167ffffffffffffffff1681526020018e60a0015163ffffffff1681526020018d68ffffffffffffffffff1681526020018e60e0015168ffffffffffffffffff1681526020018e610100015164ffffffffff1681526020018e610120015164ffffffffff1681526020018e610140015163ffffffff1681525060405161123899989796959493929190614fa6565b60405180910390a3505b919050565b600080611254898961314d565b915091508115611265575050611854565b604080518b3580825262ffffff6020808f0135600881901c9290921690840152909290917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16112c28b8b8b8b8b8b6132d6565b6003546000906002906112e09060ff8082169161010090041661505c565b6112ea9190615075565b6112f590600161505c565b60ff169050888114611363576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e61747572657300000000000060448201526064016109c6565b8887146113f2576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f7265706f727420727320616e64207373206d757374206265206f66206571756160448201527f6c206c656e67746800000000000000000000000000000000000000000000000060648201526084016109c6565b3360009081526004602090815260408083208151808301909252805460ff8082168452929391929184019161010090910416600281111561143557611435615097565b600281111561144657611446615097565b905250905060028160200151600281111561146357611463615097565b141580156114ac57506006816000015160ff168154811061148657611486614d76565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff163314155b15611513576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d6974746572000000000000000060448201526064016109c6565b5050505061151f613faf565b60008a8a6040516115319291906150c6565b604051908190038120611548918e906020016150d6565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b898110156118445760006001848984602081106115b1576115b1614d76565b6115be91901a601b61505c565b8e8e868181106115d0576115d0614d76565b905060200201358d8d878181106115e9576115e9614d76565b9050602002013560405160008152602001604052604051611626949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611648573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff808216855292965092945084019161010090041660028111156116c8576116c8615097565b60028111156116d9576116d9615097565b90525092506001836020015160028111156116f6576116f6615097565b1461175d576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e000060448201526064016109c6565b8251600090869060ff16601f811061177757611777614d76565b602002015173ffffffffffffffffffffffffffffffffffffffff16146117f9576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e617475726500000000000000000000000060448201526064016109c6565b8085846000015160ff16601f811061181357611813614d76565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201525061183d81614da5565b9050611592565b5050506118508261338d565b5050505b5050505050505050565b611866612d93565b80516008805460208401516040808601516060870151608088015160a089015160c08a015160e08b015160ff167f0100000000000000000000000000000000000000000000000000000000000000027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff67ffffffffffffffff90921677010000000000000000000000000000000000000000000000029190911676ffffffffffffffffffffffffffffffffffffffffffffff61ffff9384167501000000000000000000000000000000000000000000027fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff64ffffffffff90961670010000000000000000000000000000000002959095167fffffffffffffffffff00000000000000ffffffffffffffffffffffffffffffff63ffffffff9788166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9989166801000000000000000002999099167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff9b8916640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909d169e89169e909e179b909b17999099169b909b17959095179790971695909517179690961617929092179092556101008401516101208501519093167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90931692909217600955610140830151600a8054610160860151841662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000919091169290931691909117919091179055517f2e2c8535dcc25459d519f2300c114d2d2128bf6399722d04eca078461a3bf33a90610fab90839061476a565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b158015611bc957600080fd5b505afa158015611bdd573d6000803e3d6000fd5b5050505066038d7ea4c68000821115611c22576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611c2c6129e7565b90506000611c6f87878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061066392505050565b90506000611c7b6129ae565b9050611c8a86868486856134dc565b9998505050505050505050565b6060600e8054611ca690614a79565b9050600003611ce1576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e8054610e7f90614a79565b855185518560ff16601f831115611d61576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e6572730000000000000000000000000000000060448201526064016109c6565b80600003611dcb576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f736974697665000000000000000000000000000060448201526064016109c6565b818314611e59576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e0000000000000000000000000000000000000000000000000000000060648201526084016109c6565b611e648160036150ea565b8311611ecc576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f2068696768000000000000000060448201526064016109c6565b611ed4612a78565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611f1b9088613658565b600554156120d057600554600090611f3590600190614d46565b9050600060058281548110611f4c57611f4c614d76565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611f8657611f86614d76565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009081169091559290911680845292208054909116905560058054919250908061200657612006615101565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055600680548061206f5761206f615101565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611f1b915050565b60005b815151811015612687578151805160009190839081106120f5576120f5614d76565b602002602001015173ffffffffffffffffffffffffffffffffffffffff160361217a576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f7369676e6572206d757374206e6f7420626520656d707479000000000000000060448201526064016109c6565b600073ffffffffffffffffffffffffffffffffffffffff16826020015182815181106121a8576121a8614d76565b602002602001015173ffffffffffffffffffffffffffffffffffffffff160361222d576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f7472616e736d6974746572206d757374206e6f7420626520656d70747900000060448201526064016109c6565b6000600460008460000151848151811061224957612249614d76565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff16600281111561229357612293615097565b146122fa576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e6572206164647265737300000000000000000060448201526064016109c6565b6040805180820190915260ff8216815260016020820152825180516004916000918590811061232b5761232b614d76565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016176101008360028111156123cc576123cc615097565b0217905550600091506123dc9050565b60046000846020015184815181106123f6576123f6614d76565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff16600281111561244057612440615097565b146124a7576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d697474657220616464726573730000000060448201526064016109c6565b6040805180820190915260ff8216815260208101600281525060046000846020015184815181106124da576124da614d76565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561257b5761257b615097565b02179055505082518051600592508390811061259957612599614d76565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909316929092179091558201518051600691908390811061261557612615614d76565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790558061267f81614da5565b9150506120d3565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff438116820292909217808555920481169291829160149161273f91849174010000000000000000000000000000000000000000900416615130565b92506101000a81548163ffffffff021916908363ffffffff16021790555061279e4630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a00151613671565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0598612855988b9891977401000000000000000000000000000000000000000090920463ffffffff1696909591949193919261514d565b60405180910390a15050505050505050505050565b6000806000600c8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156128da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128fe9190614cf6565b5093505092505080426129119190614d46565b600854640100000000900463ffffffff1610801561293e5750600854640100000000900463ffffffff1615155b1561296b5750506009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b600082136129a8576040517f43d4cf66000000000000000000000000000000000000000000000000000000008152600481018390526024016109c6565b50919050565b600a546000906129ce9060649061067d9062010000900461ffff16612afb565b905090565b6129db612a78565b6129e48161371c565b50565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a54573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ce91906151ee565b60005473ffffffffffffffffffffffffffffffffffffffff163314612af9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016109c6565b565b6000806000612b08610859565b9092509050612b4082612b1c83601261505c565b612b2790600a61532b565b612b3190876150ea565b612b3b919061533a565b613811565b949350505050565b600068ffffffffffffffffff821115612be3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203760448201527f322062697473000000000000000000000000000000000000000000000000000060648201526084016109c6565b5090565b600c546bffffffffffffffffffffffff16600003612c0157565b6000612c0b610db9565b80519091506000819003612c4b576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c54600090612c6a9083906bffffffffffffffffffffffff16614c85565b905060005b82811015612d355781600b6000868481518110612c8e57612c8e614d76565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff16612cf6919061534e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080612d2e90614da5565b9050612c6f565b50612d408282615373565b600c8054600090612d609084906bffffffffffffffffffffffff16614cb0565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505050565b612af9612a78565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915260085461010083015160009161ffff7501000000000000000000000000000000000000000000909104811691161115612e59576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612e688460000151610663565b9050612e726129ae565b91506000612e8b8560e001513a848860800151876134dc565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612ee7576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600954600090612f1d907c0100000000000000000000000000000000000000000000000000000000900463ffffffff164261539b565b905060003087604001518860a001518960c001516001612f3d91906153ae565b8a5180516020918201206101008d015160e08e0151604051612ff198979695948c918c9132910173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a015267ffffffffffffffff97881660408a0152959096166060880152608087019390935261ffff9190911660a086015263ffffffff90811660c08601526bffffffffffffffffffffffff9190911660e0850152919091166101008301529091166101208201526101400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201206101608401835280845230848301526bffffffffffffffffffffffff8716848401528a83015173ffffffffffffffffffffffffffffffffffffffff16606085015260a0808c015167ffffffffffffffff1660808087019190915260e0808e015163ffffffff90811693880193909352908d015168ffffffffffffffffff90811660c08801528a169086015260085468010000000000000000810482166101008701526c0100000000000000000000000090048116610120860152861661014085015291519298509092506130fd918891016144bf565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181528151602092830120600093845260079092529091205550929491935090915050565b60006131816040518060a0016040528060608152602001606081526020016060815260200160608152602001606081525090565b600080808080613193888a018a6154aa565b84519499509297509095509350915060ff168015806131b3575084518114155b806131bf575083518114155b806131cb575082518114155b806131d7575081518114155b1561323e576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4669656c6473206d75737420626520657175616c206c656e677468000000000060448201526064016109c6565b60005b818110156132a45761327a87828151811061325e5761325e614d76565b6020026020010151600090815260076020526040902054151590565b6132a457613289600183614d46565b810361329457600198505b61329d81614da5565b9050613241565b50506040805160a0810182529586526020860194909452928401919091526060830152608082015290505b9250929050565b60006132e38260206150ea565b6132ee8560206150ea565b6132fa8861014461539b565b613304919061539b565b61330e919061539b565b61331990600061539b565b9050368114613384576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d61746368000000000000000060448201526064016109c6565b50505050505050565b80515160ff1660005b8181101561065e57600061343f846000015183815181106133b9576133b9614d76565b6020026020010151856020015184815181106133d7576133d7614d76565b6020026020010151866040015185815181106133f5576133f5614d76565b60200260200101518760600151868151811061341357613413614d76565b60200260200101518860800151878151811061343157613431614d76565b6020026020010151886138af565b9050600081600681111561345557613455615097565b14806134725750600181600681111561347057613470615097565b145b156134cb57835180518390811061348b5761348b614d76565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b506134d581614da5565b9050613396565b600854600090700100000000000000000000000000000000900464ffffffffff1685101561352557600854700100000000000000000000000000000000900464ffffffffff1694505b6008546000906127109061353f9063ffffffff16886150ea565b613549919061533a565b613553908761539b565b600854909150600090889061358c9063ffffffff6c01000000000000000000000000820481169168010000000000000000900416615130565b6135969190615130565b63ffffffff16905060006135e06000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613d7392505050565b90506000613601826135f285876150ea565b6135fc919061539b565b613eb5565b905060008668ffffffffffffffffff168868ffffffffffffffffff168a68ffffffffffffffffff16613633919061534e565b61363d919061534e565b9050613649818361534e565b9b9a5050505050505050505050565b6000613662610db9565b511115610d6557610d65612be7565b6000808a8a8a8a8a8a8a8a8a6040516020016136959998979695949392919061557c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff82160361379b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016109c6565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60006bffffffffffffffffffffffff821115612be3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f362062697473000000000000000000000000000000000000000000000000000060648201526084016109c6565b600080848060200190518101906138c69190615648565b905060003a8261012001518361010001516138e19190615710565b64ffffffffff166138f291906150ea565b905060008460ff1661393a6000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613d7392505050565b613944919061533a565b905060006139556135fc838561539b565b905060006139623a613eb5565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298e8e868b60c0015168ffffffffffffffffff168c60e0015168ffffffffffffffffff168a6139d1919061534e565b6139db919061534e565b336040518061016001604052808f6000015181526020018f6020015173ffffffffffffffffffffffffffffffffffffffff1681526020018f604001516bffffffffffffffffffffffff1681526020018f6060015173ffffffffffffffffffffffffffffffffffffffff1681526020018f6080015167ffffffffffffffff1681526020018f60a0015163ffffffff168152602001600068ffffffffffffffffff1681526020018f60e0015168ffffffffffffffffff1681526020018f610100015164ffffffffff1681526020018f610120015164ffffffffff1681526020018f610140015163ffffffff168152506040518763ffffffff1660e01b8152600401613ae99695949392919061572e565b60408051808303816000875af1158015613b07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b2b91906157aa565b90925090506000826006811115613b4457613b44615097565b1480613b6157506001826006811115613b5f57613b5f615097565b145b15613d625760008e815260076020526040812055613b7f818561534e565b336000908152600b602052604081208054909190613bac9084906bffffffffffffffffffffffff1661534e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508660e0015168ffffffffffffffffff16600c60008282829054906101000a90046bffffffffffffffffffffffff16613c12919061534e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508660c0015168ffffffffffffffffff16600b6000613c5c613ed4565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160009081208054909190613ca29084906bffffffffffffffffffffffff1661534e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508d7f08a4a0761e3c98d288cb4af9342660f49550d83139fb3b762b70d34bed6273688487848b60e0015160008d60c00151604051613d59969594939291906bffffffffffffffffffffffff9687168152602081019590955292909416604084015268ffffffffffffffffff9081166060840152928316608083015290911660a082015260c00190565b60405180910390a25b509c9b505050505050505050505050565b600046613d7f81613f45565b15613dfb57606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613dd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613df491906157dd565b9392505050565b613e0481613f68565b15613eac5773420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e8460405180608001604052806048815260200161584360489139604051602001613e649291906157f6565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401613e8f91906140c0565b602060405180830381865afa158015613dd0573d6000803e3d6000fd5b50600092915050565b600061069a613ec261286a565b612b3184670de0b6b3a76400006150ea565b60003073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613f21573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ce9190615825565b600061a4b1821480613f59575062066eed82145b8061069a57505062066eee1490565b6000600a821480613f7a57506101a482145b80613f87575062aa37dc82145b80613f93575061210582145b80613fa0575062014a3382145b8061069a57505062014a341490565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f840112613fe057600080fd5b50813567ffffffffffffffff811115613ff857600080fd5b6020830191508360208285010111156132cf57600080fd5b6000806020838503121561402357600080fd5b823567ffffffffffffffff81111561403a57600080fd5b61404685828601613fce565b90969095509350505050565b60005b8381101561406d578181015183820152602001614055565b50506000910152565b6000815180845261408e816020860160208601614052565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000613df46020830184614076565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610180810167ffffffffffffffff81118282101715614126576141266140d3565b60405290565b604051610160810167ffffffffffffffff81118282101715614126576141266140d3565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614197576141976140d3565b604052919050565b600082601f8301126141b057600080fd5b813567ffffffffffffffff8111156141ca576141ca6140d3565b6141fb60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614150565b81815284602083860101111561421057600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561423f57600080fd5b813567ffffffffffffffff81111561425657600080fd5b612b408482850161419f565b73ffffffffffffffffffffffffffffffffffffffff811681146129e457600080fd5b803561124281614262565b6bffffffffffffffffffffffff811681146129e457600080fd5b80356112428161428f565b600080604083850312156142c757600080fd5b82356142d281614262565b915060208301356142e28161428f565b809150509250929050565b600081518084526020808501945080840160005b8381101561433357815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614301565b509495945050505050565b602081526000613df460208301846142ed565b60006020828403121561436357600080fd5b5035919050565b60006020828403121561437c57600080fd5b813567ffffffffffffffff81111561439357600080fd5b82016101608185031215613df457600080fd5b8051825260208101516143d1602084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060408101516143f160408401826bffffffffffffffffffffffff169052565b506060810151614419606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151614435608084018267ffffffffffffffff169052565b5060a081015161444d60a084018263ffffffff169052565b5060c081015161446a60c084018268ffffffffffffffffff169052565b5060e081015161448760e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b610160810161069a82846143a6565b60008083601f8401126144e057600080fd5b50813567ffffffffffffffff8111156144f857600080fd5b6020830191508360208260051b85010111156132cf57600080fd5b60008060008060008060008060e0898b03121561452f57600080fd5b606089018a81111561454057600080fd5b8998503567ffffffffffffffff8082111561455a57600080fd5b6145668c838d01613fce565b909950975060808b013591508082111561457f57600080fd5b61458b8c838d016144ce565b909750955060a08b01359150808211156145a457600080fd5b506145b18b828c016144ce565b999c989b50969995989497949560c00135949350505050565b63ffffffff811681146129e457600080fd5b8035611242816145ca565b64ffffffffff811681146129e457600080fd5b8035611242816145e7565b803561ffff8116811461124257600080fd5b67ffffffffffffffff811681146129e457600080fd5b803561124281614617565b60ff811681146129e457600080fd5b803561124281614638565b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461124257600080fd5b6000610180828403121561469157600080fd5b614699614102565b6146a2836145dc565b81526146b0602084016145dc565b60208201526146c1604084016145dc565b60408201526146d2606084016145dc565b60608201526146e3608084016145fa565b60808201526146f460a08401614605565b60a082015261470560c0840161462d565b60c082015261471660e08401614647565b60e0820152610100614729818501614652565b9082015261012061473b8482016145dc565b9082015261014061474d848201614605565b9082015261016061475f848201614605565b908201529392505050565b815163ffffffff16815261018081016020830151614790602084018263ffffffff169052565b5060408301516147a8604084018263ffffffff169052565b5060608301516147c0606084018263ffffffff169052565b5060808301516147d9608084018264ffffffffff169052565b5060a08301516147ef60a084018261ffff169052565b5060c083015161480b60c084018267ffffffffffffffff169052565b5060e083015161482060e084018260ff169052565b50610100838101517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16908301526101208084015163ffffffff16908301526101408084015161ffff908116918401919091526101608085015191821681850152905b505092915050565b60008060008060006080868803121561489f57600080fd5b85356148aa81614617565b9450602086013567ffffffffffffffff8111156148c657600080fd5b6148d288828901613fce565b90955093505060408601356148e6816145ca565b949793965091946060013592915050565b600067ffffffffffffffff821115614911576149116140d3565b5060051b60200190565b600082601f83011261492c57600080fd5b8135602061494161493c836148f7565b614150565b82815260059290921b8401810191818101908684111561496057600080fd5b8286015b8481101561498457803561497781614262565b8352918301918301614964565b509695505050505050565b60008060008060008060c087890312156149a857600080fd5b863567ffffffffffffffff808211156149c057600080fd5b6149cc8a838b0161491b565b975060208901359150808211156149e257600080fd5b6149ee8a838b0161491b565b96506149fc60408a01614647565b95506060890135915080821115614a1257600080fd5b614a1e8a838b0161419f565b9450614a2c60808a0161462d565b935060a0890135915080821115614a4257600080fd5b50614a4f89828a0161419f565b9150509295509295509295565b600060208284031215614a6e57600080fd5b8135613df481614262565b600181811c90821680614a8d57607f821691505b6020821081036129a8577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b601f82111561065e57600081815260208120601f850160051c81016020861015614aed5750805b601f850160051c820191505b8181101561085157828155600101614af9565b67ffffffffffffffff831115614b2457614b246140d3565b614b3883614b328354614a79565b83614ac6565b6000601f841160018114614b8a5760008515614b545750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614c20565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015614bd95786850135825560209485019460019092019101614bb9565b5086821015614c14577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006bffffffffffffffffffffffff80841680614ca457614ca4614c27565b92169190910492915050565b6bffffffffffffffffffffffff828116828216039080821115614cd557614cd5614c56565b5092915050565b805169ffffffffffffffffffff8116811461124257600080fd5b600080600080600060a08688031215614d0e57600080fd5b614d1786614cdc565b9450602086015193506040860151925060608601519150614d3a60808701614cdc565b90509295509295909350565b8181038181111561069a5761069a614c56565b600060208284031215614d6b57600080fd5b8151613df481614638565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614dd657614dd6614c56565b5060010190565b68ffffffffffffffffff811681146129e457600080fd5b803561124281614ddd565b60006101608236031215614e1257600080fd5b614e1a61412c565b823567ffffffffffffffff811115614e3157600080fd5b614e3d3682860161419f565b82525060208301356020820152614e5660408401614284565b6040820152614e67606084016142a9565b6060820152614e7860808401614df4565b6080820152614e8960a0840161462d565b60a0820152614e9a60c0840161462d565b60c0820152614eab60e084016145dc565b60e0820152610100614ebe818501614605565b90820152610120614ed084820161462d565b90820152610140614ee2848201614284565b9082015292915050565b600060208284031215614efe57600080fd5b8135613df481614617565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614f3e57600080fd5b83018035915067ffffffffffffffff821115614f5957600080fd5b6020019150368190038213156132cf57600080fd5b600060208284031215614f8057600080fd5b613df482614605565b600060208284031215614f9b57600080fd5b8135613df4816145ca565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016830101905061504e60e08301846143a6565b9a9950505050505050505050565b60ff818116838216019081111561069a5761069a614c56565b600060ff83168061508857615088614c27565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b808202811582820484141761069a5761069a614c56565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff818116838216019080821115614cd557614cd5614c56565b600061012063ffffffff808d1684528b6020850152808b1660408501525080606084015261517d8184018a6142ed565b9050828103608084015261519181896142ed565b905060ff871660a084015282810360c08401526151ae8187614076565b905067ffffffffffffffff851660e08401528281036101008401526151d38185614076565b9c9b505050505050505050505050565b805161124281614ddd565b60006020828403121561520057600080fd5b8151613df481614ddd565b600181815b8085111561526457817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561524a5761524a614c56565b8085161561525757918102915b93841c9390800290615210565b509250929050565b60008261527b5750600161069a565b816152885750600061069a565b816001811461529e57600281146152a8576152c4565b600191505061069a565b60ff8411156152b9576152b9614c56565b50506001821b61069a565b5060208310610133831016604e8410600b84101617156152e7575081810a61069a565b6152f1838361520b565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561532357615323614c56565b029392505050565b6000613df460ff84168361526c565b60008261534957615349614c27565b500490565b6bffffffffffffffffffffffff818116838216019080821115614cd557614cd5614c56565b6bffffffffffffffffffffffff81811683821602808216919082811461487f5761487f614c56565b8082018082111561069a5761069a614c56565b67ffffffffffffffff818116838216019080821115614cd557614cd5614c56565b600082601f8301126153e057600080fd5b813560206153f061493c836148f7565b82815260059290921b8401810191818101908684111561540f57600080fd5b8286015b848110156149845780358352918301918301615413565b600082601f83011261543b57600080fd5b8135602061544b61493c836148f7565b82815260059290921b8401810191818101908684111561546a57600080fd5b8286015b8481101561498457803567ffffffffffffffff81111561548e5760008081fd5b61549c8986838b010161419f565b84525091830191830161546e565b600080600080600060a086880312156154c257600080fd5b853567ffffffffffffffff808211156154da57600080fd5b6154e689838a016153cf565b965060208801359150808211156154fc57600080fd5b61550889838a0161542a565b9550604088013591508082111561551e57600080fd5b61552a89838a0161542a565b9450606088013591508082111561554057600080fd5b61554c89838a0161542a565b9350608088013591508082111561556257600080fd5b5061556f8882890161542a565b9150509295509295909350565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526155c38285018b6142ed565b915083820360808501526155d7828a6142ed565b915060ff881660a085015283820360c08501526155f48288614076565b90861660e085015283810361010085015290506151d38185614076565b805161124281614262565b80516112428161428f565b805161124281614617565b8051611242816145ca565b8051611242816145e7565b6000610160828403121561565b57600080fd5b61566361412c565b8251815261567360208401615611565b60208201526156846040840161561c565b604082015261569560608401615611565b60608201526156a660808401615627565b60808201526156b760a08401615632565b60a08201526156c860c084016151e3565b60c08201526156d960e084016151e3565b60e08201526101006156ec81850161563d565b908201526101206156fe84820161563d565b9082015261014061475f848201615632565b64ffffffffff818116838216019080821115614cd557614cd5614c56565b60006102008083526157428184018a614076565b905082810360208401526157568189614076565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff86166080850152915061579f905060a08301846143a6565b979650505050505050565b600080604083850312156157bd57600080fd5b8251600781106157cc57600080fd5b60208401519092506142e28161428f565b6000602082840312156157ef57600080fd5b5051919050565b60008351615808818460208801614052565b83519083019061581c818360208801614052565b01949350505050565b60006020828403121561583757600080fd5b8151613df48161426256fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000813000a000000000000000000000000aa8aaa682c9ef150c0c8e96a8d60945bcb21faad00000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000000000000009fe98000000000000000000000000000000000000000000000000000000000000dea8000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000073f2206600000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000018dc6e34596c2f000000000000000000000000000000000000000000000000000000000000012c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000464a1515adc20de946f8d0deb99cead8ceae310d000000000000000000000000cc232dcfaae6354ce191bd574108c1ad03f86450
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101a35760003560e01c80638da5cb5b116100ee578063d227d24511610097578063e4ddcea611610071578063e4ddcea6146105d5578063f2f22ef1146105eb578063f2fde38b146105f3578063f6ea41f61461060657600080fd5b8063d227d2451461058a578063d328a91e146105ba578063e3d0e712146105c257600080fd5b8063b1dc65a4116100c8578063b1dc65a414610396578063ba9c924d146103a9578063c3f909d4146103bc57600080fd5b80638da5cb5b1461032e578063a631571e14610356578063afcb95d71461037657600080fd5b80637d4807871161015057806381f1b9381161012a57806381f1b938146102a657806381ff7048146102ae57806385b214cf1461031b57600080fd5b80637d480787146102765780637f15e1661461027e578063814118341461029157600080fd5b806366316d8d1161018157806366316d8d1461023c5780637212762f1461024f57806379ba50971461026e57600080fd5b8063083a5466146101a8578063181f5a77146101bd578063626f458c1461020f575b600080fd5b6101bb6101b6366004614010565b61060e565b005b6101f96040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e332e300000000081525081565b60405161020691906140c0565b60405180910390f35b61022261021d36600461422d565b610663565b60405168ffffffffffffffffff9091168152602001610206565b6101bb61024a3660046142b4565b6106a0565b610257610859565b6040805192835260ff909116602083015201610206565b6101bb610a6c565b6101bb610b69565b6101bb61028c366004614010565b610d69565b610299610db9565b604051610206919061433e565b6101f9610e28565b6102f860015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610206565b6101bb610329366004614351565b610ef9565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610206565b61036961036436600461436a565b610fb6565b60405161020691906144bf565b604080516001815260006020820181905291810191909152606001610206565b6101bb6103a4366004614513565b611247565b6101bb6103b736600461467e565b61185e565b61057d6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915250604080516101808101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c01000000000000000000000000810483166060830152700100000000000000000000000000000000810464ffffffffff1660808301527501000000000000000000000000000000000000000000810461ffff90811660a084015277010000000000000000000000000000000000000000000000820467ffffffffffffffff1660c08401527f010000000000000000000000000000000000000000000000000000000000000090910460ff1660e08301526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81166101008401527c01000000000000000000000000000000000000000000000000000000009004909216610120820152600a5480831661014083015262010000900490911661016082015290565b604051610206919061476a565b61059d610598366004614887565b611b29565b6040516bffffffffffffffffffffffff9091168152602001610206565b6101f9611c97565b6101bb6105d036600461498f565b611cee565b6105dd61286a565b604051908152602001610206565b6102226129ae565b6101bb610601366004614a5c565b6129d3565b6102226129e7565b610616612a78565b6000819003610651576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f61065e828483614b0c565b505050565b600a5460009061069a9060649061067d9061ffff16612afb565b6106879190614c85565b6bffffffffffffffffffffffff16612b48565b92915050565b6106a8612be7565b806bffffffffffffffffffffffff166000036106e25750336000908152600b60205260409020546bffffffffffffffffffffffff1661073c565b336000908152600b60205260409020546bffffffffffffffffffffffff8083169116101561073c576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b6020526040812080548392906107699084906bffffffffffffffffffffffff16614cb0565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506107be7f000000000000000000000000aa8aaa682c9ef150c0c8e96a8d60945bcb21faad90565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b15801561083d57600080fd5b505af1158015610851573d6000803e3d6000fd5b505050505050565b600080600080600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156108cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f09190614cf6565b5093505092505080426109039190614d46565b600854640100000000900463ffffffff161080156109305750600854640100000000900463ffffffff1615155b1561098d57505060085477010000000000000000000000000000000000000000000000810467ffffffffffffffff16937f010000000000000000000000000000000000000000000000000000000000000090910460ff1692509050565b600082136109cf576040517f56b22ab8000000000000000000000000000000000000000000000000000000008152600481018390526024015b60405180910390fd5b600d54604080517f313ce5670000000000000000000000000000000000000000000000000000000081529051849273ffffffffffffffffffffffffffffffffffffffff169163313ce5679160048083019260209291908290030181865afa158015610a3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a629190614d59565b9350935050509091565b60015473ffffffffffffffffffffffffffffffffffffffff163314610aed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016109c6565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b71612d93565b610b79612be7565b6000610b83610db9565b905060005b8151811015610d65576000600b6000848481518110610ba957610ba9614d76565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610d54576000600b6000858581518110610c0857610c08614d76565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610c9f7f000000000000000000000000aa8aaa682c9ef150c0c8e96a8d60945bcb21faad90565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610ccc57610ccc614d76565b6020026020010151836040518363ffffffff1660e01b8152600401610d2192919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610d3b57600080fd5b505af1158015610d4f573d6000803e3d6000fd5b505050505b50610d5e81614da5565b9050610b88565b5050565b610d71612a78565b6000819003610dac576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e61065e828483614b0c565b60606006805480602002602001604051908101604052809291908181526020018280548015610e1e57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610df3575b5050505050905090565b6060600f8054610e3790614a79565b9050600003610e72576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f8054610e7f90614a79565b80601f0160208091040260200160405190810160405280929190818152602001828054610eab90614a79565b8015610e1e5780601f10610ecd57610100808354040283529160200191610e1e565b820191906000526020600020905b815481529060010190602001808311610edb57509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000aa8aaa682c9ef150c0c8e96a8d60945bcb21faad1614610f68576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f41690610fab9083815260200190565b60405180910390a150565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000aa8aaa682c9ef150c0c8e96a8d60945bcb21faad161461107e576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061109161108c84614dff565b612d9b565b90925090506110a66060840160408501614a5c565b825173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff326110f460c0880160a08901614eec565b61110661016089016101408a01614a5c565b6111108980614f09565b6111226101208c016101008d01614f6e565b60208c01356111386101008e0160e08f01614f89565b6040518061016001604052808e6000015181526020018e6020015173ffffffffffffffffffffffffffffffffffffffff1681526020018e604001516bffffffffffffffffffffffff1681526020018e6060015173ffffffffffffffffffffffffffffffffffffffff1681526020018e6080015167ffffffffffffffff1681526020018e60a0015163ffffffff1681526020018d68ffffffffffffffffff1681526020018e60e0015168ffffffffffffffffff1681526020018e610100015164ffffffffff1681526020018e610120015164ffffffffff1681526020018e610140015163ffffffff1681525060405161123899989796959493929190614fa6565b60405180910390a3505b919050565b600080611254898961314d565b915091508115611265575050611854565b604080518b3580825262ffffff6020808f0135600881901c9290921690840152909290917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16112c28b8b8b8b8b8b6132d6565b6003546000906002906112e09060ff8082169161010090041661505c565b6112ea9190615075565b6112f590600161505c565b60ff169050888114611363576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e61747572657300000000000060448201526064016109c6565b8887146113f2576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f7265706f727420727320616e64207373206d757374206265206f66206571756160448201527f6c206c656e67746800000000000000000000000000000000000000000000000060648201526084016109c6565b3360009081526004602090815260408083208151808301909252805460ff8082168452929391929184019161010090910416600281111561143557611435615097565b600281111561144657611446615097565b905250905060028160200151600281111561146357611463615097565b141580156114ac57506006816000015160ff168154811061148657611486614d76565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff163314155b15611513576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d6974746572000000000000000060448201526064016109c6565b5050505061151f613faf565b60008a8a6040516115319291906150c6565b604051908190038120611548918e906020016150d6565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b898110156118445760006001848984602081106115b1576115b1614d76565b6115be91901a601b61505c565b8e8e868181106115d0576115d0614d76565b905060200201358d8d878181106115e9576115e9614d76565b9050602002013560405160008152602001604052604051611626949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611648573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff808216855292965092945084019161010090041660028111156116c8576116c8615097565b60028111156116d9576116d9615097565b90525092506001836020015160028111156116f6576116f6615097565b1461175d576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e000060448201526064016109c6565b8251600090869060ff16601f811061177757611777614d76565b602002015173ffffffffffffffffffffffffffffffffffffffff16146117f9576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e617475726500000000000000000000000060448201526064016109c6565b8085846000015160ff16601f811061181357611813614d76565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201525061183d81614da5565b9050611592565b5050506118508261338d565b5050505b5050505050505050565b611866612d93565b80516008805460208401516040808601516060870151608088015160a089015160c08a015160e08b015160ff167f0100000000000000000000000000000000000000000000000000000000000000027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff67ffffffffffffffff90921677010000000000000000000000000000000000000000000000029190911676ffffffffffffffffffffffffffffffffffffffffffffff61ffff9384167501000000000000000000000000000000000000000000027fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff64ffffffffff90961670010000000000000000000000000000000002959095167fffffffffffffffffff00000000000000ffffffffffffffffffffffffffffffff63ffffffff9788166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9989166801000000000000000002999099167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff9b8916640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909d169e89169e909e179b909b17999099169b909b17959095179790971695909517179690961617929092179092556101008401516101208501519093167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90931692909217600955610140830151600a8054610160860151841662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000919091169290931691909117919091179055517f2e2c8535dcc25459d519f2300c114d2d2128bf6399722d04eca078461a3bf33a90610fab90839061476a565b60007f000000000000000000000000aa8aaa682c9ef150c0c8e96a8d60945bcb21faad6040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b158015611bc957600080fd5b505afa158015611bdd573d6000803e3d6000fd5b5050505066038d7ea4c68000821115611c22576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611c2c6129e7565b90506000611c6f87878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061066392505050565b90506000611c7b6129ae565b9050611c8a86868486856134dc565b9998505050505050505050565b6060600e8054611ca690614a79565b9050600003611ce1576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e8054610e7f90614a79565b855185518560ff16601f831115611d61576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e6572730000000000000000000000000000000060448201526064016109c6565b80600003611dcb576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f736974697665000000000000000000000000000060448201526064016109c6565b818314611e59576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e0000000000000000000000000000000000000000000000000000000060648201526084016109c6565b611e648160036150ea565b8311611ecc576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f2068696768000000000000000060448201526064016109c6565b611ed4612a78565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611f1b9088613658565b600554156120d057600554600090611f3590600190614d46565b9050600060058281548110611f4c57611f4c614d76565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611f8657611f86614d76565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009081169091559290911680845292208054909116905560058054919250908061200657612006615101565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055600680548061206f5761206f615101565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611f1b915050565b60005b815151811015612687578151805160009190839081106120f5576120f5614d76565b602002602001015173ffffffffffffffffffffffffffffffffffffffff160361217a576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f7369676e6572206d757374206e6f7420626520656d707479000000000000000060448201526064016109c6565b600073ffffffffffffffffffffffffffffffffffffffff16826020015182815181106121a8576121a8614d76565b602002602001015173ffffffffffffffffffffffffffffffffffffffff160361222d576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f7472616e736d6974746572206d757374206e6f7420626520656d70747900000060448201526064016109c6565b6000600460008460000151848151811061224957612249614d76565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff16600281111561229357612293615097565b146122fa576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e6572206164647265737300000000000000000060448201526064016109c6565b6040805180820190915260ff8216815260016020820152825180516004916000918590811061232b5761232b614d76565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016176101008360028111156123cc576123cc615097565b0217905550600091506123dc9050565b60046000846020015184815181106123f6576123f6614d76565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff16600281111561244057612440615097565b146124a7576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d697474657220616464726573730000000060448201526064016109c6565b6040805180820190915260ff8216815260208101600281525060046000846020015184815181106124da576124da614d76565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561257b5761257b615097565b02179055505082518051600592508390811061259957612599614d76565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909316929092179091558201518051600691908390811061261557612615614d76565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790558061267f81614da5565b9150506120d3565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff438116820292909217808555920481169291829160149161273f91849174010000000000000000000000000000000000000000900416615130565b92506101000a81548163ffffffff021916908363ffffffff16021790555061279e4630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a00151613671565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0598612855988b9891977401000000000000000000000000000000000000000090920463ffffffff1696909591949193919261514d565b60405180910390a15050505050505050505050565b6000806000600c8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156128da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128fe9190614cf6565b5093505092505080426129119190614d46565b600854640100000000900463ffffffff1610801561293e5750600854640100000000900463ffffffff1615155b1561296b5750506009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b600082136129a8576040517f43d4cf66000000000000000000000000000000000000000000000000000000008152600481018390526024016109c6565b50919050565b600a546000906129ce9060649061067d9062010000900461ffff16612afb565b905090565b6129db612a78565b6129e48161371c565b50565b60007f000000000000000000000000aa8aaa682c9ef150c0c8e96a8d60945bcb21faad73ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a54573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ce91906151ee565b60005473ffffffffffffffffffffffffffffffffffffffff163314612af9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016109c6565b565b6000806000612b08610859565b9092509050612b4082612b1c83601261505c565b612b2790600a61532b565b612b3190876150ea565b612b3b919061533a565b613811565b949350505050565b600068ffffffffffffffffff821115612be3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203760448201527f322062697473000000000000000000000000000000000000000000000000000060648201526084016109c6565b5090565b600c546bffffffffffffffffffffffff16600003612c0157565b6000612c0b610db9565b80519091506000819003612c4b576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c54600090612c6a9083906bffffffffffffffffffffffff16614c85565b905060005b82811015612d355781600b6000868481518110612c8e57612c8e614d76565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff16612cf6919061534e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080612d2e90614da5565b9050612c6f565b50612d408282615373565b600c8054600090612d609084906bffffffffffffffffffffffff16614cb0565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505050565b612af9612a78565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915260085461010083015160009161ffff7501000000000000000000000000000000000000000000909104811691161115612e59576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612e688460000151610663565b9050612e726129ae565b91506000612e8b8560e001513a848860800151876134dc565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612ee7576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600954600090612f1d907c0100000000000000000000000000000000000000000000000000000000900463ffffffff164261539b565b905060003087604001518860a001518960c001516001612f3d91906153ae565b8a5180516020918201206101008d015160e08e0151604051612ff198979695948c918c9132910173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a015267ffffffffffffffff97881660408a0152959096166060880152608087019390935261ffff9190911660a086015263ffffffff90811660c08601526bffffffffffffffffffffffff9190911660e0850152919091166101008301529091166101208201526101400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201206101608401835280845230848301526bffffffffffffffffffffffff8716848401528a83015173ffffffffffffffffffffffffffffffffffffffff16606085015260a0808c015167ffffffffffffffff1660808087019190915260e0808e015163ffffffff90811693880193909352908d015168ffffffffffffffffff90811660c08801528a169086015260085468010000000000000000810482166101008701526c0100000000000000000000000090048116610120860152861661014085015291519298509092506130fd918891016144bf565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181528151602092830120600093845260079092529091205550929491935090915050565b60006131816040518060a0016040528060608152602001606081526020016060815260200160608152602001606081525090565b600080808080613193888a018a6154aa565b84519499509297509095509350915060ff168015806131b3575084518114155b806131bf575083518114155b806131cb575082518114155b806131d7575081518114155b1561323e576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4669656c6473206d75737420626520657175616c206c656e677468000000000060448201526064016109c6565b60005b818110156132a45761327a87828151811061325e5761325e614d76565b6020026020010151600090815260076020526040902054151590565b6132a457613289600183614d46565b810361329457600198505b61329d81614da5565b9050613241565b50506040805160a0810182529586526020860194909452928401919091526060830152608082015290505b9250929050565b60006132e38260206150ea565b6132ee8560206150ea565b6132fa8861014461539b565b613304919061539b565b61330e919061539b565b61331990600061539b565b9050368114613384576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d61746368000000000000000060448201526064016109c6565b50505050505050565b80515160ff1660005b8181101561065e57600061343f846000015183815181106133b9576133b9614d76565b6020026020010151856020015184815181106133d7576133d7614d76565b6020026020010151866040015185815181106133f5576133f5614d76565b60200260200101518760600151868151811061341357613413614d76565b60200260200101518860800151878151811061343157613431614d76565b6020026020010151886138af565b9050600081600681111561345557613455615097565b14806134725750600181600681111561347057613470615097565b145b156134cb57835180518390811061348b5761348b614d76565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b506134d581614da5565b9050613396565b600854600090700100000000000000000000000000000000900464ffffffffff1685101561352557600854700100000000000000000000000000000000900464ffffffffff1694505b6008546000906127109061353f9063ffffffff16886150ea565b613549919061533a565b613553908761539b565b600854909150600090889061358c9063ffffffff6c01000000000000000000000000820481169168010000000000000000900416615130565b6135969190615130565b63ffffffff16905060006135e06000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613d7392505050565b90506000613601826135f285876150ea565b6135fc919061539b565b613eb5565b905060008668ffffffffffffffffff168868ffffffffffffffffff168a68ffffffffffffffffff16613633919061534e565b61363d919061534e565b9050613649818361534e565b9b9a5050505050505050505050565b6000613662610db9565b511115610d6557610d65612be7565b6000808a8a8a8a8a8a8a8a8a6040516020016136959998979695949392919061557c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff82160361379b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016109c6565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60006bffffffffffffffffffffffff821115612be3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f362062697473000000000000000000000000000000000000000000000000000060648201526084016109c6565b600080848060200190518101906138c69190615648565b905060003a8261012001518361010001516138e19190615710565b64ffffffffff166138f291906150ea565b905060008460ff1661393a6000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613d7392505050565b613944919061533a565b905060006139556135fc838561539b565b905060006139623a613eb5565b90506000807f000000000000000000000000aa8aaa682c9ef150c0c8e96a8d60945bcb21faad73ffffffffffffffffffffffffffffffffffffffff1663330605298e8e868b60c0015168ffffffffffffffffff168c60e0015168ffffffffffffffffff168a6139d1919061534e565b6139db919061534e565b336040518061016001604052808f6000015181526020018f6020015173ffffffffffffffffffffffffffffffffffffffff1681526020018f604001516bffffffffffffffffffffffff1681526020018f6060015173ffffffffffffffffffffffffffffffffffffffff1681526020018f6080015167ffffffffffffffff1681526020018f60a0015163ffffffff168152602001600068ffffffffffffffffff1681526020018f60e0015168ffffffffffffffffff1681526020018f610100015164ffffffffff1681526020018f610120015164ffffffffff1681526020018f610140015163ffffffff168152506040518763ffffffff1660e01b8152600401613ae99695949392919061572e565b60408051808303816000875af1158015613b07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b2b91906157aa565b90925090506000826006811115613b4457613b44615097565b1480613b6157506001826006811115613b5f57613b5f615097565b145b15613d625760008e815260076020526040812055613b7f818561534e565b336000908152600b602052604081208054909190613bac9084906bffffffffffffffffffffffff1661534e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508660e0015168ffffffffffffffffff16600c60008282829054906101000a90046bffffffffffffffffffffffff16613c12919061534e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508660c0015168ffffffffffffffffff16600b6000613c5c613ed4565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160009081208054909190613ca29084906bffffffffffffffffffffffff1661534e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508d7f08a4a0761e3c98d288cb4af9342660f49550d83139fb3b762b70d34bed6273688487848b60e0015160008d60c00151604051613d59969594939291906bffffffffffffffffffffffff9687168152602081019590955292909416604084015268ffffffffffffffffff9081166060840152928316608083015290911660a082015260c00190565b60405180910390a25b509c9b505050505050505050505050565b600046613d7f81613f45565b15613dfb57606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613dd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613df491906157dd565b9392505050565b613e0481613f68565b15613eac5773420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e8460405180608001604052806048815260200161584360489139604051602001613e649291906157f6565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401613e8f91906140c0565b602060405180830381865afa158015613dd0573d6000803e3d6000fd5b50600092915050565b600061069a613ec261286a565b612b3184670de0b6b3a76400006150ea565b60003073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613f21573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ce9190615825565b600061a4b1821480613f59575062066eed82145b8061069a57505062066eee1490565b6000600a821480613f7a57506101a482145b80613f87575062aa37dc82145b80613f93575061210582145b80613fa0575062014a3382145b8061069a57505062014a341490565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f840112613fe057600080fd5b50813567ffffffffffffffff811115613ff857600080fd5b6020830191508360208285010111156132cf57600080fd5b6000806020838503121561402357600080fd5b823567ffffffffffffffff81111561403a57600080fd5b61404685828601613fce565b90969095509350505050565b60005b8381101561406d578181015183820152602001614055565b50506000910152565b6000815180845261408e816020860160208601614052565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000613df46020830184614076565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610180810167ffffffffffffffff81118282101715614126576141266140d3565b60405290565b604051610160810167ffffffffffffffff81118282101715614126576141266140d3565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614197576141976140d3565b604052919050565b600082601f8301126141b057600080fd5b813567ffffffffffffffff8111156141ca576141ca6140d3565b6141fb60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614150565b81815284602083860101111561421057600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561423f57600080fd5b813567ffffffffffffffff81111561425657600080fd5b612b408482850161419f565b73ffffffffffffffffffffffffffffffffffffffff811681146129e457600080fd5b803561124281614262565b6bffffffffffffffffffffffff811681146129e457600080fd5b80356112428161428f565b600080604083850312156142c757600080fd5b82356142d281614262565b915060208301356142e28161428f565b809150509250929050565b600081518084526020808501945080840160005b8381101561433357815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614301565b509495945050505050565b602081526000613df460208301846142ed565b60006020828403121561436357600080fd5b5035919050565b60006020828403121561437c57600080fd5b813567ffffffffffffffff81111561439357600080fd5b82016101608185031215613df457600080fd5b8051825260208101516143d1602084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060408101516143f160408401826bffffffffffffffffffffffff169052565b506060810151614419606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151614435608084018267ffffffffffffffff169052565b5060a081015161444d60a084018263ffffffff169052565b5060c081015161446a60c084018268ffffffffffffffffff169052565b5060e081015161448760e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b610160810161069a82846143a6565b60008083601f8401126144e057600080fd5b50813567ffffffffffffffff8111156144f857600080fd5b6020830191508360208260051b85010111156132cf57600080fd5b60008060008060008060008060e0898b03121561452f57600080fd5b606089018a81111561454057600080fd5b8998503567ffffffffffffffff8082111561455a57600080fd5b6145668c838d01613fce565b909950975060808b013591508082111561457f57600080fd5b61458b8c838d016144ce565b909750955060a08b01359150808211156145a457600080fd5b506145b18b828c016144ce565b999c989b50969995989497949560c00135949350505050565b63ffffffff811681146129e457600080fd5b8035611242816145ca565b64ffffffffff811681146129e457600080fd5b8035611242816145e7565b803561ffff8116811461124257600080fd5b67ffffffffffffffff811681146129e457600080fd5b803561124281614617565b60ff811681146129e457600080fd5b803561124281614638565b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461124257600080fd5b6000610180828403121561469157600080fd5b614699614102565b6146a2836145dc565b81526146b0602084016145dc565b60208201526146c1604084016145dc565b60408201526146d2606084016145dc565b60608201526146e3608084016145fa565b60808201526146f460a08401614605565b60a082015261470560c0840161462d565b60c082015261471660e08401614647565b60e0820152610100614729818501614652565b9082015261012061473b8482016145dc565b9082015261014061474d848201614605565b9082015261016061475f848201614605565b908201529392505050565b815163ffffffff16815261018081016020830151614790602084018263ffffffff169052565b5060408301516147a8604084018263ffffffff169052565b5060608301516147c0606084018263ffffffff169052565b5060808301516147d9608084018264ffffffffff169052565b5060a08301516147ef60a084018261ffff169052565b5060c083015161480b60c084018267ffffffffffffffff169052565b5060e083015161482060e084018260ff169052565b50610100838101517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16908301526101208084015163ffffffff16908301526101408084015161ffff908116918401919091526101608085015191821681850152905b505092915050565b60008060008060006080868803121561489f57600080fd5b85356148aa81614617565b9450602086013567ffffffffffffffff8111156148c657600080fd5b6148d288828901613fce565b90955093505060408601356148e6816145ca565b949793965091946060013592915050565b600067ffffffffffffffff821115614911576149116140d3565b5060051b60200190565b600082601f83011261492c57600080fd5b8135602061494161493c836148f7565b614150565b82815260059290921b8401810191818101908684111561496057600080fd5b8286015b8481101561498457803561497781614262565b8352918301918301614964565b509695505050505050565b60008060008060008060c087890312156149a857600080fd5b863567ffffffffffffffff808211156149c057600080fd5b6149cc8a838b0161491b565b975060208901359150808211156149e257600080fd5b6149ee8a838b0161491b565b96506149fc60408a01614647565b95506060890135915080821115614a1257600080fd5b614a1e8a838b0161419f565b9450614a2c60808a0161462d565b935060a0890135915080821115614a4257600080fd5b50614a4f89828a0161419f565b9150509295509295509295565b600060208284031215614a6e57600080fd5b8135613df481614262565b600181811c90821680614a8d57607f821691505b6020821081036129a8577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b601f82111561065e57600081815260208120601f850160051c81016020861015614aed5750805b601f850160051c820191505b8181101561085157828155600101614af9565b67ffffffffffffffff831115614b2457614b246140d3565b614b3883614b328354614a79565b83614ac6565b6000601f841160018114614b8a5760008515614b545750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614c20565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015614bd95786850135825560209485019460019092019101614bb9565b5086821015614c14577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006bffffffffffffffffffffffff80841680614ca457614ca4614c27565b92169190910492915050565b6bffffffffffffffffffffffff828116828216039080821115614cd557614cd5614c56565b5092915050565b805169ffffffffffffffffffff8116811461124257600080fd5b600080600080600060a08688031215614d0e57600080fd5b614d1786614cdc565b9450602086015193506040860151925060608601519150614d3a60808701614cdc565b90509295509295909350565b8181038181111561069a5761069a614c56565b600060208284031215614d6b57600080fd5b8151613df481614638565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614dd657614dd6614c56565b5060010190565b68ffffffffffffffffff811681146129e457600080fd5b803561124281614ddd565b60006101608236031215614e1257600080fd5b614e1a61412c565b823567ffffffffffffffff811115614e3157600080fd5b614e3d3682860161419f565b82525060208301356020820152614e5660408401614284565b6040820152614e67606084016142a9565b6060820152614e7860808401614df4565b6080820152614e8960a0840161462d565b60a0820152614e9a60c0840161462d565b60c0820152614eab60e084016145dc565b60e0820152610100614ebe818501614605565b90820152610120614ed084820161462d565b90820152610140614ee2848201614284565b9082015292915050565b600060208284031215614efe57600080fd5b8135613df481614617565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614f3e57600080fd5b83018035915067ffffffffffffffff821115614f5957600080fd5b6020019150368190038213156132cf57600080fd5b600060208284031215614f8057600080fd5b613df482614605565b600060208284031215614f9b57600080fd5b8135613df4816145ca565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016830101905061504e60e08301846143a6565b9a9950505050505050505050565b60ff818116838216019081111561069a5761069a614c56565b600060ff83168061508857615088614c27565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b808202811582820484141761069a5761069a614c56565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff818116838216019080821115614cd557614cd5614c56565b600061012063ffffffff808d1684528b6020850152808b1660408501525080606084015261517d8184018a6142ed565b9050828103608084015261519181896142ed565b905060ff871660a084015282810360c08401526151ae8187614076565b905067ffffffffffffffff851660e08401528281036101008401526151d38185614076565b9c9b505050505050505050505050565b805161124281614ddd565b60006020828403121561520057600080fd5b8151613df481614ddd565b600181815b8085111561526457817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561524a5761524a614c56565b8085161561525757918102915b93841c9390800290615210565b509250929050565b60008261527b5750600161069a565b816152885750600061069a565b816001811461529e57600281146152a8576152c4565b600191505061069a565b60ff8411156152b9576152b9614c56565b50506001821b61069a565b5060208310610133831016604e8410600b84101617156152e7575081810a61069a565b6152f1838361520b565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561532357615323614c56565b029392505050565b6000613df460ff84168361526c565b60008261534957615349614c27565b500490565b6bffffffffffffffffffffffff818116838216019080821115614cd557614cd5614c56565b6bffffffffffffffffffffffff81811683821602808216919082811461487f5761487f614c56565b8082018082111561069a5761069a614c56565b67ffffffffffffffff818116838216019080821115614cd557614cd5614c56565b600082601f8301126153e057600080fd5b813560206153f061493c836148f7565b82815260059290921b8401810191818101908684111561540f57600080fd5b8286015b848110156149845780358352918301918301615413565b600082601f83011261543b57600080fd5b8135602061544b61493c836148f7565b82815260059290921b8401810191818101908684111561546a57600080fd5b8286015b8481101561498457803567ffffffffffffffff81111561548e5760008081fd5b61549c8986838b010161419f565b84525091830191830161546e565b600080600080600060a086880312156154c257600080fd5b853567ffffffffffffffff808211156154da57600080fd5b6154e689838a016153cf565b965060208801359150808211156154fc57600080fd5b61550889838a0161542a565b9550604088013591508082111561551e57600080fd5b61552a89838a0161542a565b9450606088013591508082111561554057600080fd5b61554c89838a0161542a565b9350608088013591508082111561556257600080fd5b5061556f8882890161542a565b9150509295509295909350565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526155c38285018b6142ed565b915083820360808501526155d7828a6142ed565b915060ff881660a085015283820360c08501526155f48288614076565b90861660e085015283810361010085015290506151d38185614076565b805161124281614262565b80516112428161428f565b805161124281614617565b8051611242816145ca565b8051611242816145e7565b6000610160828403121561565b57600080fd5b61566361412c565b8251815261567360208401615611565b60208201526156846040840161561c565b604082015261569560608401615611565b60608201526156a660808401615627565b60808201526156b760a08401615632565b60a08201526156c860c084016151e3565b60c08201526156d960e084016151e3565b60e08201526101006156ec81850161563d565b908201526101206156fe84820161563d565b9082015261014061475f848201615632565b64ffffffffff818116838216019080821115614cd557614cd5614c56565b60006102008083526157428184018a614076565b905082810360208401526157568189614076565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff86166080850152915061579f905060a08301846143a6565b979650505050505050565b600080604083850312156157bd57600080fd5b8251600781106157cc57600080fd5b60208401519092506142e28161428f565b6000602082840312156157ef57600080fd5b5051919050565b60008351615808818460208801614052565b83519083019061581c818360208801614052565b01949350505050565b60006020828403121561583757600080fd5b8151613df48161426256fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000813000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000aa8aaa682c9ef150c0c8e96a8d60945bcb21faad00000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000000000000009fe98000000000000000000000000000000000000000000000000000000000000dea8000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000073f2206600000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000018dc6e34596c2f000000000000000000000000000000000000000000000000000000000000012c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000464a1515adc20de946f8d0deb99cead8ceae310d000000000000000000000000cc232dcfaae6354ce191bd574108c1ad03f86450
-----Decoded View---------------
Arg [0] : router (address): 0xaA8AaA682C9eF150C0C8E96a8D60945BCB21faad
Arg [1] : config (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [2] : linkToNativeFeed (address): 0x464A1515ADc20de946f8d0DEB99cead8CEAE310d
Arg [3] : linkToUsdFeed (address): 0xCc232dcFAAE6354cE191Bd574108c1aD03f86450
-----Encoded View---------------
15 Constructor Arguments found :
Arg [0] : 000000000000000000000000aa8aaa682c9ef150c0c8e96a8d60945bcb21faad
Arg [1] : 0000000000000000000000000000000000000000000000000000000000002710
Arg [2] : 0000000000000000000000000000000000000000000000000000000000015180
Arg [3] : 000000000000000000000000000000000000000000000000000000000009fe98
Arg [4] : 000000000000000000000000000000000000000000000000000000000000dea8
Arg [5] : 000000000000000000000000000000000000000000000000000000003b9aca00
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [7] : 0000000000000000000000000000000000000000000000000000000073f22066
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [9] : 0000000000000000000000000000000000000000000000000018dc6e34596c2f
Arg [10] : 000000000000000000000000000000000000000000000000000000000000012c
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [13] : 000000000000000000000000464a1515adc20de946f8d0deb99cead8ceae310d
Arg [14] : 000000000000000000000000cc232dcfaae6354ce191bd574108c1ad03f86450
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.