// 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;
import "./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 "../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) {
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,
* pending.
*/
function transferOwnership(address to) public override onlyOwner {
_transferOwnership(to);
}
/**
* @notice Allows an ownership transfer to be completed by the recipient.
*/
function acceptOwnership() external override {
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 {
require(to != msg.sender, "Cannot transfer to self");
s_pendingOwner = to;
emit OwnershipTransferRequested(s_owner, to);
}
/**
* @notice validate access
*/
function _validateOwnership() internal view {
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.19;
import {IFunctionsSubscriptions} from "./interfaces/IFunctionsSubscriptions.sol";
import {AggregatorV3Interface} from "../../../interfaces/AggregatorV3Interface.sol";
import {IFunctionsBilling} from "./interfaces/IFunctionsBilling.sol";
import {Routable} from "./Routable.sol";
import {FunctionsResponse} from "./libraries/FunctionsResponse.sol";
import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol";
/// @title Functions Billing contract
/// @notice Contract that calculates payment from users to the nodes of the Decentralized Oracle Network (DON).
/// @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD.
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
// ================================================================
// | Request Commitment state |
// ================================================================
mapping(bytes32 requestId => bytes32 commitmentHash) private s_requestCommitments;
event CommitmentDeleted(bytes32 requestId);
// ================================================================
// | Configuration state |
// ================================================================
struct Config {
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.
uint32 requestTimeoutSeconds; // ║ How many seconds it takes before we consider a request to be timed out
uint72 donFee; // ║ Additional flat fee (in Juels of LINK) that will be split between Node Operators. Max value is 2^80 - 1 == 1.2m LINK.
uint16 maxSupportedRequestDataVersion; // ═══════╝ The highest support request data version supported by the node. All lower versions should also be supported.
uint224 fallbackNativePerUnitLink; // ═══════════╸ fallback NATIVE CURRENCY / LINK conversion rate if the data feed is stale
}
Config private s_config;
event ConfigUpdated(Config config);
error UnsupportedRequestDataVersion();
error InsufficientBalance();
error InvalidSubscription();
error UnauthorizedSender();
error MustBeSubOwner(address owner);
error InvalidLinkWeiPrice(int256 linkWei);
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;
// ================================================================
// | Initialization |
// ================================================================
constructor(address router, Config memory config, address linkToNativeFeed) Routable(router) {
s_linkToNativeFeed = AggregatorV3Interface(linkToNativeFeed);
updateConfig(config);
}
// ================================================================
// | Configuration |
// ================================================================
/// @notice Gets the Chainlink Coordinator's billing configuration
/// @return config
function getConfig() external view returns (Config memory) {
return s_config;
}
/// @notice Sets the Chainlink Coordinator's billing configuration
/// @param config - See the contents of the Config struct in IFunctionsBilling.Config for more information
function updateConfig(Config memory config) public {
_onlyOwner();
s_config = config;
emit ConfigUpdated(config);
}
// ================================================================
// | Fee Calculation |
// ================================================================
/// @inheritdoc IFunctionsBilling
function getDONFee(bytes memory /* requestData */) public view override returns (uint72) {
return s_config.donFee;
}
/// @inheritdoc IFunctionsBilling
function getAdminFee() public view override returns (uint72) {
return _getRouter().getAdminFee();
}
/// @inheritdoc IFunctionsBilling
function getWeiPerUnitLink() public view returns (uint256) {
Config memory config = s_config;
(, int256 weiPerUnitLink, , uint256 timestamp, ) = s_linkToNativeFeed.latestRoundData();
// solhint-disable-next-line not-rely-on-time
if (config.feedStalenessSeconds < block.timestamp - timestamp && config.feedStalenessSeconds > 0) {
return config.fallbackNativePerUnitLink;
}
if (weiPerUnitLink <= 0) {
revert InvalidLinkWeiPrice(weiPerUnitLink);
}
return uint256(weiPerUnitLink);
}
function _getJuelsPerGas(uint256 gasPriceWei) private view returns (uint96) {
// (1e18 juels/link) * (wei/gas) / (wei/link) = juels per gas
// There are only 1e9*1e18 = 1e27 juels in existence, should not exceed uint96 (2^96 ~ 7e28)
return SafeCast.toUint96((1e18 * gasPriceWei) / getWeiPerUnitLink());
}
// ================================================================
// | 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 = getAdminFee();
uint72 donFee = getDONFee(data);
return _calculateCostEstimate(callbackGasLimit, gasPriceWei, donFee, adminFee);
}
/// @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 donFee,
uint72 adminFee
) internal view returns (uint96) {
uint256 executionGas = s_config.gasOverheadBeforeCallback + s_config.gasOverheadAfterCallback + callbackGasLimit;
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
uint96 juelsPerGas = _getJuelsPerGas(gasPriceWithOverestimation);
uint256 estimatedGasReimbursement = juelsPerGas * executionGas;
uint96 fees = uint96(donFee) + uint96(adminFee);
return SafeCast.toUint96(estimatedGasReimbursement + fees);
}
// ================================================================
// | 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) {
Config memory config = s_config;
// Nodes should support all past versions of the structure
if (request.dataVersion > config.maxSupportedRequestDataVersion) {
revert UnsupportedRequestDataVersion();
}
uint72 donFee = getDONFee(request.data);
uint96 estimatedTotalCostJuels = _calculateCostEstimate(
request.callbackGasLimit,
tx.gasprice,
donFee,
request.adminFee
);
// Check that subscription can afford the estimated cost
if ((request.availableBalance) < estimatedTotalCostJuels) {
revert InsufficientBalance();
}
bytes32 requestId = _computeRequestId(
address(this),
request.requestingContract,
request.subscriptionId,
request.initiatedRequests + 1
);
commitment = FunctionsResponse.Commitment({
adminFee: request.adminFee,
coordinator: address(this),
client: request.requestingContract,
subscriptionId: request.subscriptionId,
callbackGasLimit: request.callbackGasLimit,
estimatedTotalCostJuels: estimatedTotalCostJuels,
timeoutTimestamp: uint32(block.timestamp + config.requestTimeoutSeconds),
requestId: requestId,
donFee: donFee,
gasOverheadBeforeCallback: config.gasOverheadBeforeCallback,
gasOverheadAfterCallback: config.gasOverheadAfterCallback
});
s_requestCommitments[requestId] = keccak256(abi.encode(commitment));
return commitment;
}
/// @notice Generate a keccak hash request ID
/// @dev uses the number of requests that the consumer of a subscription has sent as a nonce
function _computeRequestId(
address don,
address client,
uint64 subscriptionId,
uint64 nonce
) private pure returns (bytes32) {
return keccak256(abi.encode(don, client, subscriptionId, nonce));
}
/// @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
/// @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 */
) internal returns (FunctionsResponse.FulfillResult) {
FunctionsResponse.Commitment memory commitment = abi.decode(onchainMetadata, (FunctionsResponse.Commitment));
if (s_requestCommitments[requestId] == bytes32(0)) {
return FunctionsResponse.FulfillResult.INVALID_REQUEST_ID;
}
if (s_requestCommitments[requestId] != keccak256(abi.encode(commitment))) {
return FunctionsResponse.FulfillResult.INVALID_COMMITMENT;
}
uint96 juelsPerGas = _getJuelsPerGas(tx.gasprice);
// Gas overhead without callback
uint96 gasOverheadJuels = juelsPerGas *
(commitment.gasOverheadBeforeCallback + commitment.gasOverheadAfterCallback);
// The Functions Router will perform the callback to the client contract
(FunctionsResponse.FulfillResult resultCode, uint96 callbackCostJuels) = _getRouter().fulfill(
response,
err,
juelsPerGas,
gasOverheadJuels + commitment.donFee, // costWithoutFulfillment
msg.sender,
commitment
);
// 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;
}
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();
if (transmitters.length == 0) {
revert NoTransmittersSet();
}
uint96 feePoolShare = s_feePool / uint96(transmitters.length);
// Bounded by "maxNumOracles" on OCR2Abstract.sol
for (uint256 i = 0; i < transmitters.length; ++i) {
s_withdrawableTokens[transmitters[i]] += feePoolShare;
}
s_feePool -= feePoolShare * uint96(transmitters.length);
}
// Overriden in FunctionsCoordinator.sol
function _onlyOwner() internal view virtual;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {IFunctionsCoordinator} from "./interfaces/IFunctionsCoordinator.sol";
import {IFunctionsBilling} from "./interfaces/IFunctionsBilling.sol";
import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol";
import {FunctionsBilling} 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
/// @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD.
contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilling {
using FunctionsResponse for FunctionsResponse.RequestMeta;
using FunctionsResponse for FunctionsResponse.Commitment;
using FunctionsResponse for FunctionsResponse.FulfillResult;
/// @inheritdoc ITypeAndVersion
string public constant override typeAndVersion = "Functions Coordinator v1.0.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,
Config memory config,
address linkToNativeFeed
) OCR2Base(true) FunctionsBilling(router, config, linkToNativeFeed) {}
/// @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) {
address[] memory nodes = s_transmitters;
// Bounded by "maxNumOracles" on OCR2Abstract.sol
for (uint256 i = 0; i < nodes.length; ++i) {
if (nodes[i] == node) {
return true;
}
}
return false;
}
/// @inheritdoc IFunctionsCoordinator
function startRequest(
FunctionsResponse.RequestMeta calldata request
) external override onlyRouter returns (FunctionsResponse.Commitment memory commitment) {
commitment = _startBilling(request);
emit OracleRequest(
commitment.requestId,
request.requestingContract,
tx.origin,
request.subscriptionId,
request.subscriptionOwner,
request.data,
request.dataVersion,
request.flags,
request.callbackGasLimit,
commitment
);
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;
}
/// @dev Report hook called within OCR2Base.sol
function _report(
uint256 /*initialGas*/,
address /*transmitter*/,
uint8 /*signerCount*/,
address[MAX_NUM_ORACLES] memory /*signers*/,
bytes calldata report
) internal override {
bytes32[] memory requestIds;
bytes[] memory results;
bytes[] memory errors;
bytes[] memory onchainMetadata;
bytes[] memory offchainMetadata;
(requestIds, results, errors, onchainMetadata, offchainMetadata) = abi.decode(
report,
(bytes32[], bytes[], bytes[], bytes[], bytes[])
);
if (
requestIds.length == 0 ||
requestIds.length != results.length ||
requestIds.length != errors.length ||
requestIds.length != onchainMetadata.length ||
requestIds.length != offchainMetadata.length
) {
revert ReportInvalid();
}
// Bounded by "MaxRequestBatchSize" on the Job's ReportingPluginConfig
for (uint256 i = 0; i < requestIds.length; ++i) {
FunctionsResponse.FulfillResult result = FunctionsResponse.FulfillResult(
_fulfillAndBill(requestIds[i], results[i], errors[i], onchainMetadata[i], offchainMetadata[i])
);
// 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(requestIds[i], msg.sender);
}
}
}
/// @dev Used in FunctionsBilling.sol
function _onlyOwner() internal view override {
_validateOwnership();
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {IFunctionsSubscriptions} from "../interfaces/IFunctionsSubscriptions.sol";
/// @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;
/// @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 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 getDONFee(bytes memory requestCBOR) 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 getAdminFee() 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
function oracleWithdrawAll() 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.0;
interface IOwnable {
function owner() external returns (address);
function transferOwnership(address recipient) external;
function acceptOwnership() external;
}
// 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.0;
interface ITypeAndVersion {
function typeAndVersion() external pure returns (string memory);
}
// 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);
function _configDigestFromConfigData(
uint256 chainId,
address contractAddress,
uint64 configCount,
address[] memory signers,
address[] memory transmitters,
uint8 f,
bytes memory onchainConfig,
uint64 offchainConfigVersion,
bytes memory offchainConfig
) internal pure returns (bytes32) {
uint256 h = uint256(
keccak256(
abi.encode(
chainId,
contractAddress,
configCount,
signers,
transmitters,
f,
onchainConfig,
offchainConfigVersion,
offchainConfig
)
)
);
uint256 prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00
uint256 prefix = 0x0001 << (256 - 16); // 0x000100..00
return bytes32((prefix & prefixMask) | (h & ~prefixMask));
}
/**
* @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 THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD.
* @dev For details on its operation, see the offchain reporting protocol design
* doc, which refers to this contract as simply the "contract".
* @dev This contract is meant to aid rapid development of new applications based on OCR2.
* However, for actual production contracts, it is expected that most of the logic of this contract
* will be folded directly into the application contract. Inheritance prevents us from doing lots
* of juicy storage layout optimizations, leading to a substantial increase in gas cost.
*/
abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract {
error ReportInvalid();
error InvalidConfig(string message);
bool internal immutable i_uniqueReports;
constructor(bool uniqueReports) ConfirmedOwner(msg.sender) {
i_uniqueReports = uniqueReports;
}
uint256 private constant maxUint32 = (1 << 32) - 1;
// 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;
/*
* 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++) {
// add new signer/transmitter addresses
require(s_oracles[args.signers[i]].role == Role.Unset, "repeated signer address");
s_oracles[args.signers[i]] = Oracle(uint8(i), Role.Signer);
require(s_oracles[args.transmitters[i]].role == Role.Unset, "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 initialGas the amount of gas before validation
* @param transmitter the address of the account that submitted the report
* @param signers the addresses of all signing accounts
* @param report serialized report
*/
function _report(
uint256 initialGas,
address transmitter,
uint8 signerCount,
address[MAX_NUM_ORACLES] memory signers,
bytes calldata report
) 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
require(msg.data.length == expected, "calldata length mismatch");
}
/**
* @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 {
uint256 initialGas = gasleft(); // This line must come first
{
// 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));
ConfigInfo memory configInfo = s_configInfo;
require(configInfo.latestConfigDigest == configDigest, "configDigest mismatch");
requireExpectedMsgDataLength(report, rs, ss);
uint256 expectedNumSignatures;
if (i_uniqueReports) {
expectedNumSignatures = (configInfo.n + configInfo.f) / 2 + 1;
} else {
expectedNumSignatures = configInfo.f + 1;
}
require(rs.length == expectedNumSignatures, "wrong number of signatures");
require(rs.length == ss.length, "signatures out of registration");
Oracle memory transmitter = s_oracles[msg.sender];
require( // Check that sender is authorized to report
transmitter.role == Role.Transmitter && msg.sender == s_transmitters[transmitter.index],
"unauthorized transmitter"
);
}
address[MAX_NUM_ORACLES] memory signed;
uint8 signerCount = 0;
{
// 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];
require(o.role == Role.Signer, "address not authorized to sign");
require(signed[o.index] == address(0), "non-unique signature");
signed[o.index] = signer;
signerCount += 1;
}
}
_report(initialGas, msg.sender, signerCount, signed, report);
}
}
// 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_router;
error RouterMustBeSet();
error OnlyCallableByRouter();
error OnlyCallableByRouterOwner();
/// @dev Initializes the contract.
constructor(address router) {
if (router == address(0)) {
revert RouterMustBeSet();
}
i_router = IOwnableFunctionsRouter(router);
}
/// @notice Return the Router
function _getRouter() internal view returns (IOwnableFunctionsRouter router) {
return i_router;
}
/// @notice Reverts if called by anyone other than the router.
modifier onlyRouter() {
if (msg.sender != address(i_router)) {
revert OnlyCallableByRouter();
}
_;
}
/// @notice Reverts if called by anyone other than the router owner.
modifier onlyRouterOwner() {
if (msg.sender != i_router.owner()) {
revert OnlyCallableByRouterOwner();
}
_;
}
}
// 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);
}
}
{
"compilationTarget": {
"src/v0.8/functions/dev/1_0_0/FunctionsCoordinator.sol": "FunctionsCoordinator"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 1000000
},
"remappings": [
":@eth-optimism/=node_modules/@eth-optimism/",
":@openzeppelin/=node_modules/@openzeppelin/",
":ds-test/=foundry-lib/forge-std/lib/ds-test/src/",
":erc4626-tests/=foundry-lib/openzeppelin-contracts/lib/erc4626-tests/",
":forge-std/=foundry-lib/forge-std/src/",
":hardhat/=node_modules/hardhat/",
":openzeppelin-contracts/=foundry-lib/openzeppelin-contracts/contracts/"
]
}
[{"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":"uint32","name":"requestTimeoutSeconds","type":"uint32"},{"internalType":"uint72","name":"donFee","type":"uint72"},{"internalType":"uint16","name":"maxSupportedRequestDataVersion","type":"uint16"},{"internalType":"uint224","name":"fallbackNativePerUnitLink","type":"uint224"}],"internalType":"struct FunctionsBilling.Config","name":"config","type":"tuple"},{"internalType":"address","name":"linkToNativeFeed","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":"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":[],"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":"uint32","name":"requestTimeoutSeconds","type":"uint32"},{"internalType":"uint72","name":"donFee","type":"uint72"},{"internalType":"uint16","name":"maxSupportedRequestDataVersion","type":"uint16"},{"internalType":"uint224","name":"fallbackNativePerUnitLink","type":"uint224"}],"indexed":false,"internalType":"struct FunctionsBilling.Config","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":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":"getAdminFee","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":"uint32","name":"requestTimeoutSeconds","type":"uint32"},{"internalType":"uint72","name":"donFee","type":"uint72"},{"internalType":"uint16","name":"maxSupportedRequestDataVersion","type":"uint16"},{"internalType":"uint224","name":"fallbackNativePerUnitLink","type":"uint224"}],"internalType":"struct FunctionsBilling.Config","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"getDONFee","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":"getThresholdPublicKey","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"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":"uint32","name":"requestTimeoutSeconds","type":"uint32"},{"internalType":"uint72","name":"donFee","type":"uint72"},{"internalType":"uint16","name":"maxSupportedRequestDataVersion","type":"uint16"},{"internalType":"uint224","name":"fallbackNativePerUnitLink","type":"uint224"}],"internalType":"struct FunctionsBilling.Config","name":"config","type":"tuple"}],"name":"updateConfig","outputs":[],"stateMutability":"nonpayable","type":"function"}]