// SPDX-License-Identifier: MITpragmasolidity ^0.8.19;import {FunctionsClient} from"@chainlink/contracts/src/v0.8/functions/dev/v1_X/FunctionsClient.sol";
import {ConfirmedOwner} from"@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol";
import {FunctionsRequest} from"@chainlink/contracts/src/v0.8/functions/dev/v1_X/libraries/FunctionsRequest.sol";
import {AutomationCompatibleInterface} from"@chainlink/contracts/src/v0.8/automation/AutomationCompatible.sol";
/**
* @title Automated Functions Consumer contract using Chainlink Automations
* @notice This contract is for demonstration not production use.
*/contractAutomatedFunctionsConsumerisFunctionsClient, ConfirmedOwner, AutomationCompatibleInterface{
usingFunctionsRequestforFunctionsRequest.Request;
// State variables for Chainlink Functionsbytes32public donId;
bytespublic s_requestCBOR;
uint64public s_subscriptionId;
uint32public s_fulfillGasLimit;
bytes32public s_lastRequestId;
bytespublic s_lastResponse;
bytespublic s_lastError;
// State variables for Chainlink Automationuint256public s_updateInterval;
uint256public s_lastUpkeepTimeStamp;
uint256public s_upkeepCounter;
uint256public s_responseCounter;
eventOCRResponse(bytes32indexed requestId, bytes result, bytes err);
/**
* @notice Executes once when a contract is created to initialize state variables
*
* @param router The Functions Router contract for the network
* @param _donId The DON Id for the DON that will execute the Function
*/constructor(address router, bytes32 _donId) FunctionsClient(router) ConfirmedOwner(msg.sender) {
donId = _donId;
s_lastUpkeepTimeStamp =0;
}
/**
* @notice Sets the bytes representing the CBOR-encoded FunctionsRequest.Request that is sent when performUpkeep is called
* @param _subscriptionId The Functions billing subscription ID used to pay for Functions requests
* @param _fulfillGasLimit Maximum amount of gas used to call the client contract's `handleOracleFulfillment` function
* @param _updateInterval Time interval at which Chainlink Automation should call performUpkeep
* @param requestCBOR Bytes representing the CBOR-encoded FunctionsRequest.Request
*/functionsetRequest(uint64 _subscriptionId,
uint32 _fulfillGasLimit,
uint256 _updateInterval,
bytescalldata requestCBOR
) externalonlyOwner{
s_updateInterval = _updateInterval;
s_subscriptionId = _subscriptionId;
s_fulfillGasLimit = _fulfillGasLimit;
s_requestCBOR = requestCBOR;
}
/**
* @notice Used by Automation to check if performUpkeep should be called.
*
* The function's argument is unused in this example, but there is an option to have Automation pass custom data
* that can be used by the checkUpkeep function.
*
* Returns a tuple where the first element is a boolean which determines if upkeep is needed and the
* second element contains custom bytes data which is passed to performUpkeep when it is called by Automation.
*/functioncheckUpkeep(bytesmemory) publicviewoverridereturns (bool upkeepNeeded, bytesmemory) {
upkeepNeeded = (block.timestamp- s_lastUpkeepTimeStamp) > s_updateInterval;
}
/**
* @notice Called by Automation to trigger a Functions request
*
* The function's argument is unused in this example, but there is an option to have Automation pass custom data
* returned by checkUpkeep (See Chainlink Automation documentation)
*/functionperformUpkeep(bytescalldata) externaloverride{
(bool upkeepNeeded, ) = checkUpkeep("");
require(upkeepNeeded, "Time interval not met");
s_lastUpkeepTimeStamp =block.timestamp;
s_upkeepCounter = s_upkeepCounter +1;
bytes32 requestId = _sendRequest(s_requestCBOR, s_subscriptionId, s_fulfillGasLimit, donId);
s_lastRequestId = requestId;
}
/**
* @notice Callback that is invoked once the DON has resolved the request or hit an error
*
* @param requestId The request ID, returned by sendRequest()
* @param response Aggregated response from the user code
* @param err Aggregated error from the user code or from the execution pipeline
* Either response or error parameter will be set, but never both
*/function_fulfillRequest(bytes32 requestId, bytesmemory response, bytesmemory err) internaloverride{
s_lastResponse = response;
s_lastError = err;
s_responseCounter = s_responseCounter +1;
emit OCRResponse(requestId, response, err);
}
/**
* @notice Set the DON ID
* @param newDonId New DON ID
*/functionsetDonId(bytes32 newDonId) externalonlyOwner{
donId = newDonId;
}
}
Contract Source Code
File 5 of 18: AutomationBase.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;contractAutomationBase{
errorOnlySimulatedBackend();
/**
* @notice method that allows it to be simulated via eth_call by checking that
* the sender is the zero address.
*/functionpreventExecution() internalview{
if (tx.origin!=address(0)) {
revert OnlySimulatedBackend();
}
}
/**
* @notice modifier that allows it to be simulated via eth_call by checking
* that the sender is the zero address.
*/modifiercannotExecute() {
preventExecution();
_;
}
}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;interfaceAutomationCompatibleInterface{
/**
* @notice method that is simulated by the keepers to see if any work actually
* needs to be performed. This method does does not actually need to be
* executable, and since it is only ever simulated it can consume lots of gas.
* @dev To ensure that it is never called, you may want to add the
* cannotExecute modifier from KeeperBase to your implementation of this
* method.
* @param checkData specified in the upkeep registration so it is always the
* same for a registered upkeep. This can easily be broken down into specific
* arguments using `abi.decode`, so multiple upkeeps can be registered on the
* same contract and easily differentiated by the contract.
* @return upkeepNeeded boolean to indicate whether the keeper should call
* performUpkeep or not.
* @return performData bytes that the keeper should call performUpkeep with, if
* upkeep is needed. If you would like to encode data to decode later, try
* `abi.encode`.
*/functioncheckUpkeep(bytescalldata checkData) externalreturns (bool upkeepNeeded, bytesmemory performData);
/**
* @notice method that is actually executed by the keepers, via the registry.
* The data returned by the checkUpkeep simulation will be passed into
* this method to actually be executed.
* @dev The input to this method should not be trusted, and the caller of the
* method should not even be restricted to any single registry. Anyone should
* be able call it, and the input should be validated, there is no guarantee
* that the data passed in is the performData returned from checkUpkeep. This
* could happen due to malicious keepers, racing keepers, or simply a state
* change while the performUpkeep transaction is waiting for confirmation.
* Always validate the data passed in.
* @param performData is the data which was passed back from the checkData
* simulation. If it is encoded, it can easily be decoded into other types by
* calling `abi.decode`. This data should not be trusted, and should be
* validated against the contract's current state.
*/functionperformUpkeep(bytescalldata performData) external;
}
Contract Source Code
File 8 of 18: Buffer.sol
// SPDX-License-Identifier: BSD-2-Clausepragmasolidity ^0.8.4;/**
* @dev A library for working with mutable byte buffers in Solidity.
*
* Byte buffers are mutable and expandable, and provide a variety of primitives
* for appending to them. At any time you can fetch a bytes object containing the
* current contents of the buffer. The bytes object should not be stored between
* operations, as it may change due to resizing of the buffer.
*/libraryBuffer{
/**
* @dev Represents a mutable buffer. Buffers have a current value (buf) and
* a capacity. The capacity may be longer than the current value, in
* which case it can be extended without the need to allocate more memory.
*/structbuffer {
bytes buf;
uint capacity;
}
/**
* @dev Initializes a buffer with an initial capacity.
* @param buf The buffer to initialize.
* @param capacity The number of bytes of space to allocate the buffer.
* @return The buffer, for chaining.
*/functioninit(buffer memory buf, uint capacity) internalpurereturns(buffer memory) {
if (capacity %32!=0) {
capacity +=32- (capacity %32);
}
// Allocate space for the buffer data
buf.capacity = capacity;
assembly {
let ptr :=mload(0x40)
mstore(buf, ptr)
mstore(ptr, 0)
let fpm :=add(32, add(ptr, capacity))
iflt(fpm, ptr) {
revert(0, 0)
}
mstore(0x40, fpm)
}
return buf;
}
/**
* @dev Initializes a new buffer from an existing bytes object.
* Changes to the buffer may mutate the original value.
* @param b The bytes object to initialize the buffer with.
* @return A new buffer.
*/functionfromBytes(bytesmemory b) internalpurereturns(buffer memory) {
buffer memory buf;
buf.buf = b;
buf.capacity = b.length;
return buf;
}
functionresize(buffer memory buf, uint capacity) privatepure{
bytesmemory oldbuf = buf.buf;
init(buf, capacity);
append(buf, oldbuf);
}
/**
* @dev Sets buffer length to 0.
* @param buf The buffer to truncate.
* @return The original buffer, for chaining..
*/functiontruncate(buffer memory buf) internalpurereturns (buffer memory) {
assembly {
let bufptr :=mload(buf)
mstore(bufptr, 0)
}
return buf;
}
/**
* @dev Appends len bytes of a byte string to a buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @param len The number of bytes to copy.
* @return The original buffer, for chaining.
*/functionappend(buffer memory buf, bytesmemory data, uint len) internalpurereturns(buffer memory) {
require(len <= data.length);
uint off = buf.buf.length;
uint newCapacity = off + len;
if (newCapacity > buf.capacity) {
resize(buf, newCapacity *2);
}
uint dest;
uint src;
assembly {
// Memory address of the buffer datalet bufptr :=mload(buf)
// Length of existing buffer datalet buflen :=mload(bufptr)
// Start address = buffer address + offset + sizeof(buffer length)
dest :=add(add(bufptr, 32), off)
// Update buffer length if we're extending itifgt(newCapacity, buflen) {
mstore(bufptr, newCapacity)
}
src :=add(data, 32)
}
// Copy word-length chunks while possiblefor (; len >=32; len -=32) {
assembly {
mstore(dest, mload(src))
}
dest +=32;
src +=32;
}
// Copy remaining bytesunchecked {
uint mask = (256** (32- len)) -1;
assembly {
let srcpart :=and(mload(src), not(mask))
let destpart :=and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
return buf;
}
/**
* @dev Appends a byte string to a buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chaining.
*/functionappend(buffer memory buf, bytesmemory data) internalpurereturns (buffer memory) {
return append(buf, data, data.length);
}
/**
* @dev Appends a byte to the buffer. Resizes if doing so would exceed the
* capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chaining.
*/functionappendUint8(buffer memory buf, uint8 data) internalpurereturns(buffer memory) {
uint off = buf.buf.length;
uint offPlusOne = off +1;
if (off >= buf.capacity) {
resize(buf, offPlusOne *2);
}
assembly {
// Memory address of the buffer datalet bufptr :=mload(buf)
// Address = buffer address + sizeof(buffer length) + offlet dest :=add(add(bufptr, off), 32)
mstore8(dest, data)
// Update buffer length if we extended itifgt(offPlusOne, mload(bufptr)) {
mstore(bufptr, offPlusOne)
}
}
return buf;
}
/**
* @dev Appends len bytes of bytes32 to a buffer. Resizes if doing so would
* exceed the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @param len The number of bytes to write (left-aligned).
* @return The original buffer, for chaining.
*/functionappend(buffer memory buf, bytes32 data, uint len) privatepurereturns(buffer memory) {
uint off = buf.buf.length;
uint newCapacity = len + off;
if (newCapacity > buf.capacity) {
resize(buf, newCapacity *2);
}
unchecked {
uint mask = (256** len) -1;
// Right-align data
data = data >> (8* (32- len));
assembly {
// Memory address of the buffer datalet bufptr :=mload(buf)
// Address = buffer address + sizeof(buffer length) + newCapacitylet dest :=add(bufptr, newCapacity)
mstore(dest, or(and(mload(dest), not(mask)), data))
// Update buffer length if we extended itifgt(newCapacity, mload(bufptr)) {
mstore(bufptr, newCapacity)
}
}
}
return buf;
}
/**
* @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chhaining.
*/functionappendBytes20(buffer memory buf, bytes20 data) internalpurereturns (buffer memory) {
return append(buf, bytes32(data), 20);
}
/**
* @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chaining.
*/functionappendBytes32(buffer memory buf, bytes32 data) internalpurereturns (buffer memory) {
return append(buf, data, 32);
}
/**
* @dev Appends a byte to the end of the buffer. Resizes if doing so would
* exceed the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @param len The number of bytes to write (right-aligned).
* @return The original buffer.
*/functionappendInt(buffer memory buf, uint data, uint len) internalpurereturns(buffer memory) {
uint off = buf.buf.length;
uint newCapacity = len + off;
if (newCapacity > buf.capacity) {
resize(buf, newCapacity *2);
}
uint mask = (256** len) -1;
assembly {
// Memory address of the buffer datalet bufptr :=mload(buf)
// Address = buffer address + sizeof(buffer length) + newCapacitylet dest :=add(bufptr, newCapacity)
mstore(dest, or(and(mload(dest), not(mask)), data))
// Update buffer length if we extended itifgt(newCapacity, mload(bufptr)) {
mstore(bufptr, newCapacity)
}
}
return buf;
}
}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import {ConfirmedOwnerWithProposal} from"./ConfirmedOwnerWithProposal.sol";
/**
* @title The ConfirmedOwner contract
* @notice A contract with helpers for basic contract ownership.
*/contractConfirmedOwnerisConfirmedOwnerWithProposal{
constructor(address newOwner) ConfirmedOwnerWithProposal(newOwner, address(0)) {}
}
Contract Source Code
File 11 of 18: ConfirmedOwnerWithProposal.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import {IOwnable} from"../interfaces/IOwnable.sol";
/**
* @title The ConfirmedOwner contract
* @notice A contract with helpers for basic contract ownership.
*/contractConfirmedOwnerWithProposalisIOwnable{
addressprivate s_owner;
addressprivate s_pendingOwner;
eventOwnershipTransferRequested(addressindexedfrom, addressindexed to);
eventOwnershipTransferred(addressindexedfrom, addressindexed to);
constructor(address newOwner, address pendingOwner) {
// solhint-disable-next-line custom-errorsrequire(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.
*/functiontransferOwnership(address to) publicoverrideonlyOwner{
_transferOwnership(to);
}
/**
* @notice Allows an ownership transfer to be completed by the recipient.
*/functionacceptOwnership() externaloverride{
// solhint-disable-next-line custom-errorsrequire(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
*/functionowner() publicviewoverridereturns (address) {
return s_owner;
}
/**
* @notice validate, transfer ownership, and emit relevant events
*/function_transferOwnership(address to) private{
// solhint-disable-next-line custom-errorsrequire(to !=msg.sender, "Cannot transfer to self");
s_pendingOwner = to;
emit OwnershipTransferRequested(s_owner, to);
}
/**
* @notice validate access
*/function_validateOwnership() internalview{
// solhint-disable-next-line custom-errorsrequire(msg.sender== s_owner, "Only callable by owner");
}
/**
* @notice Reverts if called by anyone other than the contract owner.
*/modifieronlyOwner() {
_validateOwnership();
_;
}
}
Contract Source Code
File 12 of 18: FunctionsClient.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.19;import {IFunctionsRouter} from"./interfaces/IFunctionsRouter.sol";
import {IFunctionsClient} from"./interfaces/IFunctionsClient.sol";
import {FunctionsRequest} from"./libraries/FunctionsRequest.sol";
/// @title The Chainlink Functions client contract/// @notice Contract developers can inherit this contract in order to make Chainlink Functions requestsabstractcontractFunctionsClientisIFunctionsClient{
usingFunctionsRequestforFunctionsRequest.Request;
IFunctionsRouter internalimmutable i_router;
eventRequestSent(bytes32indexed id);
eventRequestFulfilled(bytes32indexed id);
errorOnlyRouterCanFulfill();
constructor(address router) {
i_router = IFunctionsRouter(router);
}
/// @notice Sends a Chainlink Functions request/// @param data The CBOR encoded bytes data for a Functions request/// @param subscriptionId The subscription ID that will be charged to service the request/// @param callbackGasLimit the amount of gas that will be available for the fulfillment callback/// @return requestId The generated request ID for this requestfunction_sendRequest(bytesmemory data,
uint64 subscriptionId,
uint32 callbackGasLimit,
bytes32 donId
) internalreturns (bytes32) {
bytes32 requestId = i_router.sendRequest(
subscriptionId,
data,
FunctionsRequest.REQUEST_DATA_VERSION,
callbackGasLimit,
donId
);
emit RequestSent(requestId);
return requestId;
}
/// @notice User defined function to handle a response from the DON/// @param requestId The request ID, returned by sendRequest()/// @param response Aggregated response from the execution of the user's source code/// @param err Aggregated error from the execution of the user code or from the execution pipeline/// @dev Either response or error parameter will be set, but never bothfunction_fulfillRequest(bytes32 requestId, bytesmemory response, bytesmemory err) internalvirtual;
/// @inheritdoc IFunctionsClientfunctionhandleOracleFulfillment(bytes32 requestId, bytesmemory response, bytesmemory err) externaloverride{
if (msg.sender!=address(i_router)) {
revert OnlyRouterCanFulfill();
}
_fulfillRequest(requestId, response, err);
emit RequestFulfilled(requestId);
}
}
Contract Source Code
File 13 of 18: FunctionsRequest.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.19;import {CBOR} from"../../../../vendor/solidity-cborutils/v2.0.0/CBOR.sol";
/// @title Library for encoding the input data of a Functions request into CBORlibraryFunctionsRequest{
usingCBORforCBOR.CBORBuffer;
uint16publicconstant REQUEST_DATA_VERSION =1;
uint256internalconstant DEFAULT_BUFFER_SIZE =256;
enumLocation {
Inline, // Provided within the Request
Remote, // Hosted through remote location that can be accessed through a provided URL
DONHosted // Hosted on the DON's storage
}
enumCodeLanguage {
JavaScript
// In future version we may add other languages
}
structRequest {
Location codeLocation; // ════════════╸ The location of the source code that will be executed on each node in the DON
Location secretsLocation; // ═════════╸ The location of secrets that will be passed into the source code. *Only Remote secrets are supported
CodeLanguage language; // ════════════╸ The coding language that the source code is written instring source; // ════════════════════╸ Raw source code for Request.codeLocation of Location.Inline, URL for Request.codeLocation of Location.Remote, or slot decimal number for Request.codeLocation of Location.DONHostedbytes encryptedSecretsReference; // ══╸ Encrypted URLs for Request.secretsLocation of Location.Remote (use addSecretsReference()), or CBOR encoded slotid+version for Request.secretsLocation of Location.DONHosted (use addDONHostedSecrets())string[] args; // ════════════════════╸ String arguments that will be passed into the source codebytes[] bytesArgs; // ════════════════╸ Bytes arguments that will be passed into the source code
}
errorEmptySource();
errorEmptySecrets();
errorEmptyArgs();
errorNoInlineSecrets();
/// @notice Encodes a Request to CBOR encoded bytes/// @param self The request to encode/// @return CBOR encoded bytesfunction_encodeCBOR(Request memoryself) internalpurereturns (bytesmemory) {
CBOR.CBORBuffer memory buffer = CBOR.create(DEFAULT_BUFFER_SIZE);
buffer.writeString("codeLocation");
buffer.writeUInt256(uint256(self.codeLocation));
buffer.writeString("language");
buffer.writeUInt256(uint256(self.language));
buffer.writeString("source");
buffer.writeString(self.source);
if (self.args.length>0) {
buffer.writeString("args");
buffer.startArray();
for (uint256 i =0; i <self.args.length; ++i) {
buffer.writeString(self.args[i]);
}
buffer.endSequence();
}
if (self.encryptedSecretsReference.length>0) {
if (self.secretsLocation == Location.Inline) {
revert NoInlineSecrets();
}
buffer.writeString("secretsLocation");
buffer.writeUInt256(uint256(self.secretsLocation));
buffer.writeString("secrets");
buffer.writeBytes(self.encryptedSecretsReference);
}
if (self.bytesArgs.length>0) {
buffer.writeString("bytesArgs");
buffer.startArray();
for (uint256 i =0; i <self.bytesArgs.length; ++i) {
buffer.writeBytes(self.bytesArgs[i]);
}
buffer.endSequence();
}
return buffer.buf.buf;
}
/// @notice Initializes a Chainlink Functions Request/// @dev Sets the codeLocation and code on the request/// @param self The uninitialized request/// @param codeLocation The user provided source code location/// @param language The programming language of the user code/// @param source The user provided source code or a urlfunction_initializeRequest(
Request memoryself,
Location codeLocation,
CodeLanguage language,
stringmemory source
) internalpure{
if (bytes(source).length==0) revert EmptySource();
self.codeLocation = codeLocation;
self.language = language;
self.source = source;
}
/// @notice Initializes a Chainlink Functions Request/// @dev Simplified version of initializeRequest for PoC/// @param self The uninitialized request/// @param javaScriptSource The user provided JS code (must not be empty)function_initializeRequestForInlineJavaScript(Request memoryself, stringmemory javaScriptSource) internalpure{
_initializeRequest(self, Location.Inline, CodeLanguage.JavaScript, javaScriptSource);
}
/// @notice Adds Remote user encrypted secrets to a Request/// @param self The initialized request/// @param encryptedSecretsReference Encrypted comma-separated string of URLs pointing to off-chain secretsfunction_addSecretsReference(Request memoryself, bytesmemory encryptedSecretsReference) internalpure{
if (encryptedSecretsReference.length==0) revert EmptySecrets();
self.secretsLocation = Location.Remote;
self.encryptedSecretsReference = encryptedSecretsReference;
}
/// @notice Adds DON-hosted secrets reference to a Request/// @param self The initialized request/// @param slotID Slot ID of the user's secrets hosted on DON/// @param version User data version (for the slotID)function_addDONHostedSecrets(Request memoryself, uint8 slotID, uint64 version) internalpure{
CBOR.CBORBuffer memory buffer = CBOR.create(DEFAULT_BUFFER_SIZE);
buffer.writeString("slotID");
buffer.writeUInt64(slotID);
buffer.writeString("version");
buffer.writeUInt64(version);
self.secretsLocation = Location.DONHosted;
self.encryptedSecretsReference = buffer.buf.buf;
}
/// @notice Sets args for the user run function/// @param self The initialized request/// @param args The array of string args (must not be empty)function_setArgs(Request memoryself, string[] memory args) internalpure{
if (args.length==0) revert EmptyArgs();
self.args = args;
}
/// @notice Sets bytes args for the user run function/// @param self The initialized request/// @param args The array of bytes args (must not be empty)function_setBytesArgs(Request memoryself, bytes[] memory args) internalpure{
if (args.length==0) revert EmptyArgs();
self.bytesArgs = args;
}
}
Contract Source Code
File 14 of 18: FunctionsResponse.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.19;/// @title Library of types that are used for fulfillment of a Functions requestlibraryFunctionsResponse{
// Used to send request information from the Router to the CoordinatorstructRequestMeta {
bytes data; // ══════════════════╸ CBOR encoded Chainlink Functions request data, use FunctionsRequest library to encode a requestbytes32 flags; // ═══════════════╸ Per-subscription flagsaddress requestingContract; // ══╗ The client contract that is sending the requestuint96 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 networkuint64 subscriptionId; // ║ Identifier of the billing subscription that will be charged for the requestuint64 initiatedRequests; // ║ The number of requests that have been starteduint32 callbackGasLimit; // ║ The amount of gas that the callback to the consuming contract will be givenuint16 dataVersion; // ══════════╝ The version of the structure of the CBOR encoded request datauint64 completedRequests; // ════╗ The number of requests that have successfully completed or timed outaddress subscriptionOwner; // ═══╝ The owner of the billing subscription
}
enumFulfillResult {
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
}
structCommitment {
bytes32 requestId; // ═════════════════╸ A unique identifier for a Chainlink Functions requestaddress coordinator; // ═══════════════╗ The Coordinator contract that manages the DON that is servicing a requestuint96 estimatedTotalCostJuels; // ════╝ The maximum cost in Juels (1e18) of LINK that will be charged to fulfill a requestaddress client; // ════════════════════╗ The client contract that sent the requestuint64 subscriptionId; // ║ Identifier of the billing subscription that will be charged for the requestuint32 callbackGasLimit; // ═══════════╝ The amount of gas that the callback to the consuming contract will be givenuint72 adminFee; // ═══════════════════╗ Flat fee (in Juels of LINK) that will be paid to the Router Owner for operation of the networkuint72 donFee; // ║ Fee (in Juels of LINK) that will be split between Node Operators for servicing a requestuint40 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
}
}
Contract Source Code
File 15 of 18: IFunctionsClient.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.19;/// @title Chainlink Functions client interface.interfaceIFunctionsClient{
/// @notice Chainlink Functions response handler called by the Functions Router/// during fullilment from the designated transmitter node in an OCR round./// @param requestId The requestId returned by FunctionsClient.sendRequest()./// @param response Aggregated response from the request's source code./// @param err Aggregated error either from the request's source code or from the execution pipeline./// @dev Either response or error parameter will be set, but never both.functionhandleOracleFulfillment(bytes32 requestId, bytesmemory response, bytesmemory err) external;
}
Contract Source Code
File 16 of 18: IFunctionsRouter.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.19;import {FunctionsResponse} from"../libraries/FunctionsResponse.sol";
/// @title Chainlink Functions Router interface.interfaceIFunctionsRouter{
/// @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 RouterfunctiongetAllowListId() externalviewreturns (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 subscriptionsfunctionsetAllowListId(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 adminFeefunctiongetAdminFee() externalviewreturns (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 identifierfunctionsendRequest(uint64 subscriptionId,
bytescalldata data,
uint16 dataVersion,
uint32 callbackGasLimit,
bytes32 donId
) externalreturns (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 identifierfunctionsendRequestToProposed(uint64 subscriptionId,
bytescalldata data,
uint16 dataVersion,
uint32 callbackGasLimit,
bytes32 donId
) externalreturns (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 -functionfulfill(bytesmemory response,
bytesmemory err,
uint96 juelsPerGas,
uint96 costWithoutFulfillment,
address transmitter,
FunctionsResponse.Commitment memory commitment
) externalreturns (FunctionsResponse.FulfillResult, uint96);
/// @notice Validate requested gas limit is below the subscription max./// @param subscriptionId subscription ID/// @param callbackGasLimit desired callback gas limitfunctionisValidCallbackGasLimit(uint64 subscriptionId, uint32 callbackGasLimit) externalview;
/// @notice Get the current contract given an ID/// @param id A bytes32 identifier for the route/// @return contract The current contract addressfunctiongetContractById(bytes32 id) externalviewreturns (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 addressfunctiongetProposedContractById(bytes32 id) externalviewreturns (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 tofunctiongetProposedContractSet() externalviewreturns (bytes32[] memory, address[] memory);
/// @notice Proposes one or more updates to the contract routes/// @dev Only callable by ownerfunctionproposeContractsUpdate(bytes32[] memory proposalSetIds, address[] memory proposalSetAddresses) external;
/// @notice Updates the current contract routes to the proposed contracts/// @dev Only callable by ownerfunctionupdateContracts() external;
/// @dev Puts the system into an emergency stopped state./// @dev Only callable by ownerfunctionpause() external;
/// @dev Takes the system out of an emergency stopped state./// @dev Only callable by ownerfunctionunpause() external;
}