# https://docs.chain.link/chainlink-functions llms-full.txt On this page # [Chainlink Functions](https://docs.chain.link/chainlink-functions\#overview) Chainlink Functions provides your smart contracts access to trust-minimized compute infrastructure, allowing you to fetch data from APIs and perform custom computation. Your smart contract sends source code in a request to a [Decentralized Oracle Network (DON)](https://docs.chain.link/chainlink-functions/resources/concepts), and each node in the DON executes the code in a serverless environment. The DON then aggregates all the independent return values from each execution and sends the final result back to your smart contract. Chainlink Functions eliminates the need for you to manage your own Chainlink node and provides decentralized offchain computation and consensus, ensuring that a minority of the network cannot manipulate the response sent back to your smart contract. Furthermore, Chainlink Functions allows you to include secret values in your request that are encrypted using threshold encryption. These values can only be decrypted via a multi-party decryption process, meaning that every node can only decrypt the secrets with participation from other DON nodes. This feature can provide API keys or other sensitive values to your source code, enabling access to APIs that require authentication. To pay for requests, you fund a subscription account with LINK. Your subscription is billed when the DON fulfills your requests. Check out the [subscriptions](https://docs.chain.link/chainlink-functions/resources/subscriptions) page for more information. Read the [architecture](https://docs.chain.link/chainlink-functions/resources/architecture) page to learn more about how Chainlink Functions works. See the [Tutorials](https://docs.chain.link/chainlink-functions/tutorials) page for simple tutorials showing you different GET and POST requests that run on Chainlink Functions. You can also gain hands-on experience with Chainlink Functions with the [Chainlink Functions Playground](https://functions.chain.link/playground). ## [When to use Chainlink Functions](https://docs.chain.link/chainlink-functions\#when-to-use-chainlink-functions) Chainlink Functions enables a variety of use cases. Use Chainlink Functions to: - Connect to any public data. For example, you can connect your smart contracts to weather statistics for parametric insurance or real-time sports results for Dynamic NFTs. - Connect to public data and transform it before consumption. You could calculate Twitter sentiment after reading data from the Twitter API, or derive asset prices after reading price data from [Chainlink Price Feeds](https://docs.chain.link/data-feeds/price-feeds). - Connect to a password-protected data source; from IoT devices like smartwatches to enterprise resource planning systems. - Connect to an external decentralized database, such as IPFS, to facilitate offchain processes for a dApp or build a low-cost governance voting system. - Connect to your Web2 application and build complex hybrid smart contracts. - Fetch data from almost any Web2 system such as AWS S3, Firebase, or Google Cloud Storage. You can find several community examples at [useChainlinkFunctions.com](https://www.usechainlinkfunctions.com/) ## [Supported networks](https://docs.chain.link/chainlink-functions\#supported-networks) See the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks) page to find a list of supported networks and contract addresses. ## What's next - [\> Learn the basics in the Getting Started guide.](https://docs.chain.link/chainlink-functions/getting-started) - [\> Learn how to use more advanced capabilities in one of the Tutorials.](https://docs.chain.link/chainlink-functions/tutorials) - [\> Learn about core concepts, the Chainlink Functions architecture, and billing.](https://docs.chain.link/chainlink-functions/resources) ## Get the latest Chainlink content straight to your inbox. Email Address ## Chainlink FunctionsClient API [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [FunctionsClient API Reference](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#overview) Consumer contract developers inherit [FunctionsClient](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol) to create Chainlink Functions requests. ## [Events](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#events) ### [RequestSent](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#requestsent) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity event RequestSent(bytes32 id) ``` ### [RequestFulfilled](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#requestfulfilled) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity event RequestFulfilled(bytes32 id) ``` ## [Errors](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#errors) ### [OnlyRouterCanFulfill](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#onlyroutercanfulfill) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity error OnlyRouterCanFulfill() ``` ## [Methods](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#methods) ### [constructor](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#constructor) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity constructor(address router) ``` ### [\_sendRequest](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#_sendrequest) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity function _sendRequest(bytes data, uint64 subscriptionId, uint32 callbackGasLimit, bytes32 donId) internal returns (bytes32) ``` Sends a Chainlink Functions request to the stored router address #### [Parameters](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#parameters) | Name | Type | Description | | --- | --- | --- | | data | bytes | The CBOR encoded bytes data for a Functions request | | subscriptionId | uint64 | The subscription ID that will be charged to service the request | | callbackGasLimit | uint32 | the amount of gas that will be available for the fulfillment callback | | donId | bytes32 | | #### [Return Values](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#return-values) | Name | Type | Description | | --- | --- | --- | | \[0\] | bytes32 | requestId The generated request ID for this request | ### [fulfillRequest](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#fulfillrequest) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity function fulfillRequest(bytes32 requestId, bytes response, bytes err) internal virtual ``` User defined function to handle a response from the DON _Either response or error parameter will be set, but never both_ #### [Parameters](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#parameters-1) | Name | Type | Description | | --- | --- | --- | | requestId | bytes32 | The request ID, returned by sendRequest() | | response | bytes | Aggregated response from the execution of the user's source code | | err | bytes | Aggregated error from the execution of the user code or from the execution pipeline | ### [handleOracleFulfillment](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#handleoraclefulfillment) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity function handleOracleFulfillment(bytes32 requestId, bytes response, bytes err) external ``` Chainlink Functions response handler called by the Functions Router during fulfillment from the designated transmitter node in an OCR round _Either response or error parameter will be set, but never both_ #### [Parameters](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#parameters-2) | Name | Type | Description | | --- | --- | --- | | requestId | bytes32 | The requestId returned by FunctionsClient.sendRequest(). | | response | bytes | Aggregated response from the request's source code. | | err | bytes | Aggregated error either from the request's source code or from the execution pipeline. | ## Get the latest Chainlink content straight to your inbox. Email Address ## Chainlink FunctionsRequest API [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [FunctionsRequest library API Reference](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#overview) Consumer contract developers use the [FunctionsRequest library](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol) to build their [requests](https://docs.chain.link/chainlink-functions/api-reference/functions-request#request). ## [Types and Constants](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#types-and-constants) ### [REQUEST\_DATA\_VERSION](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#request_data_version) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity uint16 REQUEST_DATA_VERSION ``` ### [DEFAULT\_BUFFER\_SIZE](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#default_buffer_size) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity uint256 DEFAULT_BUFFER_SIZE ``` ### [Location](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#location) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity enum Location { Inline, Remote, DONHosted } ``` | Value | Description | | --- | --- | | `Inline` | Provided within the Request. | | `Remote` | Hosted through a remote location that can be accessed through a provided URL. | | `DONHosted` | Hosted on the DON's storage. | ### [CodeLanguage](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#codelanguage) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity enum CodeLanguage { JavaScript } ``` ### [Request](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#request) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity struct Request { enum FunctionsRequest.Location codeLocation; enum FunctionsRequest.Location secretsLocation; enum FunctionsRequest.CodeLanguage language; string source; bytes encryptedSecretsReference; string[] args; bytes[] bytesArgs; } ``` | Field | Type | Description | | --- | --- | --- | | `codeLocation` | `Location` | The location of the source code that will be executed on each node in the DON. | | `secretsLocation` | `Location` | The location of secrets that will be passed into the source code. \*Only Remote secrets are supported. | | `language` | `CodeLanguage` | The coding language that the source code is written in. | | `source` | `string` | Raw source code for `Request.codeLocation` of `Location.Inline`, URL for `Request.codeLocation` of `Location.Remote`, or slot decimal number for `Request.codeLocation` of `Location.DONHosted`. | | `encryptedSecretsReference` | `bytes` | Encrypted URLs for `Request.secretsLocation` of `Location.Remote`, or CBOR encoded `slotid+version` for `Request.secretsLocation` of `Location.DONHosted`. | | `args` | `string[]` | String arguments that will be passed into the source code. | | `bytesArgs` | `bytes[]` | Bytes arguments that will be passed into the source code. | ## [Errors](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#errors) ### [EmptySource](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#emptysource) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity error EmptySource() ``` ### [EmptySecrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#emptysecrets) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity error EmptySecrets() ``` ### [EmptyArgs](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#emptyargs) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity error EmptyArgs() ``` ### [NoInlineSecrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#noinlinesecrets) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity error NoInlineSecrets() ``` ## [Functions](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#functions) ### [encodeCBOR](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#encodecbor) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity function encodeCBOR(struct FunctionsRequest.Request self) internal pure returns (bytes) ``` Encodes a Request to CBOR encoded bytes #### [Parameters](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#parameters) | Name | Type | Description | | --- | --- | --- | | self | struct FunctionsRequest.Request | The request to encode | #### [Return values](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#return-values) | Name | Type | Description | | --- | --- | --- | | \[0\] | bytes | CBOR encoded bytes | ### [initializeRequest](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#initializerequest) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity function initializeRequest(struct FunctionsRequest.Request self, enum FunctionsRequest.Location codeLocation, enum FunctionsRequest.CodeLanguage language, string source) internal pure ``` Initializes a Chainlink Functions Request _Sets the codeLocation and code on the request_ #### [Parameters](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#parameters-1) | Name | Type | Description | | --- | --- | --- | | self | struct FunctionsRequest.Request | The uninitialized request | | codeLocation | enum FunctionsRequest.Location | The user provided source code location | | language | enum FunctionsRequest.CodeLanguage | The programming language of the user code | | source | string | The user provided source code or a url | ### [initializeRequestForInlineJavaScript](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#initializerequestforinlinejavascript) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity function initializeRequestForInlineJavaScript(struct FunctionsRequest.Request self, string javaScriptSource) internal pure ``` Initializes a Chainlink Functions Request _Simplified version of initializeRequest for PoC_ #### [Parameters](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#parameters-2) | Name | Type | Description | | --- | --- | --- | | self | struct FunctionsRequest.Request | The uninitialized request | | javaScriptSource | string | The user provided JS code (must not be empty) | ### [addSecretsReference](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#addsecretsreference) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity function addSecretsReference(struct FunctionsRequest.Request self, bytes encryptedSecretsReference) internal pure ``` Adds Remote user encrypted secrets to a Request #### [Parameters](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#parameters-3) | Name | Type | Description | | --- | --- | --- | | self | struct FunctionsRequest.Request | The initialized request | | encryptedSecretsReference | bytes | Encrypted comma-separated string of URLs pointing to offchain secrets | ### [addDONHostedSecrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#adddonhostedsecrets) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity function addDONHostedSecrets(struct FunctionsRequest.Request self, uint8 slotID, uint64 version) internal pure ``` Adds DON-hosted secrets reference to a Request #### [Parameters](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#parameters-4) | Name | Type | Description | | --- | --- | --- | | self | struct FunctionsRequest.Request | The initialized request | | slotID | uint8 | Slot ID of the user's secrets hosted on DON | | version | uint64 | User data version (for the slotID) | ### [setArgs](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#setargs) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity function setArgs(struct FunctionsRequest.Request self, string[] args) internal pure ``` Sets args for the user run function #### [Parameters](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#parameters-5) | Name | Type | Description | | --- | --- | --- | | self | struct FunctionsRequest.Request | The initialized request | | args | string\[\] | The array of string args (must not be empty) | ### [setBytesArgs](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#setbytesargs) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity function setBytesArgs(struct FunctionsRequest.Request self, bytes[] args) internal pure ``` Sets bytes args for the user run function #### [Parameters](https://docs.chain.link/chainlink-functions/api-reference/functions-request\#parameters-6) | Name | Type | Description | | --- | --- | --- | | self | struct FunctionsRequest.Request | The initialized request | | args | bytes\[\] | The array of bytes args (must not be empty) | ## Get the latest Chainlink content straight to your inbox. Email Address ## Chainlink Functions API [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) ## 404 ## Page not found We're sorry, but we couldn't find the page you were looking for. You can select a section from the top of the page, or browse the links on the left. If you followed a broken link, [let us know](https://github.com/smartcontractkit/documentation/issues/new), or send a PR on [GitHub](https://github.com/smartcontractkit/documentation/) ## Get the latest Chainlink content straight to your inbox. Email Address ## Chainlink FunctionsClient API [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [FunctionsClient API Reference](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#overview) Consumer contract developers inherit [FunctionsClient](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol) to create Chainlink Functions requests. ## [Events](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#events) ### [RequestSent](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#requestsent) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity event RequestSent(bytes32 id) ``` ### [RequestFulfilled](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#requestfulfilled) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity event RequestFulfilled(bytes32 id) ``` ## [Errors](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#errors) ### [OnlyRouterCanFulfill](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#onlyroutercanfulfill) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity error OnlyRouterCanFulfill() ``` ## [Methods](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#methods) ### [constructor](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#constructor) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity constructor(address router) ``` ### [\_sendRequest](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#_sendrequest) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity function _sendRequest(bytes data, uint64 subscriptionId, uint32 callbackGasLimit, bytes32 donId) internal returns (bytes32) ``` Sends a Chainlink Functions request to the stored router address #### [Parameters](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#parameters) | Name | Type | Description | | --- | --- | --- | | data | bytes | The CBOR encoded bytes data for a Functions request | | subscriptionId | uint64 | The subscription ID that will be charged to service the request | | callbackGasLimit | uint32 | the amount of gas that will be available for the fulfillment callback | | donId | bytes32 | | #### [Return Values](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#return-values) | Name | Type | Description | | --- | --- | --- | | \[0\] | bytes32 | requestId The generated request ID for this request | ### [fulfillRequest](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#fulfillrequest) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity function fulfillRequest(bytes32 requestId, bytes response, bytes err) internal virtual ``` User defined function to handle a response from the DON _Either response or error parameter will be set, but never both_ #### [Parameters](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#parameters-1) | Name | Type | Description | | --- | --- | --- | | requestId | bytes32 | The request ID, returned by sendRequest() | | response | bytes | Aggregated response from the execution of the user's source code | | err | bytes | Aggregated error from the execution of the user code or from the execution pipeline | ### [handleOracleFulfillment](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#handleoraclefulfillment) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity function handleOracleFulfillment(bytes32 requestId, bytes response, bytes err) external ``` Chainlink Functions response handler called by the Functions Router during fulfillment from the designated transmitter node in an OCR round _Either response or error parameter will be set, but never both_ #### [Parameters](https://docs.chain.link/chainlink-functions/api-reference/functions-client\#parameters-2) | Name | Type | Description | | --- | --- | --- | | requestId | bytes32 | The requestId returned by FunctionsClient.sendRequest(). | | response | bytes | Aggregated response from the request's source code. | | err | bytes | Aggregated error either from the request's source code or from the execution pipeline. | ## Get the latest Chainlink content straight to your inbox. Email Address [iframe](https://td.doubleclick.net/td/rul/346357746?random=1747665268497&cv=11&fst=1747665268497&fmt=3&bg=ffffff&guid=ON&async=1&gcl_ctr=1>m=45be55g2v891173849z8847174275za200zb847174275&gcd=13l3l3l3l1l1&dma=0&tag_exp=101509157~103116025~103130495~103130497~103136993~103136995~103200001~103207802~103233427~103252644~103252646~103263073~103301114~103301116&ptag_exp=101509157~103116025~103130498~103130500~103136993~103136995~103200001~103207802~103233427~103252644~103252646~103263073~103301114~103301116&u_w=1280&u_h=1024&url=https%3A%2F%2Fdocs.chain.link%2Fchainlink-functions%2Fapi-reference%2Ffunctions-client&ref=https%3A%2F%2Fdocs.chain.link%2Fchainlink-functions%2Fapi-reference%2FFunctionsClient&label=_duuCKn_k4cYEPL_k6UB&hn=www.googleadservices.com&frm=0&tiba=FunctionsClient%20API%20Reference%20%7C%20Chainlink%20Documentation&value=0&bttype=purchase&npa=0&pscdl=noapi&auid=532928745.1747665268&uaa=x86&uab=64&uafvl=Chromium%3B136.0.7103.113%7CGoogle%2520Chrome%3B136.0.7103.113%7CNot.A%252FBrand%3B99.0.0.0&uamb=0&uam=&uap=Linux%20x86_64&uapv=6.6.72&uaw=0&ec_mode=a&fledge=1&capi=1&_tu=Cg&em=tv.1&ct_cookie_present=0) ## Chainlink Functions API [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [JavaScript code API Reference](https://docs.chain.link/chainlink-functions/api-reference/javascript-source\#overview) JavaScript source code for a Functions request should comply with certain restrictions: - **Allowed Modules**: Vanilla [Deno](https://deno.land/) and module [imports](https://docs.chain.link/chainlink-functions/tutorials/importing-packages). - **Return Type**: Must return a JavaScript `Buffer` object representing the response bytes sent back to the invoking contract. - **Time Limit**: Scripts must execute within a 10-second timeframe; otherwise, they will be terminated, and an error will be returned to the requesting contract. ## [HTTP requests](https://docs.chain.link/chainlink-functions/api-reference/javascript-source\#http-requests) For making HTTP requests, use the `Functions.makeHttpRequest` function. ### [Syntax](https://docs.chain.link/chainlink-functions/api-reference/javascript-source\#syntax) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const response = await Functions.makeHttpRequest({ url: "http://example.com", method: "GET", // Optional // Other optional parameters }) ``` ### [Parameters](https://docs.chain.link/chainlink-functions/api-reference/javascript-source\#parameters) | Parameter | Optionality | Description | Default Value | | --- | --- | --- | --- | | `url` | Required | The target URL. | N/A | | `method` | Optional | HTTP method to be used. | `'GET'` | | `headers` | Optional | HTTP headers for the request. | N/A | | `params` | Optional | URL query parameters. | N/A | | `data` | Optional | Body content for the request. | N/A | | `timeout` | Optional | Maximum request duration in milliseconds. | `3000 ms` | | `responseType` | Optional | Expected response type. | `'json'` | ### [Return Object](https://docs.chain.link/chainlink-functions/api-reference/javascript-source\#return-object) | Response Type | Fields | Description | | --- | --- | --- | | Success | `data` | Response data sent by the server. | | | `status` | Numeric HTTP status code. | | | `statusText` | Textual representation of HTTP status. | | | `headers` | HTTP headers sent by the server in the response. | | Error | `error` | Indicates an error occurred ( `true`). | | | `message` | Optional error message. | | | `code` | Optional error code. | | | `response` | Optional server response. | ## [Data encoding functions](https://docs.chain.link/chainlink-functions/api-reference/javascript-source\#data-encoding-functions) The Functions library includes several encoding functions, which are useful for preparing data for blockchain contracts. | Function | Input Type | Output Type | Description | | --- | --- | --- | --- | | `Functions.encodeUint256` | Positive Integer | 32-byte `Buffer` | Converts a positive integer to a 32-byte `Buffer` for a `uint256` in Solidity. | | `Functions.encodeInt256` | Integer | 32-byte `Buffer` | Converts an integer to a 32-byte `Buffer` for an `int256` in Solidity. | | `Functions.encodeString` | String | `Buffer` | Converts a string to a `Buffer` for a `string` type in Solidity. | **Note**: Using these encoding functions is optional. The source code must return a [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) which represents the `bytes` that are returned onchain. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const myArr = new Uint8Array(ARRAY_LENGTH) ``` ## Get the latest Chainlink content straight to your inbox. Email Address ## Chainlink Functions Guide [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Getting Started](https://docs.chain.link/chainlink-functions/getting-started\#overview) Learn how to make requests to the Chainlink Functions Decentralized Oracle Network (DON) and make any computation or API calls offchain. Chainlink Functions is available on several blockchains (see the [supported networks page](https://docs.chain.link/chainlink-functions/supported-networks)), but this guide uses Sepolia to simplify access to testnet funds. Complete the following tasks to get started with Chainlink Functions: - Set up your web3 wallet and fund it with testnet tokens. - Simulate a Chainlink Functions on the [Chainlink Functions\\ Playground](https://functions.chain.link/playground). - Send a Chainlink Functions request to the DON. The JavaScript source code makes an API call to the [Star Wars API](https://swapi.info/) and fetches the name of a given character. - Receive the response from Chainlink Functions and parse the result. Play ## [Simulation](https://docs.chain.link/chainlink-functions/getting-started\#simulation) Before making a Chainlink Functions request from your smart contract, it is always a good practice to simulate the source code offchain to make any adjustments or corrections. 1. Open the [Functions playground](https://functions.chain.link/playground). 2. Copy and paste the following source code into the playground's code block. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const characterId = args[0]; const apiResponse = await Functions.makeHttpRequest({ url: `https://swapi.info/api/people/${characterId}/`, }); if (apiResponse.error) { throw Error("Request failed"); } const { data } = apiResponse; return Functions.encodeString(data.name); ``` 3. Under _Argument_, set the first argument to `1`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg). You are going to fetch the name of the first Star Wars character. 4. Click on _Run code_. Under _Output_, you should see _Luke Skywalker_. ![](https://docs.chain.link/images/chainlink-functions/getting-started/simulation.jpg) ## [Configure your resources](https://docs.chain.link/chainlink-functions/getting-started\#configure-your-resources) ### [Configure your wallet](https://docs.chain.link/chainlink-functions/getting-started\#configure-your-wallet) You will test on Sepolia, so you must have an Ethereum web3 wallet with enough testnet ETH and LINK tokens. Testnet ETH is the native gas fee token on Sepolia. You will use testnet ETH tokens to pay for gas whenever you make a transaction on Sepolia. On the other hand, you will use LINK tokens to pay the Chainlink Functions Decentralized Oracles Network (DON) for processing your request. 1. [Install the MetaMask wallet](https://docs.chain.link/quickstarts/deploy-your-first-contract#install-and-fund-your-metamask-wallet) or other Ethereum web3 wallet. 2. Set the network for your wallet to the Sepolia testnet. If you need to add Sepolia to your wallet, you can find the chain ID and the LINK token contract address on the [LINK Token Contracts](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) page. - [Sepolia testnet and LINK token contract](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) 3. Request testnet LINK and ETH from [faucets.chain.link/sepolia](https://faucets.chain.link/sepolia). ### [Deploy a Functions consumer contract on Sepolia](https://docs.chain.link/chainlink-functions/getting-started\#deploy-a-functions-consumer-contract-on-sepolia) 1. Open the [GettingStartedFunctionsConsumer.sol](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/GettingStartedFunctionsConsumer.sol) contract in Remix. [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/GettingStartedFunctionsConsumer.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) 2. Compile the contract. 3. Open MetaMask and select the _Sepolia_ network. 4. In Remix under the **Deploy & Run Transactions** tab, select _Injected Provider - MetaMask_ in the **Environment** list. Remix will use the MetaMask wallet to communicate with _Sepolia_. ![](https://docs.chain.link/images/chainlink-functions/getting-started/injected-provider.jpg) 5. Click the **Deploy** button to deploy the contract. MetaMask prompts you to confirm the transaction. Check the transaction details to make sure you are deploying the contract to _Sepolia_. ![](https://docs.chain.link/images/chainlink-functions/getting-started/deploy.jpg) 6. After you confirm the transaction, the contract address appears in the **Deployed Contracts** list. Copy the contract address and save it for later. You will use this address with a Functions Subscription. ![](https://docs.chain.link/images/chainlink-functions/getting-started/deployed-contracts.jpg) ### [Create a subscription](https://docs.chain.link/chainlink-functions/getting-started\#create-a-subscription) You use a Chainlink Functions subscription to pay for, manage, and track Functions requests. 1. Go to [functions.chain.link](https://functions.chain.link/). 2. Click **Connect wallet**: ![Chainlink Functions subscription landing page](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/frontend-landing.jpg) 3. Read and accept the Chainlink Foundation Terms of Service. Then click **MetaMask**. ![Chainlink Functions accept ToS](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/accept-CL-foundation-tos.jpg) 4. Make sure your wallet is connected to the _Sepolia_ testnet. If not, click the network name in the top right corner of the page and select _Sepolia_. ![Chainlink Functions subscription landing page](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/wallet-connected-ethereum-sepolia.webp) 5. Click **Create Subscription**: ![Chainlink Functions subscription landing page](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/frontend-landing-wallet-connected.jpg) 6. Provide an email address and an optional subscription name: ![Chainlink Functions create subscription](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/create-subscription.jpg) 7. The first time you interact with the Subscription Manager using your EOA, you must accept the Terms of Service (ToS). A MetaMask popup appears and you are asked to accept the ToS: ![Chainlink Functions accept ToS](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/acceptTos.jpg) 8. After you approve the ToS, another MetaMask popup appears, and you are asked to approve the subscription creation: ![Chainlink Functions approve subscriptions creation](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/approve-create-subscription.jpg) 9. After the subscription is created, MetaMask prompts you to sign a message that links the subscription name and email address to your subscription: ![Chainlink Functions sign message ToS](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/sign-message-tos.jpg)![Chainlink Functions sign message ToS MetaMask](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/sign-message-tos-metamask.jpg) ### [Fund your subscription](https://docs.chain.link/chainlink-functions/getting-started\#fund-your-subscription) 1. After the subscription is created, the Functions UI prompts you to fund your subscription. Click **Add funds**: ![Chainlink Functions subscription created](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/subscription-created.jpg) 2. For this example, add 2 LINK and click **Add funds**: ![Chainlink Functions subscription add funds](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/subscription-created-add-funds.jpg) ### [Add a consumer to your subscription](https://docs.chain.link/chainlink-functions/getting-started\#add-a-consumer-to-your-subscription) 1. After you fund your subscription, add your consumer to it. Specify the address for the consumer contract that you deployed earlier and click **Add consumer**. MetaMask prompts you to confirm the transaction. ![Chainlink Functions subscription add consumer](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/subscription-created-add-consumer.jpg)![Chainlink Functions subscription add consumer](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/subscription-created-add-consumer-2.jpg) 2. Subscription creation and configuration is complete. You can always see the details of your subscription again at [functions.chain.link](https://functions.chain.link/): ![Chainlink Functions subscription details](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/subscription-details-after-creation.jpg) ## [Run the example](https://docs.chain.link/chainlink-functions/getting-started\#run-the-example) The example is hardcoded to communicate with Chainlink Functions on Sepolia. After this example is run, you can examine the code and see a detailed description of all components. 1. In Remix under the **Deploy & Run Transactions** tab, expand your contract in the **Deployed Contracts** section. 2. Expand the `sendRequest` function to display its parameters. 3. Fill in the `subscriptionId` with your subscription ID and `args` with `[1]`. You can find your subscription ID on the Chainlink Functions Subscription Manager at [functions.chain.link](https://functions.chain.link/). The `[1]` value for `args` specifies which argument in the response will be retrieved. 4. Click the **transact** button. ![](https://docs.chain.link/images/chainlink-functions/getting-started/send-request.jpg) 5. Wait for the request to be fulfilled. You can monitor the status of your request on the Chainlink Functions Subscription Manager. ![](https://docs.chain.link/images/chainlink-functions/getting-started/request-fulfilled.png) 6. Refresh the Functions UI to get the latest request status. 7. After the status is _Success_, check the character name. In Remix, under the **Deploy & Run Transactions** tab, click the `character` function. If the transaction and request ran correctly, you will see the name of your character in the response. ![](https://docs.chain.link/images/chainlink-functions/getting-started/character.jpg) Chainlink Functions is capable of much more than just retrieving data. Try one of the [Tutorials](https://docs.chain.link/chainlink-functions/tutorials) to see examples that can GET and POST to public APIs, securely handle API secrets, handle custom responses, and query multiple APIs. ## [Examine the code](https://docs.chain.link/chainlink-functions/getting-started\#examine-the-code) ### [Solidity code](https://docs.chain.link/chainlink-functions/getting-started\#solidity-code) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; /** * Request testnet LINK and ETH here: https://faucets.chain.link/ * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: https://docs.chain.link/resources/link-token-contracts/ */ /** * @title GettingStartedFunctionsConsumer * @notice This is an example contract to show how to make HTTP requests using Chainlink * @dev This contract uses hardcoded values and should not be used in production. */ contract GettingStartedFunctionsConsumer is FunctionsClient, ConfirmedOwner { using FunctionsRequest for FunctionsRequest.Request; // State variables to store the last request ID, response, and error bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; // Custom error type error UnexpectedRequestID(bytes32 requestId); // Event to log responses event Response( bytes32 indexed requestId, string character, bytes response, bytes err ); // Router address - Hardcoded for Sepolia // Check to get the router address for your supported network https://docs.chain.link/chainlink-functions/supported-networks address router = 0xb83E47C2bC239B3bf370bc41e1459A34b41238D0; // JavaScript source code // Fetch character name from the Star Wars API. // Documentation: https://swapi.info/people string source = "const characterId = args[0];" "const apiResponse = await Functions.makeHttpRequest({" "url: `https://swapi.info/api/people/${characterId}/`" "});" "if (apiResponse.error) {" "throw Error('Request failed');" "}" "const { data } = apiResponse;" "return Functions.encodeString(data.name);"; //Callback gas limit uint32 gasLimit = 300000; // donID - Hardcoded for Sepolia // Check to get the donID for your supported network https://docs.chain.link/chainlink-functions/supported-networks bytes32 donID = 0x66756e2d657468657265756d2d7365706f6c69612d3100000000000000000000; // State variable to store the returned character information string public character; /** * @notice Initializes the contract with the Chainlink router address and sets the contract owner */ constructor() FunctionsClient(router) ConfirmedOwner(msg.sender) {} /** * @notice Sends an HTTP request for character information * @param subscriptionId The ID for the Chainlink subscription * @param args The arguments to pass to the HTTP request * @return requestId The ID of the request */ function sendRequest( uint64 subscriptionId, string[] calldata args ) external onlyOwner returns (bytes32 requestId) { FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); // Initialize the request with JS code if (args.length > 0) req.setArgs(args); // Set the arguments for the request // Send the request and store the request ID s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Callback function for fulfilling a request * @param requestId The ID of the request to fulfill * @param response The HTTP response data * @param err Any errors from the Functions request */ function fulfillRequest( bytes32 requestId, bytes memory response, bytes memory err ) internal override { if (s_lastRequestId != requestId) { revert UnexpectedRequestID(requestId); // Check if request IDs match } // Update the contract's state variables with the response and any errors s_lastResponse = response; character = string(response); s_lastError = err; // Emit an event to log the response emit Response(requestId, character, s_lastResponse, s_lastError); } } ``` [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/GettingStartedFunctionsConsumer.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) - To write a Chainlink Functions consumer contract, your contract must import [FunctionsClient.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol) and [FunctionsRequest.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol). You can read the API references: [FunctionsClient](https://docs.chain.link/chainlink-functions/api-reference/functions-client) and [FunctionsRequest](https://docs.chain.link/chainlink-functions/api-reference/functions-request). These contracts are available in an NPM package so that you can import them from within your project. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; ``` - Use the FunctionsRequest.sol library to get all the functions needed for building a Chainlink Functions request. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext using FunctionsRequest for FunctionsRequest.Request; ``` - The latest request ID, latest received response, and latest received error (if any) are defined as state variables: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; ``` - We define the `Response` event that your smart contract will emit during the callback ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext event Response(bytes32 indexed requestId, string character, bytes response, bytes err); ``` - The Chainlink Functions router address and donID are hardcoded for Sepolia. Check the [supported networks page](https://docs.chain.link/chainlink-functions/supported-networks) to try the code sample on another testnet. - The `gasLimit` is hardcoded to `300000`, the amount of gas that Chainlink Functions will use to fulfill your request. - The JavaScript source code is hardcoded in the `source` state variable. For more explanation, read the [JavaScript code section](https://docs.chain.link/chainlink-functions/getting-started#javascript-code). - Pass the router address for your network when you deploy the contract: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext constructor() FunctionsClient(router) ``` - The two remaining functions are: - `sendRequest` for sending a request. It receives the subscription ID and list of arguments to pass to the source code. Then: - It uses the `FunctionsRequest` library to initialize the request and add the source code and arguments. You can read the API Reference for [Initializing a request](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#initializerequestforinlinejavascript) and [adding arguments](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#setargs). ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); if (args.length > 0) req.setArgs(args); ``` - It sends the request to the router by calling the `FunctionsClient` `sendRequest` function. You can read the API reference for [sending a request](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#_sendrequest). Finally, it stores the request id in `s_lastRequestId` and returns it. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, jobId ); return s_lastRequestId; ``` **Note**: `_sendRequest` accepts requests encoded in `bytes`. Therefore, you must encode it using [encodeCBOR](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#encodecbor). - `fulfillRequest` to be invoked during the callback. This function is defined in `FunctionsClient` as `virtual` (read `fulfillRequest` [API reference](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#fulfillrequest)). So, your smart contract must override the function to implement the callback. The implementation of the callback is straightforward: the contract stores the latest response and error in `s_lastResponse` and `s_lastError`, parses the `response` from `bytes` to `string` to fetch the character name before emitting the `Response` event. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastResponse = response; character = string(response); s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); ``` ### [JavaScript code](https://docs.chain.link/chainlink-functions/getting-started\#javascript-code) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const characterId = args[0]; const apiResponse = await Functions.makeHttpRequest({ url: `https://swapi.info/api/people/${characterId}/`, }); if (apiResponse.error) { throw Error("Request failed"); } const { data } = apiResponse; return Functions.encodeString(data.name); ``` This JavaScript source code uses [Functions.makeHttpRequest](https://docs.chain.link/chainlink-functions/api-reference/javascript-source#http-requests) to make HTTP requests. The source code calls the `https://swapi.info/` API to request a Star Wars character name. If you read the [Functions.makeHttpRequest](https://docs.chain.link/chainlink-functions/api-reference/javascript-source#http-requests) documentation and the [Star Wars API documentation](https://swapi.info/people), you notice that URL has the following format where `$characterId` is provided as parameter when making the HTTP request: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext url: `https://swapi.info/api/people/${characterId}/` ``` To check the expected API response for the first character, you can directly paste the following URL in your browser `https://swapi.info/api/people/1/` or run the `curl` command in your terminal: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```bash curl -X 'GET' \ 'https://swapi.info/api/people/1/' \ -H 'accept: application/json' ``` The response should be similar to the following example: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```json { "name": "Luke Skywalker", "height": "172", "mass": "77", "hair_color": "blond", "skin_color": "fair", "eye_color": "blue", "birth_year": "19BBY", "gender": "male", "homeworld": "https://swapi.info/api/planets/1/", "films": [\ "https://swapi.info/api/films/1/",\ "https://swapi.info/api/films/2/",\ "https://swapi.info/api/films/3/",\ "https://swapi.info/api/films/6/"\ ], "species": [], "vehicles": ["https://swapi.info/api/vehicles/14/", "https://swapi.info/api/vehicles/30/"], "starships": ["https://swapi.info/api/starships/12/", "https://swapi.info/api/starships/22/"], "created": "2014-12-09T13:50:51.644000Z", "edited": "2014-12-20T21:17:56.891000Z", "url": "https://swapi.info/api/people/1/" } ``` Now that you understand the structure of the API. Let's delve into the JavaScript code. The main steps are: - Fetch `characterId` from `args`. Args is an array. The `characterId` is located in the first element. - Make the HTTP call using `Functions.makeHttpRequest` and store the response in `apiResponse`. - Throw an error if the call is not successful. - The API response is located at `data`. - Read the name from the API response `data.name` and return the result as a [buffer](https://nodejs.org/api/buffer.html#buffer) using the `Functions.encodeString` helper function. Because the `name` is a `string`, we use `encodeString`. For other data types, you can use different [data encoding functions](https://docs.chain.link/chainlink-functions/api-reference/javascript-source#data-encoding-functions). **Note**: Read this [article](https://www.freecodecamp.org/news/do-you-want-a-better-understanding-of-buffer-in-node-js-check-this-out-2e29de2968e8/) if you are new to Javascript Buffers and want to understand why they are important. ## What's next - [\> Try out the Chainlink Functions Tutorials](https://docs.chain.link/chainlink-functions/tutorials) - [\> Read the Architecture to understand how Chainlink Functions operates](https://docs.chain.link/chainlink-functions/resources/architecture) ## Get the latest Chainlink content straight to your inbox. Email Address ## Chainlink Functions Overview [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Chainlink Functions Beta](https://docs.chain.link/chainlink-functions\#overview) Chainlink Functions provides your smart contracts access to trust-minimized compute infrastructure, allowing you to fetch data from APIs and perform custom computation. Your smart contract sends source code in a request to a [Decentralized Oracle Network (DON)](https://docs.chain.link/chainlink-functions/resources/concepts), and each node in the DON executes the code in a serverless environment. The DON then aggregates all the independent return values from each execution and sends the final result back to your smart contract. Chainlink Functions eliminates the need for you to manage your own Chainlink node and provides decentralized offchain computation and consensus, ensuring that a minority of the network cannot manipulate the response sent back to your smart contract. Furthermore, Chainlink Functions allows you to include secret values in your request that are encrypted using threshold encryption. These values can only be decrypted via a multi-party decryption process, meaning that every node can only decrypt the secrets with participation from other DON nodes. This feature can provide API keys or other sensitive values to your source code, enabling access to APIs that require authentication. To pay for requests, you fund a subscription account with LINK. Your subscription is billed when the DON fulfills your requests. Check out the [subscriptions](https://docs.chain.link/chainlink-functions/resources/subscriptions) page for more information. Read the [architecture](https://docs.chain.link/chainlink-functions/resources/architecture) page to learn more about how Chainlink Functions works. See the [Tutorials](https://docs.chain.link/chainlink-functions/tutorials) page for simple tutorials showing you different GET and POST requests that run on Chainlink Functions. You can also gain hands-on experience with Chainlink Functions with the [Chainlink Functions Playground](https://functions.chain.link/playground). ## [When to use Chainlink Functions](https://docs.chain.link/chainlink-functions\#when-to-use-chainlink-functions) Chainlink Functions enables a variety of use cases. Use Chainlink Functions to: - Connect to any public data. For example, you can connect your smart contracts to weather statistics for parametric insurance or real-time sports results for Dynamic NFTs. - Connect to public data and transform it before consumption. You could calculate Twitter sentiment after reading data from the Twitter API, or derive asset prices after reading price data from [Chainlink Price Feeds](https://docs.chain.link/data-feeds/price-feeds). - Connect to a password-protected data source; from IoT devices like smartwatches to enterprise resource planning systems. - Connect to an external decentralized database, such as IPFS, to facilitate offchain processes for a dApp or build a low-cost governance voting system. - Connect to your Web2 application and build complex hybrid smart contracts. - Fetch data from almost any Web2 system such as AWS S3, Firebase, or Google Cloud Storage. You can find several community examples at [useChainlinkFunctions.com](https://www.usechainlinkfunctions.com/) ## [Supported networks](https://docs.chain.link/chainlink-functions\#supported-networks) See the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks) page to find a list of supported networks and contract addresses. ## What's next - [\> Learn the basics in the Getting Started guide.](https://docs.chain.link/chainlink-functions/getting-started) - [\> Learn how to use more advanced capabilities in one of the Tutorials.](https://docs.chain.link/chainlink-functions/tutorials) - [\> Learn about core concepts, the Chainlink Functions architecture, and billing.](https://docs.chain.link/chainlink-functions/resources) ## Get the latest Chainlink content straight to your inbox. Email Address ## Chainlink Functions Resources [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Chainlink Functions Resources](https://docs.chain.link/chainlink-functions/resources\#overview) ## [Topics](https://docs.chain.link/chainlink-functions/resources\#topics) - [Architecture](https://docs.chain.link/chainlink-functions/resources/architecture) - [Managing Subscriptions](https://docs.chain.link/chainlink-functions/resources/subscriptions) - [Billing](https://docs.chain.link/chainlink-functions/resources/billing) - [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks) - [Service Limits](https://docs.chain.link/chainlink-functions/resources/service-limits) ## Get the latest Chainlink content straight to your inbox. Email Address [iframe](https://td.doubleclick.net/td/rul/346357746?random=1747665271789&cv=11&fst=1747665271789&fmt=3&bg=ffffff&guid=ON&async=1&gcl_ctr=1>m=45be55g2v891173849z8847174275za201zb847174275&gcd=13l3l3l3l1l1&dma=0&tag_exp=101509157~103116026~103130495~103130497~103136993~103136995~103200004~103207802~103233427~103252644~103252646~103263073~103301114~103301116&ptag_exp=101509157~103116026~103130495~103130497~103136993~103136995~103200004~103207802~103211513~103233427~103252644~103252646~103263073~103301114~103301116&u_w=1280&u_h=1024&url=https%3A%2F%2Fdocs.chain.link%2Fchainlink-functions%2Fresources&label=_duuCKn_k4cYEPL_k6UB&hn=www.googleadservices.com&frm=0&tiba=Chainlink%20Functions%20Resources%20%7C%20Chainlink%20Documentation&value=0&bttype=purchase&npa=0&pscdl=noapi&auid=226934100.1747665271&uaa=x86&uab=64&uafvl=Chromium%3B136.0.7103.113%7CGoogle%2520Chrome%3B136.0.7103.113%7CNot.A%252FBrand%3B99.0.0.0&uamb=0&uam=&uap=Linux%20x86_64&uapv=6.6.72&uaw=0&fledge=1&capi=1&_tu=Cg&ct_cookie_present=0) ## Chainlink Functions Architecture [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Chainlink Functions Architecture](https://docs.chain.link/chainlink-functions/resources/architecture\#overview) ## [Request and Receive Data](https://docs.chain.link/chainlink-functions/resources/architecture\#request-and-receive-data) This model is similar to the [Basic Request Model](https://docs.chain.link/architecture-overview/architecture-request-model): The consumer contract initiates the cycle by sending a request to the [FunctionsRouter contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsRouter.sol). Oracle nodes watch for events emitted by the [FunctionsCoordinator contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_1_0/FunctionsCoordinator.sol) and run the computation offchain. Finally, oracle nodes use the [Chainlink OCR](https://docs.chain.link/architecture-overview/off-chain-reporting) protocol to aggregate all the returned before passing the single aggregated response back to the consumer contract via a callback function. ![Chainlink Functions request and receive diagram](https://docs.chain.link/images/chainlink-functions/requestAndReceive.png) The main actors and components are: - Initiator (or end-user): initiates the request to Chainlink Functions. It can be an [EOA (Externally Owned Account)](https://ethereum.org/en/developers/docs/accounts/#types-of-account) or Chainlink Automation. - Consumer contract: smart contract deployed by developers, which purpose is to interact with the FunctionsRouter to initiate a request. - FunctionsRouter contract: manages subscriptions and is the entry point for consumers. The interface of the router is stable. Consumers call the `sendRequest` method to initiate a request. - FunctionsCoordinator contracts: interface for the [Decentralized Oracle Network](https://chain.link/education/blockchain-oracles#decentralized-oracles). Oracle nodes listen to events emitted by the coordinator contract and interact with the coordinator to transmit the responses. - DON: Chainlink Functions are powered by a [Decentralized Oracle Network](https://chain.link/education/blockchain-oracles#decentralized-oracles). The oracle nodes are independent of each other and are responsible for executing the request's source code. The nodes use the [Chainlink OCR](https://docs.chain.link/architecture-overview/off-chain-reporting) protocol to aggregate all the nodes' responses. Finally, a DON's oracle sends the aggregate response to the consumer contract in a callback. - Secrets endpoint: To transmit their secrets, users can encrypt them with the DON public key and then upload them to the secrets endpoint, a highly available service for securely sharing encrypted secrets with the nodes. **Note**: An alternative method involves self-hosting secrets. In this approach, users provide a publicly accessible HTTP(s) URL, allowing nodes to retrieve the encrypted secrets. Refer to the [secrets management](https://docs.chain.link/chainlink-functions/resources/secrets) page for detailed information on both methods. - Serverless Environment: Every Oracle node accesses a distinct, sandboxed environment for computation. While the diagram illustrates an API request, the computation isn't restricted solely to this. You can perform any computation, from API calls to mathematical operations, using vanilla [Deno](https://deno.land/) code without module imports. Note: All nodes execute identical computations. If the target API has throttling limits, know that multiple simultaneous calls will occur since each DON node will independently run the request's source code. Let's walk through the sequence of interactions among these components, as illustrated in the diagram: 1. If there are secrets, a user encrypts secrets with the public key linked to the DON master secret key (MSK) and then uploads the encrypted secrets to the secrets endpoint. The secrets endpoint pushes the encrypted secrets to the nodes part of the DON (The secrets capability depicted in this diagram is called _threshold encryption_ and is explained in [secrets management](https://docs.chain.link/chainlink-functions/resources/secrets#threshold-encryption)). 2. An [EOA (Externally Owned Account)](https://ethereum.org/en/developers/docs/accounts/#types-of-account) or Chainlink Automation initiates the request by calling the consumer contract. 3. The consumer contract should inherit the [FunctionsClient](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol) contract. This ensures it will be able to receive responses from the [FunctionsRouter](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsRouter.sol) contract via the `handleOracleFulfillment` callback. The router contract starts the billing to estimate the fulfillment costs and block the amount in the _reservation balance_ (To learn more, read [Cost simulation](https://docs.chain.link/chainlink-functions/resources/billing#cost-simulation-reservation)). Then it calls the [FunctionsCoordinator contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_1_0/FunctionsCoordinator.sol). 4. The coordinator contract emits an `OracleRequest` event containing information about the request. 5. On reception of the event by the DON, the DON's nodes decrypt the secrets using threshold decryption (The threshold encryption feature is explained in [secrets management](https://docs.chain.link/chainlink-functions/resources/secrets#threshold-encryption)). Each DON's Oracle node executes the request's source code in a serverless environment. 6. The DON runs the Offchain Reporting protocol (OCR) to aggregate the values returned by each node's execution of the source code. 7. A DON's oracle node transmits the attested report (which includes the aggregated response) to the FunctionsCoordinator contract. 8. The FunctionsCoordinator contract calls the FunctionsRouter's `fulfill` method to calculate the fulfillment costs and finalize the billing (To learn more, read [Cost calculation](https://docs.chain.link/chainlink-functions/resources/billing#cost-calculation-fulfillment)). 9. The FunctionsRouter contract calls the consumer contract's callback with the aggregated response. **Note**: Chainlink Functions requests are not limited to API requests. The diagram depicts an example of API requests, but you can request the DON to run any computation. ## [Subscription management](https://docs.chain.link/chainlink-functions/resources/architecture\#subscription-management) Chainlink Functions do not require your consumer contracts to hold LINK tokens and send them to oracles when making requests. Instead, you must create a subscription account and fund it to pay for your Chainlink Functions requests, so your consumer contracts don't need to hold LINK when calling Chainlink Functions. ### [Concepts](https://docs.chain.link/chainlink-functions/resources/architecture\#concepts) - Terms of service (ToS): Before interacting with Chainlink Functions, users must agree to the terms of service. Once signed, the accounts that can manage subscriptions are added to the `allowedSenders` in the [ToS allow list contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/accessControl/TermsOfServiceAllowList.sol). - Chainlink Functions Subscription Manager: A user interface that allows users to agree to the sign Terms of service and interact with the FunctionsRouter to manage subscriptions. - Subscription account: An account that holds LINK tokens and makes them available to fund requests to Chainlink DON. A _Subscription ID_ uniquely identifies each account. - Subscription ID: 64-bit unsigned integer representing the unique identifier of the _Subscription account_. - Subscription owner: The wallet address that creates and manages a _Subscription account_. Any account can add LINK tokens to the subscription balance. Still, only the owner can add consumer contracts to the subscription, remove consumer contracts from the subscription, withdraw funds, or transfer a subscription. Only the subscription owner can generate encrypted secrets for requests that use their _Subscription ID_. - Subscription balance: The amount of LINK maintained on your _Subscription account_. Requests from consumer contracts are funded as long as sufficient funds are in the balance, so be sure to maintain sufficient funds in your _Subscription balance_ to pay for the requests and keep your applications running. - Subscription reservation: The amount of LINK blocked on the _Subscription balance_. It corresponds to the total LINK amount to be paid by in-flight requests. - Effective balance: The amount of LINK available on your _Subscription account_. `Effective balance = Subscription balance - Subscription reservation`. - Subscription consumers: Consumer contracts are approved to use funding from your _Subscription account_ while making Chainlink Functions requests. The consumers receive response data in a callback. ### [Accept ToS](https://docs.chain.link/chainlink-functions/resources/architecture\#accept-tos) To ensure compliance and governance, Chainlink Functions mandates that any account that manages a subscription must first accept the platform's Terms of Service (ToS). The acceptance is verified by cross-referencing the account with the `allowedSenders` registry contained within the [TermsOfServiceAllowList contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/accessControl/TermsOfServiceAllowList.sol). ![](https://docs.chain.link/images/chainlink-functions/subscription/acceptToSEOA.png) The acceptance process is initiated via the Chainlink Functions Subscription Manager. After a user accepts the ToS by generating the required signature with their externally owned account (EOA), they transmit proof of acceptance to the [TermsOfServiceAllowList contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/accessControl/TermsOfServiceAllowList.sol). Upon successful validation of the proof, the EOA is added to the `allowedSenders` registry, permitting it to manage subscriptions. ### [Create subscription](https://docs.chain.link/chainlink-functions/resources/architecture\#create-subscription) ![](https://docs.chain.link/images/chainlink-functions/subscription/createSubscription.png) After the ToS is accepted, EOAs can create subscriptions. Upon creation, the [FunctionsRouter](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsRouter.sol) assigns a unique identifier, _Subscription ID_. **Note**: EOAs can directly interact with the FunctionsRouter contract using their preferred web3 library, such as web3.js or ethers.js. ### [Fund subscription](https://docs.chain.link/chainlink-functions/resources/architecture\#fund-subscription) ![](https://docs.chain.link/images/chainlink-functions/subscription/fundSubscription.png) You must fund your subscription accounts with enough LINK tokens: 1. Connect your EOA to the Chainlink Functions Subscription Manager. 2. Fund your subscription account. The Chainlink Functions Subscription Manager abstracts the following: 1. Call `transferAndCall` on the LINK token contract, transferring LINK tokens along with the _Subscription ID_ in the payload. 2. The FunctionsRouter contract implements `onTokenTransfer`: It parses the _Subscription ID_ from the payload and funds the subscription account with the transferred LINK amount. **Note**: EOAs can directly interact with the LinkToken contract using their preferred web3 library, such as web3.js or ethers.js. ### [Add consumer](https://docs.chain.link/chainlink-functions/resources/architecture\#add-consumer) ![](https://docs.chain.link/images/chainlink-functions/subscription/addConsumer.png) You must allowlist your consumers' contracts on your subscription account before they can make Chainlink Functions requests: 1. Connect your EOA to the Chainlink Functions Subscription Manager. 2. Add the address of the consumer contract to the subscription account. 3. The Chainlink Functions Subscription Manager interacts with the FunctionsRouter contract to register the consumer contract address to the subscription account. **Note**: EOAs can directly interact with the FunctionsRouter contract using a web3 library, such as web3.js or ethers.js. ### [Remove consumer](https://docs.chain.link/chainlink-functions/resources/architecture\#remove-consumer) ![](https://docs.chain.link/images/chainlink-functions/subscription/removeConsumer.png) To prevent further Chainlink Functions requests from a given consumer contract, you must remove it from your subscription account: 1. Connect your EOA to the Chainlink Functions Subscription Manager. 2. Remove the address of the consumer contract from the subscription account. 3. The Chainlink Functions Subscription Manager communicates with the FunctionsRouter contract to remove the consumer contract address from the subscription account. **Note**: You can still remove consumers from your subscription even if in-flight requests exist. The consumer contract will still receive a callback, and your _Subscription Account_ will be charged. **Note**: EOAs can directly interact with the FunctionsRouter contract using a web3 library, such as web3.js or ethers.js. ### [Cancel subscription](https://docs.chain.link/chainlink-functions/resources/architecture\#cancel-subscription) ![](https://docs.chain.link/images/chainlink-functions/subscription/cancelSubscription.png) To cancel a subscription: 1. Connect your EOA to the Chainlink Functions Subscription Manager. 2. Cancel your subscription, providing the _Subscription Balance_ receiver account address. The Chainlink Functions Subscription Manager handles the following processes: 1. Invokes the `cancelSubscription` function on the FunctionsRouter contract, deleting the _Subscription ID_ and removing all associated consumers. 2. Transfers the remaining _Subscription Balance_ to the specified receiver account. **Note**: EOAs can directly interact with the FunctionsRouter contract using their preferred web3 library, such as web3.js or ethers.js. **Note**: Subscriptions cannot be canceled while there are in-flight requests. Furthermore, any expired requests (requests that have yet to receive a response within 5 minutes) must be timed out before cancellation. ### [Transferring ownership of a Subscription](https://docs.chain.link/chainlink-functions/resources/architecture\#transferring-ownership-of-a-subscription) Transferring ownership is currently only supported using the [Functions Hardhat Starter kit](https://github.com/smartcontractkit/functions-hardhat-starter-kit) or the [Functions Toolkit NPM package](https://github.com/smartcontractkit/functions-toolkit): 1. Use the `functions-sub-transfer` command to initiate the transfer of ownership by specifying the new owner's address. 2. As a prerequisite, the prospective owner must be part of the `allowedSenders` registry within the [TermsOfServiceAllowList contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/accessControl/TermsOfServiceAllowList.sol). This verifies their acceptance of the Chainlink Functions' Terms of Service (ToS). 3. The prospective owner should use the [Functions Hardhat Starter kit](https://github.com/smartcontractkit/functions-hardhat-starter-kit) and run the `functions-sub-accept` command to confirm the ownership transfer. **Note**: This guide will be updated as soon as the Chainlink Functions Subscription Manager supports ownership transfers. ## What's next - [\> Billing](https://docs.chain.link/chainlink-functions/resources/billing) ## Get the latest Chainlink content straight to your inbox. Email Address ## Chainlink Functions Billing [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Chainlink Functions Billing](https://docs.chain.link/chainlink-functions/resources/billing\#overview) ## [Request costs](https://docs.chain.link/chainlink-functions/resources/billing\#request-costs) To send Chainlink Functions requests, you must maintain a sufficient amount of LINK in your subscription balance. Because Chainlink Functions follows the [Request and Receive Data](https://docs.chain.link/chainlink-functions/resources/architecture) model, billing is done in two steps: 1. During the **request** step, the cost to fulfill a Chainlink Functions request is **estimated** and blocked on the subscription balance by adding it to the subscription reservation. 2. During the **receive** step, the exact fulfillment cost is **calculated**, then billed to the subscription account, and the subscription reservation is removed. You can break down total costs into the following components: - Gas cost: This cost is paid back to the transmitter oracle in LINK for fulfilling the request. - Premium fees: These fees are paid in LINK to compensate nodes for their work and for the maintenance of the FunctionsRouter contract. Gas cost calculation includes the following variables: - Gas price: The current gas price fluctuates depending on network conditions. - Overestimated gas price: refers to a deliberately higher gas price estimation to account for potential price fluctuations between the time a request is made and the time Chainlink Functions fulfills it. By setting the gas price higher than the current one, Chainlink Functions increases the likelihood that the request will be fulfilled, even if gas prices rise unexpectedly in the short term. The overestimation is calculated as a percentage increase over the current gas price. - Callback gas: The amount of gas used for the callback request. See the [Cost Calculation](https://docs.chain.link/chainlink-functions/resources/billing#cost-calculation-fulfillment) section. - Callback gas limit: The maximum amount of gas that can be used to call the `handleOracleFulfillment` callback function of the consumer contract in order to provide the response. See the [Cost Simulation](https://docs.chain.link/chainlink-functions/resources/billing#cost-simulation-reservation) section. - Gas overhead: The amount of gas used by the FunctionsRouter and FunctionsCoordinator contracts. It is an estimate of the total gas cost of fulfilling a request. - Native to LINK translation: Your subscription balance can be billed only in LINK tokens. - Translate the network's native gas tokens to LINK: The total gas cost in _native_ units is translated using the correct [Price Feed](https://docs.chain.link/data-feeds/price-feeds/addresses). For example, on Sepolia, the translation uses the ETH/LINK Price Feed, and on Polygon, the translation uses POL/LINK Price Feed. - Fallback Wei to LINK ratio: In the unlikely event that the _Native to LINK_ price data feed is unavailable, the fallback translation is used. You can find this ratio by running the `getConfig` function in the FunctionsCoordinator contract. See the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks) page to find the contract addresses for each network. ### [Cost simulation (reservation)](https://docs.chain.link/chainlink-functions/resources/billing\#cost-simulation-reservation) During the **request** step: 1. The total cost in LINK is **estimated** using the following formula: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext total estimated gas cost in LINK = (Overestimated gas price * (Gas overhead + Callback gas limit)) / Native to LINK translation total estimated cost in LINK = total estimated gas cost + premium fees ``` All networks have USD-denominated premium fees. This means that the fixed premium fee is denominated in USD, but no USD is ever used. The LINK equivalent of this fee is calculated at request time. 2. The total estimated cost is then added to the subscription reservation. ### [Cost calculation (fulfillment)](https://docs.chain.link/chainlink-functions/resources/billing\#cost-calculation-fulfillment) When a DON's oracle reports the response, subscription accounts are charged based on the gas amount used in the callback: 1. The total cost in LINK is **calculated** using the following formula: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext total gas cost in LINK = (Gas price * (Gas overhead + Callback gas)) / Native to LINK translation total cost in LINK = total gas cost + premium fees ``` All networks have USD-denominated premium fees. This means that the fixed premium fee is denominated in USD, but no USD is ever used. The LINK equivalent of this fee is calculated at request time. 2. The FunctionsRouter contract performs several accounting movements. ### [Cost calculation example](https://docs.chain.link/chainlink-functions/resources/billing\#cost-calculation-example) This is an example of cost estimation for a request and then cost calculation at fulfillment. For networks with USD-denominated premium fees, the premium fees are set in USD, but no USD is ever used. The LINK equivalent of the fee is calculated at request time, and then deducted from your subscription in LINK at response time. #### [Cost Simulation (Reservation)](https://docs.chain.link/chainlink-functions/resources/billing\#cost-simulation-reservation-1) | Parameter | Value | | --- | --- | | Overestimated gas price | 9 gwei | | Callback gas limit | 300000 | | Gas overhead | 185000 | | Premium fee | 320 cents USD | 1. Calculate the total estimated gas cost in LINK, using an overestimated gas price, the gas overhead, and the full callback gas limit: | Gas cost calculation | Total estimated gas cost | | --- | --- | | Overestimated gas price x (Gas overhead + Callback gas limit) | | | 9 gwei x (300000 + 185000) | 4365000 gwei (0.004365 ETH) | 2. Convert the gas cost to LINK using the [LINK/ETH feed](https://data.chain.link/ethereum/mainnet/crypto-eth/link-eth). For this example, assume the feed returns a conversion value of Ξ0.007 ETH per 1 LINK. | ETH to LINK cost conversion | Total gas cost (LINK) | | --- | --- | | 0.004365 ETH / 0.007 ETH/LINK | 0.62 LINK | 3. Convert the USD-denominated premium fee to LINK using the [LINK/USD feed](https://data.chain.link/feeds/ethereum/mainnet/link-usd). For this example, assume the feed returns a conversion value of $20.00 USD per 1 LINK: | USD to LINK cost conversion | Premium fee (LINK) | | --- | --- | | $3.20 USD / 20.00 USD/LINK | 0.16 LINK | 4. Add the converted premium fee to get the estimated cost for a subscription reservation: | Adding converted LINK premium | Maximum request cost (LINK) | | --- | --- | | Total gas cost (LINK) + Premium fee | | | 0.62 LINK + 0.16 LINK | 0.78 LINK | For this example request, 0.78 LINK is reserved from your subscription balance, but not yet deducted. When the request is fulfilled, the exact request cost is deducted. The estimated cost of a request is overestimated to allow for 99% of gas price fluctuation increases in between request and response time. #### [Cost calculation (fulfillment)](https://docs.chain.link/chainlink-functions/resources/billing\#cost-calculation-fulfillment-1) | Parameter | Value | | --- | --- | | Gas price | 1.5 gwei | | Callback gas | 200000 | | Gas overhead | 185000 | | Premium fee converted to LINK | 0.16 LINK | 1. Calculate the total gas cost: | Gas cost calculation | Total gas cost | | --- | --- | | Gas price x (Gas overhead + Callback gas) | | | 1.5 gwei x (200000 + 185000) | 577500 gwei (0.0005775 ETH) | 2. Convert the gas cost to LINK using the [LINK/ETH feed](https://data.chain.link/ethereum/mainnet/crypto-eth/link-eth). For this example, assume the feed returns a conversion value of Ξ0.007 ETH per 1 LINK. | ETH to LINK cost conversion | Total gas cost (LINK) | | --- | --- | | 0.0005775 ETH / 0.007 ETH/LINK | 0.0825 LINK | 3. The premium fee was converted from USD to LINK at the time of the request. Add this converted premium fee to get the total cost of a request: | Adding premium fee | Total request cost (LINK) | | --- | --- | | Total gas cost (LINK) + premium fee | | | 0.0825 LINK + 0.16 LINK | 0.2425 LINK | This example request would cost 0.2425 LINK when it is fulfilled. The subscription reservation for the 0.78 LINK is released, and the actual cost of 0.2425 LINK is deducted from your subscription balance. ## [Minimum balance for uploading encrypted secrets](https://docs.chain.link/chainlink-functions/resources/billing\#minimum-balance-for-uploading-encrypted-secrets) If you choose to store the encrypted secrets with the DON (learn more on the [Secrets Management page](https://docs.chain.link/chainlink-functions/resources/secrets)), then one of your subscriptions must maintain a balance greater than the minimum required for uploading encrypted secrets. This balance is blockchain-specific. You can find the specific values for each blockchain on the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks) page. **Note**: Uploading encrypted secrets is free of charge. However, to prevent misuse of Chainlink Functions, you are required to maintain a minimum balance in one of the subscriptions owned by your externally-owned account (EOA) before you can upload encrypted secrets to a DON. ## [Withdrawing funds](https://docs.chain.link/chainlink-functions/resources/billing\#withdrawing-funds) To withdraw your LINK balance, you must first cancel your subscription. To prevent misuse of Chainlink Functions, any subscription with fulfilled requests below the _request threshold_ will incur a cancellation fee. Both the request threshold and the cancellation fee are blockchain-specific. You can find their values for each blockchain on the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks) page. **Example 1**: - **Request Threshold**: Two requests - **Cancellation Fee**: 0.5 LINK - **Your Balance**: 0.4 LINK - **Number of Fulfilled Requests**: One - **Outcome**: Canceling your subscription results in a non-refundable balance **Example 2**: - **Request Threshold**: Two requests - **Cancellation Fee**: 0.5 LINK - **Your Balance**: 1 LINK - **Number of Fulfilled Requests**: One - **Outcome**: You will receive 0.5 LINK if you cancel your subscription **Example 3**: - **Request Threshold**: Two requests - **Cancellation Fee**: 0.5 LINK - **Your Balance**: 1 LINK - **Number of Fulfilled Requests**: Two or more - **Outcome**: You will receive 1 LINK if you cancel your subscription. Your subscription will not incur the cancellation fee ## Get the latest Chainlink content straight to your inbox. Email Address ## Chainlink Functions Architecture [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Chainlink Functions Architecture](https://docs.chain.link/chainlink-functions/resources/architecture\#overview) ## [Request and Receive Data](https://docs.chain.link/chainlink-functions/resources/architecture\#request-and-receive-data) This model is similar to the [Basic Request Model](https://docs.chain.link/architecture-overview/architecture-request-model): The consumer contract initiates the cycle by sending a request to the [FunctionsRouter contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsRouter.sol). Oracle nodes watch for events emitted by the [FunctionsCoordinator contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_1_0/FunctionsCoordinator.sol) and run the computation offchain. Finally, oracle nodes use the [Chainlink OCR](https://docs.chain.link/architecture-overview/off-chain-reporting) protocol to aggregate all the returned before passing the single aggregated response back to the consumer contract via a callback function. ![Chainlink Functions request and receive diagram](https://docs.chain.link/images/chainlink-functions/requestAndReceive.png) The main actors and components are: - Initiator (or end-user): initiates the request to Chainlink Functions. It can be an [EOA (Externally Owned Account)](https://ethereum.org/en/developers/docs/accounts/#types-of-account) or Chainlink Automation. - Consumer contract: smart contract deployed by developers, which purpose is to interact with the FunctionsRouter to initiate a request. - FunctionsRouter contract: manages subscriptions and is the entry point for consumers. The interface of the router is stable. Consumers call the `sendRequest` method to initiate a request. - FunctionsCoordinator contracts: interface for the [Decentralized Oracle Network](https://chain.link/education/blockchain-oracles#decentralized-oracles). Oracle nodes listen to events emitted by the coordinator contract and interact with the coordinator to transmit the responses. - DON: Chainlink Functions are powered by a [Decentralized Oracle Network](https://chain.link/education/blockchain-oracles#decentralized-oracles). The oracle nodes are independent of each other and are responsible for executing the request's source code. The nodes use the [Chainlink OCR](https://docs.chain.link/architecture-overview/off-chain-reporting) protocol to aggregate all the nodes' responses. Finally, a DON's oracle sends the aggregate response to the consumer contract in a callback. - Secrets endpoint: To transmit their secrets, users can encrypt them with the DON public key and then upload them to the secrets endpoint, a highly available service for securely sharing encrypted secrets with the nodes. **Note**: An alternative method involves self-hosting secrets. In this approach, users provide a publicly accessible HTTP(s) URL, allowing nodes to retrieve the encrypted secrets. Refer to the [secrets management](https://docs.chain.link/chainlink-functions/resources/secrets) page for detailed information on both methods. - Serverless Environment: Every Oracle node accesses a distinct, sandboxed environment for computation. While the diagram illustrates an API request, the computation isn't restricted solely to this. You can perform any computation, from API calls to mathematical operations, using vanilla [Deno](https://deno.land/) code without module imports. Note: All nodes execute identical computations. If the target API has throttling limits, know that multiple simultaneous calls will occur since each DON node will independently run the request's source code. Let's walk through the sequence of interactions among these components, as illustrated in the diagram: 1. If there are secrets, a user encrypts secrets with the public key linked to the DON master secret key (MSK) and then uploads the encrypted secrets to the secrets endpoint. The secrets endpoint pushes the encrypted secrets to the nodes part of the DON (The secrets capability depicted in this diagram is called _threshold encryption_ and is explained in [secrets management](https://docs.chain.link/chainlink-functions/resources/secrets#threshold-encryption)). 2. An [EOA (Externally Owned Account)](https://ethereum.org/en/developers/docs/accounts/#types-of-account) or Chainlink Automation initiates the request by calling the consumer contract. 3. The consumer contract should inherit the [FunctionsClient](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol) contract. This ensures it will be able to receive responses from the [FunctionsRouter](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsRouter.sol) contract via the `handleOracleFulfillment` callback. The router contract starts the billing to estimate the fulfillment costs and block the amount in the _reservation balance_ (To learn more, read [Cost simulation](https://docs.chain.link/chainlink-functions/resources/billing#cost-simulation-reservation)). Then it calls the [FunctionsCoordinator contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_1_0/FunctionsCoordinator.sol). 4. The coordinator contract emits an `OracleRequest` event containing information about the request. 5. On reception of the event by the DON, the DON's nodes decrypt the secrets using threshold decryption (The threshold encryption feature is explained in [secrets management](https://docs.chain.link/chainlink-functions/resources/secrets#threshold-encryption)). Each DON's Oracle node executes the request's source code in a serverless environment. 6. The DON runs the Offchain Reporting protocol (OCR) to aggregate the values returned by each node's execution of the source code. 7. A DON's oracle node transmits the attested report (which includes the aggregated response) to the FunctionsCoordinator contract. 8. The FunctionsCoordinator contract calls the FunctionsRouter's `fulfill` method to calculate the fulfillment costs and finalize the billing (To learn more, read [Cost calculation](https://docs.chain.link/chainlink-functions/resources/billing#cost-calculation-fulfillment)). 9. The FunctionsRouter contract calls the consumer contract's callback with the aggregated response. **Note**: Chainlink Functions requests are not limited to API requests. The diagram depicts an example of API requests, but you can request the DON to run any computation. ## [Subscription management](https://docs.chain.link/chainlink-functions/resources/architecture\#subscription-management) Chainlink Functions do not require your consumer contracts to hold LINK tokens and send them to oracles when making requests. Instead, you must create a subscription account and fund it to pay for your Chainlink Functions requests, so your consumer contracts don't need to hold LINK when calling Chainlink Functions. ### [Concepts](https://docs.chain.link/chainlink-functions/resources/architecture\#concepts) - Terms of service (ToS): Before interacting with Chainlink Functions, users must agree to the terms of service. Once signed, the accounts that can manage subscriptions are added to the `allowedSenders` in the [ToS allow list contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/accessControl/TermsOfServiceAllowList.sol). - Chainlink Functions Subscription Manager: A user interface that allows users to agree to the sign Terms of service and interact with the FunctionsRouter to manage subscriptions. - Subscription account: An account that holds LINK tokens and makes them available to fund requests to Chainlink DON. A _Subscription ID_ uniquely identifies each account. - Subscription ID: 64-bit unsigned integer representing the unique identifier of the _Subscription account_. - Subscription owner: The wallet address that creates and manages a _Subscription account_. Any account can add LINK tokens to the subscription balance. Still, only the owner can add consumer contracts to the subscription, remove consumer contracts from the subscription, withdraw funds, or transfer a subscription. Only the subscription owner can generate encrypted secrets for requests that use their _Subscription ID_. - Subscription balance: The amount of LINK maintained on your _Subscription account_. Requests from consumer contracts are funded as long as sufficient funds are in the balance, so be sure to maintain sufficient funds in your _Subscription balance_ to pay for the requests and keep your applications running. - Subscription reservation: The amount of LINK blocked on the _Subscription balance_. It corresponds to the total LINK amount to be paid by in-flight requests. - Effective balance: The amount of LINK available on your _Subscription account_. `Effective balance = Subscription balance - Subscription reservation`. - Subscription consumers: Consumer contracts are approved to use funding from your _Subscription account_ while making Chainlink Functions requests. The consumers receive response data in a callback. ### [Accept ToS](https://docs.chain.link/chainlink-functions/resources/architecture\#accept-tos) To ensure compliance and governance, Chainlink Functions mandates that any account that manages a subscription must first accept the platform's Terms of Service (ToS). The acceptance is verified by cross-referencing the account with the `allowedSenders` registry contained within the [TermsOfServiceAllowList contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/accessControl/TermsOfServiceAllowList.sol). ![](https://docs.chain.link/images/chainlink-functions/subscription/acceptToSEOA.png) The acceptance process is initiated via the Chainlink Functions Subscription Manager. After a user accepts the ToS by generating the required signature with their externally owned account (EOA), they transmit proof of acceptance to the [TermsOfServiceAllowList contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/accessControl/TermsOfServiceAllowList.sol). Upon successful validation of the proof, the EOA is added to the `allowedSenders` registry, permitting it to manage subscriptions. ### [Create subscription](https://docs.chain.link/chainlink-functions/resources/architecture\#create-subscription) ![](https://docs.chain.link/images/chainlink-functions/subscription/createSubscription.png) After the ToS is accepted, EOAs can create subscriptions. Upon creation, the [FunctionsRouter](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsRouter.sol) assigns a unique identifier, _Subscription ID_. **Note**: EOAs can directly interact with the FunctionsRouter contract using their preferred web3 library, such as web3.js or ethers.js. ### [Fund subscription](https://docs.chain.link/chainlink-functions/resources/architecture\#fund-subscription) ![](https://docs.chain.link/images/chainlink-functions/subscription/fundSubscription.png) You must fund your subscription accounts with enough LINK tokens: 1. Connect your EOA to the Chainlink Functions Subscription Manager. 2. Fund your subscription account. The Chainlink Functions Subscription Manager abstracts the following: 1. Call `transferAndCall` on the LINK token contract, transferring LINK tokens along with the _Subscription ID_ in the payload. 2. The FunctionsRouter contract implements `onTokenTransfer`: It parses the _Subscription ID_ from the payload and funds the subscription account with the transferred LINK amount. **Note**: EOAs can directly interact with the LinkToken contract using their preferred web3 library, such as web3.js or ethers.js. ### [Add consumer](https://docs.chain.link/chainlink-functions/resources/architecture\#add-consumer) ![](https://docs.chain.link/images/chainlink-functions/subscription/addConsumer.png) You must allowlist your consumers' contracts on your subscription account before they can make Chainlink Functions requests: 1. Connect your EOA to the Chainlink Functions Subscription Manager. 2. Add the address of the consumer contract to the subscription account. 3. The Chainlink Functions Subscription Manager interacts with the FunctionsRouter contract to register the consumer contract address to the subscription account. **Note**: EOAs can directly interact with the FunctionsRouter contract using a web3 library, such as web3.js or ethers.js. ### [Remove consumer](https://docs.chain.link/chainlink-functions/resources/architecture\#remove-consumer) ![](https://docs.chain.link/images/chainlink-functions/subscription/removeConsumer.png) To prevent further Chainlink Functions requests from a given consumer contract, you must remove it from your subscription account: 1. Connect your EOA to the Chainlink Functions Subscription Manager. 2. Remove the address of the consumer contract from the subscription account. 3. The Chainlink Functions Subscription Manager communicates with the FunctionsRouter contract to remove the consumer contract address from the subscription account. **Note**: You can still remove consumers from your subscription even if in-flight requests exist. The consumer contract will still receive a callback, and your _Subscription Account_ will be charged. **Note**: EOAs can directly interact with the FunctionsRouter contract using a web3 library, such as web3.js or ethers.js. ### [Cancel subscription](https://docs.chain.link/chainlink-functions/resources/architecture\#cancel-subscription) ![](https://docs.chain.link/images/chainlink-functions/subscription/cancelSubscription.png) To cancel a subscription: 1. Connect your EOA to the Chainlink Functions Subscription Manager. 2. Cancel your subscription, providing the _Subscription Balance_ receiver account address. The Chainlink Functions Subscription Manager handles the following processes: 1. Invokes the `cancelSubscription` function on the FunctionsRouter contract, deleting the _Subscription ID_ and removing all associated consumers. 2. Transfers the remaining _Subscription Balance_ to the specified receiver account. **Note**: EOAs can directly interact with the FunctionsRouter contract using their preferred web3 library, such as web3.js or ethers.js. **Note**: Subscriptions cannot be canceled while there are in-flight requests. Furthermore, any expired requests (requests that have yet to receive a response within 5 minutes) must be timed out before cancellation. ### [Transferring ownership of a Subscription](https://docs.chain.link/chainlink-functions/resources/architecture\#transferring-ownership-of-a-subscription) Transferring ownership is currently only supported using the [Functions Hardhat Starter kit](https://github.com/smartcontractkit/functions-hardhat-starter-kit) or the [Functions Toolkit NPM package](https://github.com/smartcontractkit/functions-toolkit): 1. Use the `functions-sub-transfer` command to initiate the transfer of ownership by specifying the new owner's address. 2. As a prerequisite, the prospective owner must be part of the `allowedSenders` registry within the [TermsOfServiceAllowList contract](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/accessControl/TermsOfServiceAllowList.sol). This verifies their acceptance of the Chainlink Functions' Terms of Service (ToS). 3. The prospective owner should use the [Functions Hardhat Starter kit](https://github.com/smartcontractkit/functions-hardhat-starter-kit) and run the `functions-sub-accept` command to confirm the ownership transfer. **Note**: This guide will be updated as soon as the Chainlink Functions Subscription Manager supports ownership transfers. ## What's next - [\> Billing](https://docs.chain.link/chainlink-functions/resources/billing) ## Get the latest Chainlink content straight to your inbox. Email Address ## Simulate Chainlink Functions [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Simulate your Functions](https://docs.chain.link/chainlink-functions/resources/simulation\#overview) Before making a Chainlink Functions request from your smart contract, it is always a good practice to simulate the source code off-chain to make any adjustments or corrections. Currently, there are several options for simulating a request: - [Chainlink Functions playground](https://functions.chain.link/playground). - [Chainlink Functions Hardhat Starter Kit](https://github.com/smartcontractkit/functions-hardhat-starter-kit): Use the `npx hardhat functions-simulate-script` command to simulate your Functions JavaScript source code. - [Chainlink Functions Toolkit NPM package](https://github.com/smartcontractkit/functions-toolkit): Import this NPM package into your JavaScript/TypeScript project, then use the `simulateScript` function to simulate your Functions JavaScript source code. ## [Chainlink Functions playground](https://docs.chain.link/chainlink-functions/resources/simulation\#chainlink-functions-playground) To use the [Chainlink Functions\\ Playground](https://functions.chain.link/playground), enter any source code, arguments, and secrets you would like to use. Click the **Run code** button to view the output. ![](https://docs.chain.link/images/chainlink-functions/functions-playground.png) ## [Chainlink Functions Hardhat Starter Kit](https://docs.chain.link/chainlink-functions/resources/simulation\#chainlink-functions-hardhat-starter-kit) This repository comes preconfigured with [Hardhat](https://hardhat.org/) and the [Chainlink Functions Toolkit NPM package](https://github.com/smartcontractkit/functions-toolkit), allowing you to quickly get started with Functions. To simulate: 1. In a terminal, clone the [functions-hardhat-starter-kit repository](https://github.com/smartcontractkit/functions-hardhat-starter-kit) and change to the `functions-hardhat-starter-kit` directory. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell git clone https://github.com/smartcontractkit/functions-hardhat-starter-kit && \ cd functions-hardhat-starter-kit ``` 2. Run `npm install` to install the dependencies. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npm install ``` 3. For simulation, you don't need to set up the environment variables. Run `npx hardhat functions-simulate-script` to simulate the [calculation-example.js](https://github.com/smartcontractkit/functions-hardhat-starter-kit/blob/main/calculation-example.js) JavaScript source code. **Note:** This example calculates the continuously compounding interest for a given principal amount over one month. It takes the principal amount and annual percentage yield (APY) as input arguments and uses [Euler's number](https://www.investopedia.com/terms/e/eulers-constant.asp) to compute the total amount after interest. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx hardhat functions-simulate-script ``` Result: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```text secp256k1 unavailable, reverting to browser version Response returned by script during local simulation: 1003757 ``` ## [Chainlink Functions Toolkit NPM package](https://docs.chain.link/chainlink-functions/resources/simulation\#chainlink-functions-toolkit-npm-package) Follow the [Simple Computation](https://docs.chain.link/chainlink-functions/tutorials/simple-computation) guide to learn how to import the [Chainlink Functions Toolkit NPM package](https://github.com/smartcontractkit/functions-toolkit) into your JavaScript project to simulate and execute a Functions request. You can read the [Examine the code section](https://docs.chain.link/chainlink-functions/tutorials/simple-computation#javascript-example) for a detailed description of the code example. ## Get the latest Chainlink content straight to your inbox. Email Address ## Chainlink Functions Updates [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Chainlink Functions Release Notes](https://docs.chain.link/chainlink-functions/resources/release-notes\#overview) ## [2025-04-01 - Functions on Soneium](https://docs.chain.link/chainlink-functions/resources/release-notes\#2025-04-01-functions-on-soneium) Chainlink Functions is available on Soneium Mainnet. Visit the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks#soneium) page for more information. ## [2025-02-07 - Functions on Celo](https://docs.chain.link/chainlink-functions/resources/release-notes\#2025-02-07-functions-on-celo) Chainlink Functions is available on Celo. Visit the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks#celo) page for more information. ## [2024-11-26 - Functions on Optimism mainnet](https://docs.chain.link/chainlink-functions/resources/release-notes\#2024-11-26-functions-on-optimism-mainnet) Chainlink Functions is available on Optimism mainnet. Visit the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks#op-mainnet) page for more information. ## [2024-10-22 - Functions on Soneium Minato](https://docs.chain.link/chainlink-functions/resources/release-notes\#2024-10-22-functions-on-soneium-minato) Chainlink Functions is available on Soneium Minato testnet. Visit the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks#soneium-minato-testnet) page for more information. ## [2024-08-21 - Timing out requests manually](https://docs.chain.link/chainlink-functions/resources/release-notes\#2024-08-21-timing-out-requests-manually) The [Chainlink Functions Subscription Manager](https://functions.chain.link/) now supports [timing out requests manually](https://docs.chain.link/chainlink-functions/resources/subscriptions#time-out-pending-requests-manually). You can time out requests that are pending for longer than five minutes to unlock your subscription funds. ## [2024-07-31 - USD-denominated premium fees on all supported networks](https://docs.chain.link/chainlink-functions/resources/release-notes\#2024-07-31-usd-denominated-premium-fees-on-all-supported-networks) Chainlink Functions now uses USD-denominated fixed premium fees on all [supported networks](https://docs.chain.link/chainlink-functions/supported-networks). This means that the premium fees are set in USD, but no USD is ever used. The LINK equivalent of the fee is calculated at request time, and then deducted from your subscription in LINK at response time. See the [example cost calculation](https://docs.chain.link/chainlink-functions/resources/billing#cost-calculation-example) for more information. The networks that have just switched from LINK-denominated premium fees to USD-denominated premium fees are: - Ethereum mainnet and Sepolia testnet - Arbitrum mainnet - Avalanche mainnet ## [2024-04-26 - Polygon Amoy support](https://docs.chain.link/chainlink-functions/resources/release-notes\#2024-04-26-polygon-amoy-support) Chainlink Functions is available on [Polygon Amoy](https://docs.chain.link/chainlink-functions/supported-networks#polygon-amoy-testnet). ## [2024-04-13 - Polygon testnet support](https://docs.chain.link/chainlink-functions/resources/release-notes\#2024-04-13-polygon-testnet-support) The Mumbai network has stopped producing blocks, so example code will not function on this network. Check again soon for updates about future testnet support on Polygon. ## [2024-04-09 - Base Mainnet support](https://docs.chain.link/chainlink-functions/resources/release-notes\#2024-04-09-base-mainnet-support) Chainlink Functions is available on [Base Mainnet](https://docs.chain.link/chainlink-functions/supported-networks#base-mainnet). ## [2024-03-22 - USD-denominated premium fees and new testnets](https://docs.chain.link/chainlink-functions/resources/release-notes\#2024-03-22-usd-denominated-premium-fees-and-new-testnets) Chainlink Functions is available as an open beta on the [BASE Sepolia](https://docs.chain.link/chainlink-functions/supported-networks#base-sepolia-testnet) and [Optimism Sepolia](https://docs.chain.link/chainlink-functions/supported-networks#op-sepolia) testnets. These networks have USD-denominated fixed premium fees. This means that the premium fees are set in USD, but no USD is ever used. The LINK equivalent of the fee is calculated at request time, and then deducted from your subscription in LINK at response time. See the [example cost calculation](https://docs.chain.link/chainlink-functions/resources/billing#cost-calculation-example) for more information. ## [2024-01-12 - Module imports supported on mainnet](https://docs.chain.link/chainlink-functions/resources/release-notes\#2024-01-12-module-imports-supported-on-mainnet) You can use external module imports with Chainlink Functions source code on mainnet networks. See the [Using Imports with Functions](https://docs.chain.link/chainlink-functions/tutorials/importing-packages) tutorial to see an example of how to import and use imported modules with your Functions source code. This feature requires the [Functions Toolkit NPM package](https://www.npmjs.com/package/@chainlink/functions-toolkit/v/0.2.7) `v0.2.7` or later. ## [2024-01-10 - Arbitrum Mainnet support](https://docs.chain.link/chainlink-functions/resources/release-notes\#2024-01-10-arbitrum-mainnet-support) Chainlink Functions is available on [Arbitrum Mainnet](https://docs.chain.link/chainlink-functions/supported-networks#arbitrum-mainnet). ## [2023-12-15 - Module imports for Functions on testnets](https://docs.chain.link/chainlink-functions/resources/release-notes\#2023-12-15-module-imports-for-functions-on-testnets) You can use external module imports with Chainlink Functions source code on testnet networks. See the [Using Imports with Functions](https://docs.chain.link/chainlink-functions/tutorials/importing-packages) tutorial to see an example of how to import and use imported modules with your Functions source code. This feature requires the [Functions Toolkit NPM package](https://www.npmjs.com/package/@chainlink/functions-toolkit/v/0.2.7) `v0.2.7` or later. This feature is available only on testnets. Modules will not import or execute on Functions requests for mainnet networks at this time. ## [2023-12-15 - Functions on Arbitrum Sepolia testnet](https://docs.chain.link/chainlink-functions/resources/release-notes\#2023-12-15-functions-on-arbitrum-sepolia-testnet) Chainlink Functions is available on the [Arbitrum Sepolia](https://docs.chain.link/chainlink-functions/supported-networks#arbitrum-sepolia-testnet) testnet. ## [2023-09-29 - Chainlink Functions Open Beta](https://docs.chain.link/chainlink-functions/resources/release-notes\#2023-09-29-chainlink-functions-open-beta) Chainlink Functions is available as an open beta on several networks. See the [supported networks](https://docs.chain.link/chainlink-functions/supported-networks) page for more a complete list. New features: - You must accept the Chainlink Functions Terms of Service (ToS) before using Chainlink Functions. The ToS must be accepted by subscriptions owners. Once accepted, the ToS is transitive to all contracts belong the subscription, so your end-users don't have to accept the ToS to interact with your contracts. Read this [guide](https://docs.chain.link/chainlink-functions/resources/subscriptions#create-a-subscription) to learn more. - The Chainlink Functions Subscription Manager is available at [functions.chain.link](https://functions.chain.link/). The Functions Subscription Manager lets you manage your subscriptions. - Chainlink Functions uses threshold encryption to handle users' encrypted secrets. Read the [secrets conceptual page](https://docs.chain.link/chainlink-functions/resources/secrets) to learn more. - Users can host their encrypted secrets within the DON. This hosting method is called DON-hosted. Read the [secrets conceptual page](https://docs.chain.link/chainlink-functions/resources/secrets) to learn more. - JavaScript source code can only use vanilla [Deno](https://deno.land/). Read the [JavaScript code API reference](https://docs.chain.link/chainlink-functions/api-reference/javascript-source) to learn more. - Chainlink Functions contracts are part of the [@chainlink/contracts npm package](https://www.npmjs.com/package/@chainlink/contracts). Read the [FunctionsClient](https://docs.chain.link/chainlink-functions/api-reference/functions-client) and [FunctionsRequest](https://docs.chain.link/chainlink-functions/api-reference/functions-request) API references. - Use the [Functions npm package](https://www.npmjs.com/package/@chainlink/functions-toolkit) in your own JavaScript or TypeScript project to make requests to the Chainlink Functions Decentralized Oracle Network (DON). Try the [getting-started guide](https://docs.chain.link/chainlink-functions/getting-started) to learn more. - Make sure to check the [service limits page](https://docs.chain.link/chainlink-functions/resources/service-limits) as the limits have been adapted. Additionally, you can [contact us](https://chain.link/contact?v=Integrate%20Functions) to increase the limits for your Chainlink Function. ## [2023-07-14 - Functions Playground](https://docs.chain.link/chainlink-functions/resources/release-notes\#2023-07-14-functions-playground) The [Functions Playground](https://functions.chain.link/playground) is now available. Use it to simulate Chainlink Functions within your browser. ## [2023-05-05 - Chainlink Functions Closed Beta on Avalanche Fuji](https://docs.chain.link/chainlink-functions/resources/release-notes\#2023-05-05-chainlink-functions-closed-beta-on-avalanche-fuji) Chainlink Functions is now available for the closed beta on [Avalanche Fuji](https://docs.chain.link/chainlink-functions/supported-networks#avalanche-fuji-testnet). ## [2023-03-01 - Chainlink Functions Closed Beta](https://docs.chain.link/chainlink-functions/resources/release-notes\#2023-03-01-chainlink-functions-closed-beta) Chainlink Functions is available as a closed beta on [Ethereum Sepolia](https://docs.chain.link/chainlink-functions/supported-networks#sepolia-testnet) and Polygon Mumbai. ## Get the latest Chainlink content straight to your inbox. Email Address ## Secrets Management Overview [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Secrets Management](https://docs.chain.link/chainlink-functions/resources/secrets\#overview) Chainlink Functions enables users to fetch data from HTTP(s) APIs and perform custom computation. To enable access to APIs that require authentication credentials, Chainlink Functions allows users to provide encrypted secret values, which can be used when the DON executes a Functions request. These values can only be decrypted via a multi-party decryption process called threshold decryption. This means that every node can only decrypt the secrets with participation from other DON nodes. These encrypted secret values can either be uploaded to the DON or hosted at a remote URL. Then, a reference to the encrypted secrets can be used when making a Functions request. ## [Threshold encryption](https://docs.chain.link/chainlink-functions/resources/secrets\#threshold-encryption) Using a single private key to decrypt user secrets poses a considerable security risk. If any node with this key becomes malicious or compromised, it can decrypt all accessible user secrets. To address this vulnerability, we have integrated a feature known as _threshold encryption_. The characteristics of this enhanced security measure include: 1. Decentralized Nodes Deployment: The system operates on a Decentralized Oracle Network (DON) with N nodes. 2. Master Secret Key Distribution: Instead of centralizing the private key, the master secret key (MSK) is partitioned into shares. Each node within the DON possesses a distinct share of this MSK. 3. The system enforces two thresholds: - Liveness: This feature ensures the system's availability and fault tolerance. It can tolerate up to F Byzantine nodes (nodes that can act arbitrarily or maliciously) while remaining operational. The system adheres to the mathematical relationship `3F+1≤N`. This means the total number of nodes N must be at least three times the number of faulty or malicious nodes F, plus one more. - Decryption security: Considering that the MSK is distributed across multiple nodes, safeguarding it is essential. To recover the master secret key (MSK), an attacker must corrupt a number of K nodes, adhering to the relationship: `F(Request fulfillment timeout) | The maximum duration of a request is the time allowed for processing a Chainlink Functions request from start to finish, covering all steps such as reading from the chain, executing code, and posting back on chain. If processing takes longer, the request times out, and no charges are applied to your subscription for that request. In such cases, the initially locked estimated request costs must be manually requested to be returned to your subscription balance | 5 minutes | | Maximum request size | The maximum size of a Chainlink Request. This includes the source code, arguments, and secrets | 30 kilobytes | | Maximum returned value size | The maximum size of the value that your Function can return | 256 bytes | | Maximum source code execution time | The maximum amount of time that a source code can run | 10 seconds | | Maximum memory allocated to the source code | The maximum amount of memory allocated to your source code during execution | 128 megabytes | | HTTP - Maximum queries | The maximum number of HTTP requests that your source code can make | 5 | | HTTP - query timeout | The maximum duration of an HTTP request before it times out | 9 seconds | | HTTP - Maximum URL length | Length of the HTTP URL | 2048 characters | | HTTP - Maximum request length | The maximum size of an HTTP request, including the request body and HTTP headers | 30 kilobytes | | HTTP - Maximum response length | The maximum size of an HTTP response | 2 megabytes | | Max size of request payload CBOR | The maximum size of an encoded request | 30 kilobytes | | Don-hosted secrets - Maximum Time to live (TTL) | The maximum duration for which a secret hosted on a DON remains valid before it gets deleted | - Mainnets: 3 months (2160 hours)
- Testnets: 3 days (72 hours) | | External module imports - Maximum size | The maximum size in MB that each imported module can be | 10 MB | | External module imports - Number of imports | The maximum number of external module imports allowed in each request | 100 imports | ## Get the latest Chainlink content straight to your inbox. Email Address ## Chainlink Functions Simulation [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) On this page # [Simulate your Functions](https://docs.chain.link/chainlink-functions/resources/simulation\#overview) Before making a Chainlink Functions request from your smart contract, it is always a good practice to simulate the source code off-chain to make any adjustments or corrections. Currently, there are several options for simulating a request: - [Chainlink Functions playground](https://functions.chain.link/playground). - [Chainlink Functions Hardhat Starter Kit](https://github.com/smartcontractkit/functions-hardhat-starter-kit): Use the `npx hardhat functions-simulate-script` command to simulate your Functions JavaScript source code. - [Chainlink Functions Toolkit NPM package](https://github.com/smartcontractkit/functions-toolkit): Import this NPM package into your JavaScript/TypeScript project, then use the `simulateScript` function to simulate your Functions JavaScript source code. ## [Chainlink Functions playground](https://docs.chain.link/chainlink-functions/resources/simulation\#chainlink-functions-playground) To use the [Chainlink Functions\\ Playground](https://functions.chain.link/playground), enter any source code, arguments, and secrets you would like to use. Click the **Run code** button to view the output. ![](https://docs.chain.link/images/chainlink-functions/functions-playground.png) ## [Chainlink Functions Hardhat Starter Kit](https://docs.chain.link/chainlink-functions/resources/simulation\#chainlink-functions-hardhat-starter-kit) This repository comes preconfigured with [Hardhat](https://hardhat.org/) and the [Chainlink Functions Toolkit NPM package](https://github.com/smartcontractkit/functions-toolkit), allowing you to quickly get started with Functions. To simulate: 1. In a terminal, clone the [functions-hardhat-starter-kit repository](https://github.com/smartcontractkit/functions-hardhat-starter-kit) and change to the `functions-hardhat-starter-kit` directory. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell git clone https://github.com/smartcontractkit/functions-hardhat-starter-kit && \ cd functions-hardhat-starter-kit ``` 2. Run `npm install` to install the dependencies. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npm install ``` 3. For simulation, you don't need to set up the environment variables. Run `npx hardhat functions-simulate-script` to simulate the [calculation-example.js](https://github.com/smartcontractkit/functions-hardhat-starter-kit/blob/main/calculation-example.js) JavaScript source code. **Note:** This example calculates the continuously compounding interest for a given principal amount over one month. It takes the principal amount and annual percentage yield (APY) as input arguments and uses [Euler's number](https://www.investopedia.com/terms/e/eulers-constant.asp) to compute the total amount after interest. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx hardhat functions-simulate-script ``` Result: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```text secp256k1 unavailable, reverting to browser version Response returned by script during local simulation: 1003757 ``` ## [Chainlink Functions Toolkit NPM package](https://docs.chain.link/chainlink-functions/resources/simulation\#chainlink-functions-toolkit-npm-package) Follow the [Simple Computation](https://docs.chain.link/chainlink-functions/tutorials/simple-computation) guide to learn how to import the [Chainlink Functions Toolkit NPM package](https://github.com/smartcontractkit/functions-toolkit) into your JavaScript project to simulate and execute a Functions request. You can read the [Examine the code section](https://docs.chain.link/chainlink-functions/tutorials/simple-computation#javascript-example) for a detailed description of the code example. ## Get the latest Chainlink content straight to your inbox. Email Address ## Chainlink Functions Subscriptions [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Managing CL Functions Subscriptions](https://docs.chain.link/chainlink-functions/resources/subscriptions\#overview) The Chainlink Functions Subscription Manager is available [here](https://functions.chain.link/). The Functions Subscription Manager lets you create a subscription, add consumers to it, remove consumers from it, fund it with LINK, and delete it. When you connect to the Subscription Manager, choose the correct network, then click _connect wallet_. ## [Subscriptions](https://docs.chain.link/chainlink-functions/resources/subscriptions\#subscriptions) You use a Chainlink Functions subscription to pay for, manage, and track Functions requests. ### [Create a subscription](https://docs.chain.link/chainlink-functions/resources/subscriptions\#create-a-subscription) 1. Open [functions.chain.link](https://functions.chain.link/) and click _Create Subscription_: ![Chainlink Functions subscription landing page](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/frontend-landing-wallet-connected.jpg) 2. Provide an email address and an optional subscription name: ![Chainlink Functions create subscription](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/create-subscription.jpg) 3. The first time that you interact with the Subscription Manager using your EOA, you have to approve the Terms of Service (ToS): ![Chainlink Functions accept ToS](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/acceptTos.jpg) 4. When you approve the ToS, a MetaMask popup appears that asks you to approve the subscription creation: ![Chainlink Functions approve subscriptions creation](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/approve-create-subscription.jpg) 5. After the subscription is created, you are asked to sign a message in MetaMask to link the subscription name and email address to your subscription: ![Chainlink Functions sign message ToS](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/sign-message-tos.jpg)![Chainlink Functions sign message ToS MetaMask](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/sign-message-tos-metamask.jpg) 1. After the subscription is created, fund it with LINK: ![Chainlink Functions subscription add funds](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/subscription-created-add-funds.jpg) 2. After funding, you can add a consumer to it: ![Chainlink Functions subscription add consumer](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/subscription-created-add-consumer.jpg)![Chainlink Functions subscription add consumer](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/subscription-created-add-consumer-2.jpg) 3. After creation, you can fetch the details of your subscription: ![Chainlink Functions subscription details](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/subscription-details-after-creation.jpg) ### [Fund a subscription](https://docs.chain.link/chainlink-functions/resources/subscriptions\#fund-a-subscription) 1. Open your subscription details and click _Actions_ then click _Fund subscription_: ![Chainlink Functions click fund](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/your-subscription-click-fund.jpg) 2. Fund your subscription. For instance, _0.1 LINK_: ![Chainlink Functions add fund to your subscription](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/your-subscription-add-fund.jpg) 3. A MetaMask popup appears, and you are asked to confirm the transaction. After you confirm the transaction, a confirmation screen appears: ![Chainlink Functions subscription funded](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/your-subscription-funded.jpg) ### [Add a consumer contract to a subscription](https://docs.chain.link/chainlink-functions/resources/subscriptions\#add-a-consumer-contract-to-a-subscription) 1. Open your subscription details and click _Add Consumer_: ![Chainlink Functions add consumer](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/your-subscription-add-consumer.jpg) 2. Fill in the consumer address: ![Chainlink Functions provider consumer address](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/your-subscription-fill-consumer.jpg) 3. A MetaMask popup appears, and you are asked to confirm the transaction. After you confirm the transaction, a confirmation screen appears: ![Chainlink Functions consumer added](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/your-subscription-consumer-added.jpg) ### [Remove a consumer contract from a subscription](https://docs.chain.link/chainlink-functions/resources/subscriptions\#remove-a-consumer-contract-from-a-subscription) 1. Open your subscription details and click the consumer you want to remove, then _Remove Consumer_: ![Chainlink Functions remove consumer](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/your-subscription-remove-consumer.jpg) 2. A MetaMask popup appears, and you are asked to confirm the transaction. ![Chainlink Functions confirm the removal of the consumer](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/your-subscription-remove-consumer-confirm.jpg)![Chainlink Functions confirm the removal of the consumer in MetaMask](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/your-subscription-remove-consumer-confirm2.jpg) 3. After you confirm the transaction, a confirmation screen appears: ![Chainlink Functions consumer removed](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/your-subscription-consumer-removed.jpg) ### [Cancel a subscription](https://docs.chain.link/chainlink-functions/resources/subscriptions\#cancel-a-subscription) **Note**: You cannot cancel a subscription if there are in-flight requests. In-flight requests are requests that still need to be fulfilled. 1. Open your subscription details, click _Actions_, then _Cancel subscription_: ![Chainlink Functions cancel subscription](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/your-subscription-cancel.jpg) 2. Fill in the receiver address of the remaining funds: ![Chainlink Functions cancel subscription](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/your-subscription-cancel2.jpg) 3. A MetaMask popup appears, and you are asked to confirm the transaction. ![Chainlink Functions confirm the removal of the subscription](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/your-subscription-cancel-confirm.jpg)![Chainlink Functions confirm the removal of the subscription in MetaMask](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/your-subscription-cancel-confirm2.jpg) 4. After you confirm the transaction, a confirmation screen appears: ![Chainlink Functions subscription canceled](https://docs.chain.link/images/chainlink-functions/tutorials/subscription/your-subscription-cancelled.jpg) ## [Time out pending requests manually](https://docs.chain.link/chainlink-functions/resources/subscriptions\#time-out-pending-requests-manually) The Subscription Manager provides the option to time out requests manually. You can time out requests that have been pending for longer than five minutes to unlock your subscription funds. 1. Open your subscription details and scroll to the **Pending** section. If a request has been pending longer than five minutes, its status displays as _Time out required_. Click the link within the red banner that says **Time out request**: ![Pending Functions request eligible for timeout](https://docs.chain.link/images/chainlink-functions/tutorials/request-timeout/1-request-eligible-for-timeout.png) If you have multiple requests that are eligible for timeout, the **Time out request** link in the red banner times out all the requests at once. Alternatively, you can time out an individual request. Open the **Actions** menu for that request, and click **Time out request**: ![Individual request timeout](https://docs.chain.link/images/chainlink-functions/tutorials/request-timeout/individual-request-timeout.png) 2. A MetaMask popup appears, and you are asked to confirm the transaction: ![Prompt to approve timeout transaction](https://docs.chain.link/images/chainlink-functions/tutorials/request-timeout/2-approve-timeout-transaction.png) 3. After you confirm the transaction, a confirmation screen appears: ![Timeout transaction confirmation](https://docs.chain.link/images/chainlink-functions/tutorials/request-timeout/3-timeout-successful-confirmation.png) 4. The subscription details page displays another confirmation in the upper right corner showing that the request has been timed out successfully: ![Request timed out dialog](https://docs.chain.link/images/chainlink-functions/tutorials/request-timeout/4-subscription-page-updates.png) 5. The timed out request appears in the **Failed fulfillments** tab of the **History** section: ![Chainlink Functions subscription canceled](https://docs.chain.link/images/chainlink-functions/tutorials/request-timeout/5-failed-fulfillments.png) ## Get the latest Chainlink content straight to your inbox. Email Address ## Chainlink Functions Responsibilities [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Chainlink Functions Service Responsibility](https://docs.chain.link/chainlink-functions/service-responsibility\#overview) Chainlink Functions provides access to trust-minimized compute infrastructure that allows you to retrieve data and run computation. Because the service is highly-flexible and runs offchain, both developers and Chainlink service providers share responsibility in ensuring that operation and performance match expectations. ## [Developer responsibilities](https://docs.chain.link/chainlink-functions/service-responsibility\#developer-responsibilities) Developers who implement Chainlink Functions in their code and applications are responsible for several components. ### [Data](https://docs.chain.link/chainlink-functions/service-responsibility\#data) - **Data quality:** When using Chainlink Functions, developers are responsible for ensuring that any external data they retrieve meet the data quality requirements for their applications. This responsibility applies to data retrieved via APIs or other data retrieval mechanisms. You must ensure that the data sources you consume through Chainlink Functions are accurate, reliable, secure, and not at risk of manipulation by malicious actors. When possible, use multiple data sources to reduce single points of failure and manipulation risks. - **Data availability:** Developers must ensure that the data sources and APIs that they use with Chainlink Functions meet the fault-tolerance and availability requirements for their applications. Node operators are geographically distributed, so developers must ensure that APIs do not have geographic or other restrictions that would prohibit node operators from retrieving data. When possible, use redundant data sources to reduce the risk that your applications cannot execute due to unavailable data. In situations where data isn't available, ensure proper error handling. - **Data privacy and ethics:** Developers are responsible for determining what data they have a right to use with Chainlink Functions and ensuring that they use that data ethically. Developers must ensure that their Chainlink Functions code does not expose their private information or the private information of users without proper consent. Do not use data that you are not authorized to access. Your Chainlink Functions code and your application must ensure that private or sensitive information remains secure. ### [Code](https://docs.chain.link/chainlink-functions/service-responsibility\#code) - **Code quality and reliability:** Developers must execute code on Chainlink Functions only if the code meets the quality and reliability requirements for their use case and application. - **Code and application audits:** Developers are responsible for auditing their code and applications before deploying to production. You must determine the quality of any audits and ensure that they meet the requirements for your application and any code that runs on Chainlink Functions. - **Code dependencies and imports:** Developers are responsible for ensuring the quality, reliability, and security of any dependencies or imported packages that they use with Chainlink Functions. Review and audit these dependencies and packages. ### [Secrets](https://docs.chain.link/chainlink-functions/service-responsibility\#secrets) - **Self-hosted secrets**: Developers are responsible for securing self-hosted secrets, monitoring unauthorized access, auditing permissions, and ensuring that secrets are available for retrieval by Chainlink Functions when executing code. - **Secrets best practices**: For all types of secrets used with Chainlink Functions, developers must follow common best practices for managing secrets for applications. Developers are responsible for selecting, setting expiration time, monitoring, and rotating secrets to ensure the security of their applications and Chainlink Functions code. ### [Subscriptions](https://docs.chain.link/chainlink-functions/service-responsibility\#subscriptions) - **Subscription owner wallet management:** Developers must ensure the security of any wallets that own Chainlink Functions subscriptions or wallets that secure funds for subscriptions. - **Subscription balances:** Subscription owners are responsible for maintaining the Chainlink Function balance that is necessary to fund Chainlink Functions requests and computation. Monitor your subscription balance and implement the necessary processes to fund your subscription balance at a level that meets your application's requirements. ## [Node Operator responsibilities](https://docs.chain.link/chainlink-functions/service-responsibility\#node-operator-responsibilities) High-quality node operators participate in the Functions DONs using a configuration specified in the Chainlink software. As participants in these deployments, Node Operators are responsible for the following components of Chainlink Functions: - Ensuring the proper configuration, maintenance, and monitoring of nodes participating in the Chainlink Functions DON. - Storing encrypted secrets that developers provide using threshold encryption. - Ensuring that transactions execute onchain in a timely manner and apply gas bumping when necessary. - Selecting and properly employing blockchain clients to connect to supported blockchain networks. - Maintaining continuous uptime and active participation in OCR consensus. - Employ defensive measures to prevent unauthorized access to their Chainlink node deployments. - Ensure that Chainlink node deployments are running the latest software versions. - Responding to important communication from Chainlink Labs or from other node operators in a timely manner. ## What's next - [\> Try out the Chainlink Functions Tutorials](https://docs.chain.link/chainlink-functions/tutorials) - [\> Read the Architecture to understand how Chainlink Functions operates](https://docs.chain.link/chainlink-functions/resources/architecture) ## Get the latest Chainlink content straight to your inbox. Email Address ## Chainlink Functions Networks [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks\#overview) Read the [LINK Token Contracts](https://docs.chain.link/resources/link-token-contracts) page to learn where to get testnet LINK and ETH. To use Chainlink Functions on certain networks, you may need to conduct token transfers. You can transfer tokens by using [Chainlink CCIP](https://docs.chain.link/ccip/tutorials/evm/transfer-tokens-from-contract), [Transporter](https://www.transporter.io/) or third-party applications such as [XSwap](https://xswap.link/). ## [![Arbitrum icon](https://docs.chain.link/assets/chains/arbitrum.svg)Arbitrum](https://docs.chain.link/chainlink-functions/supported-networks\#arbitrum) ### [Arbitrum Mainnet](https://docs.chain.link/chainlink-functions/supported-networks\#arbitrum-mainnet) | Item | Value | | --- | --- | | Functions router | [0x97083e831f8f0638855e2a515c90edcf158df238](https://arbiscan.io/address/0x97083e831f8f0638855e2a515c90edcf158df238 "0x97083e831f8f0638855e2a515c90edcf158df238")![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | DON ID![info](https://smartcontract.imgix.net/icons/info.svg?auto=compress%2Cformat) | `fun-arbitrum-mainnet-1`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) / `0x6675...0000`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Encrypted secrets upload endpoints | - `https://01.functions-gateway.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg)
- `https://02.functions-gateway.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Billing Item | Value | | --- | --- | | Premium fees | 3 cents USD | | Request threshold (withdrawing funds) | 10 requests | | Cancellation fees (withdrawing funds) | 0.1 LINK | | Minimum balance for uploading encrypted secrets | 0.1 LINK | ### [Arbitrum Sepolia testnet](https://docs.chain.link/chainlink-functions/supported-networks\#arbitrum-sepolia-testnet) | Item | Value | | --- | --- | | Functions router | [0x234a5fb5Bd614a7AA2FfAB244D603abFA0Ac5C5C](https://sepolia.arbiscan.io/address/0x234a5fb5Bd614a7AA2FfAB244D603abFA0Ac5C5C "0x234a5fb5Bd614a7AA2FfAB244D603abFA0Ac5C5C")![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | DON ID![info](https://smartcontract.imgix.net/icons/info.svg?auto=compress%2Cformat) | `fun-arbitrum-sepolia-1`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) / `0x6675...0000`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Encrypted secrets upload endpoints | - `https://01.functions-gateway.testnet.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg)
- `https://02.functions-gateway.testnet.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Billing Item | Value | | --- | --- | | Premium fees | 320 cents USD | | Request threshold (withdrawing funds) | 10 requests | | Cancellation fees (withdrawing funds) | 2 LINK | | Minimum balance for uploading encrypted secrets | 2 LINK | ## [![Avalanche icon](https://docs.chain.link/assets/chains/avalanche.svg)Avalanche](https://docs.chain.link/chainlink-functions/supported-networks\#avalanche) ### [Avalanche Mainnet](https://docs.chain.link/chainlink-functions/supported-networks\#avalanche-mainnet) | Item | Value | | --- | --- | | Functions router | [0x9f82a6A0758517FD0AfA463820F586999AF314a0](https://snowtrace.io/address/0x9f82a6A0758517FD0AfA463820F586999AF314a0 "0x9f82a6A0758517FD0AfA463820F586999AF314a0")![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | DON ID![info](https://smartcontract.imgix.net/icons/info.svg?auto=compress%2Cformat) | `fun-avalanche-mainnet-1`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) / `0x6675...0000`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Encrypted secrets upload endpoints | - `https://01.functions-gateway.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg)
- `https://02.functions-gateway.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Billing Item | Value | | --- | --- | | Premium fees | 3 cents USD | | Request threshold (withdrawing funds) | 1 request | | Cancellation fees (withdrawing funds) | 1 LINK | | Minimum balance for uploading encrypted secrets | 1 LINK | ### [Avalanche Fuji testnet](https://docs.chain.link/chainlink-functions/supported-networks\#avalanche-fuji-testnet) | Item | Value | | --- | --- | | Functions router | [0xA9d587a00A31A52Ed70D6026794a8FC5E2F5dCb0](https://testnet.snowtrace.io/address/0xA9d587a00A31A52Ed70D6026794a8FC5E2F5dCb0 "0xA9d587a00A31A52Ed70D6026794a8FC5E2F5dCb0")![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | DON ID![info](https://smartcontract.imgix.net/icons/info.svg?auto=compress%2Cformat) | `fun-avalanche-fuji-1`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) / `0x6675...0000`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Encrypted secrets upload endpoints | - `https://01.functions-gateway.testnet.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg)
- `https://02.functions-gateway.testnet.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Billing Item | Value | | --- | --- | | Premium fees | 320 cents USD | | Request threshold (withdrawing funds) | 10 requests | | Cancellation fees (withdrawing funds) | 2 LINK | | Minimum balance for uploading encrypted secrets | 2 LINK | ## [![BASE icon](https://docs.chain.link/assets/chains/base.svg)BASE](https://docs.chain.link/chainlink-functions/supported-networks\#base) ### [BASE Mainnet](https://docs.chain.link/chainlink-functions/supported-networks\#base-mainnet) | Item | Value | | --- | --- | | Functions router | [0xf9b8fc078197181c841c296c876945aaa425b278](https://basescan.org/address/0xf9b8fc078197181c841c296c876945aaa425b278 "0xf9b8fc078197181c841c296c876945aaa425b278")![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | DON ID![info](https://smartcontract.imgix.net/icons/info.svg?auto=compress%2Cformat) | `fun-base-mainnet-1`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) / `0x6675...0000`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Encrypted secrets upload endpoints | - `https://01.functions-gateway.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg)
- `https://02.functions-gateway.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Billing Item | Value | | --- | --- | | Premium fees (converted to LINK at request time) | 3 cents USD | | Request threshold (withdrawing funds) | 1 request | | Cancellation fees (withdrawing funds) | 0.1 LINK | | Minimum balance for uploading encrypted secrets | 0.1 LINK | ### [BASE Sepolia testnet](https://docs.chain.link/chainlink-functions/supported-networks\#base-sepolia-testnet) | Item | Value | | --- | --- | | Functions router | [0xf9B8fc078197181C841c296C876945aaa425B278](https://sepolia.basescan.org/address/0xf9B8fc078197181C841c296C876945aaa425B278 "0xf9B8fc078197181C841c296C876945aaa425B278")![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | DON ID![info](https://smartcontract.imgix.net/icons/info.svg?auto=compress%2Cformat) | `fun-base-sepolia-1`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) / `0x6675...0000`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Encrypted secrets upload endpoints | - `https://01.functions-gateway.testnet.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg)
- `https://02.functions-gateway.testnet.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Billing Item | Value | | --- | --- | | Premium fees (converted to LINK at request time) | 320 cents USD | | Request threshold (withdrawing funds) | 10 requests | | Cancellation fees (withdrawing funds) | 2 LINK | | Minimum balance for uploading encrypted secrets | 2 LINK | ## [![Celo icon](https://docs.chain.link/assets/chains/celo.svg)Celo](https://docs.chain.link/chainlink-functions/supported-networks\#celo) ### [Celo Mainnet](https://docs.chain.link/chainlink-functions/supported-networks\#celo-mainnet) | Item | Value | | --- | --- | | Functions router | [0xd74646C75163f9dA0F3666C3BE8A9C42F4b3b261](https://explorer.celo.org/mainnet/address/0xd74646C75163f9dA0F3666C3BE8A9C42F4b3b261 "0xd74646C75163f9dA0F3666C3BE8A9C42F4b3b261")![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | DON ID![info](https://smartcontract.imgix.net/icons/info.svg?auto=compress%2Cformat) | `fun-celo-mainnet-1`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) / `0x6675...0000`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Encrypted secrets upload endpoints | - `https://01.functions-gateway.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg)
- `https://02.functions-gateway.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Billing Item | Value | | --- | --- | | Premium fees (converted to LINK at request time) | 3 cents USD | | Request threshold (withdrawing funds) | 1 request | | Cancellation fees (withdrawing funds) | 0.1 LINK | | Minimum balance for uploading encrypted secrets | 0.1 LINK | ### [Celo Alfajores testnet](https://docs.chain.link/chainlink-functions/supported-networks\#celo-alfajores-testnet) | Item | Value | | --- | --- | | Functions router | [0x53BA5D8E5aab0cf9589aCE139666Be2b9Fd268e2](https://explorer.celo.org/alfajores/address/0x53BA5D8E5aab0cf9589aCE139666Be2b9Fd268e2 "0x53BA5D8E5aab0cf9589aCE139666Be2b9Fd268e2")![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | DON ID![info](https://smartcontract.imgix.net/icons/info.svg?auto=compress%2Cformat) | `fun-celo-alfajores-1`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) / `0x6675...0000`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Encrypted secrets upload endpoints | - `https://01.functions-gateway.testnet.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg)
- `https://02.functions-gateway.testnet.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Billing Item | Value | | --- | --- | | Premium fees (converted to LINK at request time) | 320 cents USD | | Request threshold (withdrawing funds) | 10 requests | | Cancellation fees (withdrawing funds) | 2 LINK | | Minimum balance for uploading encrypted secrets | 2 LINK | ## [![Ethereum icon](https://docs.chain.link/assets/chains/ethereum.svg)Ethereum](https://docs.chain.link/chainlink-functions/supported-networks\#ethereum) ### [Ethereum mainnet](https://docs.chain.link/chainlink-functions/supported-networks\#ethereum-mainnet) | Item | Value | | --- | --- | | Functions router | [0x65Dcc24F8ff9e51F10DCc7Ed1e4e2A61e6E14bd6](https://etherscan.io/address/0x65Dcc24F8ff9e51F10DCc7Ed1e4e2A61e6E14bd6 "0x65Dcc24F8ff9e51F10DCc7Ed1e4e2A61e6E14bd6")![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | DON ID![info](https://smartcontract.imgix.net/icons/info.svg?auto=compress%2Cformat) | `fun-ethereum-mainnet-1`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) / `0x6675...0000`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Encrypted secrets upload endpoints | - `https://01.functions-gateway.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg)
- `https://02.functions-gateway.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Billing Item | Value | | --- | --- | | Premium fees | 400 cents USD | | Request threshold (withdrawing funds) | 1 request | | Cancellation fees (withdrawing funds) | 1 LINK | | Minimum balance for uploading encrypted secrets | 1 LINK | ### [Sepolia testnet](https://docs.chain.link/chainlink-functions/supported-networks\#sepolia-testnet) | Item | Value | | --- | --- | | Functions router | [0xb83E47C2bC239B3bf370bc41e1459A34b41238D0](https://sepolia.etherscan.io/address/0xb83E47C2bC239B3bf370bc41e1459A34b41238D0 "0xb83E47C2bC239B3bf370bc41e1459A34b41238D0")![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | DON ID![info](https://smartcontract.imgix.net/icons/info.svg?auto=compress%2Cformat) | `fun-ethereum-sepolia-1`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) / `0x6675...0000`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Encrypted secrets upload endpoints | - `https://01.functions-gateway.testnet.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg)
- `https://02.functions-gateway.testnet.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Billing Item | Value | | --- | --- | | Premium fees | 320 cents USD | | Request threshold (withdrawing funds) | 10 requests | | Cancellation fees (withdrawing funds) | 2 LINK | | Minimum balance for uploading encrypted secrets | 2 LINK | ## [![OP icon](https://docs.chain.link/assets/chains/optimism.svg)OP](https://docs.chain.link/chainlink-functions/supported-networks\#op) ### [OP Mainnet](https://docs.chain.link/chainlink-functions/supported-networks\#op-mainnet) | Item | Value | | --- | --- | | Functions router | [0xaA8AaA682C9eF150C0C8E96a8D60945BCB21faad](https://optimistic.etherscan.io/address/0xaA8AaA682C9eF150C0C8E96a8D60945BCB21faad "0xaA8AaA682C9eF150C0C8E96a8D60945BCB21faad")![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | DON ID![info](https://smartcontract.imgix.net/icons/info.svg?auto=compress%2Cformat) | `fun-optimism-mainnet-1`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) / `0x6675...0000`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Encrypted secrets upload endpoints | - `https://01.functions-gateway.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg)
- `https://02.functions-gateway.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Billing Item | Value | | --- | --- | | Premium fees (converted to LINK at request time) | 3 cents USD | | Request threshold (withdrawing funds) | 1 request | | Cancellation fees (withdrawing funds) | 0.1 LINK | | Minimum balance for uploading encrypted secrets | 0.1 LINK | ### [OP Sepolia](https://docs.chain.link/chainlink-functions/supported-networks\#op-sepolia) | Item | Value | | --- | --- | | Functions router | [0xC17094E3A1348E5C7544D4fF8A36c28f2C6AAE28](https://sepolia-optimism.etherscan.io/address/0xC17094E3A1348E5C7544D4fF8A36c28f2C6AAE28 "0xC17094E3A1348E5C7544D4fF8A36c28f2C6AAE28")![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | DON ID![info](https://smartcontract.imgix.net/icons/info.svg?auto=compress%2Cformat) | `fun-optimism-sepolia-1`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) / `0x6675...0000`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Encrypted secrets upload endpoints | - `https://01.functions-gateway.testnet.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg)
- `https://02.functions-gateway.testnet.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Billing Item | Value | | --- | --- | | Premium fees (converted to LINK at request time) | 320 cents USD | | Request threshold (withdrawing funds) | 10 requests | | Cancellation fees (withdrawing funds) | 2 LINK | | Minimum balance for uploading encrypted secrets | 2 LINK | ## [![Polygon icon](https://docs.chain.link/assets/chains/polygon.svg)Polygon](https://docs.chain.link/chainlink-functions/supported-networks\#polygon) ### [Polygon mainnet](https://docs.chain.link/chainlink-functions/supported-networks\#polygon-mainnet) | Item | Value | | --- | --- | | Functions router | [0xdc2AAF042Aeff2E68B3e8E33F19e4B9fA7C73F10](https://polygonscan.com/address/0xdc2AAF042Aeff2E68B3e8E33F19e4B9fA7C73F10 "0xdc2AAF042Aeff2E68B3e8E33F19e4B9fA7C73F10")![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | DON ID![info](https://smartcontract.imgix.net/icons/info.svg?auto=compress%2Cformat) | `fun-polygon-mainnet-1`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) / `0x6675...0000`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Encrypted secrets upload endpoints | - `https://01.functions-gateway.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg)
- `https://02.functions-gateway.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Billing Item | Value | | --- | --- | | Premium fees | 3 cents USD | | Request threshold (withdrawing funds) | 1 request | | Cancellation fees (withdrawing funds) | 1 LINK | | Minimum balance for uploading encrypted secrets | 1 LINK | ### [Polygon Amoy testnet](https://docs.chain.link/chainlink-functions/supported-networks\#polygon-amoy-testnet) | Item | Value | | --- | --- | | Functions router | [0xC22a79eBA640940ABB6dF0f7982cc119578E11De](https://amoy.polygonscan.com/address/0xC22a79eBA640940ABB6dF0f7982cc119578E11De "0xC22a79eBA640940ABB6dF0f7982cc119578E11De")![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | DON ID![info](https://smartcontract.imgix.net/icons/info.svg?auto=compress%2Cformat) | `fun-polygon-amoy-1`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) / `0x6675...0000`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Encrypted secrets upload endpoints | - `https://01.functions-gateway.testnet.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg)
- `https://02.functions-gateway.testnet.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Billing Item | Value | | --- | --- | | Premium fees (converted to LINK at request time) | 320 cents USD | | Request threshold (withdrawing funds) | 10 requests | | Cancellation fees (withdrawing funds) | 2 LINK | | Minimum balance for uploading encrypted secrets | 2 LINK | ## [![Soneium icon](https://docs.chain.link/assets/chains/soneium.svg)Soneium](https://docs.chain.link/chainlink-functions/supported-networks\#soneium) ### [Soneium Mainnet](https://docs.chain.link/chainlink-functions/supported-networks\#soneium-mainnet) | Item | Value | | --- | --- | | Functions router | [0x20fef1B12FA78fAc8CFB8a7ac1bf032Bd8DcAdDa](https://soneium.blockscout.com/address/0x20fef1B12FA78fAc8CFB8a7ac1bf032Bd8DcAdDa "0x20fef1B12FA78fAc8CFB8a7ac1bf032Bd8DcAdDa")![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | DON ID![info](https://smartcontract.imgix.net/icons/info.svg?auto=compress%2Cformat) | `fun-soneium-mainnet-1`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) / `0x6675...0000`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Encrypted secrets upload endpoints | - `https://01.functions-gateway.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg)
- `https://02.functions-gateway.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Billing Item | Value | | --- | --- | | Premium fees (converted to LINK at request time) | 3 cents USD | | Request threshold (withdrawing funds) | 1 requests | | Cancellation fees (withdrawing funds) | 0.1 LINK | | Minimum balance for uploading encrypted secrets | 0.1 LINK | ### [Soneium Minato testnet](https://docs.chain.link/chainlink-functions/supported-networks\#soneium-minato-testnet) | Item | Value | | --- | --- | | Functions router | [0x3704dc1eefCDCE04C58813836AEcfdBC8e7cB3D8](https://soneium-minato.blockscout.com/address/0x3704dc1eefCDCE04C58813836AEcfdBC8e7cB3D8 "0x3704dc1eefCDCE04C58813836AEcfdBC8e7cB3D8")![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | DON ID![info](https://smartcontract.imgix.net/icons/info.svg?auto=compress%2Cformat) | `fun-soneium-sepolia-1`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) / `0x6675...0000`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Encrypted secrets upload endpoints | - `https://01.functions-gateway.testnet.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg)
- `https://02.functions-gateway.testnet.chain.link/`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) | | Billing Item | Value | | --- | --- | | Premium fees (converted to LINK at request time) | 320 cents USD | | Request threshold (withdrawing funds) | 10 requests | | Cancellation fees (withdrawing funds) | 2 LINK | | Minimum balance for uploading encrypted secrets | 2 LINK | ## Get the latest Chainlink content straight to your inbox. Email Address [iframe](https://td.doubleclick.net/td/rul/346357746?random=1747665277712&cv=11&fst=1747665277712&fmt=3&bg=ffffff&guid=ON&async=1&gcl_ctr=1>m=45be55g2h1v891173849z8847174275za201zb847174275&gcd=13l3l3l3l1l1&dma=0&tag_exp=101509157~103116026~103130495~103130497~103136993~103136995~103200004~103207802~103233427~103252644~103252646~103263073~103301114~103301116&ptag_exp=101509157~103116025~103130495~103130497~103136993~103136995~103200001~103207802~103233427~103252644~103252646~103263073~103301114~103301116&u_w=1280&u_h=1024&url=https%3A%2F%2Fdocs.chain.link%2Fchainlink-functions%2Fsupported-networks&label=_duuCKn_k4cYEPL_k6UB&hn=www.googleadservices.com&frm=0&tiba=Supported%20Networks%20%7C%20Chainlink%20Documentation&value=0&bttype=purchase&npa=0&pscdl=noapi&auid=698598865.1747665277&uaa=x86&uab=64&uafvl=Chromium%3B136.0.7103.113%7CGoogle%2520Chrome%3B136.0.7103.113%7CNot.A%252FBrand%3B99.0.0.0&uamb=0&uam=&uap=Linux%20x86_64&uapv=6.6.72&uaw=0&fledge=1&capi=1&_tu=Cg&ct_cookie_present=0) ## Chainlink Functions Tutorials [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Chainlink Functions Tutorials](https://docs.chain.link/chainlink-functions/tutorials\#overview) ## [Topics](https://docs.chain.link/chainlink-functions/tutorials\#topics) - [Simple Computation](https://docs.chain.link/chainlink-functions/tutorials/simple-computation) - [Call an API](https://docs.chain.link/chainlink-functions/tutorials/api-query-parameters) - [POST Data to an API](https://docs.chain.link/chainlink-functions/tutorials/api-post-data) - [Using DON-hosted Secrets in Requests](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets) - [Using Imports with Functions](https://docs.chain.link/chainlink-functions/tutorials/importing-packages) - [Use ABI encoding and decoding](https://docs.chain.link/chainlink-functions/tutorials/abi-decoding) - [Using User-hosted (gist) Secrets in Requests](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-gist) - [Using User-hosted Secrets in Requests](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-offchain) - [Call Multiple Data Sources](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls) - [Encode request data offchain](https://docs.chain.link/chainlink-functions/tutorials/encode-request-offchain) - [Automate your Functions (Time-based Automation)](https://docs.chain.link/chainlink-functions/tutorials/automate-functions) - [Automate your Functions (Custom Logic Automation)](https://docs.chain.link/chainlink-functions/tutorials/automate-functions-custom-logic) ## Get the latest Chainlink content straight to your inbox. Email Address ## ABI Decoding Tutorial [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Return multiple responses and decode them in your smart contract](https://docs.chain.link/chainlink-functions/tutorials/abi-decoding\#overview) In the [Using Imports with Functions](https://docs.chain.link/chainlink-functions/tutorials/importing-packages) tutorial, we explored the fundamentals of module imports. This tutorial will teach you how to use the Ethers library [encode](https://docs.ethers.org/v6/api/abi/abi-coder/#AbiCoder-encode) function to perform ABI encoding of several responses. Then, you will use the [ABI specifications](https://docs.soliditylang.org/en/v0.8.24/abi-spec.html) in Solidity to decode the responses in your smart contract. ## [Prerequisites](https://docs.chain.link/chainlink-functions/tutorials/abi-decoding\#prerequisites) This tutorial assumes you have completed the [Using Imports with Functions](https://docs.chain.link/chainlink-functions/tutorials/importing-packages) tutorial. Also, check your subscription details (including the balance in LINK) in the [Chainlink Functions Subscription\\ Manager](https://functions.chain.link/). If your subscription runs out of LINK, follow the [Fund a\\ Subscription](https://docs.chain.link/chainlink-functions/resources/subscriptions#fund-a-subscription) guide. In this tutorial, you will use a different Chainlink Functions consumer contract, which shows how to use ABI decoding to decode the response received from Chainlink Functions: 1. [Open the FunctionsConsumerDecoder.sol contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerDecoder.sol) in Remix. [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerDecoder.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) 2. Compile the contract. 3. Open MetaMask and select the _Ethereum Sepolia_ network. 4. In Remix under the **Deploy & Run Transactions** tab, select _Injected Provider - MetaMask_ in the **Environment** list. Remix will use the MetaMask wallet to communicate with _Ethereum Sepolia_. 5. Under the **Deploy** section, fill in the router address for your specific blockchain. You can find this address on the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks) page. For _Ethereum Sepolia_, the router address is `0xb83E47C2bC239B3bf370bc41e1459A34b41238D0`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg). 6. Click the **Deploy** button to deploy the contract. MetaMask prompts you to confirm the transaction. Check the transaction details to make sure you are deploying the contract to _Ethereum Sepolia_. 7. After you confirm the transaction, the contract address appears in the **Deployed Contracts** list. Copy the contract address. 8. Add your consumer contract address to your subscription on _Ethereum Sepolia_. ## [Tutorial](https://docs.chain.link/chainlink-functions/tutorials/abi-decoding\#tutorial) This tutorial demonstrates using the [ethers](https://www.npmjs.com/package/ethers) library to interact with smart contract functions through a JSON RPC provider. It involves calling the [`latestRoundData`](https://docs.chain.link/data-feeds/api-reference#latestrounddata), [`decimals`](https://docs.chain.link/data-feeds/api-reference#decimals), and [`description`](https://docs.chain.link/data-feeds/api-reference#description) functions of a price feed contract based on the `AggregatorV3Interface`. After retrieving the necessary data, the guide shows how to use ABI encoding to encode these responses into a single hexadecimal string and then convert this string to a [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array). This step ensures compliance with the [Chainlink Functions API requirements](https://docs.chain.link/chainlink-functions/api-reference/javascript-source#data-encoding-functions), which specify that the source code must return a Uint8Array representing the bytes for on-chain use. You can locate the scripts used in this tutorial in the [_examples/12-abi-encoding_ directory](https://github.com/smartcontractkit/smart-contract-examples/tree/main/functions-examples/examples/12-abi-encoding). To run the example: 1. Make sure you have correctly set up your environment first. If you haven't already, follow the [Set up your environment](https://docs.chain.link/chainlink-functions/tutorials/importing-packages#set-up-your-environment) section of the [Using Imports with Functions](https://docs.chain.link/chainlink-functions/tutorials/importing-packages) tutorial. 2. Open the file `request.js`, located in the [`12-abi-encoding`](https://github.com/smartcontractkit/smart-contract-examples/tree/main/functions-examples/examples/12-abi-encoding) folder. 3. Replace the consumer contract address and the subscription ID with your own values. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x5fC6e53646CC53f0C3575fd2c71b5056c4823f5c" // REPLACE this with your Functions consumer address const subscriptionId = 139 // REPLACE this with your subscription ID ``` 4. Make a request: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node examples/12-abi-encoding/request.js ``` The script runs your function in a sandbox environment before making an onchain transaction: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```text $ node examples/12-abi-encoding/request.js secp256k1 unavailable, reverting to browser version Start simulation... Simulation result { capturedTerminalOutput: 'Fetched BTC / USD price: dataFeedResponse.answer\n' + 'Updated at: 1712941559\n' + 'Decimals: 8\n' + 'Description: BTC / USD\n', responseBytesHexstring: '0x0000000000000000000000000000000000000000000000000000063c3570cc8400000000000000000000000000000000000000000000000000000000661969f7000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000009425443202f205553440000000000000000000000000000000000000000000000' } ✅ Decoded response to bytes: 0x0000000000000000000000000000000000000000000000000000063c3570cc8400000000000000000000000000000000000000000000000000000000661969f7000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000009425443202f205553440000000000000000000000000000000000000000000000 Estimate request costs... Fulfillment cost estimated to 1.007671833192655 LINK Make request... ✅ Functions request sent! Transaction hash 0x5618089ec9b5e662ec72c81241d78cb6daa135ecc3fa3a33032d910e3b47c2b1. Waiting for a response... See your request in the explorer https://sepolia.etherscan.io/tx/0x5618089ec9b5e662ec72c81241d78cb6daa135ecc3fa3a33032d910e3b47c2b1 ✅ Request 0xdf22fa28c81a3ea78f356334b6d28d969e953009fae8ece4fe544f2eb466419b successfully fulfilled. Cost is 0.282344694329387405 LINK.Complete response: { requestId: '0xdf22fa28c81a3ea78f356334b6d28d969e953009fae8ece4fe544f2eb466419b', subscriptionId: 2303, totalCostInJuels: 282344694329387405n, responseBytesHexstring: '0x0000000000000000000000000000000000000000000000000000063c3570cc8400000000000000000000000000000000000000000000000000000000661969f7000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000009425443202f205553440000000000000000000000000000000000000000000000', errorString: '', returnDataBytesHexstring: '0x', fulfillmentCode: 0 } ✅ Raw response: 0x0000000000000000000000000000000000000000000000000000063c3570cc8400000000000000000000000000000000000000000000000000000000661969f7000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000009425443202f205553440000000000000000000000000000000000000000000000 ✅ Fetched BTC / USD price: 6855664389252 (updatedAt: 1712941559) (decimals: 8) (description: BTC / USD) ``` The output of the example gives you the following information: - Your request is first run on a sandbox environment to ensure it is correctly configured. - The fulfillment costs are estimated before making the request. - Your request was successfully sent to Chainlink Functions. The transaction in this example is `0x5618089ec9b5e662ec72c81241d78cb6daa135ecc3fa3a33032d910e3b47c2b1`, and the request ID is `0xdf22fa28c81a3ea78f356334b6d28d969e953009fae8ece4fe544f2eb466419b`. - The DON successfully fulfilled your request. The total cost was: `0.282344694329387405 LINK`. - The consumer contract received a response in hexadecimal string with a value of `0x0000000000000000000000000000000000000000000000000000063c3570cc8400000000000000000000000000000000000000000000000000000000661969f7000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000009425443202f205553440000000000000000000000000000000000000000000000`. This value is the ABI encoded response of the `latestRoundData`, `decimals`, and `description` of the _BTC / USD_ price feed. This value is then decoded and stored in the consumer contract. - The script calls the consumer contract to fetch the decoded values and then logs them to the console. The output is `Fetched BTC / USD price: 6855664389252 (updatedAt: 1712941559) (decimals: 8) (description: BTC / USD)`. ## [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/abi-decoding\#examine-the-code) ### [FunctionsConsumerDecoder.sol](https://docs.chain.link/chainlink-functions/tutorials/abi-decoding\#functionsconsumerdecodersol) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; /** * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. * DO NOT USE THIS CODE IN PRODUCTION. */ contract FunctionsConsumerDecoder is FunctionsClient, ConfirmedOwner { using FunctionsRequest for FunctionsRequest.Request; bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; uint256 public s_answer; uint256 public s_updatedAt; uint8 public s_decimals; string public s_description; error UnexpectedRequestID(bytes32 requestId); event Response(bytes32 indexed requestId, bytes response, bytes err); event DecodedResponse( bytes32 indexed requestId, uint256 answer, uint256 updatedAt, uint8 decimals, string description ); constructor( address router ) FunctionsClient(router) ConfirmedOwner(msg.sender) {} /** * @notice Send a simple request * @param source JavaScript source code * @param encryptedSecretsUrls Encrypted URLs where to fetch user secrets * @param donHostedSecretsSlotID Don hosted secrets slotId * @param donHostedSecretsVersion Don hosted secrets version * @param args List of arguments accessible from within the source code * @param bytesArgs Array of bytes arguments, represented as hex strings * @param subscriptionId Billing ID */ function sendRequest( string memory source, bytes memory encryptedSecretsUrls, uint8 donHostedSecretsSlotID, uint64 donHostedSecretsVersion, string[] memory args, bytes[] memory bytesArgs, uint64 subscriptionId, uint32 gasLimit, bytes32 donID ) external onlyOwner returns (bytes32 requestId) { FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); if (encryptedSecretsUrls.length > 0) req.addSecretsReference(encryptedSecretsUrls); else if (donHostedSecretsVersion > 0) { req.addDONHostedSecrets( donHostedSecretsSlotID, donHostedSecretsVersion ); } if (args.length > 0) req.setArgs(args); if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Send a pre-encoded CBOR request * @param request CBOR-encoded request data * @param subscriptionId Billing ID * @param gasLimit The maximum amount of gas the request can consume * @param donID ID of the job to be invoked * @return requestId The ID of the sent request */ function sendRequestCBOR( bytes memory request, uint64 subscriptionId, uint32 gasLimit, bytes32 donID ) external onlyOwner returns (bytes32 requestId) { s_lastRequestId = _sendRequest( request, subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @dev Internal function to process the outcome of a data request. It stores the latest response or error and updates the contract state accordingly. This function is designed to handle only one of `response` or `err` at a time, not both. It decodes the response if present and emits events to log both raw and decoded data. * * @param requestId The unique identifier of the request, originally returned by `sendRequest`. Used to match responses with requests. * @param response The raw aggregated response data from the external source. This data is ABI-encoded and is expected to contain specific information (e.g., answer, updatedAt) if no error occurred. The function attempts to decode this data if `response` is not empty. * @param err The raw aggregated error information, indicating an issue either from the user's code or within the execution of the user Chainlink Function. * * Emits a `DecodedResponse` event if the `response` is successfully decoded, providing detailed information about the data received. * Emits a `Response` event for every call to log the raw response and error data. * * Requirements: * - The `requestId` must match the last stored request ID to ensure the response corresponds to the latest request sent. * - Only one of `response` or `err` should contain data for a given call; the other should be empty. */ function fulfillRequest( bytes32 requestId, bytes memory response, bytes memory err ) internal override { if (s_lastRequestId != requestId) { revert UnexpectedRequestID(requestId); } s_lastError = err; s_lastResponse = response; if (response.length > 0) { ( uint256 answer, uint256 updatedAt, uint8 decimals, string memory description ) = abi.decode(response, (uint256, uint256, uint8, string)); s_answer = answer; s_updatedAt = updatedAt; s_decimals = decimals; s_description = description; emit DecodedResponse( requestId, answer, updatedAt, decimals, description ); } emit Response(requestId, response, err); } } ``` [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerDecoder.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) This Solidity contract is similar to the [FunctionsConsumer.sol](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumer.sol) contract used in the [Using Imports with Functions](https://docs.chain.link/chainlink-functions/tutorials/importing-packages) tutorial. The main difference is the processing of the response in the `fulfillRequest` function: - It uses Solidity `abi.decode` to decode the `response` to retrieve the `answer`, `updatedAt`, `decimals`, and `description`. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity ( uint256 answer, uint256 updatedAt, uint8 decimals, string memory description ) = abi.decode(response, (uint256, uint256, uint8, string)); ``` - Then stores the decoded values in the contract state. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity s_answer = answer; s_updatedAt = updatedAt; s_decimals = decimals; s_description = description; ``` ### [JavaScript example](https://docs.chain.link/chainlink-functions/tutorials/abi-decoding\#javascript-example) #### [source.js](https://docs.chain.link/chainlink-functions/tutorials/abi-decoding\#sourcejs) The Decentralized Oracle Network will run the [JavaScript code](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/12-abi-encoding/source.js). The code is self-explanatory and has comments to help you understand all the steps. The example `source.js` file is similar to the one used in the [Using Imports with Functions](https://docs.chain.link/chainlink-functions/tutorials/importing-packages#sourcejs) tutorial. It uses a JSON RPC call to the [`latestRoundData`](https://docs.chain.link/data-feeds/api-reference#latestrounddata), [`decimals`](https://docs.chain.link/data-feeds/api-reference#decimals), and [`description`](https://docs.chain.link/data-feeds/api-reference#description) functions of a [Chainlink Data Feed](https://docs.chain.link/data-feeds). It then uses the `ethers` library to encode the response of these functions into a single hexadecimal string. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const encoded = ethers.AbiCoder.defaultAbiCoder().encode( ["uint256", "uint256", "uint8", "string"], [dataFeedResponse.answer, dataFeedResponse.updatedAt, decimals, description] ) ``` Finally, it uses the `ethers` library [`getBytes`](https://docs.ethers.org/v6/api/utils/#getBytes) to convert the hexadecimal string to a `Uint8Array`: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript return ethers.getBytes(encoded) ``` #### [request.js](https://docs.chain.link/chainlink-functions/tutorials/abi-decoding\#requestjs) This explanation focuses on the [request.js](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/12-abi-encoding/request.js) script and shows how to use the [Chainlink Functions NPM package](https://github.com/smartcontractkit/functions-toolkit) in your own JavaScript/TypeScript project to send requests to a DON. The code is self-explanatory and has comments to help you understand all the steps. The script imports: - [path](https://nodejs.org/docs/latest/api/path.html) and [fs](https://nodejs.org/api/fs.html): Used to read the [source file](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/12-abi-encoding/source.js). - [ethers](https://docs.ethers.org/v5/): Ethers.js library, enables the script to interact with the blockchain. - `@chainlink/functions-toolkit`: Chainlink Functions NPM package. All its utilities are documented in the [NPM README](https://github.com/smartcontractkit/functions-toolkit/blob/main/README.md). - `@chainlink/env-enc`: A tool for loading and storing encrypted environment variables. Read the [official documentation](https://www.npmjs.com/package/@chainlink/env-enc) to learn more. - `../abi/functionsDecoder.json`: The abi of the contract your script will interact with. **Note**: The script was tested with this [FunctionsConsumerDecoder contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerDecoder.sol). The script has two hardcoded values that you have to change using your own Functions consumer contract and subscription ID: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x5fC6e53646CC53f0C3575fd2c71b5056c4823f5c" // REPLACE this with your Functions consumer address const subscriptionId = 139 // REPLACE this with your subscription ID ``` The primary function that the script executes is `makeRequestSepolia`. This function consists of five main parts: 1. Definition of necessary identifiers: - `routerAddress`: Chainlink Functions router address on Sepolia. - `donId`: Identifier of the DON that will fulfill your requests on Sepolia. - `explorerUrl`: Block explorer URL of the Sepolia testnet. - `source`: The source code must be a string object. That's why we use `fs.readFileSync` to read `source.js` and then call `toString()` to get the content as a `string` object. - `args`: During the execution of your function, These arguments are passed to the source code. - `gasLimit`: Maximum gas that Chainlink Functions can use when transmitting the response to your contract. - Initialization of ethers `signer` and `provider` objects. The signer is used to make transactions on the blockchain, and the provider reads data from the blockchain. 2. Simulating your request in a local sandbox environment: - Use `simulateScript` from the Chainlink Functions NPM package. - Read the `response` of the simulation. If successful, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.bytes` in this example). 3. Estimating the costs: - Initialize a `SubscriptionManager` from the Functions NPM package, then call the `estimateFunctionsRequestCost`. - The response is returned in Juels (1 LINK = 10\*\*18 Juels). Use the `ethers.utils.formatEther` utility function to convert the output to LINK. 4. Making a Chainlink Functions request: - Initialize your functions consumer contract using the contract address, abi, and ethers signer. - Call the `sendRequest` function of your consumer contract. 5. Waiting for the response: - Initialize a `ResponseListener` from the Functions NPM package and then call the `listenForResponseFromTransaction` function to wait for a response. By default, this function waits for five minutes. - Upon reception of the response, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.bytes` in this example). 6. Read the decoded response: - Call the `s_answer`, `s_updatedAt`, `s_decimals`, and `s_description` functions of your consumer contract to fetch the decoded values. - Log the decoded values to the console. ## [Handling complex data types with ABI Encoding and Decoding](https://docs.chain.link/chainlink-functions/tutorials/abi-decoding\#handling-complex-data-types-with-abi-encoding-and-decoding) This section details the process of encoding complex data types into [`Uint8Array` typed arrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) to fulfill the Ethereum Virtual Machine (EVM) data handling requirements for transactions and smart contract interactions. It will then outline the steps for decoding these byte arrays to align with corresponding structures defined in Solidity. Consider a scenario where a contract needs to interact with a data structure that encapsulates multiple properties, including nested objects: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```json { "id": 1, "metadata": { "description": "Decentralized Oracle Network", "awesome": true } } ``` Transferring and storing this kind of structured data requires encoding it into a format (array of 8-bit unsigned integers) that smart contracts can accept and process. ### [Encoding in JavaScript](https://docs.chain.link/chainlink-functions/tutorials/abi-decoding\#encoding-in-javascript) Because Chainlink Functions supports important external modules, you can import a web3 library such as `ethers.js` and perform encoding. To encode complex data structures, you can use the [`defaultAbiCoder.encode`](https://docs.ethers.org/v6/api/abi/abi-coder/#AbiCoder-encode) function from the `ethers.js` library. The function takes two arguments: - An array of Solidity data types. - The corresponding data in JavaScript format. and returns the encoded data as a hexadecimal string. Here's how you can encode the aforementioned complex data: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const { ethers } = await import("npm:ethers@6.10.0") // Import ethers.js v6.10.0 const abiCoder = ethers.AbiCoder.defaultAbiCoder() // Define the data structure const complexData = { id: 1, metadata: { description: "Decentralized Oracle Network", awesome: true, }, } // Define the Solidity types for encoding const types = ["tuple(uint256 id, tuple(string description, bool awesome) metadata)"] // Encoding the data const encodedData = abiCoder.encode(types, [complexData]) ``` After encoding the data, it's necessary to format it as a `Uint8Array` array for smart contract interactions and blockchain transactions. In Solidity, the data type for byte arrays data is `bytes`. However, when working in a JavaScript environment, such as when using the `ethers.js` library, the equivalent data structure is a `Uint8Array`. The `ethers.js` library provides the [`getBytes`](https://docs.ethers.org/v6/api/utils/#getBytes) function to convert encoded hexadecimal strings into a `Uint8Array`: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript return ethers.getBytes(encodedData) // Return the encoded data converted into a Uint8Array ``` ### [Decoding in Solidity](https://docs.chain.link/chainlink-functions/tutorials/abi-decoding\#decoding-in-solidity) The encoded data can be decoded using the `abi.decode` function. To decode the data, you'll need to handle the decoding in your `fulfillRequest` function: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.19; contract DataDecoder { // Example of a structure to hold the complex data struct Metadata { string description; bool awesome; } struct ComplexData { uint256 id; Metadata metadata; } // ... other contract functions (including the send request function) // Fulfill function (callback function) function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal override { // Decode the response ComplexData memory metadata = abi.decode(response, (ComplexData)); // ... rest of the function } } ``` ## What's next - [\> Try out the Chainlink Functions Tutorials](https://docs.chain.link/chainlink-functions/tutorials) - [\> Read the Architecture to understand how Chainlink Functions operates](https://docs.chain.link/chainlink-functions/resources/architecture) ## Get the latest Chainlink content straight to your inbox. Email Address ## API Multiple Calls Tutorial [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Call Multiple Data Sources](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls\#overview) This tutorial shows you how make multiple API calls from your smart contract to a Decentralized Oracle Network. After [OCR](https://docs.chain.link/chainlink-functions/resources/architecture) completes offchain computation and aggregation, the DON returns the asset price to your smart contract. This example returns the `BTC/USD` price. This guide assumes that you know how to build HTTP requests and how to use secrets. Read the [API query parameters](https://docs.chain.link/chainlink-functions/tutorials/api-query-parameters) and [API use secrets](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets) guides before you follow the example in this document. To build a decentralized asset price, send a request to the DON to fetch the price from many different API providers. Then, calculate the median price. The API providers in this example are: - [CoinMarket](https://coinmarketcap.com/api/documentation/v1/) - [CoinGecko](https://www.coingecko.com/en/api/documentation) - [CoinPaprika](https://api.coinpaprika.com/) ## [Prerequisites](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls\#prerequisites) ### [Set up your environment](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls\#set-up-your-environment) You must provide the private key from a testnet wallet to run the examples in this documentation. Install a Web3 wallet, configure [Node.js](https://nodejs.org/en/download/), clone the [smartcontractkit/smart-contract-examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository, and configure a `.env.enc` file with the required environment variables. Install and configure your Web3 wallet for Ethereum Sepolia: 1. [Install Deno](https://docs.deno.com/runtime/manual/) so you can compile and simulate your Functions source code on your local machine. 2. [Install the MetaMask wallet](https://docs.chain.link/quickstarts/deploy-your-first-contract#install-and-fund-your-metamask-wallet) or other Ethereum Web3 wallet. 3. Set the network for your wallet to the Sepolia testnet. If you need to add Sepolia to your wallet, you can find the chain ID and the LINK token contract address on the [LINK Token Contracts](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) page. - [Sepolia testnet and LINK token contract](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) 4. Request testnet LINK and ETH from [faucets.chain.link/sepolia](https://faucets.chain.link/sepolia). Install the required frameworks and dependencies: 1. [Install the latest release of Node.js 20](https://nodejs.org/en/download/). Optionally, you can use the [nvm package](https://www.npmjs.com/package/nvm) to switch between Node.js versions with `nvm use 20`. **Note**: To ensure you are running the correct version in a terminal, type `node -v`. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node -v ``` ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell $ node -v v20.9.0 ``` 2. In a terminal, clone the [smart-contract examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository and change directories. This example repository imports the [Chainlink Functions Toolkit NPM package](https://www.npmjs.com/package/@chainlink/functions-toolkit). You can import this package to your own projects to enable them to work with Chainlink Functions. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell git clone https://github.com/smartcontractkit/smart-contract-examples.git && \ cd ./smart-contract-examples/functions-examples/ ``` 3. Run `npm install` to install the dependencies. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npm install ``` 4. For higher security, the examples repository encrypts your environment variables at rest. 1. Set an encryption password for your environment variables. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set-pw ``` 2. Run `npx env-enc set` to configure a `.env.enc` file with the basic variables that you need to send your requests to the Sepolia network. - `ETHEREUM_SEPOLIA_RPC_URL`: Set a URL for the Sepolia testnet. You can sign up for a personal endpoint from [Alchemy](https://www.alchemy.com/), [Infura](https://www.infura.io/), or another node provider service. - `PRIVATE_KEY`: Find the private key for your testnet wallet. If you use MetaMask, follow the instructions to [Export a Private Key](https://support.metamask.io/managing-my-wallet/secret-recovery-phrase-and-private-keys/how-to-export-an-accounts-private-key/). **Note**: Your private key is needed to sign any transactions you make such as making requests. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set ``` ### [Configure your onchain resources](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls\#configure-your-onchain-resources) After you configure your local environment, configure some onchain resources to process your requests, receive the responses, and pay for the work done by the DON. #### [Deploy a Functions consumer contract on _Sepolia_](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls\#deploy-a-functions-consumer-contract-on-sepolia) 1. [Open the FunctionsConsumerExample.sol contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol) in Remix. [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) 2. Compile the contract. 3. Open MetaMask and select the _Sepolia_ network. 4. In Remix under the **Deploy & Run Transactions** tab, select _Injected Provider - MetaMask_ in the **Environment** list. Remix will use the MetaMask wallet to communicate with _Sepolia_. 5. Under the **Deploy** section, fill in the router address for your specific blockchain. You can find both of these addresses on the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks) page. For _Sepolia_, the router address is `0xb83E47C2bC239B3bf370bc41e1459A34b41238D0`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg). 6. Click the **Deploy** button to deploy the contract. MetaMask prompts you to confirm the transaction. Check the transaction details to make sure you are deploying the contract to _Sepolia_. 7. After you confirm the transaction, the contract address appears in the **Deployed Contracts** list. Copy the contract address. #### [Create a subscription](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls\#create-a-subscription) Follow the [Managing Functions Subscriptions](https://docs.chain.link/chainlink-functions/resources/subscriptions#create-a-subscription) guide to accept the Chainlink Functions Terms of Service (ToS), create a subscription, fund it, then add your consumer contract address to it. You can find the Chainlink Functions Subscription Manager at [functions.chain.link](https://functions.chain.link/). ## [Tutorial](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls\#tutorial) This tutorial is configured to get the median `BTC/USD` price from multiple data sources. For a detailed explanation of the code example, read the [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls#examine-the-code) section. You can locate the scripts used in this tutorial in the [_examples/8-multiple-apis_ directory](https://github.com/smartcontractkit/smart-contract-examples/tree/main/functions-examples/examples/8-multiple-apis). 1. Make sure your subscription has enough LINK to pay for your requests. Also, you must maintain a minimum balance to upload encrypted secrets to the DON (Read the [minimum balance for uploading encrypted secrets section](https://docs.chain.link/chainlink-functions/resources/billing#minimum-balance-for-uploading-encrypted-secrets) to learn more). You can check your subscription details (including the balance in LINK) in the [Chainlink Functions Subscription Manager](https://docs.chain.link/chainlink-functions/resources/subscriptions). If your subscription runs out of LINK, follow the [Fund a Subscription](https://docs.chain.link/chainlink-functions/resources/subscriptions#fund-a-subscription) guide. This guide recommends maintaining at least 2 LINK within your subscription. 2. Get a free API key from [CoinMarketCap](https://coinmarketcap.com/api/) and note your API key. 3. Run `npx env-enc set` to add an encrypted `COINMARKETCAP_API_KEY` to your `.env.enc` file. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set ``` To run the example: 1. Open the file `request.js`, which is located in the `8-multiple-apis` folder. 2. Replace the consumer contract address and the subscription ID with your own values. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x8dFf78B7EE3128D00E90611FBeD20A71397064D9" // REPLACE this with your Functions consumer address const subscriptionId = 3 // REPLACE this with your subscription ID ``` 3. Make a request: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node examples/8-multiple-apis/request.js ``` The script runs your function in a sandbox environment before making an onchain transaction: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```text $ node examples/8-multiple-apis/request.js secp256k1 unavailable, reverting to browser version Start simulation... Simulation result { capturedTerminalOutput: 'Median Bitcoin price: 66822.81\n', responseBytesHexstring: '0x000000000000000000000000000000000000000000000000000000000065f6a9' } ✅ Decoded response to uint256: 6682281n Estimate request costs... Fulfillment cost estimated to 1.104471544715335 LINK Make request... Upload encrypted secret to gateways https://01.functions-gateway.testnet.chain.link/,https://02.functions-gateway.testnet.chain.link/. slotId 0. Expiration in minutes: 15 ✅ Secrets uploaded properly to gateways https://01.functions-gateway.testnet.chain.link/,https://02.functions-gateway.testnet.chain.link/! Gateways response: { version: 1712949659, success: true } ✅ Functions request sent! Transaction hash 0x8defda7d48f91efa4f7bfa8e7d99f115a4e1d71882852ee6e91f438542d840ec. Waiting for a response... See your request in the explorer https://sepolia.etherscan.io/tx/0x8defda7d48f91efa4f7bfa8e7d99f115a4e1d71882852ee6e91f438542d840ec ✅ Request 0xff18de309a7845ef99b042d008aa3c5e67c51e649b771cbaab7dd96fada66e27 successfully fulfilled. Cost is 0.25590956997723491 LINK.Complete response: { requestId: '0xff18de309a7845ef99b042d008aa3c5e67c51e649b771cbaab7dd96fada66e27', subscriptionId: 2303, totalCostInJuels: 255909569977234910n, responseBytesHexstring: '0x000000000000000000000000000000000000000000000000000000000065f6a9', errorString: '', returnDataBytesHexstring: '0x', fulfillmentCode: 0 } ✅ Decoded response to uint256: 6682281n ``` The output of the example gives you the following information: - Your request is first run on a sandbox environment to ensure it is correctly configured. - The fulfillment costs are estimated before making the request. - The encrypted secrets were uploaded to the secrets endpoint `https://01.functions-gateway.testnet.chain.link/user`. - Your request was successfully sent to Chainlink Functions. - The DON successfully fulfilled your request. The total cost was: `0.25590956997723491 LINK`. - The consumer contract received a response in `bytes` with a value of `0x000000000000000000000000000000000000000000000000000000000065f6a9`. Decoding it offchain to `uint256` gives you a result: `6682281`. The median BTC price is 66822.81 USD. ## [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls\#examine-the-code) ### [FunctionsConsumerExample.sol](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls\#functionsconsumerexamplesol) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; /** * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. * DO NOT USE THIS CODE IN PRODUCTION. */ contract FunctionsConsumerExample is FunctionsClient, ConfirmedOwner { using FunctionsRequest for FunctionsRequest.Request; bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; error UnexpectedRequestID(bytes32 requestId); event Response(bytes32 indexed requestId, bytes response, bytes err); constructor( address router ) FunctionsClient(router) ConfirmedOwner(msg.sender) {} /** * @notice Send a simple request * @param source JavaScript source code * @param encryptedSecretsUrls Encrypted URLs where to fetch user secrets * @param donHostedSecretsSlotID Don hosted secrets slotId * @param donHostedSecretsVersion Don hosted secrets version * @param args List of arguments accessible from within the source code * @param bytesArgs Array of bytes arguments, represented as hex strings * @param subscriptionId Billing ID */ function sendRequest( string memory source, bytes memory encryptedSecretsUrls, uint8 donHostedSecretsSlotID, uint64 donHostedSecretsVersion, string[] memory args, bytes[] memory bytesArgs, uint64 subscriptionId, uint32 gasLimit, bytes32 donID ) external onlyOwner returns (bytes32 requestId) { FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); if (encryptedSecretsUrls.length > 0) req.addSecretsReference(encryptedSecretsUrls); else if (donHostedSecretsVersion > 0) { req.addDONHostedSecrets( donHostedSecretsSlotID, donHostedSecretsVersion ); } if (args.length > 0) req.setArgs(args); if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Send a pre-encoded CBOR request * @param request CBOR-encoded request data * @param subscriptionId Billing ID * @param gasLimit The maximum amount of gas the request can consume * @param donID ID of the job to be invoked * @return requestId The ID of the sent request */ function sendRequestCBOR( bytes memory request, uint64 subscriptionId, uint32 gasLimit, bytes32 donID ) external onlyOwner returns (bytes32 requestId) { s_lastRequestId = _sendRequest( request, subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Store latest result/error * @param requestId The request ID, returned by sendRequest() * @param response Aggregated response from the user code * @param err Aggregated error from the user code or from the execution pipeline * Either response or error parameter will be set, but never both */ function fulfillRequest( bytes32 requestId, bytes memory response, bytes memory err ) internal override { if (s_lastRequestId != requestId) { revert UnexpectedRequestID(requestId); } s_lastResponse = response; s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); } } ``` [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) - To write a Chainlink Functions consumer contract, your contract must import [FunctionsClient.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol) and [FunctionsRequest.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol). You can read the API references: [FunctionsClient](https://docs.chain.link/chainlink-functions/api-reference/functions-client) and [FunctionsRequest](https://docs.chain.link/chainlink-functions/api-reference/functions-request). These contracts are available in an NPM package, so you can import them from within your project. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; ``` - Use the FunctionsRequest.sol library to get all the functions needed for building a Chainlink Functions request. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext using FunctionsRequest for FunctionsRequest.Request; ``` - The latest request id, latest received response, and latest received error (if any) are defined as state variables: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; ``` - We define the `Response` event that your smart contract will emit during the callback ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext event Response(bytes32 indexed requestId, bytes response, bytes err); ``` - Pass the router address for your network when you deploy the contract: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext constructor(address router) FunctionsClient(router) ``` - The three remaining functions are: - `sendRequest` for sending a request. It receives the JavaScript source code, encrypted secretsUrls (in case the encrypted secrets are hosted by the user), DON hosted secrets slot id and version (in case the encrypted secrets are hosted by the DON), list of arguments to pass to the source code, subscription id, and callback gas limit as parameters. Then: - It uses the `FunctionsRequest` library to initialize the request and add any passed encrypted secrets reference or arguments. You can read the API Reference for [Initializing a request](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#initializerequestforinlinejavascript), [adding user hosted secrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#addsecretsreference), [adding DON hosted secrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#adddonhostedsecrets), [adding arguments](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#setargs), and [adding bytes arguments](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#setbytesargs). ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); if (encryptedSecretsUrls.length > 0) req.addSecretsReference(encryptedSecretsUrls); else if (donHostedSecretsVersion > 0) { req.addDONHostedSecrets( donHostedSecretsSlotID, donHostedSecretsVersion ); } if (args.length > 0) req.setArgs(args); if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); ``` - It sends the request to the router by calling the `FunctionsClient` `sendRequest` function. You can read the API reference for [sending a request](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#_sendrequest). Finally, it stores the request id in `s_lastRequestId` then return it. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, jobId ); return s_lastRequestId; ``` **Note**: `_sendRequest` accepts requests encoded in `bytes`. Therefore, you must encode it using [encodeCBOR](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#encodecbor). - `sendRequestCBOR` for sending a request already encoded in `bytes`. It receives the request object encoded in `bytes`, subscription id, and callback gas limit as parameters. Then, it sends the request to the router by calling the `FunctionsClient` `sendRequest` function. **Note**: This function is helpful if you want to encode a request offchain before sending it, saving gas when submitting the request. - `fulfillRequest` to be invoked during the callback. This function is defined in `FunctionsClient` as `virtual` (read `fulfillRequest` [API reference](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#fulfillrequest)). So, your smart contract must override the function to implement the callback. The implementation of the callback is straightforward: the contract stores the latest response and error in `s_lastResponse` and `s_lastError` before emitting the `Response` event. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastResponse = response; s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); ``` ### [JavaScript example](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls\#javascript-example) #### [source.js](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls\#sourcejs) The Decentralized Oracle Network will run the [JavaScript code](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/8-multiple-apis/source.js). The code is self-explanatory and has comments to help you understand all the steps. This JavaScript source code uses [Functions.makeHttpRequest](https://docs.chain.link/chainlink-functions/api-reference/javascript-source#http-requests) to make HTTP requests. The source code fetches the BTC/USD price from different data sources: `https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest/`, `https://api.coingecko.com/api/v3/simple/price`, and `https://api.coinpaprika.com/v1/tickers/btc-bitcoin` and then calculate the median price. you can read the API docs of [CoinMarketCap](https://coinmarketcap.com/api/documentation/v1/), [CoinGecko](https://www.coingecko.com/en/api/documentation), and [CoinPaprika](https://api.coinpaprika.com/) for details. To check the expected API responses, run these commands in your terminal: - CoinMarketCap: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```bash curl -X 'GET' \ 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest?id=1&convert=USD' \ -H 'accept: application/json' \ -H 'X-CMC_PRO_API_KEY: REPLACE_WITH_YOUR_API_KEY' ``` - CoinGecko: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```bash curl -X 'GET' \ 'https://api.coingecko.com/api/v3/simple/price?vs_currencies=USD&ids=bitcoin' \ -H 'accept: application/json' ``` - Coinpaprika: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```bash curl -X 'GET' \ 'https://api.coinpaprika.com/v1/tickers/btc-bitcoin' \ -H 'accept: application/json' ``` The prices are respectively located at: - CoinMarketCap: `data,1,quote,USD,price` - CoinGecko: `bitcoin,usd` - Coinpaprika: `quotes,USD,price` The main steps of the scripts are: - Construct the HTTP objects `coinMarketCapRequest`, `coinGeckoRequest`, and `coinPaprikaRequest` using `Functions.makeHttpRequest`. The values for `coinMarketCapCoinId`, `coinGeckoCoinId`, and `coinPaprikaCoinId` are fetched from the `args`. - Make the HTTP calls. - Read the asset price from each response. - Calculate the median of all the prices. - Return the result as a [buffer](https://nodejs.org/api/buffer.html#buffer) using the `Functions.encodeUint256` helper function. Because solidity doesn't support decimals, multiply the result by `100` and round the result to the nearest integer. **Note**: Read this [article](https://www.freecodecamp.org/news/do-you-want-a-better-understanding-of-buffer-in-node-js-check-this-out-2e29de2968e8/) if you are new to Javascript Buffers and want to understand why they are important. #### [request.js](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls\#requestjs) This explanation focuses on the [request.js](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/8-multiple-apis/request.js) script and shows how to use the [Chainlink Functions NPM package](https://github.com/smartcontractkit/functions-toolkit) in your own JavaScript/TypeScript project to send requests to a DON. The code is self-explanatory and has comments to help you understand all the steps. The script imports: - [path](https://nodejs.org/docs/latest/api/path.html) and [fs](https://nodejs.org/api/fs.html) : Used to read the [source file](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/8-multiple-apis/source.js). - [ethers](https://docs.ethers.org/v5/): Ethers.js library, enables the script to interact with the blockchain. - `@chainlink/functions-toolkit`: Chainlink Functions NPM package. All its utilities are documented in the [NPM README](https://github.com/smartcontractkit/functions-toolkit/blob/main/README.md). - `@chainlink/env-enc`: A tool for loading and storing encrypted environment variables. Read the [official documentation](https://www.npmjs.com/package/@chainlink/env-enc) to learn more. - `../abi/functionsClient.json`: The ABI of the contract your script will interact with. **Note**: The script was tested with this [FunctionsConsumerExample contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol). The script has two hardcoded values that you have to change using your own Functions consumer contract and subscription ID: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x8dFf78B7EE3128D00E90611FBeD20A71397064D9" // REPLACE this with your Functions consumer address const subscriptionId = 3 // REPLACE this with your subscription ID ``` The primary function that the script executes is `makeRequestSepolia`. This function can be broken into six main parts: 1. Definition of necessary identifiers: - `routerAddress`: Chainlink Functions router address on Sepolia. - `donId`: Identifier of the DON that will fulfill your requests on Sepolia. - `gatewayUrls`: The secrets endpoint URL to which you will upload the encrypted secrets. - `explorerUrl`: Block explorer URL of the Sepolia testnet. - `source`: The source code must be a string object. That's why we use `fs.readFileSync` to read `source.js` and then call `toString()` to get the content as a `string` object. - `args`: During the execution of your function, These arguments are passed to the source code. The `args` value is `["1", "bitcoin", "btc-bitcoin"]`. These arguments are BTC IDs at CoinMarketCap, CoinGecko, and Coinpaprika. You can adapt args to fetch other asset prices. - `secrets`: The secrets object that will be encrypted. - `slotIdNumber`: Slot ID at the DON where to upload the encrypted secrets. - `expirationTimeMinutes`: Expiration time in minutes of the encrypted secrets. - `gasLimit`: Maximum gas that Chainlink Functions can use when transmitting the response to your contract. - Initialization of ethers `signer` and `provider` objects. The signer is used to make transactions on the blockchain, and the provider reads data from the blockchain. 2. Simulating your request in a local sandbox environment: - Use `simulateScript` from the Chainlink Functions NPM package. - Read the `response` of the simulation. If successful, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.uint256` in this example). 3. Estimating the costs: - Initialize a `SubscriptionManager` from the Functions NPM package, then call the `estimateFunctionsRequestCost` function. - The response is returned in Juels (1 LINK = 10\*\*18 Juels). Use the `ethers.utils.formatEther` utility function to convert the output to LINK. 4. Encrypt the secrets, then upload the encrypted secrets to the DON. This is done in two steps: - Initialize a `SecretsManager` instance from the Functions NPM package, then call the `encryptSecrets` function. - Call the `uploadEncryptedSecretsToDON` function of the `SecretsManager` instance. This function returns an object containing a `success` boolean as long as `version`, the secret version on the DON storage. **Note**: When making the request, you must pass the slot ID and version to tell the DON where to fetch the encrypted secrets. 5. Making a Chainlink Functions request: - Initialize your functions consumer contract using the contract address, abi, and ethers signer. - Call the `sendRequest` function of your consumer contract. 6. Waiting for the response: - Initialize a `ResponseListener` from the Functions NPM package and then call the `listenForResponseFromTransaction` function to wait for a response. By default, this function waits for five minutes. - Upon reception of the response, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.uint256` in this example). ## Get the latest Chainlink content straight to your inbox. Email Address ## API POST Data Tutorial [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [POST Data to an API](https://docs.chain.link/chainlink-functions/tutorials/api-post-data\#overview) This tutorial shows you how to send a request to a Decentralized Oracle Network to call the [Countries information GraphQL API](https://trevorblades.github.io/countries/queries/continent). After [OCR](https://docs.chain.link/chainlink-functions/resources/architecture) completes offchain computation and aggregation, it returns the name, capital, and currency for the specified country to your smart contract. Because the endpoint is a GraphQL API, write a function that sends a GraphQL query in a [POST HTTP method](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST). ## [Prerequisites](https://docs.chain.link/chainlink-functions/tutorials/api-post-data\#prerequisites) ### [Set up your environment](https://docs.chain.link/chainlink-functions/tutorials/api-post-data\#set-up-your-environment) You must provide the private key from a testnet wallet to run the examples in this documentation. Install a Web3 wallet, configure [Node.js](https://nodejs.org/en/download/), clone the [smartcontractkit/smart-contract-examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository, and configure a `.env.enc` file with the required environment variables. Install and configure your Web3 wallet for Ethereum Sepolia: 1. [Install Deno](https://docs.deno.com/runtime/manual/) so you can compile and simulate your Functions source code on your local machine. 2. [Install the MetaMask wallet](https://docs.chain.link/quickstarts/deploy-your-first-contract#install-and-fund-your-metamask-wallet) or other Ethereum Web3 wallet. 3. Set the network for your wallet to the Sepolia testnet. If you need to add Sepolia to your wallet, you can find the chain ID and the LINK token contract address on the [LINK Token Contracts](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) page. - [Sepolia testnet and LINK token contract](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) 4. Request testnet LINK and ETH from [faucets.chain.link/sepolia](https://faucets.chain.link/sepolia). Install the required frameworks and dependencies: 1. [Install the latest release of Node.js 20](https://nodejs.org/en/download/). Optionally, you can use the [nvm package](https://www.npmjs.com/package/nvm) to switch between Node.js versions with `nvm use 20`. **Note**: To ensure you are running the correct version in a terminal, type `node -v`. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node -v ``` ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell $ node -v v20.9.0 ``` 2. In a terminal, clone the [smart-contract examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository and change directories. This example repository imports the [Chainlink Functions Toolkit NPM package](https://www.npmjs.com/package/@chainlink/functions-toolkit). You can import this package to your own projects to enable them to work with Chainlink Functions. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell git clone https://github.com/smartcontractkit/smart-contract-examples.git && \ cd ./smart-contract-examples/functions-examples/ ``` 3. Run `npm install` to install the dependencies. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npm install ``` 4. For higher security, the examples repository encrypts your environment variables at rest. 1. Set an encryption password for your environment variables. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set-pw ``` 2. Run `npx env-enc set` to configure a `.env.enc` file with the basic variables that you need to send your requests to the Sepolia network. - `ETHEREUM_SEPOLIA_RPC_URL`: Set a URL for the Sepolia testnet. You can sign up for a personal endpoint from [Alchemy](https://www.alchemy.com/), [Infura](https://www.infura.io/), or another node provider service. - `PRIVATE_KEY`: Find the private key for your testnet wallet. If you use MetaMask, follow the instructions to [Export a Private Key](https://support.metamask.io/managing-my-wallet/secret-recovery-phrase-and-private-keys/how-to-export-an-accounts-private-key/). **Note**: Your private key is needed to sign any transactions you make such as making requests. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set ``` ### [Configure your onchain resources](https://docs.chain.link/chainlink-functions/tutorials/api-post-data\#configure-your-onchain-resources) After you configure your local environment, configure some onchain resources to process your requests, receive the responses, and pay for the work done by the DON. #### [Deploy a Functions consumer contract on _Sepolia_](https://docs.chain.link/chainlink-functions/tutorials/api-post-data\#deploy-a-functions-consumer-contract-on-sepolia) 1. [Open the FunctionsConsumerExample.sol contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol) in Remix. [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) 2. Compile the contract. 3. Open MetaMask and select the _Sepolia_ network. 4. In Remix under the **Deploy & Run Transactions** tab, select _Injected Provider - MetaMask_ in the **Environment** list. Remix will use the MetaMask wallet to communicate with _Sepolia_. 5. Under the **Deploy** section, fill in the router address for your specific blockchain. You can find both of these addresses on the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks) page. For _Sepolia_, the router address is `0xb83E47C2bC239B3bf370bc41e1459A34b41238D0`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg). 6. Click the **Deploy** button to deploy the contract. MetaMask prompts you to confirm the transaction. Check the transaction details to make sure you are deploying the contract to _Sepolia_. 7. After you confirm the transaction, the contract address appears in the **Deployed Contracts** list. Copy the contract address. #### [Create a subscription](https://docs.chain.link/chainlink-functions/tutorials/api-post-data\#create-a-subscription) Follow the [Managing Functions Subscriptions](https://docs.chain.link/chainlink-functions/resources/subscriptions#create-a-subscription) guide to accept the Chainlink Functions Terms of Service (ToS), create a subscription, fund it, then add your consumer contract address to it. You can find the Chainlink Functions Subscription Manager at [functions.chain.link](https://functions.chain.link/). ## [Tutorial](https://docs.chain.link/chainlink-functions/tutorials/api-post-data\#tutorial) This tutorial is configured to get the country name, capital, and currency from [countries.trevorblades.com](https://countries.trevorblades.com/) in one request. For a detailed explanation of the code example, read the [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/api-post-data#examine-the-code) section. You can locate the scripts used in this tutorial in the [_examples/4-post-data_ directory](https://github.com/smartcontractkit/smart-contract-examples/tree/main/functions-examples/examples/4-post-data). To run the example: 1. Open the file `request.js`, which is located in the `4-post-data` folder. 2. Replace the consumer contract address and the subscription ID with your own values. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x8dFf78B7EE3128D00E90611FBeD20A71397064D9" // REPLACE this with your Functions consumer address const subscriptionId = 3 // REPLACE this with your subscription ID ``` 3. Make a request: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node examples/4-post-data/request.js ``` The script runs your function in a sandbox environment before making an onchain transaction: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```text $ node examples/4-post-data/request.js secp256k1 unavailable, reverting to browser version Start simulation... Simulation result { capturedTerminalOutput: 'Get name, capital and currency for country code: JP\n' + 'HTTP POST Request to https://countries.trevorblades.com/\n' + 'country response { country: { name: "Japan", capital: "Tokyo", currency: "JPY" } }\n', responseBytesHexstring: '0x7b226e616d65223a224a6170616e222c226361706974616c223a22546f6b796f222c2263757272656e6379223a224a5059227d' } ✅ Decoded response to string: {"name":"Japan","capital":"Tokyo","currency":"JPY"} Estimate request costs... Fulfillment cost estimated to 1.007671833192655 LINK Make request... ✅ Functions request sent! Transaction hash 0x5a315eeebea90f4828d176906d13dd3133e8a8d9afa912b1f8c34e90e775d081. Waiting for a response... See your request in the explorer https://sepolia.etherscan.io/tx/0x5a315eeebea90f4828d176906d13dd3133e8a8d9afa912b1f8c34e90e775d081 ✅ Request 0xc760ee5ca5c73999ca9c4ce426b9d2d44eab4429d3110276e57c445537ad5ddd successfully fulfilled. Cost is 0.257726519296170771 LINK.Complete response: { requestId: '0xc760ee5ca5c73999ca9c4ce426b9d2d44eab4429d3110276e57c445537ad5ddd', subscriptionId: 2303, totalCostInJuels: 257726519296170771n, responseBytesHexstring: '0x7b226e616d65223a224a6170616e222c226361706974616c223a22546f6b796f222c2263757272656e6379223a224a5059227d', errorString: '', returnDataBytesHexstring: '0x', fulfillmentCode: 0 } ✅ Decoded response to string: {"name":"Japan","capital":"Tokyo","currency":"JPY"} ``` The output of the example gives you the following information: - Your request is first run on a sandbox environment to ensure it is correctly configured. - The fulfillment costs are estimated before making the request. - Your request was successfully sent to Chainlink Functions. The transaction in this example is [0x5a315eeebea90f4828d176906d13dd3133e8a8d9afa912b1f8c34e90e775d081](https://sepolia.etherscan.io/tx/0x5a315eeebea90f4828d176906d13dd3133e8a8d9afa912b1f8c34e90e775d081) and the request ID is `0xc760ee5ca5c73999ca9c4ce426b9d2d44eab4429d3110276e57c445537ad5ddd`. - The DON successfully fulfilled your request. The total cost was: `0.257726519296170771 LINK`. - The consumer contract received a response in `bytes` with a value of `0x7b226e616d65223a224a6170616e222c226361706974616c223a22546f6b796f222c2263757272656e6379223a224a5059227d`. Decoding it offchain to `string` gives you a result: `{"name":"Japan","capital":"Tokyo","currency":"JPY"}`. ## [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/api-post-data\#examine-the-code) ### [FunctionsConsumerExample.sol](https://docs.chain.link/chainlink-functions/tutorials/api-post-data\#functionsconsumerexamplesol) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; /** * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. * DO NOT USE THIS CODE IN PRODUCTION. */ contract FunctionsConsumerExample is FunctionsClient, ConfirmedOwner { using FunctionsRequest for FunctionsRequest.Request; bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; error UnexpectedRequestID(bytes32 requestId); event Response(bytes32 indexed requestId, bytes response, bytes err); constructor( address router ) FunctionsClient(router) ConfirmedOwner(msg.sender) {} /** * @notice Send a simple request * @param source JavaScript source code * @param encryptedSecretsUrls Encrypted URLs where to fetch user secrets * @param donHostedSecretsSlotID Don hosted secrets slotId * @param donHostedSecretsVersion Don hosted secrets version * @param args List of arguments accessible from within the source code * @param bytesArgs Array of bytes arguments, represented as hex strings * @param subscriptionId Billing ID */ function sendRequest( string memory source, bytes memory encryptedSecretsUrls, uint8 donHostedSecretsSlotID, uint64 donHostedSecretsVersion, string[] memory args, bytes[] memory bytesArgs, uint64 subscriptionId, uint32 gasLimit, bytes32 donID ) external onlyOwner returns (bytes32 requestId) { FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); if (encryptedSecretsUrls.length > 0) req.addSecretsReference(encryptedSecretsUrls); else if (donHostedSecretsVersion > 0) { req.addDONHostedSecrets( donHostedSecretsSlotID, donHostedSecretsVersion ); } if (args.length > 0) req.setArgs(args); if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Send a pre-encoded CBOR request * @param request CBOR-encoded request data * @param subscriptionId Billing ID * @param gasLimit The maximum amount of gas the request can consume * @param donID ID of the job to be invoked * @return requestId The ID of the sent request */ function sendRequestCBOR( bytes memory request, uint64 subscriptionId, uint32 gasLimit, bytes32 donID ) external onlyOwner returns (bytes32 requestId) { s_lastRequestId = _sendRequest( request, subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Store latest result/error * @param requestId The request ID, returned by sendRequest() * @param response Aggregated response from the user code * @param err Aggregated error from the user code or from the execution pipeline * Either response or error parameter will be set, but never both */ function fulfillRequest( bytes32 requestId, bytes memory response, bytes memory err ) internal override { if (s_lastRequestId != requestId) { revert UnexpectedRequestID(requestId); } s_lastResponse = response; s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); } } ``` [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) - To write a Chainlink Functions consumer contract, your contract must import [FunctionsClient.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol) and [FunctionsRequest.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol). You can read the API references: [FunctionsClient](https://docs.chain.link/chainlink-functions/api-reference/functions-client) and [FunctionsRequest](https://docs.chain.link/chainlink-functions/api-reference/functions-request). These contracts are available in an NPM package, so you can import them from within your project. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; ``` - Use the FunctionsRequest.sol library to get all the functions needed for building a Chainlink Functions request. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext using FunctionsRequest for FunctionsRequest.Request; ``` - The latest request id, latest received response, and latest received error (if any) are defined as state variables: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; ``` - We define the `Response` event that your smart contract will emit during the callback ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext event Response(bytes32 indexed requestId, bytes response, bytes err); ``` - Pass the router address for your network when you deploy the contract: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext constructor(address router) FunctionsClient(router) ``` - The three remaining functions are: - `sendRequest` for sending a request. It receives the JavaScript source code, encrypted secretsUrls (in case the encrypted secrets are hosted by the user), DON hosted secrets slot id and version (in case the encrypted secrets are hosted by the DON), list of arguments to pass to the source code, subscription id, and callback gas limit as parameters. Then: - It uses the `FunctionsRequest` library to initialize the request and add any passed encrypted secrets reference or arguments. You can read the API Reference for [Initializing a request](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#initializerequestforinlinejavascript), [adding user hosted secrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#addsecretsreference), [adding DON hosted secrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#adddonhostedsecrets), [adding arguments](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#setargs), and [adding bytes arguments](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#setbytesargs). ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); if (encryptedSecretsUrls.length > 0) req.addSecretsReference(encryptedSecretsUrls); else if (donHostedSecretsVersion > 0) { req.addDONHostedSecrets( donHostedSecretsSlotID, donHostedSecretsVersion ); } if (args.length > 0) req.setArgs(args); if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); ``` - It sends the request to the router by calling the `FunctionsClient` `sendRequest` function. You can read the API reference for [sending a request](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#_sendrequest). Finally, it stores the request id in `s_lastRequestId` then return it. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, jobId ); return s_lastRequestId; ``` **Note**: `_sendRequest` accepts requests encoded in `bytes`. Therefore, you must encode it using [encodeCBOR](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#encodecbor). - `sendRequestCBOR` for sending a request already encoded in `bytes`. It receives the request object encoded in `bytes`, subscription id, and callback gas limit as parameters. Then, it sends the request to the router by calling the `FunctionsClient` `sendRequest` function. **Note**: This function is helpful if you want to encode a request offchain before sending it, saving gas when submitting the request. - `fulfillRequest` to be invoked during the callback. This function is defined in `FunctionsClient` as `virtual` (read `fulfillRequest` [API reference](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#fulfillrequest)). So, your smart contract must override the function to implement the callback. The implementation of the callback is straightforward: the contract stores the latest response and error in `s_lastResponse` and `s_lastError` before emitting the `Response` event. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastResponse = response; s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); ``` ### [JavaScript example](https://docs.chain.link/chainlink-functions/tutorials/api-post-data\#javascript-example) #### [source.js](https://docs.chain.link/chainlink-functions/tutorials/api-post-data\#sourcejs) The Decentralized Oracle Network will run the [JavaScript code](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/4-post-data/source.js). The code is self-explanatory and has comments to help you understand all the steps. This JavaScript source code uses [Functions.makeHttpRequest](https://docs.chain.link/chainlink-functions/api-reference/javascript-source#http-requests) to make HTTP requests. To request the `JP` country information, the source code calls the `https://countries.trevorblades.com/` URL and provides the query data in the HTTP request body. If you read the [Functions.makeHttpRequest](https://docs.chain.link/chainlink-functions/api-reference/javascript-source#http-requests) documentation, you see that you must provide the following parameters: - url: `https://countries.trevorblades.com/` - data (HTTP body): ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext { query: `{\ country(code: "${countryCode}") { \ name \ capital \ currency \ } \ }`, } ``` To check the expected API response: - In your browser, open the countries GraphQL playground: `https://countries.trevorblades.com/` - Write this query: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext { country(code: "JP") { name capital currency } } ``` - Click on _play_ to get the answer : ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```json { "data": { "country": { "name": "Japan", "capital": "Tokyo", "currency": "JPY" } } } ``` The main steps of the scripts are: - Fetch the `countryCode` from `args`. - Construct the HTTP object `countryRequest` using `Functions.makeHttpRequest`. - Run the HTTP request. - Read the country name, capital, and currency from the response. - Construct a JSON object: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const result = { name: countryData.country.name, capital: countryData.country.capital, currency: countryData.country.currency, } ``` - Convert the JSON object to a JSON string using `JSON.stringify(result)`. This step is mandatory before encoding `string` to `bytes`. - Return the result as a [buffer](https://nodejs.org/api/buffer.html#buffer) using the `Functions.string` helper function. **Note**: Read this [article](https://www.freecodecamp.org/news/do-you-want-a-better-understanding-of-buffer-in-node-js-check-this-out-2e29de2968e8/) if you are new to Javascript Buffers and want to understand why they are important. #### [request.js](https://docs.chain.link/chainlink-functions/tutorials/api-post-data\#requestjs) This explanation focuses on the [request.js](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/4-post-data/request.js) script and shows how to use the [Chainlink Functions NPM package](https://github.com/smartcontractkit/functions-toolkit) in your own JavaScript/TypeScript project to send requests to a DON. The code is self-explanatory and has comments to help you understand all the steps. The script imports: - [path](https://nodejs.org/docs/latest/api/path.html) and [fs](https://nodejs.org/api/fs.html) : Used to read the [source file](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/4-post-data/source.js). - [ethers](https://docs.ethers.org/v5/): Ethers.js library, enables the script to interact with the blockchain. - `@chainlink/functions-toolkit`: Chainlink Functions NPM package. All its utilities are documented in the [NPM README](https://github.com/smartcontractkit/functions-toolkit/blob/main/README.md). - `@chainlink/env-enc`: A tool for loading and storing encrypted environment variables. Read the [official documentation](https://www.npmjs.com/package/@chainlink/env-enc) to learn more. - `../abi/functionsClient.json`: The abi of the contract your script will interact with. **Note**: The script was tested with this [FunctionsConsumerExample contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol). The script has two hardcoded values that you have to change using your own Functions consumer contract and subscription ID: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x8dFf78B7EE3128D00E90611FBeD20A71397064D9" // REPLACE this with your Functions consumer address const subscriptionId = 3 // REPLACE this with your subscription ID ``` The primary function that the script executes is `makeRequestSepolia`. This function consists of five main parts: 1. Definition of necessary identifiers: - `routerAddress`: Chainlink Functions router address on Sepolia. - `donId`: Identifier of the DON that will fulfill your requests on Sepolia. - `explorerUrl`: Block explorer URL of the Sepolia testnet. - `source`: The source code must be a string object. That's why we use `fs.readFileSync` to read `source.js` and then call `toString()` to get the content as a `string` object. - `args`: During the execution of your function, These arguments are passed to the source code. The `args` value is `["JP"]`, which fetches country data for Japan. - `gasLimit`: Maximum gas that Chainlink Functions can use when transmitting the response to your contract. - Initialization of ethers `signer` and `provider` objects. The signer is used to make transactions on the blockchain, and the provider reads data from the blockchain. 2. Simulating your request in a local sandbox environment: - Use `simulateScript` from the Chainlink Functions NPM package. - Read the `response` of the simulation. If successful, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.string` in this example). 3. Estimating the costs: - Initialize a `SubscriptionManager` from the Functions NPM package, then call the `estimateFunctionsRequestCost`. - The response is returned in Juels (1 LINK = 10\*\*18 Juels). Use the `ethers.utils.formatEther` utility function to convert the output to LINK. 4. Making a Chainlink Functions request: - Initialize your functions consumer contract using the contract address, abi, and ethers signer. - Call the `sendRequest` function of your consumer contract. 5. Waiting for the response: - Initialize a `ResponseListener` from the Functions NPM package and then call the `listenForResponseFromTransaction` function to wait for a response. By default, this function waits for five minutes. - Upon reception of the response, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.string` in this example). ## Get the latest Chainlink content straight to your inbox. Email Address ## API Query Parameters Tutorial [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Call an API with HTTP Query Parameters](https://docs.chain.link/chainlink-functions/tutorials/api-query-parameters\#overview) This tutorial shows you how to send a request to a Decentralized Oracle Network to call the [Cryptocompare GET /data/pricemultifull API](https://min-api.cryptocompare.com/documentation?key=Price&cat=multipleSymbolsFullPriceEndpoint). After [OCR](https://docs.chain.link/chainlink-functions/resources/architecture) completes offchain computation and aggregation, it returns the asset price for ETH/USD to your smart contract. This guide also shows you how to configure HTTP query parameters to request different asset prices. ## [Prerequisites](https://docs.chain.link/chainlink-functions/tutorials/api-query-parameters\#prerequisites) ### [Set up your environment](https://docs.chain.link/chainlink-functions/tutorials/api-query-parameters\#set-up-your-environment) You must provide the private key from a testnet wallet to run the examples in this documentation. Install a Web3 wallet, configure [Node.js](https://nodejs.org/en/download/), clone the [smartcontractkit/smart-contract-examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository, and configure a `.env.enc` file with the required environment variables. Install and configure your Web3 wallet for Ethereum Sepolia: 1. [Install Deno](https://docs.deno.com/runtime/manual/) so you can compile and simulate your Functions source code on your local machine. 2. [Install the MetaMask wallet](https://docs.chain.link/quickstarts/deploy-your-first-contract#install-and-fund-your-metamask-wallet) or other Ethereum Web3 wallet. 3. Set the network for your wallet to the Sepolia testnet. If you need to add Sepolia to your wallet, you can find the chain ID and the LINK token contract address on the [LINK Token Contracts](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) page. - [Sepolia testnet and LINK token contract](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) 4. Request testnet LINK and ETH from [faucets.chain.link/sepolia](https://faucets.chain.link/sepolia). Install the required frameworks and dependencies: 1. [Install the latest release of Node.js 20](https://nodejs.org/en/download/). Optionally, you can use the [nvm package](https://www.npmjs.com/package/nvm) to switch between Node.js versions with `nvm use 20`. **Note**: To ensure you are running the correct version in a terminal, type `node -v`. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node -v ``` ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell $ node -v v20.9.0 ``` 2. In a terminal, clone the [smart-contract examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository and change directories. This example repository imports the [Chainlink Functions Toolkit NPM package](https://www.npmjs.com/package/@chainlink/functions-toolkit). You can import this package to your own projects to enable them to work with Chainlink Functions. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell git clone https://github.com/smartcontractkit/smart-contract-examples.git && \ cd ./smart-contract-examples/functions-examples/ ``` 3. Run `npm install` to install the dependencies. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npm install ``` 4. For higher security, the examples repository encrypts your environment variables at rest. 1. Set an encryption password for your environment variables. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set-pw ``` 2. Run `npx env-enc set` to configure a `.env.enc` file with the basic variables that you need to send your requests to the Sepolia network. - `ETHEREUM_SEPOLIA_RPC_URL`: Set a URL for the Sepolia testnet. You can sign up for a personal endpoint from [Alchemy](https://www.alchemy.com/), [Infura](https://www.infura.io/), or another node provider service. - `PRIVATE_KEY`: Find the private key for your testnet wallet. If you use MetaMask, follow the instructions to [Export a Private Key](https://support.metamask.io/managing-my-wallet/secret-recovery-phrase-and-private-keys/how-to-export-an-accounts-private-key/). **Note**: Your private key is needed to sign any transactions you make such as making requests. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set ``` ### [Configure your onchain resources](https://docs.chain.link/chainlink-functions/tutorials/api-query-parameters\#configure-your-onchain-resources) After you configure your local environment, configure some onchain resources to process your requests, receive the responses, and pay for the work done by the DON. #### [Deploy a Functions consumer contract on _Sepolia_](https://docs.chain.link/chainlink-functions/tutorials/api-query-parameters\#deploy-a-functions-consumer-contract-on-sepolia) 1. [Open the FunctionsConsumerExample.sol contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol) in Remix. [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) 2. Compile the contract. 3. Open MetaMask and select the _Sepolia_ network. 4. In Remix under the **Deploy & Run Transactions** tab, select _Injected Provider - MetaMask_ in the **Environment** list. Remix will use the MetaMask wallet to communicate with _Sepolia_. 5. Under the **Deploy** section, fill in the router address for your specific blockchain. You can find both of these addresses on the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks) page. For _Sepolia_, the router address is `0xb83E47C2bC239B3bf370bc41e1459A34b41238D0`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg). 6. Click the **Deploy** button to deploy the contract. MetaMask prompts you to confirm the transaction. Check the transaction details to make sure you are deploying the contract to _Sepolia_. 7. After you confirm the transaction, the contract address appears in the **Deployed Contracts** list. Copy the contract address. #### [Create a subscription](https://docs.chain.link/chainlink-functions/tutorials/api-query-parameters\#create-a-subscription) Follow the [Managing Functions Subscriptions](https://docs.chain.link/chainlink-functions/resources/subscriptions#create-a-subscription) guide to accept the Chainlink Functions Terms of Service (ToS), create a subscription, fund it, then add your consumer contract address to it. You can find the Chainlink Functions Subscription Manager at [functions.chain.link](https://functions.chain.link/). ## [Tutorial](https://docs.chain.link/chainlink-functions/tutorials/api-query-parameters\#tutorial) This tutorial is configured to get the `ETH/USD` price. For a detailed explanation of the code example, read the [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/api-query-parameters#examine-the-code) section. You can locate the scripts used in this tutorial in the [_examples/2-call-api_ directory](https://github.com/smartcontractkit/smart-contract-examples/tree/main/functions-examples/examples/2-call-api). To run the example: 1. Open the file `request.js`, which is located in the `2-call-api` folder. 2. Replace the consumer contract address and the subscription ID with your own values. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x8dFf78B7EE3128D00E90611FBeD20A71397064D9" // REPLACE this with your Functions consumer address const subscriptionId = 3 // REPLACE this with your subscription ID ``` 3. Make a request: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node examples/2-call-api/request.js ``` The script runs your function in a sandbox environment before making an onchain transaction: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```text $ node examples/2-call-api/request.js secp256k1 unavailable, reverting to browser version Start simulation... Simulation result { capturedTerminalOutput: 'HTTP GET Request to https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD\n' + 'ETH price is: 3420.54 USD\n', responseBytesHexstring: '0x0000000000000000000000000000000000000000000000000000000000053826' } ✅ Decoded response to uint256: 342054n Estimate request costs... Fulfillment cost estimated to 1.004325887213695 LINK Make request... ✅ Functions request sent! Transaction hash 0xbbe473ccc6593b6f3baf30fd66b2329b05a32fe0321a319d09142f4b9ba4547c. Waiting for a response... See your request in the explorer https://sepolia.etherscan.io/tx/0xbbe473ccc6593b6f3baf30fd66b2329b05a32fe0321a319d09142f4b9ba4547c ✅ Request 0xe55201188012e3ec198427937f7897729999ab7b287207ff8f0c157a9662e5f0 successfully fulfilled. Cost is 0.249819373001796045 LINK.Complete response: { requestId: '0xe55201188012e3ec198427937f7897729999ab7b287207ff8f0c157a9662e5f0', subscriptionId: 2303, totalCostInJuels: 249819373001796045n, responseBytesHexstring: '0x0000000000000000000000000000000000000000000000000000000000053892', errorString: '', returnDataBytesHexstring: '0x', fulfillmentCode: 0 } ✅ Decoded response to uint256: 342162n ``` The output of the example gives you the following information: - Your request is first run on a sandbox environment to ensure it is correctly configured. - The fulfillment costs are estimated before making the request. - Your request was successfully sent to Chainlink Functions. The transaction in this example is [0xbbe473ccc6593b6f3baf30fd66b2329b05a32fe0321a319d09142f4b9ba4547c](https://sepolia.etherscan.io/tx/0xbbe473ccc6593b6f3baf30fd66b2329b05a32fe0321a319d09142f4b9ba4547c) and the request ID is `0xe55201188012e3ec198427937f7897729999ab7b287207ff8f0c157a9662e5f0`. - The DON successfully fulfilled your request. The total cost was: `0.249819373001796045 LINK`. - The consumer contract received a response in `bytes` with a value of `0x0000000000000000000000000000000000000000000000000000000000053892`. Decoding it offchain to `uint256` gives you a result: `342162`. ## [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/api-query-parameters\#examine-the-code) ### [FunctionsConsumerExample.sol](https://docs.chain.link/chainlink-functions/tutorials/api-query-parameters\#functionsconsumerexamplesol) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; /** * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. * DO NOT USE THIS CODE IN PRODUCTION. */ contract FunctionsConsumerExample is FunctionsClient, ConfirmedOwner { using FunctionsRequest for FunctionsRequest.Request; bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; error UnexpectedRequestID(bytes32 requestId); event Response(bytes32 indexed requestId, bytes response, bytes err); constructor( address router ) FunctionsClient(router) ConfirmedOwner(msg.sender) {} /** * @notice Send a simple request * @param source JavaScript source code * @param encryptedSecretsUrls Encrypted URLs where to fetch user secrets * @param donHostedSecretsSlotID Don hosted secrets slotId * @param donHostedSecretsVersion Don hosted secrets version * @param args List of arguments accessible from within the source code * @param bytesArgs Array of bytes arguments, represented as hex strings * @param subscriptionId Billing ID */ function sendRequest( string memory source, bytes memory encryptedSecretsUrls, uint8 donHostedSecretsSlotID, uint64 donHostedSecretsVersion, string[] memory args, bytes[] memory bytesArgs, uint64 subscriptionId, uint32 gasLimit, bytes32 donID ) external onlyOwner returns (bytes32 requestId) { FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); if (encryptedSecretsUrls.length > 0) req.addSecretsReference(encryptedSecretsUrls); else if (donHostedSecretsVersion > 0) { req.addDONHostedSecrets( donHostedSecretsSlotID, donHostedSecretsVersion ); } if (args.length > 0) req.setArgs(args); if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Send a pre-encoded CBOR request * @param request CBOR-encoded request data * @param subscriptionId Billing ID * @param gasLimit The maximum amount of gas the request can consume * @param donID ID of the job to be invoked * @return requestId The ID of the sent request */ function sendRequestCBOR( bytes memory request, uint64 subscriptionId, uint32 gasLimit, bytes32 donID ) external onlyOwner returns (bytes32 requestId) { s_lastRequestId = _sendRequest( request, subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Store latest result/error * @param requestId The request ID, returned by sendRequest() * @param response Aggregated response from the user code * @param err Aggregated error from the user code or from the execution pipeline * Either response or error parameter will be set, but never both */ function fulfillRequest( bytes32 requestId, bytes memory response, bytes memory err ) internal override { if (s_lastRequestId != requestId) { revert UnexpectedRequestID(requestId); } s_lastResponse = response; s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); } } ``` [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) - To write a Chainlink Functions consumer contract, your contract must import [FunctionsClient.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol) and [FunctionsRequest.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol). You can read the API references: [FunctionsClient](https://docs.chain.link/chainlink-functions/api-reference/functions-client) and [FunctionsRequest](https://docs.chain.link/chainlink-functions/api-reference/functions-request). These contracts are available in an NPM package, so you can import them from within your project. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; ``` - Use the FunctionsRequest.sol library to get all the functions needed for building a Chainlink Functions request. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext using FunctionsRequest for FunctionsRequest.Request; ``` - The latest request id, latest received response, and latest received error (if any) are defined as state variables: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; ``` - We define the `Response` event that your smart contract will emit during the callback ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext event Response(bytes32 indexed requestId, bytes response, bytes err); ``` - Pass the router address for your network when you deploy the contract: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext constructor(address router) FunctionsClient(router) ``` - The three remaining functions are: - `sendRequest` for sending a request. It receives the JavaScript source code, encrypted secretsUrls (in case the encrypted secrets are hosted by the user), DON hosted secrets slot id and version (in case the encrypted secrets are hosted by the DON), list of arguments to pass to the source code, subscription id, and callback gas limit as parameters. Then: - It uses the `FunctionsRequest` library to initialize the request and add any passed encrypted secrets reference or arguments. You can read the API Reference for [Initializing a request](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#initializerequestforinlinejavascript), [adding user hosted secrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#addsecretsreference), [adding DON hosted secrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#adddonhostedsecrets), [adding arguments](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#setargs), and [adding bytes arguments](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#setbytesargs). ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); if (encryptedSecretsUrls.length > 0) req.addSecretsReference(encryptedSecretsUrls); else if (donHostedSecretsVersion > 0) { req.addDONHostedSecrets( donHostedSecretsSlotID, donHostedSecretsVersion ); } if (args.length > 0) req.setArgs(args); if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); ``` - It sends the request to the router by calling the `FunctionsClient` `sendRequest` function. You can read the API reference for [sending a request](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#_sendrequest). Finally, it stores the request id in `s_lastRequestId` then return it. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, jobId ); return s_lastRequestId; ``` **Note**: `_sendRequest` accepts requests encoded in `bytes`. Therefore, you must encode it using [encodeCBOR](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#encodecbor). - `sendRequestCBOR` for sending a request already encoded in `bytes`. It receives the request object encoded in `bytes`, subscription id, and callback gas limit as parameters. Then, it sends the request to the router by calling the `FunctionsClient` `sendRequest` function. **Note**: This function is helpful if you want to encode a request offchain before sending it, saving gas when submitting the request. - `fulfillRequest` to be invoked during the callback. This function is defined in `FunctionsClient` as `virtual` (read `fulfillRequest` [API reference](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#fulfillrequest)). So, your smart contract must override the function to implement the callback. The implementation of the callback is straightforward: the contract stores the latest response and error in `s_lastResponse` and `s_lastError` before emitting the `Response` event. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastResponse = response; s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); ``` ### [JavaScript example](https://docs.chain.link/chainlink-functions/tutorials/api-query-parameters\#javascript-example) #### [source.js](https://docs.chain.link/chainlink-functions/tutorials/api-query-parameters\#sourcejs) The Decentralized Oracle Network will run the [JavaScript code](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/2-call-api/source.js). The code is self-explanatory and has comments to help you understand all the steps. This JavaScript source code uses [Functions.makeHttpRequest](https://docs.chain.link/chainlink-functions/api-reference/javascript-source#http-requests) to make HTTP requests. To request the `ETH/USD` price, the source code calls the `https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD` URL. If you read the [Functions.makeHttpRequest](https://docs.chain.link/chainlink-functions/api-reference/javascript-source#http-requests) documentation, you see that you must provide the following parameters: - `url`: `https://min-api.cryptocompare.com/data/pricemultifull` - `params`: The query parameters object: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext { fsyms: fromSymbol, tsyms: toSymbol } ``` To check the expected API response, you can directly paste the following URL in your browser `https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD` or run the `curl` command in your terminal: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```bash curl -X 'GET' \ 'https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD' \ -H 'accept: application/json' ``` The response should be similar to the following example: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```json { "RAW": { "ETH": { "USD": { "TYPE": "5", "MARKET": "CCCAGG", "FROMSYMBOL": "ETH", "TOSYMBOL": "USD", "FLAGS": "2049", "PRICE": 2867.04, "LASTUPDATE": 1650896942, "MEDIAN": 2866.2, "LASTVOLUME": 0.16533939, "LASTVOLUMETO": 474.375243849, "LASTTRADEID": "1072154517", "VOLUMEDAY": 195241.78281014622, "VOLUMEDAYTO": 556240560.4621655, "VOLUME24HOUR": 236248.94641103, ... } ``` The price is located at `RAW,ETH,USD,PRICE`. The main steps of the scripts are: - Fetch `fromSymbol` and `toSymbol` from `args`. - Construct the HTTP object `cryptoCompareRequest` using `Functions.makeHttpRequest`. - Make the HTTP call. - Read the asset price from the response. - Return the result as a [buffer](https://nodejs.org/api/buffer.html#buffer) using the `Functions.encodeUint256` helper function. Because solidity doesn't support decimals, multiply the result by `100` and round the result to the nearest integer. **Note**: Read this [article](https://www.freecodecamp.org/news/do-you-want-a-better-understanding-of-buffer-in-node-js-check-this-out-2e29de2968e8/) if you are new to Javascript Buffers and want to understand why they are important. #### [request.js](https://docs.chain.link/chainlink-functions/tutorials/api-query-parameters\#requestjs) This explanation focuses on the [request.js](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/2-call-api/request.js) script and shows how to use the [Chainlink Functions NPM package](https://github.com/smartcontractkit/functions-toolkit) in your own JavaScript/TypeScript project to send requests to a DON. The code is self-explanatory and has comments to help you understand all the steps. The script imports: - [path](https://nodejs.org/docs/latest/api/path.html) and [fs](https://nodejs.org/api/fs.html) : Used to read the [source file](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/2-call-api/source.js). - [ethers](https://docs.ethers.org/v5/): Ethers.js library, enables the script to interact with the blockchain. - `@chainlink/functions-toolkit`: Chainlink Functions NPM package. All its utilities are documented in the [NPM README](https://github.com/smartcontractkit/functions-toolkit/blob/main/README.md). - `@chainlink/env-enc`: A tool for loading and storing encrypted environment variables. Read the [official documentation](https://www.npmjs.com/package/@chainlink/env-enc) to learn more. - `../abi/functionsClient.json`: The abi of the contract your script will interact with. **Note**: The script was tested with this [FunctionsConsumerExample contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol). The script has two hardcoded values that you have to change using your own Functions consumer contract and subscription ID: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x8dFf78B7EE3128D00E90611FBeD20A71397064D9" // REPLACE this with your Functions consumer address const subscriptionId = 3 // REPLACE this with your subscription ID ``` The primary function that the script executes is `makeRequestSepolia`. This function consists of five main parts: 1. Definition of necessary identifiers: - `routerAddress`: Chainlink Functions router address on Sepolia. - `donId`: Identifier of the DON that will fulfill your requests on Sepolia. - `explorerUrl`: Block explorer URL of the Sepolia testnet. - `source`: The source code must be a string object. That's why we use `fs.readFileSync` to read `source.js` and then call `toString()` to get the content as a `string` object. - `args`: During the execution of your function, These arguments are passed to the source code. The `args` value is `["ETH", "USD"]`, which fetches the current `ETH/USD` price. You can adapt `args` to fetch another asset price. See the [CryptoCompare API docs](https://min-api.cryptocompare.com/documentation?key=Price&cat=multipleSymbolsFullPriceEndpoint) to get the list of supported symbols. - `gasLimit`: Maximum gas that Chainlink Functions can use when transmitting the response to your contract. - Initialization of ethers `signer` and `provider` objects. The signer is used to make transactions on the blockchain, and the provider reads data from the blockchain. 2. Simulating your request in a local sandbox environment: - Use `simulateScript` from the Chainlink Functions NPM package. - Read the `response` of the simulation. If successful, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.uint256` in this example). 3. Estimating the costs: - Initialize a `SubscriptionManager` from the Functions NPM package, then call the `estimateFunctionsRequestCost`. - The response is returned in Juels (1 LINK = 10\*\*18 Juels). Use the `ethers.utils.formatEther` utility function to convert the output to LINK. 4. Making a Chainlink Functions request: - Initialize your functions consumer contract using the contract address, abi, and ethers signer. - Call the `sendRequest` function of your consumer contract. 5. Waiting for the response: - Initialize a `ResponseListener` from the Functions NPM package and then call the `listenForResponseFromTransaction` function to wait for a response. By default, this function waits for five minutes. - Upon reception of the response, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.uint256` in this example). ## Get the latest Chainlink content straight to your inbox. Email Address ## API Secrets Tutorial [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Using User-hosted (gist) Secrets in Requests](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-gist\#overview) This tutorial shows you how to send a request to a Decentralized Oracle Network to call the [Coinmarketcap API](https://coinmarketcap.com/api/documentation/v1/). After [OCR](https://docs.chain.link/chainlink-functions/resources/architecture) completes offchain computation and aggregation, it returns the `BTC/USD` asset price to your smart contract. Because the API requires you to provide an API key, this guide will also show you how to encrypt, sign your API key, and share the encrypted secret offchain with a Decentralized Oracle Network (DON). The encrypted secrets are never stored onchain. This tutorial uses the threshold encryption feature. The encrypted secrets are stored by the user as [gists](https://docs.github.com/en/get-started/writing-on-github/editing-and-sharing-content-with-gists/creating-gists). Read the [Secrets Management page](https://docs.chain.link/chainlink-functions/resources/secrets) to learn more. Read the [Using Secrets in Requests](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets) tutorial before you follow the steps in this example. This tutorial uses the same example but with a slightly different process: 1. Instead of uploading the encrypted secrets to the DON, you will host your encrypted secrets as gist. 2. Encrypt the gist URL. 3. Include the encrypted gist URL in your Chainlink Functions request. ## [Prerequisites](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-gist\#prerequisites) ### [Set up your environment](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-gist\#set-up-your-environment) You must provide the private key from a testnet wallet to run the examples in this documentation. Install a Web3 wallet, configure [Node.js](https://nodejs.org/en/download/), clone the [smartcontractkit/smart-contract-examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository, and configure a `.env.enc` file with the required environment variables. Install and configure your Web3 wallet for Ethereum Sepolia: 1. [Install Deno](https://docs.deno.com/runtime/manual/) so you can compile and simulate your Functions source code on your local machine. 2. [Install the MetaMask wallet](https://docs.chain.link/quickstarts/deploy-your-first-contract#install-and-fund-your-metamask-wallet) or other Ethereum Web3 wallet. 3. Set the network for your wallet to the Sepolia testnet. If you need to add Sepolia to your wallet, you can find the chain ID and the LINK token contract address on the [LINK Token Contracts](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) page. - [Sepolia testnet and LINK token contract](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) 4. Request testnet LINK and ETH from [faucets.chain.link/sepolia](https://faucets.chain.link/sepolia). Install the required frameworks and dependencies: 1. [Install the latest release of Node.js 20](https://nodejs.org/en/download/). Optionally, you can use the [nvm package](https://www.npmjs.com/package/nvm) to switch between Node.js versions with `nvm use 20`. **Note**: To ensure you are running the correct version in a terminal, type `node -v`. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node -v ``` ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell $ node -v v20.9.0 ``` 2. In a terminal, clone the [smart-contract examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository and change directories. This example repository imports the [Chainlink Functions Toolkit NPM package](https://www.npmjs.com/package/@chainlink/functions-toolkit). You can import this package to your own projects to enable them to work with Chainlink Functions. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell git clone https://github.com/smartcontractkit/smart-contract-examples.git && \ cd ./smart-contract-examples/functions-examples/ ``` 3. Run `npm install` to install the dependencies. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npm install ``` 4. For higher security, the examples repository encrypts your environment variables at rest. 1. Set an encryption password for your environment variables. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set-pw ``` 2. Run `npx env-enc set` to configure a `.env.enc` file with the basic variables that you need to send your requests to the Sepolia network. - `ETHEREUM_SEPOLIA_RPC_URL`: Set a URL for the Sepolia testnet. You can sign up for a personal endpoint from [Alchemy](https://www.alchemy.com/), [Infura](https://www.infura.io/), or another node provider service. - `PRIVATE_KEY`: Find the private key for your testnet wallet. If you use MetaMask, follow the instructions to [Export a Private Key](https://support.metamask.io/managing-my-wallet/secret-recovery-phrase-and-private-keys/how-to-export-an-accounts-private-key/). **Note**: Your private key is needed to sign any transactions you make such as making requests. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set ``` ### [Configure your onchain resources](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-gist\#configure-your-onchain-resources) After you configure your local environment, configure some onchain resources to process your requests, receive the responses, and pay for the work done by the DON. #### [Deploy a Functions consumer contract on _Sepolia_](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-gist\#deploy-a-functions-consumer-contract-on-sepolia) 1. [Open the FunctionsConsumerExample.sol contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol) in Remix. [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) 2. Compile the contract. 3. Open MetaMask and select the _Sepolia_ network. 4. In Remix under the **Deploy & Run Transactions** tab, select _Injected Provider - MetaMask_ in the **Environment** list. Remix will use the MetaMask wallet to communicate with _Sepolia_. 5. Under the **Deploy** section, fill in the router address for your specific blockchain. You can find both of these addresses on the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks) page. For _Sepolia_, the router address is `0xb83E47C2bC239B3bf370bc41e1459A34b41238D0`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg). 6. Click the **Deploy** button to deploy the contract. MetaMask prompts you to confirm the transaction. Check the transaction details to make sure you are deploying the contract to _Sepolia_. 7. After you confirm the transaction, the contract address appears in the **Deployed Contracts** list. Copy the contract address. #### [Create a subscription](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-gist\#create-a-subscription) Follow the [Managing Functions Subscriptions](https://docs.chain.link/chainlink-functions/resources/subscriptions#create-a-subscription) guide to accept the Chainlink Functions Terms of Service (ToS), create a subscription, fund it, then add your consumer contract address to it. You can find the Chainlink Functions Subscription Manager at [functions.chain.link](https://functions.chain.link/). ## [Tutorial](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-gist\#tutorial) This tutorial is configured to get the `BTC/USD` price with a request that requires API keys. For a detailed explanation of the code example, read the [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-gist#examine-the-code) section. You can locate the scripts used in this tutorial in the [_examples/6-use-secrets-gist_ directory](https://github.com/smartcontractkit/smart-contract-examples/tree/main/functions-examples/examples/6-use-secrets-gist). 1. Get a free API key from [CoinMarketCap](https://coinmarketcap.com/api/) and note your API key. 2. The [request.js](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/6-use-secrets-gist/request.js) example stores encrypted secrets as [gists](https://docs.github.com/en/get-started/writing-on-github/editing-and-sharing-content-with-gists/creating-gists) to share them offchain with the Decentralized Oracle Network. To allow the `request.js` script to write gists on your behalf, create a [github fine-grained personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token#creating-a-fine-grained-personal-access-token). 1. Visit [Github tokens settings page](https://github.com/settings/tokens?type=beta). 2. Click on _Generate new token_. 3. Provide a name to your token and define the expiration date. 4. Under `Account permissions`, enable _Read and write_ for Gists. **Note**: Do not enable additional settings. 5. Click on _Generate token_ and copy your fine-grained personal access token. 3. Run `npx env-enc set` to add an encrypted `GITHUB_API_TOKEN` and `COINMARKETCAP_API_KEY` to your `.env.enc` file. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set ``` To run the example: 1. Open the file `request.js`, which is located in the `6-use-secrets-gist` folder. 2. Replace the consumer contract address and the subscription ID with your own values. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x8dFf78B7EE3128D00E90611FBeD20A71397064D9" // REPLACE this with your Functions consumer address const subscriptionId = 3 // REPLACE this with your subscription ID ``` 3. Make a request: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node examples/6-use-secrets-gist/request.js ``` The script runs your function in a sandbox environment before making an onchain transaction: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```text $ node examples/6-use-secrets-gist/request.js secp256k1 unavailable, reverting to browser version Start simulation... Simulation result { capturedTerminalOutput: 'Price: 66918.25 USD\n', responseBytesHexstring: '0x0000000000000000000000000000000000000000000000000000000000661bf1' } ✅ Decoded response to uint256: 6691825n Estimate request costs... Fulfillment cost estimated to 1.104471544715335 LINK Make request... Creating gist... ✅Gist created https://gist.github.com/thedriftofwords/f00db83b79df7e064253a3f396aee1f7/raw . Encrypt the URLs.. ✅ Functions request sent! Transaction hash 0xe5db77b3994e0c30934dbac779608af0b08eb9ddf57fb121c0f481a95ea9b579. Waiting for a response... See your request in the explorer https://sepolia.etherscan.io/tx/0xe5db77b3994e0c30934dbac779608af0b08eb9ddf57fb121c0f481a95ea9b579 ✅ Request 0x37f860fba46af84b84f5ce48efbb7c6ebbfb2ecde5063621f695bbd1c2547975 successfully fulfilled. Cost is 0.237283011969506455 LINK.Complete response: { requestId: '0x37f860fba46af84b84f5ce48efbb7c6ebbfb2ecde5063621f695bbd1c2547975', subscriptionId: 2303, totalCostInJuels: 237283011969506455n, responseBytesHexstring: '0x0000000000000000000000000000000000000000000000000000000000661bf1', errorString: '', returnDataBytesHexstring: '0x', fulfillmentCode: 0 } ✅ Decoded response to uint256: 6691825n Delete gistUrl https://gist.github.com/thedriftofwords/f00db83b79df7e064253a3f396aee1f7/raw ✅ Gist https://gist.github.com/thedriftofwords/f00db83b79df7e064253a3f396aee1f7/raw deleted ``` The output of the example gives you the following information: - Your request is first run on a sandbox environment to ensure it is correctly configured. - The fulfillment costs are estimated before making the request. - A gist `https://gist.github.com/thedriftofwords/f00db83b79df7e064253a3f396aee1f7/raw` containing the encrypted secrets was created . - The gist URL is encrypted before sending it in the request. - Your request was successfully sent to Chainlink Functions. The transaction in this example is [0xe5db77b3994e0c30934dbac779608af0b08eb9ddf57fb121c0f481a95ea9b579](https://sepolia.etherscan.io/tx/0xe5db77b3994e0c30934dbac779608af0b08eb9ddf57fb121c0f481a95ea9b579) and the request ID is `0x37f860fba46af84b84f5ce48efbb7c6ebbfb2ecde5063621f695bbd1c2547975`. - The DON successfully fulfilled your request. The total cost was: `0.237283011969506455 LINK`. - The consumer contract received a response in `bytes` with a value of `0x0000000000000000000000000000000000000000000000000000000000661bf1`. Decoding it offchain to `uint256` gives you a result: `6691825`. - After the request is fulfilled, the gist `https://gist.github.com/thedriftofwords/f00db83b79df7e064253a3f396aee1f7/raw` is deleted. ## [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-gist\#examine-the-code) ### [FunctionsConsumerExample.sol](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-gist\#functionsconsumerexamplesol) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; /** * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. * DO NOT USE THIS CODE IN PRODUCTION. */ contract FunctionsConsumerExample is FunctionsClient, ConfirmedOwner { using FunctionsRequest for FunctionsRequest.Request; bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; error UnexpectedRequestID(bytes32 requestId); event Response(bytes32 indexed requestId, bytes response, bytes err); constructor( address router ) FunctionsClient(router) ConfirmedOwner(msg.sender) {} /** * @notice Send a simple request * @param source JavaScript source code * @param encryptedSecretsUrls Encrypted URLs where to fetch user secrets * @param donHostedSecretsSlotID Don hosted secrets slotId * @param donHostedSecretsVersion Don hosted secrets version * @param args List of arguments accessible from within the source code * @param bytesArgs Array of bytes arguments, represented as hex strings * @param subscriptionId Billing ID */ function sendRequest( string memory source, bytes memory encryptedSecretsUrls, uint8 donHostedSecretsSlotID, uint64 donHostedSecretsVersion, string[] memory args, bytes[] memory bytesArgs, uint64 subscriptionId, uint32 gasLimit, bytes32 donID ) external onlyOwner returns (bytes32 requestId) { FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); if (encryptedSecretsUrls.length > 0) req.addSecretsReference(encryptedSecretsUrls); else if (donHostedSecretsVersion > 0) { req.addDONHostedSecrets( donHostedSecretsSlotID, donHostedSecretsVersion ); } if (args.length > 0) req.setArgs(args); if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Send a pre-encoded CBOR request * @param request CBOR-encoded request data * @param subscriptionId Billing ID * @param gasLimit The maximum amount of gas the request can consume * @param donID ID of the job to be invoked * @return requestId The ID of the sent request */ function sendRequestCBOR( bytes memory request, uint64 subscriptionId, uint32 gasLimit, bytes32 donID ) external onlyOwner returns (bytes32 requestId) { s_lastRequestId = _sendRequest( request, subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Store latest result/error * @param requestId The request ID, returned by sendRequest() * @param response Aggregated response from the user code * @param err Aggregated error from the user code or from the execution pipeline * Either response or error parameter will be set, but never both */ function fulfillRequest( bytes32 requestId, bytes memory response, bytes memory err ) internal override { if (s_lastRequestId != requestId) { revert UnexpectedRequestID(requestId); } s_lastResponse = response; s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); } } ``` [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) - To write a Chainlink Functions consumer contract, your contract must import [FunctionsClient.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol) and [FunctionsRequest.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol). You can read the API references: [FunctionsClient](https://docs.chain.link/chainlink-functions/api-reference/functions-client) and [FunctionsRequest](https://docs.chain.link/chainlink-functions/api-reference/functions-request). These contracts are available in an NPM package, so you can import them from within your project. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; ``` - Use the FunctionsRequest.sol library to get all the functions needed for building a Chainlink Functions request. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext using FunctionsRequest for FunctionsRequest.Request; ``` - The latest request id, latest received response, and latest received error (if any) are defined as state variables: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; ``` - We define the `Response` event that your smart contract will emit during the callback ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext event Response(bytes32 indexed requestId, bytes response, bytes err); ``` - Pass the router address for your network when you deploy the contract: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext constructor(address router) FunctionsClient(router) ``` - The three remaining functions are: - `sendRequest` for sending a request. It receives the JavaScript source code, encrypted secretsUrls (in case the encrypted secrets are hosted by the user), DON hosted secrets slot id and version (in case the encrypted secrets are hosted by the DON), list of arguments to pass to the source code, subscription id, and callback gas limit as parameters. Then: - It uses the `FunctionsRequest` library to initialize the request and add any passed encrypted secrets reference or arguments. You can read the API Reference for [Initializing a request](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#initializerequestforinlinejavascript), [adding user hosted secrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#addsecretsreference), [adding DON hosted secrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#adddonhostedsecrets), [adding arguments](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#setargs), and [adding bytes arguments](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#setbytesargs). ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); if (encryptedSecretsUrls.length > 0) req.addSecretsReference(encryptedSecretsUrls); else if (donHostedSecretsVersion > 0) { req.addDONHostedSecrets( donHostedSecretsSlotID, donHostedSecretsVersion ); } if (args.length > 0) req.setArgs(args); if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); ``` - It sends the request to the router by calling the `FunctionsClient` `sendRequest` function. You can read the API reference for [sending a request](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#_sendrequest). Finally, it stores the request id in `s_lastRequestId` then return it. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, jobId ); return s_lastRequestId; ``` **Note**: `_sendRequest` accepts requests encoded in `bytes`. Therefore, you must encode it using [encodeCBOR](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#encodecbor). - `sendRequestCBOR` for sending a request already encoded in `bytes`. It receives the request object encoded in `bytes`, subscription id, and callback gas limit as parameters. Then, it sends the request to the router by calling the `FunctionsClient` `sendRequest` function. **Note**: This function is helpful if you want to encode a request offchain before sending it, saving gas when submitting the request. - `fulfillRequest` to be invoked during the callback. This function is defined in `FunctionsClient` as `virtual` (read `fulfillRequest` [API reference](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#fulfillrequest)). So, your smart contract must override the function to implement the callback. The implementation of the callback is straightforward: the contract stores the latest response and error in `s_lastResponse` and `s_lastError` before emitting the `Response` event. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastResponse = response; s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); ``` ### [JavaScript example](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-gist\#javascript-example) #### [source.js](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-gist\#sourcejs) The JavaScript code is similar to the [Using Secrets in Requests](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets) tutorial. #### [request.js](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-gist\#requestjs) This explanation focuses on the [request.js](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/6-use-secrets-gist/request.js) script and shows how to use the [Chainlink Functions NPM package](https://github.com/smartcontractkit/functions-toolkit) in your own JavaScript/TypeScript project to send requests to a DON. The code is self-explanatory and has comments to help you understand all the steps. The script imports: - [path](https://nodejs.org/docs/latest/api/path.html) and [fs](https://nodejs.org/api/fs.html) : Used to read the [source file](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/6-use-secrets-gist/source.js). - [ethers](https://docs.ethers.org/v5/): Ethers.js library, enables the script to interact with the blockchain. - `@chainlink/functions-toolkit`: Chainlink Functions NPM package. All its utilities are documented in the [NPM README](https://github.com/smartcontractkit/functions-toolkit/blob/main/README.md). - `@chainlink/env-enc`: A tool for loading and storing encrypted environment variables. Read the [official documentation](https://www.npmjs.com/package/@chainlink/env-enc) to learn more. - `../abi/functionsClient.json`: The abi of the contract your script will interact with. **Note**: The script was tested with this [FunctionsConsumerExample contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol). The script has two hardcoded values that you have to change using your own Functions consumer contract and subscription ID: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x8dFf78B7EE3128D00E90611FBeD20A71397064D9" // REPLACE this with your Functions consumer address const subscriptionId = 3 // REPLACE this with your subscription ID ``` The primary function that the script executes is `makeRequestSepolia`. This function can be broken into six main parts: 1. Definition of necessary identifiers: - `routerAddress`: Chainlink Functions router address on the Sepolia testnet. - `donId`: Identifier of the DON that will fulfill your requests on the Sepolia testnet. - `explorerUrl`: Block explorer url of the Sepolia testnet. - `source`: The source code must be a string object. That's why we use `fs.readFileSync` to read `source.js` and then call `toString()` to get the content as a `string` object. - `args`: During the execution of your function, These arguments are passed to the source code. The `args` value is `["1", "USD"]`, which fetches the BTC/USD price. - `secrets`: The secrets object that will be encrypted. - `gasLimit`: Maximum gas that Chainlink Functions can use when transmitting the response to your contract. - Initialization of ethers `signer` and `provider` objects. The signer is used to make transactions on the blockchain, and the provider reads data from the blockchain. 2. Simulating your request in a local sandbox environment: - Use `simulateScript` from the Chainlink Functions NPM package. - Read the `response` of the simulation. If successful, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.uint256` in this example). 3. Estimating the costs: - Initialize a `SubscriptionManager` from the Functions NPM package, then call the `estimateFunctionsRequestCost` function. - The response is returned in Juels (1 LINK = 10\*\*18 Juels). Use the `ethers.utils.formatEther` utility function to convert the output to LINK. 4. Encrypt the secrets, then create a gist containing the encrypted secrets object. This is done in two steps: - Initialize a `SecretsManager` instance from the Functions NPM package, then call the `encryptSecrets` function. - Call the `createGist` utility function from the Functions NPM package to create a gist. - Call the `encryptedSecretsUrls` function of the `SecretsManager` instance. This function encrypts the gist URL. **Note**: The encrypted URL will be sent to the DON when making a request. 5. Making a Chainlink Functions request: - Initialize your functions consumer contract using the contract address, abi, and ethers signer. - Call the `sendRequest` function of your consumer contract. 6. Waiting for the response: - Initialize a `ResponseListener` from the Functions NPM package and then call the `listenForResponseFromTransaction` function to wait for a response. By default, this function waits for five minutes. - Upon reception of the response, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.uint256` in this example). - Call the `deleteGist` utility function from the Functions NPM package to delete the gist. ## Get the latest Chainlink content straight to your inbox. Email Address ## API Key Management [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Using User-hosted Secrets in Requests](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-offchain\#overview) This tutorial shows you how to send a request to a Decentralized Oracle Network to call the [Coinmarketcap API](https://coinmarketcap.com/api/documentation/v1/). After [OCR](https://docs.chain.link/chainlink-functions/resources/architecture) completes offchain computation and aggregation, it returns the `BTC/USD` asset price to your smart contract. Because the API requires you to provide an API key, this guide will also show you how to encrypt, sign your API key, and share the encrypted secret offchain with a Decentralized Oracle Network (DON). The encrypted secrets are never stored onchain. This tutorial uses the threshold decryption feature. This tutorial shows you how to share encrypted secrets offchain with a Decentralized Oracle Network (DON) using a storage platform such as AWS S3, Google Drive, IPFS, or any other service where the DON can fetch secrets via HTTP. Read the [Secrets Management page](https://docs.chain.link/chainlink-functions/resources/secrets) to learn more. Read the [Using User-hosted (gist) Secrets in Requests](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-gist) tutorial before you follow the steps in this example. This tutorial uses the same example but with a slightly different process: 1. Instead of relying on storing the encrypted secrets on gist, you will host your encrypted secrets on AWS S3. 2. Include the encrypted secrets in an `offchain-secrets.json` file. 3. Host the secrets file offchain (AWS S3). 4. Encrypt the S3 HTTPs URL . 5. Include the encrypted URL in your Chainlink Functions request. ## [Prerequisites](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-offchain\#prerequisites) ### [Set up your environment](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-offchain\#set-up-your-environment) You must provide the private key from a testnet wallet to run the examples in this documentation. Install a Web3 wallet, configure [Node.js](https://nodejs.org/en/download/), clone the [smartcontractkit/smart-contract-examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository, and configure a `.env.enc` file with the required environment variables. Install and configure your Web3 wallet for Ethereum Sepolia: 1. [Install Deno](https://docs.deno.com/runtime/manual/) so you can compile and simulate your Functions source code on your local machine. 2. [Install the MetaMask wallet](https://docs.chain.link/quickstarts/deploy-your-first-contract#install-and-fund-your-metamask-wallet) or other Ethereum Web3 wallet. 3. Set the network for your wallet to the Sepolia testnet. If you need to add Sepolia to your wallet, you can find the chain ID and the LINK token contract address on the [LINK Token Contracts](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) page. - [Sepolia testnet and LINK token contract](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) 4. Request testnet LINK and ETH from [faucets.chain.link/sepolia](https://faucets.chain.link/sepolia). Install the required frameworks and dependencies: 1. [Install the latest release of Node.js 20](https://nodejs.org/en/download/). Optionally, you can use the [nvm package](https://www.npmjs.com/package/nvm) to switch between Node.js versions with `nvm use 20`. **Note**: To ensure you are running the correct version in a terminal, type `node -v`. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node -v ``` ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell $ node -v v20.9.0 ``` 2. In a terminal, clone the [smart-contract examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository and change directories. This example repository imports the [Chainlink Functions Toolkit NPM package](https://www.npmjs.com/package/@chainlink/functions-toolkit). You can import this package to your own projects to enable them to work with Chainlink Functions. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell git clone https://github.com/smartcontractkit/smart-contract-examples.git && \ cd ./smart-contract-examples/functions-examples/ ``` 3. Run `npm install` to install the dependencies. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npm install ``` 4. For higher security, the examples repository encrypts your environment variables at rest. 1. Set an encryption password for your environment variables. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set-pw ``` 2. Run `npx env-enc set` to configure a `.env.enc` file with the basic variables that you need to send your requests to the Sepolia network. - `ETHEREUM_SEPOLIA_RPC_URL`: Set a URL for the Sepolia testnet. You can sign up for a personal endpoint from [Alchemy](https://www.alchemy.com/), [Infura](https://www.infura.io/), or another node provider service. - `PRIVATE_KEY`: Find the private key for your testnet wallet. If you use MetaMask, follow the instructions to [Export a Private Key](https://support.metamask.io/managing-my-wallet/secret-recovery-phrase-and-private-keys/how-to-export-an-accounts-private-key/). **Note**: Your private key is needed to sign any transactions you make such as making requests. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set ``` ### [Configure your onchain resources](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-offchain\#configure-your-onchain-resources) After you configure your local environment, configure some onchain resources to process your requests, receive the responses, and pay for the work done by the DON. #### [Deploy a Functions consumer contract on _Sepolia_](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-offchain\#deploy-a-functions-consumer-contract-on-sepolia) 1. [Open the FunctionsConsumerExample.sol contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol) in Remix. [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) 2. Compile the contract. 3. Open MetaMask and select the _Sepolia_ network. 4. In Remix under the **Deploy & Run Transactions** tab, select _Injected Provider - MetaMask_ in the **Environment** list. Remix will use the MetaMask wallet to communicate with _Sepolia_. 5. Under the **Deploy** section, fill in the router address for your specific blockchain. You can find both of these addresses on the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks) page. For _Sepolia_, the router address is `0xb83E47C2bC239B3bf370bc41e1459A34b41238D0`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg). 6. Click the **Deploy** button to deploy the contract. MetaMask prompts you to confirm the transaction. Check the transaction details to make sure you are deploying the contract to _Sepolia_. 7. After you confirm the transaction, the contract address appears in the **Deployed Contracts** list. Copy the contract address. #### [Create a subscription](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-offchain\#create-a-subscription) Follow the [Managing Functions Subscriptions](https://docs.chain.link/chainlink-functions/resources/subscriptions#create-a-subscription) guide to accept the Chainlink Functions Terms of Service (ToS), create a subscription, fund it, then add your consumer contract address to it. You can find the Chainlink Functions Subscription Manager at [functions.chain.link](https://functions.chain.link/). ## [Tutorial](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-offchain\#tutorial) This tutorial is configured to get the `BTC/USD` price with a request that requires API keys. For a detailed explanation of the code example, read the [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-offchain#examine-the-code) section. You can locate the scripts used in this tutorial in the [_examples/7-use-secrets-url_ directory](https://github.com/smartcontractkit/smart-contract-examples/tree/main/functions-examples/examples/7-use-secrets-url). 1. Get a free API key from [CoinMarketCap](https://coinmarketcap.com/api/). 2. Run `npx env-enc set` to add an encrypted `COINMARKETCAP_API_KEY` to your `.env.enc` file. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set ``` 3. Prepare the store for your encrypted secrets file. 1. Create a [AWS free tier account](https://aws.amazon.com/free/). 2. Follow [these steps](https://docs.aws.amazon.com/AmazonS3/latest/userguide/creating-bucket.html) to create a AWS S3 bucket. Choose a name for your bucket, set _ACLs enabled_, and turn off _Block all public access_. ### [Build Offchain Secrets](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-offchain\#build-offchain-secrets) Before you make a request, prepare the secrets file and host it offchain: 1. Encrypt the secrets and store them in the `offchain-secrets.json` file using the `gen-offchain-secrets` script of the `7-use-secrets-url` folder. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```bash node examples/7-use-secrets-url/gen-offchain-secrets.js ``` Example: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```text $ node examples/7-use-secrets-url/gen-offchain-secrets.js secp256k1 unavailable, reverting to browser version Encrypted secrets object written to /functions-examples/offchain-secrets.json ``` 2. Follow these [steps](https://docs.aws.amazon.com/AmazonS3/latest/userguide/uploading-an-object-bucket.html) to upload the file `offchain-secrets.json` to your AWS S3 bucket. 3. To make the file publicly accessible without authentication: 1. Find the file in the bucket list, and click on it to open the object overview. 2. Click on the _Permissions_ tab to display the _Access control list (ACL)_. 3. Click on _Edit_. 4. Set _Everyone (public access)_ Objects read, then confirm. This action makes the object readable by anyone on the internet. 5. Note the object URL. 6. To verify that the URL is publicly readable without authentication, open a new browser tab and copy/paste the object URL in the browser location bar. After you hit _Enter_ , the browser will display the content of your encrypted secrets file. 4. Note the URL. You will need it in the following section. For example: `https://clfunctions.s3.eu-north-1.amazonaws.com/offchain-secrets.json`. ### [Send a Request](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-offchain\#send-a-request) To run the example: 1. Open the file `request.js`, which is located in the `7-use-secrets-url` folder. 2. Replace the consumer contract address and the subscription ID with your own values. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x8dFf78B7EE3128D00E90611FBeD20A71397064D9" // REPLACE this with your Functions consumer address const subscriptionId = 3 // REPLACE this with your subscription ID ``` 3. Replace the `secretsUrls` with your AWS S3 URL: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const secretsUrls = ["https://clfunctions.s3.eu-north-1.amazonaws.com/offchain-secrets.json"] // REPLACE WITH YOUR VALUES after running gen-offchain-secrets.js and uploading offchain-secrets.json to a public URL ``` 4. Make a request: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node examples/7-use-secrets-url/request.js ``` The script runs your function in a sandbox environment before making an onchain transaction: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```text $ node examples/7-use-secrets-url/request.js secp256k1 unavailable, reverting to browser version Encrypted secrets object written to /Users/crystalgomes/smart-contract-examples/functions-examples/offchain-secrets.json crystalgomes@MB-CY16VK6DPG functions-examples % node examples/7-use-secrets-url/request.js secp256k1 unavailable, reverting to browser version Start simulation... Simulation result { capturedTerminalOutput: 'Price: 68196.20 USD\n', responseBytesHexstring: '0x0000000000000000000000000000000000000000000000000000000000680f24' } ✅ Decoded response to uint256: 6819620n Estimate request costs... Fulfillment cost estimated to 1.018348822253235 LINK Make request... Encrypt the URLs.. ✅ Functions request sent! Transaction hash 0xadc0db0ddea7b9836b86a9c9e008bc97d47e5f92b0dcec9694d3944d0065c789. Waiting for a response... See your request in the explorer https://sepolia.etherscan.io/tx/0xadc0db0ddea7b9836b86a9c9e008bc97d47e5f92b0dcec9694d3944d0065c789 ✅ Request 0xb308ca293859dab47d8848578291e687a0d9373274d1451a9c9667dc4bba5fca successfully fulfilled. Cost is 0.260029208488139025 LINK.Complete response: { requestId: '0xb308ca293859dab47d8848578291e687a0d9373274d1451a9c9667dc4bba5fca', subscriptionId: 2303, totalCostInJuels: 260029208488139025n, responseBytesHexstring: '0x000000000000000000000000000000000000000000000000000000000068146a', errorString: '', returnDataBytesHexstring: '0x', fulfillmentCode: 0 } ✅ Decoded response to uint256: 6820970n ``` The output of the example gives you the following information: - Your request is first run on a sandbox environment to ensure it is correctly configured. - The fulfillment costs are estimated before making the request. - The AWS S3 URL is encrypted before sending it in the request. - Your request was successfully sent to Chainlink Functions. The transaction in this example is [0xadc0db0ddea7b9836b86a9c9e008bc97d47e5f92b0dcec9694d3944d0065c789](https://sepolia.etherscan.io/tx/0xadc0db0ddea7b9836b86a9c9e008bc97d47e5f92b0dcec9694d3944d0065c789) and the request ID is `0xb308ca293859dab47d8848578291e687a0d9373274d1451a9c9667dc4bba5fca`. - The DON successfully fulfilled your request. The total cost was: `0.260029208488139025 LINK`. - The consumer contract received a response in `bytes` with a value of `0x000000000000000000000000000000000000000000000000000000000068146a`. Decoding it offchain to `uint256` gives you a result: `6820970`. ## [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-offchain\#examine-the-code) ### [FunctionsConsumerExample.sol](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-offchain\#functionsconsumerexamplesol) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; /** * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. * DO NOT USE THIS CODE IN PRODUCTION. */ contract FunctionsConsumerExample is FunctionsClient, ConfirmedOwner { using FunctionsRequest for FunctionsRequest.Request; bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; error UnexpectedRequestID(bytes32 requestId); event Response(bytes32 indexed requestId, bytes response, bytes err); constructor( address router ) FunctionsClient(router) ConfirmedOwner(msg.sender) {} /** * @notice Send a simple request * @param source JavaScript source code * @param encryptedSecretsUrls Encrypted URLs where to fetch user secrets * @param donHostedSecretsSlotID Don hosted secrets slotId * @param donHostedSecretsVersion Don hosted secrets version * @param args List of arguments accessible from within the source code * @param bytesArgs Array of bytes arguments, represented as hex strings * @param subscriptionId Billing ID */ function sendRequest( string memory source, bytes memory encryptedSecretsUrls, uint8 donHostedSecretsSlotID, uint64 donHostedSecretsVersion, string[] memory args, bytes[] memory bytesArgs, uint64 subscriptionId, uint32 gasLimit, bytes32 donID ) external onlyOwner returns (bytes32 requestId) { FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); if (encryptedSecretsUrls.length > 0) req.addSecretsReference(encryptedSecretsUrls); else if (donHostedSecretsVersion > 0) { req.addDONHostedSecrets( donHostedSecretsSlotID, donHostedSecretsVersion ); } if (args.length > 0) req.setArgs(args); if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Send a pre-encoded CBOR request * @param request CBOR-encoded request data * @param subscriptionId Billing ID * @param gasLimit The maximum amount of gas the request can consume * @param donID ID of the job to be invoked * @return requestId The ID of the sent request */ function sendRequestCBOR( bytes memory request, uint64 subscriptionId, uint32 gasLimit, bytes32 donID ) external onlyOwner returns (bytes32 requestId) { s_lastRequestId = _sendRequest( request, subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Store latest result/error * @param requestId The request ID, returned by sendRequest() * @param response Aggregated response from the user code * @param err Aggregated error from the user code or from the execution pipeline * Either response or error parameter will be set, but never both */ function fulfillRequest( bytes32 requestId, bytes memory response, bytes memory err ) internal override { if (s_lastRequestId != requestId) { revert UnexpectedRequestID(requestId); } s_lastResponse = response; s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); } } ``` [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) - To write a Chainlink Functions consumer contract, your contract must import [FunctionsClient.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol) and [FunctionsRequest.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol). You can read the API references: [FunctionsClient](https://docs.chain.link/chainlink-functions/api-reference/functions-client) and [FunctionsRequest](https://docs.chain.link/chainlink-functions/api-reference/functions-request). These contracts are available in an NPM package, so you can import them from within your project. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; ``` - Use the FunctionsRequest.sol library to get all the functions needed for building a Chainlink Functions request. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext using FunctionsRequest for FunctionsRequest.Request; ``` - The latest request id, latest received response, and latest received error (if any) are defined as state variables: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; ``` - We define the `Response` event that your smart contract will emit during the callback ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext event Response(bytes32 indexed requestId, bytes response, bytes err); ``` - Pass the router address for your network when you deploy the contract: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext constructor(address router) FunctionsClient(router) ``` - The three remaining functions are: - `sendRequest` for sending a request. It receives the JavaScript source code, encrypted secretsUrls (in case the encrypted secrets are hosted by the user), DON hosted secrets slot id and version (in case the encrypted secrets are hosted by the DON), list of arguments to pass to the source code, subscription id, and callback gas limit as parameters. Then: - It uses the `FunctionsRequest` library to initialize the request and add any passed encrypted secrets reference or arguments. You can read the API Reference for [Initializing a request](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#initializerequestforinlinejavascript), [adding user hosted secrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#addsecretsreference), [adding DON hosted secrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#adddonhostedsecrets), [adding arguments](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#setargs), and [adding bytes arguments](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#setbytesargs). ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); if (encryptedSecretsUrls.length > 0) req.addSecretsReference(encryptedSecretsUrls); else if (donHostedSecretsVersion > 0) { req.addDONHostedSecrets( donHostedSecretsSlotID, donHostedSecretsVersion ); } if (args.length > 0) req.setArgs(args); if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); ``` - It sends the request to the router by calling the `FunctionsClient` `sendRequest` function. You can read the API reference for [sending a request](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#_sendrequest). Finally, it stores the request id in `s_lastRequestId` then return it. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, jobId ); return s_lastRequestId; ``` **Note**: `_sendRequest` accepts requests encoded in `bytes`. Therefore, you must encode it using [encodeCBOR](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#encodecbor). - `sendRequestCBOR` for sending a request already encoded in `bytes`. It receives the request object encoded in `bytes`, subscription id, and callback gas limit as parameters. Then, it sends the request to the router by calling the `FunctionsClient` `sendRequest` function. **Note**: This function is helpful if you want to encode a request offchain before sending it, saving gas when submitting the request. - `fulfillRequest` to be invoked during the callback. This function is defined in `FunctionsClient` as `virtual` (read `fulfillRequest` [API reference](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#fulfillrequest)). So, your smart contract must override the function to implement the callback. The implementation of the callback is straightforward: the contract stores the latest response and error in `s_lastResponse` and `s_lastError` before emitting the `Response` event. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastResponse = response; s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); ``` ### [JavaScript example](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-offchain\#javascript-example) #### [source.js](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-offchain\#sourcejs) The JavaScript code is similar to the [Using Secrets in Requests](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets) tutorial. #### [gen-offchain-secrets.js](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-offchain\#gen-offchain-secretsjs) This explanation focuses on the [gen-offchain-secrets.js](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/7-use-secrets-url/gen-offchain-secrets.js) script and shows how to use the [Chainlink Functions NPM package](https://github.com/smartcontractkit/functions-toolkit) in your own JavaScript/TypeScript project to encrypts your secrets. After encryption, the script saves the encrypted secrets on a local file, `offchain-secrets.json`. You can then upload the file to your storage of choice (AWS S3 in this example). The script imports: - [path](https://nodejs.org/docs/latest/api/path.html) and [fs](https://nodejs.org/api/fs.html) : Used to read the [source file](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/7-use-secrets-url/source.js). - [ethers](https://docs.ethers.org/v5/): Ethers.js library, enables the script to interact with the blockchain. - `@chainlink/functions-toolkit`: Chainlink Functions NPM package. All its utilities are documented in the [NPM README](https://github.com/smartcontractkit/functions-toolkit/blob/main/README.md). - `@chainlink/env-enc`: A tool for loading and storing encrypted environment variables. Read the [official documentation](https://www.npmjs.com/package/@chainlink/env-enc) to learn more. The primary function that the script executes is `generateOffchainSecretsFile`. This function can be broken into three main parts: 1. Definition of necessary identifiers: - `routerAddress`: Chainlink Functions router address on Sepolia. - `donId`: Identifier of the DON that will fulfill your requests on Sepolia. - `secrets`: The secrets object. - Initialization of ethers `signer` and `provider` objects. The Chainlink NPM package uses the signer to sign the encrypted secrets with your private key. 2. Encrypt the secrets: - Initialize a `SecretsManager` instance from the Chainlink Functions NPM package. - Call the `encryptSecrets` function from the created instance to encrypt the secrets. 3. Use the `fs` library to store the encrypted secrets on a local file, `offchain-secrets.json`. #### [request.js](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets-offchain\#requestjs) This explanation focuses on the [request.js](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/7-use-secrets-url/request.js) script and shows how to use the [Chainlink Functions NPM package](https://github.com/smartcontractkit/functions-toolkit) in your own JavaScript/TypeScript project to send requests to a DON. The code is self-explanatory and has comments to help you understand all the steps. The script imports: - [path](https://nodejs.org/docs/latest/api/path.html) and [fs](https://nodejs.org/api/fs.html) : Used to read the [source file](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/7-use-secrets-url/source.js). - [ethers](https://docs.ethers.org/v5/): Ethers.js library, enables the script to interact with the blockchain. - `@chainlink/functions-toolkit`: Chainlink Functions NPM package. All its utilities are documented in the [NPM README](https://github.com/smartcontractkit/functions-toolkit/blob/main/README.md). - `@chainlink/env-enc`: A tool for loading and storing encrypted environment variables. Read the [official documentation](https://www.npmjs.com/package/@chainlink/env-enc) to learn more. - `../abi/functionsClient.json`: The abi of the contract your script will interact with. **Note**: The script was tested with this [FunctionsConsumerExample contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol). The script has two hardcoded values that you have to change using your own Functions consumer contract and subscription ID: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x8dFf78B7EE3128D00E90611FBeD20A71397064D9" // REPLACE this with your Functions consumer address const subscriptionId = 3 // REPLACE this with your subscription ID ``` The primary function that the script executes is `makeRequestSepolia`. This function can be broken into six main parts: 1. Definition of necessary identifiers: - `routerAddress`: Chainlink Functions router address on Sepolia. - `donId`: Identifier of the DON that will fulfill your requests on Sepolia. - `explorerUrl`: Block explorer URL of the Sepolia testnet. - `source`: The source code must be a string object. That's why we use `fs.readFileSync` to read `source.js` and then call `toString()` to get the content as a `string` object. - `args`: During the execution of your function, These arguments are passed to the source code. The `args` value is `["1", "USD"]`, which fetches the BTC/USD price. - `secrets`: The secrets object. **Note**: Because we are sharing the URL of the encrypted secrets with the DON, the `secrets` object is only used during simulation. - `secretsUrls`: The URL of the encrypted secrets object. - `gasLimit`: Maximum gas that Chainlink Functions can use when transmitting the response to your contract. - Initialization of ethers `signer` and `provider` objects. The signer is used to make transactions on the blockchain, and the provider reads data from the blockchain. 2. Simulating your request in a local sandbox environment: - Use `simulateScript` from the Chainlink Functions NPM package. - Read the `response` of the simulation. If successful, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.uint256` in this example). 3. Estimating the costs: - Initialize a `SubscriptionManager` from the Functions NPM package, then call the `estimateFunctionsRequestCost` function. - The response is returned in Juels (1 LINK = 10\*\*18 Juels). Use the `ethers.utils.formatEther` utility function to convert the output to LINK. 4. Encrypt the secrets, then create a gist containing the encrypted secrets object. This is done in two steps: - Initialize a `SecretsManager` instance from the Functions NPM package, then call the `encryptSecrets` function. - Call the `encryptedSecretsUrls` function of the `SecretsManager` instance. This function encrypts the secrets URL. **Note**: The encrypted URL will be sent to the DON when making a request. 5. Making a Chainlink Functions request: - Initialize your functions consumer contract using the contract address, abi, and ethers signer. - Call the `sendRequest` function of your consumer contract. 6. Waiting for the response: - Initialize a `ResponseListener` from the Functions NPM package and then call the `listenForResponseFromTransaction` function to wait for a response. By default, this function waits for five minutes. - Upon reception of the response, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.uint256` in this example). ## Get the latest Chainlink content straight to your inbox. Email Address ## API Secrets Tutorial [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Using DON-hosted Secrets in Requests](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets\#overview) This tutorial shows you how to send a request to a Decentralized Oracle Network to call the [Coinmarketcap API](https://coinmarketcap.com/api/documentation/v1/). After [OCR](https://docs.chain.link/chainlink-functions/resources/architecture) completes offchain computation and aggregation, it returns the `BTC/USD` asset price to your smart contract. Because the API requires you to provide an API key, this guide will also show you how to encrypt, sign your API key, and share the encrypted secret with a Decentralized Oracle Network (DON). The encrypted secrets are never stored onchain. This tutorial uses the threshold encryption feature. The encrypted secrets are stored with the DON. Read the [Secrets Management page](https://docs.chain.link/chainlink-functions/resources/secrets) to learn more. ## [Prerequisites](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets\#prerequisites) ### [Set up your environment](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets\#set-up-your-environment) You must provide the private key from a testnet wallet to run the examples in this documentation. Install a Web3 wallet, configure [Node.js](https://nodejs.org/en/download/), clone the [smartcontractkit/smart-contract-examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository, and configure a `.env.enc` file with the required environment variables. Install and configure your Web3 wallet for Ethereum Sepolia: 1. [Install Deno](https://docs.deno.com/runtime/manual/) so you can compile and simulate your Functions source code on your local machine. 2. [Install the MetaMask wallet](https://docs.chain.link/quickstarts/deploy-your-first-contract#install-and-fund-your-metamask-wallet) or other Ethereum Web3 wallet. 3. Set the network for your wallet to the Sepolia testnet. If you need to add Sepolia to your wallet, you can find the chain ID and the LINK token contract address on the [LINK Token Contracts](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) page. - [Sepolia testnet and LINK token contract](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) 4. Request testnet LINK and ETH from [faucets.chain.link/sepolia](https://faucets.chain.link/sepolia). Install the required frameworks and dependencies: 1. [Install the latest release of Node.js 20](https://nodejs.org/en/download/). Optionally, you can use the [nvm package](https://www.npmjs.com/package/nvm) to switch between Node.js versions with `nvm use 20`. **Note**: To ensure you are running the correct version in a terminal, type `node -v`. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node -v ``` ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell $ node -v v20.9.0 ``` 2. In a terminal, clone the [smart-contract examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository and change directories. This example repository imports the [Chainlink Functions Toolkit NPM package](https://www.npmjs.com/package/@chainlink/functions-toolkit). You can import this package to your own projects to enable them to work with Chainlink Functions. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell git clone https://github.com/smartcontractkit/smart-contract-examples.git && \ cd ./smart-contract-examples/functions-examples/ ``` 3. Run `npm install` to install the dependencies. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npm install ``` 4. For higher security, the examples repository encrypts your environment variables at rest. 1. Set an encryption password for your environment variables. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set-pw ``` 2. Run `npx env-enc set` to configure a `.env.enc` file with the basic variables that you need to send your requests to the Sepolia network. - `ETHEREUM_SEPOLIA_RPC_URL`: Set a URL for the Sepolia testnet. You can sign up for a personal endpoint from [Alchemy](https://www.alchemy.com/), [Infura](https://www.infura.io/), or another node provider service. - `PRIVATE_KEY`: Find the private key for your testnet wallet. If you use MetaMask, follow the instructions to [Export a Private Key](https://support.metamask.io/managing-my-wallet/secret-recovery-phrase-and-private-keys/how-to-export-an-accounts-private-key/). **Note**: Your private key is needed to sign any transactions you make such as making requests. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set ``` ### [Configure your onchain resources](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets\#configure-your-onchain-resources) After you configure your local environment, configure some onchain resources to process your requests, receive the responses, and pay for the work done by the DON. #### [Deploy a Functions consumer contract on _Sepolia_](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets\#deploy-a-functions-consumer-contract-on-sepolia) 1. [Open the FunctionsConsumerExample.sol contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol) in Remix. [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) 2. Compile the contract. 3. Open MetaMask and select the _Sepolia_ network. 4. In Remix under the **Deploy & Run Transactions** tab, select _Injected Provider - MetaMask_ in the **Environment** list. Remix will use the MetaMask wallet to communicate with _Sepolia_. 5. Under the **Deploy** section, fill in the router address for your specific blockchain. You can find both of these addresses on the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks) page. For _Sepolia_, the router address is `0xb83E47C2bC239B3bf370bc41e1459A34b41238D0`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg). 6. Click the **Deploy** button to deploy the contract. MetaMask prompts you to confirm the transaction. Check the transaction details to make sure you are deploying the contract to _Sepolia_. 7. After you confirm the transaction, the contract address appears in the **Deployed Contracts** list. Copy the contract address. #### [Create a subscription](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets\#create-a-subscription) Follow the [Managing Functions Subscriptions](https://docs.chain.link/chainlink-functions/resources/subscriptions#create-a-subscription) guide to accept the Chainlink Functions Terms of Service (ToS), create a subscription, fund it, then add your consumer contract address to it. You can find the Chainlink Functions Subscription Manager at [functions.chain.link](https://functions.chain.link/). ## [Tutorial](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets\#tutorial) This tutorial is configured to get the `BTC/USD` price with a request that requires API keys. For a detailed explanation of the code example, read the [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets#examine-the-code) section. You can locate the scripts used in this tutorial in the [_examples/5-use-secrets-threshold_ directory](https://github.com/smartcontractkit/smart-contract-examples/tree/main/functions-examples/examples/5-use-secrets-threshold). 1. Get a free API key from [CoinMarketCap](https://coinmarketcap.com/api/) and note your API key. 2. Run `npx env-enc set` to add an encrypted `COINMARKETCAP_API_KEY` to your `.env.enc` file. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set ``` 3. Make sure your subscription has enough LINK to pay for your requests. Also, you must maintain a minimum balance to upload encrypted secrets to the DON (Read the [minimum balance for uploading encrypted secrets section](https://docs.chain.link/chainlink-functions/resources/billing#minimum-balance-for-uploading-encrypted-secrets) to learn more). You can check your subscription details (including the balance in LINK) in the [Chainlink Functions Subscription Manager](https://docs.chain.link/chainlink-functions/resources/subscriptions). If your subscription runs out of LINK, follow the [Fund a Subscription](https://docs.chain.link/chainlink-functions/resources/subscriptions#fund-a-subscription) guide. This guide recommends maintaining at least 2 LINK within your subscription. To run the example: 1. Open the file `request.js`, which is located in the `5-use-secrets-threshold` folder. 2. Replace the consumer contract address and the subscription ID with your own values. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x8dFf78B7EE3128D00E90611FBeD20A71397064D9" // REPLACE this with your Functions consumer address const subscriptionId = 3 // REPLACE this with your subscription ID ``` 3. Make a request: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node examples/5-use-secrets-threshold/request.js ``` The script runs your function in a sandbox environment before making an onchain transaction: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```text $ node examples/5-use-secrets-threshold/request.js secp256k1 unavailable, reverting to browser version Start simulation... Simulation result { capturedTerminalOutput: 'Price: 66757.65 USD\n', responseBytesHexstring: '0x000000000000000000000000000000000000000000000000000000000065dd35' } ✅ Decoded response to uint256: 6675765n Estimate request costs... Fulfillment cost estimated to 1.104471544715335 LINK Make request... Upload encrypted secret to gateways https://01.functions-gateway.testnet.chain.link/,https://02.functions-gateway.testnet.chain.link/. slotId 0. Expiration in minutes: 15 ✅ Secrets uploaded properly to gateways https://01.functions-gateway.testnet.chain.link/,https://02.functions-gateway.testnet.chain.link/! Gateways response: { version: 1712949090, success: true } ✅ Functions request sent! Transaction hash 0xcac39aeea98651f307da185aed387314c453272d185e58b26b3bb399b82a90b6. Waiting for a response... See your request in the explorer https://sepolia.etherscan.io/tx/0xcac39aeea98651f307da185aed387314c453272d185e58b26b3bb399b82a90b6 ✅ Request 0xbc09de04f4dd39fa78d4b00b7ab4d2f4a37d8b9a8edf97df5c86061175b9d9c3 successfully fulfilled. Cost is 0.23730142355580769 LINK.Complete response: { requestId: '0xbc09de04f4dd39fa78d4b00b7ab4d2f4a37d8b9a8edf97df5c86061175b9d9c3', subscriptionId: 2303, totalCostInJuels: 237301423555807690n, responseBytesHexstring: '0x000000000000000000000000000000000000000000000000000000000065dc31', errorString: '', returnDataBytesHexstring: '0x', fulfillmentCode: 0 } ✅ Decoded response to uint256: 6675505n ``` The output of the example gives you the following information: - Your request is first run on a sandbox environment to ensure it is correctly configured. - The fulfillment costs are estimated before making the request. - The encrypted secrets were uploaded to the secrets endpoint `https://01.functions-gateway.testnet.chain.link/user`. - Your request was successfully sent to Chainlink Functions. The transaction in this example is [0xcac39aeea98651f307da185aed387314c453272d185e58b26b3bb399b82a90b6](https://sepolia.etherscan.io/tx/0xcac39aeea98651f307da185aed387314c453272d185e58b26b3bb399b82a90b6) and the request ID is `0xbc09de04f4dd39fa78d4b00b7ab4d2f4a37d8b9a8edf97df5c86061175b9d9c3`. - The DON successfully fulfilled your request. The total cost was: `0.23730142355580769 LINK`. - The consumer contract received a response in `bytes` with a value of `0x000000000000000000000000000000000000000000000000000000000065dc31`. Decoding it offchain to `uint256` gives you a result: `6675505`. The median BTC price is 66755.05 USD. ## [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets\#examine-the-code) ### [FunctionsConsumerExample.sol](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets\#functionsconsumerexamplesol) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; /** * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. * DO NOT USE THIS CODE IN PRODUCTION. */ contract FunctionsConsumerExample is FunctionsClient, ConfirmedOwner { using FunctionsRequest for FunctionsRequest.Request; bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; error UnexpectedRequestID(bytes32 requestId); event Response(bytes32 indexed requestId, bytes response, bytes err); constructor( address router ) FunctionsClient(router) ConfirmedOwner(msg.sender) {} /** * @notice Send a simple request * @param source JavaScript source code * @param encryptedSecretsUrls Encrypted URLs where to fetch user secrets * @param donHostedSecretsSlotID Don hosted secrets slotId * @param donHostedSecretsVersion Don hosted secrets version * @param args List of arguments accessible from within the source code * @param bytesArgs Array of bytes arguments, represented as hex strings * @param subscriptionId Billing ID */ function sendRequest( string memory source, bytes memory encryptedSecretsUrls, uint8 donHostedSecretsSlotID, uint64 donHostedSecretsVersion, string[] memory args, bytes[] memory bytesArgs, uint64 subscriptionId, uint32 gasLimit, bytes32 donID ) external onlyOwner returns (bytes32 requestId) { FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); if (encryptedSecretsUrls.length > 0) req.addSecretsReference(encryptedSecretsUrls); else if (donHostedSecretsVersion > 0) { req.addDONHostedSecrets( donHostedSecretsSlotID, donHostedSecretsVersion ); } if (args.length > 0) req.setArgs(args); if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Send a pre-encoded CBOR request * @param request CBOR-encoded request data * @param subscriptionId Billing ID * @param gasLimit The maximum amount of gas the request can consume * @param donID ID of the job to be invoked * @return requestId The ID of the sent request */ function sendRequestCBOR( bytes memory request, uint64 subscriptionId, uint32 gasLimit, bytes32 donID ) external onlyOwner returns (bytes32 requestId) { s_lastRequestId = _sendRequest( request, subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Store latest result/error * @param requestId The request ID, returned by sendRequest() * @param response Aggregated response from the user code * @param err Aggregated error from the user code or from the execution pipeline * Either response or error parameter will be set, but never both */ function fulfillRequest( bytes32 requestId, bytes memory response, bytes memory err ) internal override { if (s_lastRequestId != requestId) { revert UnexpectedRequestID(requestId); } s_lastResponse = response; s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); } } ``` [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) - To write a Chainlink Functions consumer contract, your contract must import [FunctionsClient.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol) and [FunctionsRequest.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol). You can read the API references: [FunctionsClient](https://docs.chain.link/chainlink-functions/api-reference/functions-client) and [FunctionsRequest](https://docs.chain.link/chainlink-functions/api-reference/functions-request). These contracts are available in an NPM package, so you can import them from within your project. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; ``` - Use the FunctionsRequest.sol library to get all the functions needed for building a Chainlink Functions request. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext using FunctionsRequest for FunctionsRequest.Request; ``` - The latest request id, latest received response, and latest received error (if any) are defined as state variables: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; ``` - We define the `Response` event that your smart contract will emit during the callback ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext event Response(bytes32 indexed requestId, bytes response, bytes err); ``` - Pass the router address for your network when you deploy the contract: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext constructor(address router) FunctionsClient(router) ``` - The three remaining functions are: - `sendRequest` for sending a request. It receives the JavaScript source code, encrypted secretsUrls (in case the encrypted secrets are hosted by the user), DON hosted secrets slot id and version (in case the encrypted secrets are hosted by the DON), list of arguments to pass to the source code, subscription id, and callback gas limit as parameters. Then: - It uses the `FunctionsRequest` library to initialize the request and add any passed encrypted secrets reference or arguments. You can read the API Reference for [Initializing a request](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#initializerequestforinlinejavascript), [adding user hosted secrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#addsecretsreference), [adding DON hosted secrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#adddonhostedsecrets), [adding arguments](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#setargs), and [adding bytes arguments](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#setbytesargs). ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); if (encryptedSecretsUrls.length > 0) req.addSecretsReference(encryptedSecretsUrls); else if (donHostedSecretsVersion > 0) { req.addDONHostedSecrets( donHostedSecretsSlotID, donHostedSecretsVersion ); } if (args.length > 0) req.setArgs(args); if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); ``` - It sends the request to the router by calling the `FunctionsClient` `sendRequest` function. You can read the API reference for [sending a request](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#_sendrequest). Finally, it stores the request id in `s_lastRequestId` then return it. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, jobId ); return s_lastRequestId; ``` **Note**: `_sendRequest` accepts requests encoded in `bytes`. Therefore, you must encode it using [encodeCBOR](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#encodecbor). - `sendRequestCBOR` for sending a request already encoded in `bytes`. It receives the request object encoded in `bytes`, subscription id, and callback gas limit as parameters. Then, it sends the request to the router by calling the `FunctionsClient` `sendRequest` function. **Note**: This function is helpful if you want to encode a request offchain before sending it, saving gas when submitting the request. - `fulfillRequest` to be invoked during the callback. This function is defined in `FunctionsClient` as `virtual` (read `fulfillRequest` [API reference](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#fulfillrequest)). So, your smart contract must override the function to implement the callback. The implementation of the callback is straightforward: the contract stores the latest response and error in `s_lastResponse` and `s_lastError` before emitting the `Response` event. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastResponse = response; s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); ``` ### [JavaScript example](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets\#javascript-example) #### [source.js](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets\#sourcejs) The Decentralized Oracle Network will run the [JavaScript code](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/5-use-secrets-threshold/source.js). The code is self-explanatory and has comments to help you understand all the steps. This JavaScript source code uses [Functions.makeHttpRequest](https://docs.chain.link/chainlink-functions/api-reference/javascript-source#http-requests) to make HTTP requests. To request the `BTC` asset price, the source code calls the `https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest/` URL. If you read the [Functions.makeHttpRequest](https://docs.chain.link/chainlink-functions/api-reference/javascript-source#http-requests) documentation, you see that you must provide the following parameters: - `url`: `https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest` - `headers`: This is an HTTP headers object set to `"X-CMC_PRO_API_KEY": secrets.apiKey`. The `apiKey` is passed in the secrets, see [request](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets#requestjs). - `params`: The query parameters object: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext { convert: currencyCode, id: coinMarketCapCoinId } ``` To check the expected API response, run the `curl` command in your terminal: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```bash curl -X 'GET' \ 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest?id=1&convert=USD' \ -H 'accept: application/json' \ -H 'X-CMC_PRO_API_KEY: REPLACE_WITH_YOUR_API_KEY' ``` The response should be similar to the following example: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```json { ..., "data": { "1": { "id": 1, "name": "Bitcoin", "symbol": "BTC", "slug": "bitcoin", ..., "quote": { "USD": { "price": 23036.068560170934, "volume_24h": 33185308895.694683, "volume_change_24h": 24.8581, "percent_change_1h": 0.07027098, "percent_change_24h": 1.79073805, "percent_change_7d": 10.29859656, "percent_change_30d": 38.10735851, "percent_change_60d": 39.26624921, "percent_change_90d": 11.59835416, "market_cap": 443982488416.99316, "market_cap_dominance": 42.385, "fully_diluted_market_cap": 483757439763.59, "tvl": null, "last_updated": "2023-01-26T18:27:00.000Z" } } } } } ``` The price is located at `data,1,quote,USD,price`. The main steps of the scripts are: - Fetch the `currencyCode` and `coinMarketCapCoinId` from `args`. - Construct the HTTP object `coinMarketCapRequest` using `Functions.makeHttpRequest`. - Make the HTTP call. - Read the asset price from the response. - Return the result as a [buffer](https://nodejs.org/api/buffer.html#buffer) using the helper function: `Functions.encodeUint256`. Note: Because solidity doesn't support decimals, we multiply the result by `100` and round the result to the nearest integer. **Note**: Read this [article](https://www.freecodecamp.org/news/do-you-want-a-better-understanding-of-buffer-in-node-js-check-this-out-2e29de2968e8/) if you are new to Javascript Buffers and want to understand why they are important. #### [request.js](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets\#requestjs) This explanation focuses on the [request.js](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/5-use-secrets-threshold/request.js) script and shows how to use the [Chainlink Functions NPM package](https://github.com/smartcontractkit/functions-toolkit) in your own JavaScript/TypeScript project to send requests to a DON. The code is self-explanatory and has comments to help you understand all the steps. The script imports: - [path](https://nodejs.org/docs/latest/api/path.html) and [fs](https://nodejs.org/api/fs.html) : Used to read the [source file](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/5-use-secrets-threshold/source.js). - [ethers](https://docs.ethers.org/v5/): Ethers.js library, enables the script to interact with the blockchain. - `@chainlink/functions-toolkit`: Chainlink Functions NPM package. All its utilities are documented in the [NPM README](https://github.com/smartcontractkit/functions-toolkit/blob/main/README.md). - `@chainlink/env-enc`: A tool for loading and storing encrypted environment variables. Read the [official documentation](https://www.npmjs.com/package/@chainlink/env-enc) to learn more. - `../abi/functionsClient.json`: The abi of the contract your script will interact with. **Note**: The script was tested with this [FunctionsConsumerExample contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol). The script has two hardcoded values that you have to change using your own Functions consumer contract and subscription ID: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x8dFf78B7EE3128D00E90611FBeD20A71397064D9" // REPLACE this with your Functions consumer address const subscriptionId = 3 // REPLACE this with your subscription ID ``` The primary function that the script executes is `makeRequestSepolia`. This function can be broken into six main parts: 1. Definition of necessary identifiers: - `routerAddress`: Chainlink Functions router address on Sepolia. - `donId`: Identifier of the DON that will fulfill your requests on Sepolia. - `gatewayUrls`: The secrets endpoint URL to which you will upload the encrypted secrets. - `explorerUrl`: Block explorer URL of the Sepolia testnet. - `source`: The source code must be a string object. That's why we use `fs.readFileSync` to read `source.js` and then call `toString()` to get the content as a `string` object. - `args`: During the execution of your function, These arguments are passed to the source code. The `args` value is `["1", "USD"]`, which fetches the BTC/USD price. - `secrets`: The secrets object that will be encrypted. - `slotIdNumber`: Slot ID at the DON where to upload the encrypted secrets. - `expirationTimeMinutes`: Expiration time in minutes of the encrypted secrets. - `gasLimit`: Maximum gas that Chainlink Functions can use when transmitting the response to your contract. - Initialization of ethers `signer` and `provider` objects. The signer is used to make transactions on the blockchain, and the provider reads data from the blockchain. 2. Simulating your request in a local sandbox environment: - Use `simulateScript` from the Chainlink Functions NPM package. - Read the `response` of the simulation. If successful, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.uint256` in this example). 3. Estimating the costs: - Initialize a `SubscriptionManager` from the Functions NPM package, then call the `estimateFunctionsRequestCost` function. - The response is returned in Juels (1 LINK = 10\*\*18 Juels). Use the `ethers.utils.formatEther` utility function to convert the output to LINK. 4. Encrypt the secrets, then upload the encrypted secrets to the DON. This is done in two steps: - Initialize a `SecretsManager` instance from the Functions NPM package, then call the `encryptSecrets` function. - Call the `uploadEncryptedSecretsToDON` function of the `SecretsManager` instance. This function returns an object containing a `success` boolean as long as `version`, the secret version on the DON storage. **Note**: When making the request, you must pass the slot ID and version to tell the DON where to fetch the encrypted secrets. 5. Making a Chainlink Functions request: - Initialize your functions consumer contract using the contract address, abi, and ethers signer. - Call the `sendRequest` function of your consumer contract. 6. Waiting for the response: - Initialize a `ResponseListener` from the Functions NPM package and then call the `listenForResponseFromTransaction` function to wait for a response. By default, this function waits for five minutes. - Upon reception of the response, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.uint256` in this example). ## Get the latest Chainlink content straight to your inbox. Email Address ## Automate Chainlink Functions [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Automate your Functions (Custom Logic Automation)](https://docs.chain.link/chainlink-functions/tutorials/automate-functions-custom-logic\#overview) This tutorial shows you how to use [Chainlink Automation](https://docs.chain.link/chainlink-automation) to automate your Chainlink Functions. Automation is essential when you want to trigger the same function regularly, such as fetching weather data daily or fetching an asset price on every block. Read the [Automate your Functions (Time-based Automation)](https://docs.chain.link/chainlink-functions/tutorials/automate-functions) tutorial before you follow the steps in this example. This tutorial explains how to trigger your functions using an [Automation compatible contract](https://docs.chain.link/chainlink-automation/guides/compatible-contracts). After you deploy and set up your contract, Chainlink Automation triggers your function on every block. ## [Prerequisites](https://docs.chain.link/chainlink-functions/tutorials/automate-functions-custom-logic\#prerequisites) ### [Set up your environment](https://docs.chain.link/chainlink-functions/tutorials/automate-functions-custom-logic\#set-up-your-environment) You must provide the private key from a testnet wallet to run the examples in this documentation. Install a Web3 wallet, configure [Node.js](https://nodejs.org/en/download/), clone the [smartcontractkit/smart-contract-examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository, and configure a `.env.enc` file with the required environment variables. Install and configure your Web3 wallet for Sepolia: 1. [Install Deno](https://docs.deno.com/runtime/manual/) so you can compile and simulate your Functions source code on your local machine. 2. [Install the MetaMask wallet](https://docs.chain.link/quickstarts/deploy-your-first-contract#install-and-fund-your-metamask-wallet) or other Ethereum Web3 wallet. 3. Set the network for your wallet to the Sepolia testnet. If you need to add Sepolia to your wallet, you can find the chain ID and the LINK token contract address on the [LINK Token Contracts](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) page. - [Sepolia testnet and LINK token contract](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) 4. Request testnet LINK and ETH from [faucets.chain.link/sepolia](https://faucets.chain.link/sepolia). Install the required frameworks and dependencies: 1. [Install the latest release of Node.js 20](https://nodejs.org/en/download/). Optionally, you can use the [nvm package](https://www.npmjs.com/package/nvm) to switch between Node.js versions with `nvm use 20`. **Note**: To ensure you are running the correct version in a terminal, type `node -v`. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node -v ``` ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell $ node -v v20.9.0 ``` 2. In a terminal, clone the [smart-contract examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository and change directories. This example repository imports the [Chainlink Functions Toolkit NPM package](https://www.npmjs.com/package/@chainlink/functions-toolkit). You can import this package to your own projects to enable them to work with Chainlink Functions. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell git clone https://github.com/smartcontractkit/smart-contract-examples.git && \ cd ./smart-contract-examples/functions-examples/ ``` 3. Run `npm install` to install the dependencies. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npm install ``` 4. For higher security, the examples repository encrypts your environment variables at rest. 1. Set an encryption password for your environment variables. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set-pw ``` 2. Run `npx env-enc set` to configure a `.env.enc` file with the basic variables that you need to send your requests to the Sepolia network. - `ETHEREUM_SEPOLIA_RPC_URL`: Set a URL for the Sepolia testnet. You can sign up for a personal endpoint from [Alchemy](https://www.alchemy.com/), [Infura](https://www.infura.io/), or another node provider service. - `PRIVATE_KEY`: Find the private key for your testnet wallet. If you use MetaMask, follow the instructions to [Export a Private Key](https://support.metamask.io/managing-my-wallet/secret-recovery-phrase-and-private-keys/how-to-export-an-accounts-private-key/). **Note**: Your private key is needed to sign any transactions you make such as making requests. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set ``` ### [Create and fund a Functions subscription](https://docs.chain.link/chainlink-functions/tutorials/automate-functions-custom-logic\#create-and-fund-a-functions-subscription) After you configure your local environment, create a Functions subscription to pay for the work done by the DON. Follow the [Managing Functions Subscriptions](https://docs.chain.link/chainlink-functions/resources/subscriptions#create-a-subscription) guide to accept the Chainlink Functions Terms of Service (ToS), create a subscription, and fund it. **Note**: If you followed the previous tutorials, then you can reuse an existing subscription. You will add your consumer contract to a subscription later in this guide using the [Chainlink Functions Subscription Manager](https://functions.chain.link/). ## [Tutorial](https://docs.chain.link/chainlink-functions/tutorials/automate-functions-custom-logic\#tutorial) This tutorial is configured to get the median `BTC/USD` price from multiple data sources on every block. Read the [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/automate-functions-custom-logic#examine-the-code) section for a detailed explanation of the code example. You can locate the scripts used in this tutorial in the [_examples/10-automate-functions_ directory](https://github.com/smartcontractkit/smart-contract-examples/tree/main/functions-examples/examples/10-automate-functions). 1. Make sure to understand the [API multiple calls](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls) guide. 2. Make sure your subscription has enough LINK to pay for your requests. Also, you must maintain a minimum balance to upload encrypted secrets to the DON (Read the [minimum balance for uploading encrypted secrets section](https://docs.chain.link/chainlink-functions/resources/billing#minimum-balance-for-uploading-encrypted-secrets) to learn more). You can check your subscription details (including the balance in LINK) in the [Chainlink Functions Subscription Manager](https://docs.chain.link/chainlink-functions/resources/subscriptions). If your subscription runs out of LINK, follow the [Fund a Subscription](https://docs.chain.link/chainlink-functions/resources/subscriptions#fund-a-subscription) guide. This guide recommends maintaining at least 2 LINK within your subscription. 3. Get a free API key from [CoinMarketCap](https://coinmarketcap.com/api/) and note your API key. 4. Run `npx env-enc set` to add an encrypted `COINMARKETCAP_API_KEY` to your `.env.enc` file. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set ``` ### [Deploy a Custom Automated Functions Consumer contract](https://docs.chain.link/chainlink-functions/tutorials/automate-functions-custom-logic\#deploy-a-custom-automated-functions-consumer-contract) The consumer contract for Custom Automated Functions is different from the consumer in other tutorials. Deploy the `CustomAutomatedFunctionsConsumerExample` contract on _Ethereum Sepolia_: 1. Open the [CustomAutomatedFunctionsConsumerExample.sol](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/CustomAutomatedFunctionsConsumerExample.sol) in Remix. [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/CustomAutomatedFunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) 2. Compile the contract. 3. Open MetaMask and select the _Ethereum Sepolia_ network. 4. In Remix under the **Deploy & Run Transactions** tab, select _Injected Provider - MetaMask_ in the **Environment** list. Remix will use the MetaMask wallet to communicate with _Ethereum Sepolia_. 5. Under the **Deploy** section, fill in the router address for your specific blockchain. You can find this address on the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks) page. For _Ethereum Sepolia_, the router address is `0xb83E47C2bC239B3bf370bc41e1459A34b41238D0`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg). 6. Click the **Deploy** button to deploy the contract. MetaMask prompts you to confirm the transaction. Check the transaction details to make sure you are deploying the contract to _Ethereum Sepolia_. 7. After you confirm the transaction, the contract address appears in the Deployed Contracts list. Copy your contract address. ### [Add your Consumer contract to your Functions subscription](https://docs.chain.link/chainlink-functions/tutorials/automate-functions-custom-logic\#add-your-consumer-contract-to-your-functions-subscription) Add your contract as an approved consumer contract to your Functions subscription using the [Chainlink Functions Subscription Manager](https://functions.chain.link/). ### [Configure your Consumer contract](https://docs.chain.link/chainlink-functions/tutorials/automate-functions-custom-logic\#configure-your-consumer-contract) Configure the request details by calling the `updateRequest` function. This step stores the encoded request (source code, reference to encrypted secrets if any, arguments), gas limit, subscription ID, and job ID in the contract storage (see [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/automate-functions-custom-logic#examine-the-code)). To do so, follow these steps: 1. On a terminal, change directories to the [_10-automate-functions_](https://github.com/smartcontractkit/smart-contract-examples/tree/main/functions-examples/examples/10-automate-functions) directory. 2. Open [updateRequest.js](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/10-automate-functions/updateRequest.js) and replace the consumer contract address and the subscription ID with your own values: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x5abE77Ba2aE8918bfD96e2e382d5f213f10D39fA" // REPLACE this with your Functions consumer address const subscriptionId = 3 // REPLACE this with your subscription ID ``` 3. Run the [updateRequest.js](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/10-automate-functions/updateRequest.js) script to update your Functions consumer contract's request details. ### [Configure Chainlink Automation](https://docs.chain.link/chainlink-functions/tutorials/automate-functions-custom-logic\#configure-chainlink-automation) The consumer contract that you deployed is designed to be used with a **custom logic** automation. Follow the instructions in the [Register a Custom Logic Upkeep](https://docs.chain.link/chainlink-automation/guides/register-upkeep) guide to register your deployed contract using the [Chainlink Automation App](https://automation.chain.link/). Use the following upkeep settings: - Trigger: Custom logic - Target contract address: The address of the Chainlink Functions consumer contract that you deployed - Name: Give your upkeep a name - Check data: Leave this field blank - Gas limit: `1000000`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) - Starting balance (LINK): `1`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) You can leave the other settings at their default values for the example in this tutorial. At this stage, your Functions consumer contract is configured to get the median Bitcoin price on every block. ### [Check Result](https://docs.chain.link/chainlink-functions/tutorials/automate-functions-custom-logic\#check-result) Go to the [Chainlink Automation App](https://automation.chain.link/) and connect to the Sepolia testnet. Your upkeep will be listed under _My upkeeps_: ![](https://docs.chain.link/images/chainlink-functions/tutorials/automation/cl-automation-custom-home.jpg) Click on your upkeep to fetch de details: ![](https://docs.chain.link/images/chainlink-functions/tutorials/automation/myupkeep-details-custom.jpg) On your terminal, run the [readLatest](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/10-automate-functions/readLatest.js) to read the latest received response: 1. Open `readLatest.js` and replace the consumer contract address with your own values: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x5abE77Ba2aE8918bfD96e2e382d5f213f10D39fA" // REPLACE this with your Functions consumer address ``` 2. Run the [readLatest](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/10-automate-functions/readLatest.js) script. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node examples/10-automate-functions/readLatest.js ``` Output Example: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```text $ node examples/10-automate-functions/readLatest.js secp256k1 unavailable, reverting to browser version Last request ID is 0xf4ae51b028ded52d33376810cd97f02e2b1dff424bb78d45730820fefc0b8060 ✅ Decoded response to uint256: 6688012n ``` ### [Clean up](https://docs.chain.link/chainlink-functions/tutorials/automate-functions-custom-logic\#clean-up) After you finish the guide, cancel your upkeep in the [Chainlink Automation App](https://automation.chain.link/) and withdraw the remaining funds. After you cancel the upkeep, there is a 50-block delay before you can withdraw the funds. ## [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/automate-functions-custom-logic\#examine-the-code) ### [CustomAutomatedFunctionsConsumer.sol](https://docs.chain.link/chainlink-functions/tutorials/automate-functions-custom-logic\#customautomatedfunctionsconsumersol) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {AutomationCompatibleInterface} from "@chainlink/contracts/src/v0.8/automation/AutomationCompatible.sol"; import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; /** * @title Functions contract used for Automation. * @notice This contract is a demonstration of using Functions and Automation. * @notice NOT FOR PRODUCTION USE */ contract CustomAutomatedFunctionsConsumerExample is FunctionsClient, AutomationCompatibleInterface, ConfirmedOwner { uint256 public lastBlockNumber; bytes public request; uint64 public subscriptionId; uint32 public gasLimit; bytes32 public donID; bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; uint256 public s_upkeepCounter; uint256 public s_requestCounter; uint256 public s_responseCounter; error UnexpectedRequestID(bytes32 requestId); event Response(bytes32 indexed requestId, bytes response, bytes err); event RequestRevertedWithErrorMsg(string reason); event RequestRevertedWithoutErrorMsg(bytes data); constructor( address router ) FunctionsClient(router) ConfirmedOwner(msg.sender) {} /** * @notice Checks if upkeep is needed based on the difference between the current and the last block number. * @dev This function checks if the current block number has incremented since the last recorded block number and returns a boolean indicating if upkeep is needed. * @return upkeepNeeded A boolean indicating if upkeep is needed (true if the current block number has incremented since the last recorded block number). * @return performData An empty bytes value since no additional data is needed for the upkeep in this implementation. */ function checkUpkeep( bytes calldata /* checkData */ ) external view override returns (bool upkeepNeeded, bytes memory performData) { upkeepNeeded = block.number - lastBlockNumber > 0; // Check if the current block number has incremented since the last recorded block number // We don't use the checkData in this example. The checkData is defined when the Upkeep was registered. return (upkeepNeeded, ""); // Return an empty bytes value for performData } /** * @notice Send a pre-encoded CBOR request if the current block number has incremented since the last recorded block number. */ function performUpkeep(bytes calldata /* performData */) external override { if (block.number - lastBlockNumber > 0) { lastBlockNumber = block.number; s_upkeepCounter = s_upkeepCounter + 1; try i_router.sendRequest( subscriptionId, request, FunctionsRequest.REQUEST_DATA_VERSION, gasLimit, donID ) returns (bytes32 requestId) { s_lastRequestId = requestId; s_requestCounter = s_requestCounter + 1; emit RequestSent(requestId); } catch Error(string memory reason) { emit RequestRevertedWithErrorMsg(reason); } catch (bytes memory data) { emit RequestRevertedWithoutErrorMsg(data); } } // We don't use the performData in this example. The performData is generated by the Automation Node's call to your checkUpkeep function } /// @notice Update the request settings /// @dev Only callable by the owner of the contract /// @param _request The new encoded CBOR request to be set. The request is encoded offchain /// @param _subscriptionId The new subscription ID to be set /// @param _gasLimit The new gas limit to be set /// @param _donID The new job ID to be set function updateRequest( bytes memory _request, uint64 _subscriptionId, uint32 _gasLimit, bytes32 _donID ) external onlyOwner { request = _request; subscriptionId = _subscriptionId; gasLimit = _gasLimit; donID = _donID; } /** * @notice Store latest result/error * @param requestId The request ID, returned by sendRequest() * @param response Aggregated response from the user code * @param err Aggregated error from the user code or from the execution pipeline * Either response or error parameter will be set, but never both */ function fulfillRequest( bytes32 requestId, bytes memory response, bytes memory err ) internal override { if (s_lastRequestId != requestId) { revert UnexpectedRequestID(requestId); } s_lastResponse = response; s_lastError = err; s_responseCounter = s_responseCounter + 1; emit Response(requestId, s_lastResponse, s_lastError); } } ``` [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/CustomAutomatedFunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) - To write an automated Chainlink Functions consumer contract, your contract must import [FunctionsClient.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol). You can read the API reference of [FunctionsClient](https://docs.chain.link/chainlink-functions/api-reference/functions-client). The contract is available in an NPM package, so you can import it from within your project. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; ``` - To write a compatible Automations contract, your contract must import [AutomationCompatibleInterface.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/automation/AutomationCompatible.sol). The contract is available in an NPM package, so you can import it from within your project. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext import {AutomationCompatibleInterface} from "@chainlink/contracts/src/v0.8/automation/AutomationCompatible.sol"; ``` - The `lastBlockNumber` is stored in the contract. It represents the block number of the last time `performUpkeep` was triggered. - The encoded `request`, `subscriptionId`, `gasLimit`, and `jobId` are stored in the contract storage. The contract owner sets these variables by calling the `updateRequest` function. **Note**: The request (source code, secrets, if any, and arguments) is encoded offchain. - The latest request id, latest received response, and latest received error (if any) are defined as state variables: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; ``` - We define the `Response` event that your smart contract will emit during the callback ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext event Response(bytes32 indexed requestId, bytes response, bytes err); ``` - We define two events that your smart contract emits when sending a request to Chainlink Functions fails: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext event RequestRevertedWithErrorMsg(string reason); event RequestRevertedWithoutErrorMsg(bytes data); ``` - Pass the router address for your network when you deploy the contract: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext constructor(address router) FunctionsClient(router) ``` - The three remaining functions are: - `checkUpkeep` for checking offchain if `performUpkeep` should be executed. `performUpkeep` should only be executed if the current block number is higher than the block number of the last execution. - `performUpkeep`: Executed by Chainlink Automation when `checkUpkeep` returns `true`. This function sends the request (encoded in `bytes`) to the router by calling the `FunctionsClient` `sendRequest` function. **Note**: We use _try and catch_ to gracefully handle reverts of `i_router.sendRequest` by emitting an event. We also update the `lastBlockNumber`, even when `i_router.sendRequest` is unsuccessful. - `fulfillRequest` to be invoked during the callback. This function is defined in `FunctionsClient` as `virtual` (read `fulfillRequest` [API reference](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#fulfillrequest)). So, your smart contract must override the function to implement the callback. The implementation of the callback is straightforward: the contract stores the latest response and error in `s_lastResponse` and `s_lastError`, then increments the response counter `s_responseCounter` before emitting the `Response` event. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastResponse = response; s_lastError = err; s_responseCounter = s_responseCounter + 1; emit Response(requestId, s_lastResponse, s_lastError); ``` ### [source.js](https://docs.chain.link/chainlink-functions/tutorials/automate-functions-custom-logic\#sourcejs) The JavaScript code is similar to the one used in the [Call Multiple Data Sources](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls) tutorial. ### [updateRequest.js](https://docs.chain.link/chainlink-functions/tutorials/automate-functions-custom-logic\#updaterequestjs) The JavaScript code is similar to the one used in the [Automate your Functions (Time-based Automation)](https://docs.chain.link/chainlink-functions/tutorials/automate-functions) tutorial. ### [readLatest.js](https://docs.chain.link/chainlink-functions/tutorials/automate-functions-custom-logic\#readlatestjs) The JavaScript code is similar to the one used in the [Automate your Functions (Time-based Automation)](https://docs.chain.link/chainlink-functions/tutorials/automate-functions) tutorial. ## Get the latest Chainlink content straight to your inbox. Email Address ## Automate Chainlink Functions [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Automate your Functions (Time-based Automation)](https://docs.chain.link/chainlink-functions/tutorials/automate-functions\#overview) This tutorial shows you how to use [Chainlink Automation](https://docs.chain.link/chainlink-automation) to automate your Chainlink Functions. Automation is essential when you want to trigger the same function regularly, such as fetching weather data daily or fetching an asset price on every block. Read the [API multiple calls](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls) tutorial before you follow the steps in this example. This tutorial uses the same example but with an important difference: - You will deploy [AutomatedFunctionsConsumerExample.sol](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/AutomatedFunctionsConsumerExample.sol) instead of the [FunctionsConsumerExample contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol). After you deploy and set up your contract, Chainlink Automation triggers your function according to a time schedule. ## [Prerequisites](https://docs.chain.link/chainlink-functions/tutorials/automate-functions\#prerequisites) ### [Set up your environment](https://docs.chain.link/chainlink-functions/tutorials/automate-functions\#set-up-your-environment) You must provide the private key from a testnet wallet to run the examples in this documentation. Install a Web3 wallet, configure [Node.js](https://nodejs.org/en/download/), clone the [smartcontractkit/smart-contract-examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository, and configure a `.env.enc` file with the required environment variables. Install and configure your Web3 wallet for Sepolia: 1. [Install Deno](https://docs.deno.com/runtime/manual/) so you can compile and simulate your Functions source code on your local machine. 2. [Install the MetaMask wallet](https://docs.chain.link/quickstarts/deploy-your-first-contract#install-and-fund-your-metamask-wallet) or other Ethereum Web3 wallet. 3. Set the network for your wallet to the Sepolia testnet. If you need to add Sepolia to your wallet, you can find the chain ID and the LINK token contract address on the [LINK Token Contracts](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) page. - [Sepolia testnet and LINK token contract](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) 4. Request testnet LINK and ETH from [faucets.chain.link/sepolia](https://faucets.chain.link/sepolia). Install the required frameworks and dependencies: 1. [Install the latest release of Node.js 20](https://nodejs.org/en/download/). Optionally, you can use the [nvm package](https://www.npmjs.com/package/nvm) to switch between Node.js versions with `nvm use 20`. **Note**: To ensure you are running the correct version in a terminal, type `node -v`. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node -v ``` ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell $ node -v v20.9.0 ``` 2. In a terminal, clone the [smart-contract examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository and change directories. This example repository imports the [Chainlink Functions Toolkit NPM package](https://www.npmjs.com/package/@chainlink/functions-toolkit). You can import this package to your own projects to enable them to work with Chainlink Functions. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell git clone https://github.com/smartcontractkit/smart-contract-examples.git && \ cd ./smart-contract-examples/functions-examples/ ``` 3. Run `npm install` to install the dependencies. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npm install ``` 4. For higher security, the examples repository encrypts your environment variables at rest. 1. Set an encryption password for your environment variables. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set-pw ``` 2. Run `npx env-enc set` to configure a `.env.enc` file with the basic variables that you need to send your requests to the Sepolia network. - `ETHEREUM_SEPOLIA_RPC_URL`: Set a URL for the Sepolia testnet. You can sign up for a personal endpoint from [Alchemy](https://www.alchemy.com/), [Infura](https://www.infura.io/), or another node provider service. - `PRIVATE_KEY`: Find the private key for your testnet wallet. If you use MetaMask, follow the instructions to [Export a Private Key](https://support.metamask.io/managing-my-wallet/secret-recovery-phrase-and-private-keys/how-to-export-an-accounts-private-key/). **Note**: Your private key is needed to sign any transactions you make such as making requests. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set ``` ### [Create and fund a Functions subscription](https://docs.chain.link/chainlink-functions/tutorials/automate-functions\#create-and-fund-a-functions-subscription) After you configure your local environment, create a Functions subscription to pay for the work done by the DON. Follow the [Managing Functions Subscriptions](https://docs.chain.link/chainlink-functions/resources/subscriptions#create-a-subscription) guide to accept the Chainlink Functions Terms of Service (ToS), create a subscription, and fund it. **Note**: If you followed the previous tutorials, then you can reuse an existing subscription. You will add your consumer contract to a subscription later in this guide using the [Chainlink Functions Subscription Manager](https://functions.chain.link/). ## [Tutorial](https://docs.chain.link/chainlink-functions/tutorials/automate-functions\#tutorial) This tutorial is configured to get the median `BTC/USD` price from multiple data sources according to a time schedule. For a detailed explanation of the code example, read the [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/automate-functions#examine-the-code) section. You can locate the scripts used in this tutorial in the [_examples/10-automate-functions_ directory](https://github.com/smartcontractkit/smart-contract-examples/tree/main/functions-examples/examples/10-automate-functions). 1. Make sure to understand the [API multiple calls](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls) guide. 2. Make sure your subscription has enough LINK to pay for your requests. Also, you must maintain a minimum balance to upload encrypted secrets to the DON (Read the [minimum balance for uploading encrypted secrets section](https://docs.chain.link/chainlink-functions/resources/billing#minimum-balance-for-uploading-encrypted-secrets) to learn more). You can check your subscription details (including the balance in LINK) in the [Chainlink Functions Subscription Manager](https://docs.chain.link/chainlink-functions/resources/subscriptions). If your subscription runs out of LINK, follow the [Fund a Subscription](https://docs.chain.link/chainlink-functions/resources/subscriptions#fund-a-subscription) guide. This guide recommends maintaining at least 2 LINK within your subscription. 3. Get a free API key from [CoinMarketCap](https://coinmarketcap.com/api/) and note your API key. 4. Run `npx env-enc set` to add an encrypted `COINMARKETCAP_API_KEY` to your `.env.enc` file. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set ``` ### [Deploy an Automated Functions Consumer contract](https://docs.chain.link/chainlink-functions/tutorials/automate-functions\#deploy-an-automated-functions-consumer-contract) The consumer contract for Automated Functions is different from the consumer in other tutorials. Deploy the `AutomatedFunctionsConsumerExample` contract on _Ethereum Sepolia_: 1. Open the [AutomatedFunctionsConsumerExample.sol](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/AutomatedFunctionsConsumerExample.sol) in Remix. [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/AutomatedFunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) 2. Compile the contract. 3. Open MetaMask and select the _Ethereum Sepolia_ network. 4. In Remix under the **Deploy & Run Transactions** tab, select _Injected Provider - MetaMask_ in the **Environment** list. Remix will use the MetaMask wallet to communicate with _Ethereum Sepolia_. 5. Under the **Deploy** section, fill in the router address for your specific blockchain. You can find this address on the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks) page. For _Ethereum Sepolia_, the router address is `0xb83E47C2bC239B3bf370bc41e1459A34b41238D0`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg). 6. Click the **Deploy** button to deploy the contract. MetaMask prompts you to confirm the transaction. Check the transaction details to make sure you are deploying the contract to _Ethereum Sepolia_. 7. After you confirm the transaction, the contract address appears in the Deployed Contracts list. Copy your contract address. ### [Add your Consumer contract to your Functions subscription](https://docs.chain.link/chainlink-functions/tutorials/automate-functions\#add-your-consumer-contract-to-your-functions-subscription) Add your contract as an approved consumer contract to your Functions subscription using the [Chainlink Functions Subscription Manager](https://functions.chain.link/). ### [Configure Chainlink Automation](https://docs.chain.link/chainlink-functions/tutorials/automate-functions\#configure-chainlink-automation) The consumer contract that you deployed is designed to be used with a **time-based** automation. Follow the instructions in the [Automation Job Scheduler](https://docs.chain.link/chainlink-automation/guides/job-scheduler) guide to register your deployed contract using the [Chainlink Automation App](https://automation.chain.link/). Use the following upkeep settings: - Trigger: Time-based - Target contract address: The address of the automated Functions consumer contract that you deployed - ABI: copy/paste the ABI from [automatedFunctions.json](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/abi/automatedFunctions.json) - Target function: sendRequestCBOR - Time interval: Every 15 minutes - Name: Give your upkeep a name - Gas limit: `1000000`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) - Starting balance (LINK): `1`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) You can leave the other settings at their default values for the example in this tutorial. **Note**: After creation, check your upkeep details and note the address of the upkeep contract. The upkeep contract is responsible for calling your Functions consumer contract at regular times intervals. ![Register Functions consumer with automation scheduler](https://docs.chain.link/images/chainlink-functions/tutorials/automation/automation-register-scheduler.jpg) ### [Configure your Consumer contract](https://docs.chain.link/chainlink-functions/tutorials/automate-functions\#configure-your-consumer-contract) Two important steps are done here: 1. Configure your contract so only the upkeep contract can call the `sendRequestCBOR` function. This security measure is important to prevent anyone from calling several times `sendRequestCBOR` and draining your Functions subscription balance. Follow these steps: 1. On RemixIDE, under the _Deploy & Transactions_ tab, locate your deployed Functions consumer contract. 2. Open the list of functions. 3. Fill in the `setAutomationCronContract` function with the upkeep contract address you copied from the previous step. 4. Click on _transact_. A Metamask popup appears and asks you to confirm the transaction. 5. Confirm the transaction and wait for it to be confirmed. 2. Configure the request details by calling the `updateRequest` function. This step stores the encoded request (source code, reference to encrypted secrets if any, arguments), gas limit, subscription ID, and job ID in the contract storage (see [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/automate-functions#examine-the-code)). To do so, follow these steps: 1. On a terminal, change directories to the [_10-automate-functions_](https://github.com/smartcontractkit/smart-contract-examples/tree/main/functions-examples/examples/10-automate-functions) directory. 2. Open [updateRequest.js](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/10-automate-functions/updateRequest.js) and replace the consumer contract address and the subscription ID with your own values: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x5abE77Ba2aE8918bfD96e2e382d5f213f10D39fA" // REPLACE this with your Functions consumer address const subscriptionId = 3 // REPLACE this with your subscription ID ``` 3. Run the [updateRequest.js](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/10-automate-functions/updateRequest.js) script. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node examples/10-automate-functions/updateRequest.js ``` Output example: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```text $ node examples/10-automate-functions/updateRequest.js secp256k1 unavailable, reverting to browser version Start simulation... Simulation result { capturedTerminalOutput: 'Median Bitcoin price: 66725.29\n', responseBytesHexstring: '0x000000000000000000000000000000000000000000000000000000000065d091' } ✅ Decoded response to uint256: 6672529n Make request... Upload encrypted secret to gateways https://01.functions-gateway.testnet.chain.link/,https://02.functions-gateway.testnet.chain.link/. slotId 0. Expiration in minutes: 150 ✅ Secrets uploaded properly to gateways https://01.functions-gateway.testnet.chain.link/,https://02.functions-gateway.testnet.chain.link/! Gateways response: { version: 1712948932, success: true } ✅ Automated Functions request settings updated! Transaction hash 0x670c6a768a3fbccdcc344e51827ba41a13a579427272522550ad5810ca5b81a3 - Check the explorer https://sepolia.etherscan.io/tx/0x670c6a768a3fbccdcc344e51827ba41a13a579427272522550ad5810ca5b81a3 ``` The output of the example gives you the following information: - Your request is first run on a sandbox environment to ensure it is correctly configured. - The encrypted secrets were uploaded to the secrets endpoint `https://01.functions-gateway.testnet.chain.link/user`. - The Functions consumer contract's request details are updated. At this stage, your Functions consumer contract is configured to get the median Bitcoin price every 15 minutes. ### [Check Result](https://docs.chain.link/chainlink-functions/tutorials/automate-functions\#check-result) Go to the [Chainlink Automation App](https://automation.chain.link/) and connect to the Sepolia testnet. Your upkeep will be listed under _My upkeeps_: ![](https://docs.chain.link/images/chainlink-functions/tutorials/automation/cl-automation-home.jpg) Click on your upkeep to fetch de details: ![](https://docs.chain.link/images/chainlink-functions/tutorials/automation/myupkeep-details.jpg) As you can see in the _History_ table, the upkeep is running every 15 minutes. On your terminal, run the [readLatest](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/10-automate-functions/readLatest.js) script to read the latest received response: 1. Open `readLatest.js` and replace the consumer contract address with your own values: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x5abE77Ba2aE8918bfD96e2e382d5f213f10D39fA" // REPLACE this with your Functions consumer address ``` 2. Run the [readLatest](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/10-automate-functions/readLatest.js) script. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node examples/10-automate-functions/readLatest.js ``` Output example: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```text $ node examples/10-automate-functions/readLatest.js secp256k1 unavailable, reverting to browser version Last request ID is 0xa6c0a45c9a24981e0112381f9addeeb8f8a9ad0ea91dd0426703eaa11d5a773a ✅ Decoded response to uint256: 6675568n ``` ### [Clean up](https://docs.chain.link/chainlink-functions/tutorials/automate-functions\#clean-up) After you finish the guide, cancel your upkeep in the [Chainlink Automation App](https://automation.chain.link/) and withdraw the remaining funds. After you cancel the upkeep, there is a 50-block delay before you can withdraw the funds. ## [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/automate-functions\#examine-the-code) ### [AutomatedFunctionsConsumer.sol](https://docs.chain.link/chainlink-functions/tutorials/automate-functions\#automatedfunctionsconsumersol) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; /** * @title Functions contract used for Automation. * @notice This contract is a demonstration of using Functions and Automation. * @notice You may need to add a Forwarder for additional security. * @notice NOT FOR PRODUCTION USE */ contract AutomatedFunctionsConsumerExample is FunctionsClient, ConfirmedOwner { address public upkeepContract; bytes public request; uint64 public subscriptionId; uint32 public gasLimit; bytes32 public donID; bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; error NotAllowedCaller( address caller, address owner, address automationRegistry ); error UnexpectedRequestID(bytes32 requestId); event Response(bytes32 indexed requestId, bytes response, bytes err); constructor( address router ) FunctionsClient(router) ConfirmedOwner(msg.sender) {} /** * @notice Reverts if called by anyone other than the contract owner or automation registry. */ modifier onlyAllowed() { if (msg.sender != owner() && msg.sender != upkeepContract) revert NotAllowedCaller(msg.sender, owner(), upkeepContract); _; } function setAutomationCronContract( address _upkeepContract ) external onlyOwner { upkeepContract = _upkeepContract; } /// @notice Update the request settings /// @dev Only callable by the owner of the contract /// @param _request The new encoded CBOR request to be set. The request is encoded offchain /// @param _subscriptionId The new subscription ID to be set /// @param _gasLimit The new gas limit to be set /// @param _donID The new job ID to be set function updateRequest( bytes memory _request, uint64 _subscriptionId, uint32 _gasLimit, bytes32 _donID ) external onlyOwner { request = _request; subscriptionId = _subscriptionId; gasLimit = _gasLimit; donID = _donID; } /** * @notice Send a pre-encoded CBOR request * @return requestId The ID of the sent request */ function sendRequestCBOR() external onlyAllowed returns (bytes32 requestId) { s_lastRequestId = _sendRequest( request, subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Store latest result/error * @param requestId The request ID, returned by sendRequest() * @param response Aggregated response from the user code * @param err Aggregated error from the user code or from the execution pipeline * Either response or error parameter will be set, but never both */ function fulfillRequest( bytes32 requestId, bytes memory response, bytes memory err ) internal override { if (s_lastRequestId != requestId) { revert UnexpectedRequestID(requestId); } s_lastResponse = response; s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); } } ``` [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/AutomatedFunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) - To write an automated Chainlink Functions consumer contract, your contract must import [FunctionsClient.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol). You can read the API reference of [FunctionsClient](https://docs.chain.link/chainlink-functions/api-reference/functions-client). The contract is available in an NPM package, so you can import it from within your project. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; ``` - The `upkeepContract` address is stored in the contract storage. The contract owner sets this variable by calling the `setAutomationCronContract` function. **Note**: This variable is used by the `onlyAllowed` to ensure only the upkeep contract can call the `sendRequestCBOR` function. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext address public upkeepContract ``` - The encoded `request`, `subscriptionId`, `gasLimit`, and `jobId` are stored in the contract storage. The contract owner sets these variables by calling the `updateRequest` function. **Note**: The request (source code, secrets, if any, and arguments) is encoded offchain. - The latest request id, latest received response, and latest received error (if any) are defined as state variables: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; ``` - We define the `Response` event that your smart contract will emit during the callback ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext event Response(bytes32 indexed requestId, bytes response, bytes err); ``` - Pass the router address for your network when you deploy the contract: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext constructor(address router) FunctionsClient(router) ``` - The two remaining functions are: - `sendRequestCBOR` for sending a request already encoded in `bytes`. It sends the request to the router by calling the `FunctionsClient` `sendRequest` function. - `fulfillRequest` to be invoked during the callback. This function is defined in `FunctionsClient` as `virtual` (read `fulfillRequest` [API reference](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#fulfillrequest)). So, your smart contract must override the function to implement the callback. The implementation of the callback is straightforward: the contract stores the latest response and error in `s_lastResponse` and `s_lastError` before emitting the `Response` event. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastResponse = response; s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); ``` ### [source.js](https://docs.chain.link/chainlink-functions/tutorials/automate-functions\#sourcejs) The JavaScript code is similar to the [Call Multiple Data Sources](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls) tutorial. ### [updateRequest.js](https://docs.chain.link/chainlink-functions/tutorials/automate-functions\#updaterequestjs) This explanation focuses on the [updateRequest.js](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/10-automate-functions/updateRequest.js) script and shows how to use the [Chainlink Functions NPM package](https://github.com/smartcontractkit/functions-toolkit) in your own JavaScript/TypeScript project to encode a request offchain and store it in your contract. The code is self-explanatory and has comments to help you understand all the steps. The script imports: - [path](https://nodejs.org/docs/latest/api/path.html) and [fs](https://nodejs.org/api/fs.html) : Used to read the [source file](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/5-use-secrets-threshold/source.js). - [ethers](https://docs.ethers.org/v5/): Ethers.js library, enables the script to interact with the blockchain. - `@chainlink/functions-toolkit`: Chainlink Functions NPM package. All its utilities are documented in the [NPM README](https://github.com/smartcontractkit/functions-toolkit/blob/main/README.md). - `@chainlink/env-enc`: A tool for loading and storing encrypted environment variables. Read the [official documentation](https://www.npmjs.com/package/@chainlink/env-enc) to learn more. - `../abi/automatedFunctions.json`: The ABI of the contract your script will interact with. **Note**: The script was tested with this [AutomatedFunctionsConsumer contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/AutomatedFunctionsConsumerExample.sol). The script has two hardcoded values that you have to change using your own Functions consumer contract and subscription ID: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x5abE77Ba2aE8918bfD96e2e382d5f213f10D39fA" // REPLACE this with your Functions consumer address const subscriptionId = 3 // REPLACE this with your subscription ID ``` The primary function that the script executes is `updateRequestSepolia`. This function consists of five main parts: 1. Definition of necessary identifiers: - `routerAddress`: Chainlink Functions router address on the Sepolia testnet. - `donId`: Identifier of the DON that will fulfill your requests on the Sepolia testnet. - `gatewayUrls`: The secrets endpoint URL to which you will upload the encrypted secrets. - `explorerUrl`: Block explorer URL of the Sepolia testnet. - `source`: The source code must be a string object. That's why we use `fs.readFileSync` to read `source.js` and then call `toString()` to get the content as a `string` object. - `args`: During the execution of your function, These arguments are passed to the source code. The `args` value is `["1", "bitcoin", "btc-bitcoin"]`. These arguments are BTC IDs at CoinMarketCap, CoinGecko, and Coinpaprika. You can adapt args to fetch other asset prices. - `secrets`: The secrets object that will be encrypted. - `slotIdNumber`: Slot ID at the DON where to upload the encrypted secrets. - `expirationTimeMinutes`: Expiration time in minutes of the encrypted secrets. - `gasLimit`: Maximum gas that Chainlink Functions can use when transmitting the response to your contract. - Initialization of ethers `signer` and `provider` objects. The signer is used to make transactions on the blockchain, and the provider reads data from the blockchain. 2. Simulating your request in a local sandbox environment: - Use `simulateScript` from the Chainlink Functions NPM package. - Read the `response` of the simulation. If successful, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.uint256` in this example). 3. Encrypt the secrets, upload the encrypted secrets to the DON, and then encode the reference to the DON-hosted encrypted secrets. This is done in three steps: - Initialize a `SecretsManager` instance from the Functions NPM package, then call the `encryptSecrets` function. - Call the `uploadEncryptedSecretsToDON` function of the `SecretsManager` instance. This function returns an object containing a `success` boolean as long as `version`, the secret version on the DON storage. - Call the `buildDONHostedEncryptedSecretsReference` function of the `SecretsManager` instance and use the slot ID and version to encode the DON-hosted encrypted secrets reference. 4. Encode the request data offchain using the `buildRequestCBOR` function from the Functions NPM package. 5. Update the Functions consumer contract: - Initialize your functions consumer contract using the contract address, abi, and ethers signer. - Call the `updateRequest` function of your consumer contract. ### [readLatest.js](https://docs.chain.link/chainlink-functions/tutorials/automate-functions\#readlatestjs) This explanation focuses on the [readLatest.js](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/10-automate-functions/readLatest.js) script that reads your consumer contract's latest received response and decodes it offchain using the Chainlink Function NPM package. The script contains a hardcoded value that you must replace with your own Functions consumer contract address: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x5abE77Ba2aE8918bfD96e2e382d5f213f10D39fA" // REPLACE this with your Functions consumer address ``` The primary function that the script executes is `readLatest`. This function can be broken down into two main parts: 1. Read the latest response: - Initialize your functions consumer contract using the contract address, ABI, and ethers provider. - Call the `s_lastRequestId`, `s_lastResponse`, and `s_lastError` functions of your consumer contract. 2. Decode the latest response: - If there was an error, read the latest error and parse it into a `string`. - If there was no error, use the Functions NPM package's `decodeResult` function and the `ReturnType` enum to decode the response to the expected return type ( `ReturnType.uint256` in this example). ## Get the latest Chainlink content straight to your inbox. Email Address ## Encode Offchain Requests [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Encode request data offchain](https://docs.chain.link/chainlink-functions/tutorials/encode-request-offchain\#overview) This tutorial shows you how make multiple API calls from your smart contract to a Decentralized Oracle Network. After [OCR](https://docs.chain.link/chainlink-functions/resources/architecture) completes offchain computation and aggregation, the DON returns the asset price to your smart contract. This example returns the `BTC/USD` price. This guide assumes that you know how to build HTTP requests and how to use secrets. Read the [API query parameters](https://docs.chain.link/chainlink-functions/tutorials/api-query-parameters) and [API use secrets](https://docs.chain.link/chainlink-functions/tutorials/api-use-secrets) guides before you follow the example in this document. To build a decentralized asset price, send a request to the DON to fetch the price from many different API providers. Then, calculate the median price. The API providers in this example are: - [CoinMarket](https://coinmarketcap.com/api/documentation/v1/) - [CoinGecko](https://www.coingecko.com/en/api/documentation) - [CoinPaprika](https://api.coinpaprika.com/) Read the [Call Multiple Data Sources](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls) tutorial before you follow the steps in this example. This tutorial uses the same example but with a slightly different process: - Instead of sending the request data (source code, encrypted secrets reference, and arguments) in the request, you will first encode it offchain and then send the encoded request. Encoding the request offchain from your front end or a server rather than onchain from your smart contract. This helps save gas. ## [Prerequisites](https://docs.chain.link/chainlink-functions/tutorials/encode-request-offchain\#prerequisites) ### [Set up your environment](https://docs.chain.link/chainlink-functions/tutorials/encode-request-offchain\#set-up-your-environment) You must provide the private key from a testnet wallet to run the examples in this documentation. Install a Web3 wallet, configure [Node.js](https://nodejs.org/en/download/), clone the [smartcontractkit/smart-contract-examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository, and configure a `.env.enc` file with the required environment variables. Install and configure your Web3 wallet for Ethereum Sepolia: 1. [Install Deno](https://docs.deno.com/runtime/manual/) so you can compile and simulate your Functions source code on your local machine. 2. [Install the MetaMask wallet](https://docs.chain.link/quickstarts/deploy-your-first-contract#install-and-fund-your-metamask-wallet) or other Ethereum Web3 wallet. 3. Set the network for your wallet to the Sepolia testnet. If you need to add Sepolia to your wallet, you can find the chain ID and the LINK token contract address on the [LINK Token Contracts](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) page. - [Sepolia testnet and LINK token contract](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) 4. Request testnet LINK and ETH from [faucets.chain.link/sepolia](https://faucets.chain.link/sepolia). Install the required frameworks and dependencies: 1. [Install the latest release of Node.js 20](https://nodejs.org/en/download/). Optionally, you can use the [nvm package](https://www.npmjs.com/package/nvm) to switch between Node.js versions with `nvm use 20`. **Note**: To ensure you are running the correct version in a terminal, type `node -v`. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node -v ``` ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell $ node -v v20.9.0 ``` 2. In a terminal, clone the [smart-contract examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository and change directories. This example repository imports the [Chainlink Functions Toolkit NPM package](https://www.npmjs.com/package/@chainlink/functions-toolkit). You can import this package to your own projects to enable them to work with Chainlink Functions. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell git clone https://github.com/smartcontractkit/smart-contract-examples.git && \ cd ./smart-contract-examples/functions-examples/ ``` 3. Run `npm install` to install the dependencies. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npm install ``` 4. For higher security, the examples repository encrypts your environment variables at rest. 1. Set an encryption password for your environment variables. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set-pw ``` 2. Run `npx env-enc set` to configure a `.env.enc` file with the basic variables that you need to send your requests to the Sepolia network. - `ETHEREUM_SEPOLIA_RPC_URL`: Set a URL for the Sepolia testnet. You can sign up for a personal endpoint from [Alchemy](https://www.alchemy.com/), [Infura](https://www.infura.io/), or another node provider service. - `PRIVATE_KEY`: Find the private key for your testnet wallet. If you use MetaMask, follow the instructions to [Export a Private Key](https://support.metamask.io/managing-my-wallet/secret-recovery-phrase-and-private-keys/how-to-export-an-accounts-private-key/). **Note**: Your private key is needed to sign any transactions you make such as making requests. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set ``` ### [Configure your onchain resources](https://docs.chain.link/chainlink-functions/tutorials/encode-request-offchain\#configure-your-onchain-resources) After you configure your local environment, configure some onchain resources to process your requests, receive the responses, and pay for the work done by the DON. #### [Deploy a Functions consumer contract on _Sepolia_](https://docs.chain.link/chainlink-functions/tutorials/encode-request-offchain\#deploy-a-functions-consumer-contract-on-sepolia) 1. [Open the FunctionsConsumerExample.sol contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol) in Remix. [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) 2. Compile the contract. 3. Open MetaMask and select the _Sepolia_ network. 4. In Remix under the **Deploy & Run Transactions** tab, select _Injected Provider - MetaMask_ in the **Environment** list. Remix will use the MetaMask wallet to communicate with _Sepolia_. 5. Under the **Deploy** section, fill in the router address for your specific blockchain. You can find both of these addresses on the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks) page. For _Sepolia_, the router address is `0xb83E47C2bC239B3bf370bc41e1459A34b41238D0`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg). 6. Click the **Deploy** button to deploy the contract. MetaMask prompts you to confirm the transaction. Check the transaction details to make sure you are deploying the contract to _Sepolia_. 7. After you confirm the transaction, the contract address appears in the **Deployed Contracts** list. Copy the contract address. #### [Create a subscription](https://docs.chain.link/chainlink-functions/tutorials/encode-request-offchain\#create-a-subscription) Follow the [Managing Functions Subscriptions](https://docs.chain.link/chainlink-functions/resources/subscriptions#create-a-subscription) guide to accept the Chainlink Functions Terms of Service (ToS), create a subscription, fund it, then add your consumer contract address to it. You can find the Chainlink Functions Subscription Manager at [functions.chain.link](https://functions.chain.link/). ## [Tutorial](https://docs.chain.link/chainlink-functions/tutorials/encode-request-offchain\#tutorial) This tutorial is configured to get the median `BTC/USD` price from multiple data sources. For a detailed explanation of the code example, read the [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/encode-request-offchain#examine-the-code) section. You can locate the scripts used in this tutorial in the [_examples/9-send-cbor_ directory](https://github.com/smartcontractkit/smart-contract-examples/tree/main/functions-examples/examples/9-send-cbor). 1. Make sure your subscription has enough LINK to pay for your requests. Also, you must maintain a minimum balance to upload encrypted secrets to the DON (Read the [minimum balance for uploading encrypted secrets section](https://docs.chain.link/chainlink-functions/resources/billing#minimum-balance-for-uploading-encrypted-secrets) to learn more). You can check your subscription details (including the balance in LINK) in the [Chainlink Functions Subscription Manager](https://docs.chain.link/chainlink-functions/resources/subscriptions). If your subscription runs out of LINK, follow the [Fund a Subscription](https://docs.chain.link/chainlink-functions/resources/subscriptions#fund-a-subscription) guide. This guide recommends maintaining at least 2 LINK within your subscription. 2. Get a free API key from [CoinMarketCap](https://coinmarketcap.com/api/) and note your API key. 3. Run `npx env-enc set` to add an encrypted `COINMARKETCAP_API_KEY` to your `.env.enc` file. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set ``` To run the example: 1. Open the file `request.js`, which is located in the `9-send-cbor` folder. 2. Replace the consumer contract address and the subscription ID with your own values. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x8dFf78B7EE3128D00E90611FBeD20A71397064D9" // REPLACE this with your Functions consumer address const subscriptionId = 3 // REPLACE this with your subscription ID ``` 3. Make a request: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node examples/9-send-cbor/request.js ``` The script runs your function in a sandbox environment before making an onchain transaction: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```text $ node examples/9-send-cbor/request.js secp256k1 unavailable, reverting to browser version Start simulation... Simulation result { capturedTerminalOutput: 'Median Bitcoin price: 66346.16\n', responseBytesHexstring: '0x0000000000000000000000000000000000000000000000000000000000653c78' } ✅ Decoded response to uint256: 6634616n Estimate request costs... Fulfillment cost estimated to 1.08425528035514 LINK Make request... Upload encrypted secret to gateways https://01.functions-gateway.testnet.chain.link/,https://02.functions-gateway.testnet.chain.link/. slotId 0. Expiration in minutes: 15 ✅ Secrets uploaded properly to gateways https://01.functions-gateway.testnet.chain.link/,https://02.functions-gateway.testnet.chain.link/! Gateways response: { version: 1712947615, success: true } ✅ Functions request sent! Transaction hash 0x730a66676cd797b11943635d53af9941c561d90a7088106800d05b4fdb2de189. Waiting for a response... See your request in the explorer https://sepolia.etherscan.io/tx/0x730a66676cd797b11943635d53af9941c561d90a7088106800d05b4fdb2de189 ✅ Request 0x8329a6e56461117508885f9eaee338f25095eb0f863d6972877f38c4412c0a29 successfully fulfilled. Cost is 0.236443904180225775 LINK.Complete response: { requestId: '0x8329a6e56461117508885f9eaee338f25095eb0f863d6972877f38c4412c0a29', subscriptionId: 2303, totalCostInJuels: 236443904180225775n, responseBytesHexstring: '0x0000000000000000000000000000000000000000000000000000000000653c78', errorString: '', returnDataBytesHexstring: '0x', fulfillmentCode: 0 } ✅ Decoded response to uint256: 6634616n ``` The output of the example gives you the following information: - Your request is first run on a sandbox environment to ensure it is correctly configured. - The fulfillment costs are estimated before making the request. - The encrypted secrets were uploaded to the secrets endpoint `https://01.functions-gateway.testnet.chain.link/user`. - Your request was successfully sent to Chainlink Functions. The transaction in this example is [0x730a66676cd797b11943635d53af9941c561d90a7088106800d05b4fdb2de189](https://sepolia.etherscan.io/tx/0x730a66676cd797b11943635d53af9941c561d90a7088106800d05b4fdb2de189) and the request ID is `0x8329a6e56461117508885f9eaee338f25095eb0f863d6972877f38c4412c0a29`. - The DON successfully fulfilled your request. The total cost was: `0.236443904180225775 LINK`. - The consumer contract received a response in `bytes` with a value of `0x0000000000000000000000000000000000000000000000000000000000653c78`. Decoding it offchain to `uint256` gives you a result: `6634616`. The median BTC price is 66346.16 USD. ## [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/encode-request-offchain\#examine-the-code) ### [FunctionsConsumerExample.sol](https://docs.chain.link/chainlink-functions/tutorials/encode-request-offchain\#functionsconsumerexamplesol) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; /** * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. * DO NOT USE THIS CODE IN PRODUCTION. */ contract FunctionsConsumerExample is FunctionsClient, ConfirmedOwner { using FunctionsRequest for FunctionsRequest.Request; bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; error UnexpectedRequestID(bytes32 requestId); event Response(bytes32 indexed requestId, bytes response, bytes err); constructor( address router ) FunctionsClient(router) ConfirmedOwner(msg.sender) {} /** * @notice Send a simple request * @param source JavaScript source code * @param encryptedSecretsUrls Encrypted URLs where to fetch user secrets * @param donHostedSecretsSlotID Don hosted secrets slotId * @param donHostedSecretsVersion Don hosted secrets version * @param args List of arguments accessible from within the source code * @param bytesArgs Array of bytes arguments, represented as hex strings * @param subscriptionId Billing ID */ function sendRequest( string memory source, bytes memory encryptedSecretsUrls, uint8 donHostedSecretsSlotID, uint64 donHostedSecretsVersion, string[] memory args, bytes[] memory bytesArgs, uint64 subscriptionId, uint32 gasLimit, bytes32 donID ) external onlyOwner returns (bytes32 requestId) { FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); if (encryptedSecretsUrls.length > 0) req.addSecretsReference(encryptedSecretsUrls); else if (donHostedSecretsVersion > 0) { req.addDONHostedSecrets( donHostedSecretsSlotID, donHostedSecretsVersion ); } if (args.length > 0) req.setArgs(args); if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Send a pre-encoded CBOR request * @param request CBOR-encoded request data * @param subscriptionId Billing ID * @param gasLimit The maximum amount of gas the request can consume * @param donID ID of the job to be invoked * @return requestId The ID of the sent request */ function sendRequestCBOR( bytes memory request, uint64 subscriptionId, uint32 gasLimit, bytes32 donID ) external onlyOwner returns (bytes32 requestId) { s_lastRequestId = _sendRequest( request, subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Store latest result/error * @param requestId The request ID, returned by sendRequest() * @param response Aggregated response from the user code * @param err Aggregated error from the user code or from the execution pipeline * Either response or error parameter will be set, but never both */ function fulfillRequest( bytes32 requestId, bytes memory response, bytes memory err ) internal override { if (s_lastRequestId != requestId) { revert UnexpectedRequestID(requestId); } s_lastResponse = response; s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); } } ``` [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) - To write a Chainlink Functions consumer contract, your contract must import [FunctionsClient.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol) and [FunctionsRequest.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol). You can read the API references: [FunctionsClient](https://docs.chain.link/chainlink-functions/api-reference/functions-client) and [FunctionsRequest](https://docs.chain.link/chainlink-functions/api-reference/functions-request). These contracts are available in an NPM package, so you can import them from within your project. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; ``` - Use the FunctionsRequest.sol library to get all the functions needed for building a Chainlink Functions request. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext using FunctionsRequest for FunctionsRequest.Request; ``` - The latest request id, latest received response, and latest received error (if any) are defined as state variables: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; ``` - We define the `Response` event that your smart contract will emit during the callback ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext event Response(bytes32 indexed requestId, bytes response, bytes err); ``` - Pass the router address for your network when you deploy the contract: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext constructor(address router) FunctionsClient(router) ``` - The three remaining functions are: - `sendRequest` for sending a request. It receives the JavaScript source code, encrypted secretsUrls (in case the encrypted secrets are hosted by the user), DON hosted secrets slot id and version (in case the encrypted secrets are hosted by the DON), list of arguments to pass to the source code, subscription id, and callback gas limit as parameters. Then: - It uses the `FunctionsRequest` library to initialize the request and add any passed encrypted secrets reference or arguments. You can read the API Reference for [Initializing a request](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#initializerequestforinlinejavascript), [adding user hosted secrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#addsecretsreference), [adding DON hosted secrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#adddonhostedsecrets), [adding arguments](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#setargs), and [adding bytes arguments](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#setbytesargs). ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); if (encryptedSecretsUrls.length > 0) req.addSecretsReference(encryptedSecretsUrls); else if (donHostedSecretsVersion > 0) { req.addDONHostedSecrets( donHostedSecretsSlotID, donHostedSecretsVersion ); } if (args.length > 0) req.setArgs(args); if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); ``` - It sends the request to the router by calling the `FunctionsClient` `sendRequest` function. You can read the API reference for [sending a request](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#_sendrequest). Finally, it stores the request id in `s_lastRequestId` then return it. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, jobId ); return s_lastRequestId; ``` **Note**: `_sendRequest` accepts requests encoded in `bytes`. Therefore, you must encode it using [encodeCBOR](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#encodecbor). - `sendRequestCBOR` for sending a request already encoded in `bytes`. It receives the request object encoded in `bytes`, subscription id, and callback gas limit as parameters. Then, it sends the request to the router by calling the `FunctionsClient` `sendRequest` function. **Note**: This function is helpful if you want to encode a request offchain before sending it, saving gas when submitting the request. - `fulfillRequest` to be invoked during the callback. This function is defined in `FunctionsClient` as `virtual` (read `fulfillRequest` [API reference](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#fulfillrequest)). So, your smart contract must override the function to implement the callback. The implementation of the callback is straightforward: the contract stores the latest response and error in `s_lastResponse` and `s_lastError` before emitting the `Response` event. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastResponse = response; s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); ``` ### [JavaScript example](https://docs.chain.link/chainlink-functions/tutorials/encode-request-offchain\#javascript-example) #### [source.js](https://docs.chain.link/chainlink-functions/tutorials/encode-request-offchain\#sourcejs) The JavaScript code is similar to the [Call Multiple Data Sources](https://docs.chain.link/chainlink-functions/tutorials/api-multiple-calls) tutorial. #### [request.js](https://docs.chain.link/chainlink-functions/tutorials/encode-request-offchain\#requestjs) This explanation focuses on the [request.js](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/8-multiple-apis/request.js) script and shows how to use the [Chainlink Functions NPM package](https://github.com/smartcontractkit/functions-toolkit) in your own JavaScript/TypeScript project to send requests to a DON. The code is self-explanatory and has comments to help you understand all the steps. The script imports: - [path](https://nodejs.org/docs/latest/api/path.html) and [fs](https://nodejs.org/api/fs.html) : Used to read the [source file](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/8-multiple-apis/source.js). - [ethers](https://docs.ethers.org/v5/): Ethers.js library, enables the script to interact with the blockchain. - `@chainlink/functions-toolkit`: Chainlink Functions NPM package. All its utilities are documented in the [NPM README](https://github.com/smartcontractkit/functions-toolkit/blob/main/README.md). - `@chainlink/env-enc`: A tool for loading and storing encrypted environment variables. Read the [official documentation](https://www.npmjs.com/package/@chainlink/env-enc) to learn more. - `../abi/functionsClient.json`: The abi of the contract your script will interact with. **Note**: The script was tested with this [FunctionsConsumerExample contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol). The script has two hardcoded values that you have to change using your own Functions consumer contract and subscription ID: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x8dFf78B7EE3128D00E90611FBeD20A71397064D9" // REPLACE this with your Functions consumer address const subscriptionId = 3 // REPLACE this with your subscription ID ``` The primary function that the script executes is `makeRequestSepolia`. This function can be broken into seven main parts: 1. Definition of necessary identifiers: - `routerAddress`: Chainlink Functions router address on the Sepolia testnet. - `donId`: Identifier of the DON that will fulfill your requests on the Sepolia testnet. - `gatewayUrls`: The secrets endpoint URL to which you will upload the encrypted secrets. - `explorerUrl`: Block explorer url of the Sepolia testnet. - `source`: The source code must be a string object. That's why we use `fs.readFileSync` to read `source.js` and then call `toString()` to get the content as a `string` object. - `args`: During the execution of your function, These arguments are passed to the source code. The `args` value is `["1", "bitcoin", "btc-bitcoin"]`. These arguments are BTC IDs at CoinMarketCap, CoinGecko, and Coinpaprika. You can adapt args to fetch other asset prices. - `secrets`: The secrets object that will be encrypted. - `slotIdNumber`: Slot ID at the DON where to upload the encrypted secrets. - `expirationTimeMinutes`: Expiration time in minutes of the encrypted secrets. - `gasLimit`: Maximum gas that Chainlink Functions can use when transmitting the response to your contract. - Initialization of ethers `signer` and `provider` objects. The signer is used to make transactions on the blockchain, and the provider reads data from the blockchain. 2. Simulating your request in a local sandbox environment: - Use `simulateScript` from the Chainlink Functions NPM package. - Read the `response` of the simulation. If successful, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.uint256` in this example). 3. Estimating the costs: - Initialize a `SubscriptionManager` from the Functions NPM package, then call the `estimateFunctionsRequestCost` function. - The response is returned in Juels (1 LINK = 10\*\*18 Juels). Use the `ethers.utils.formatEther` utility function to convert the output to LINK. 4. Encrypt the secrets, upload the encrypted secrets to the DON, and then encode the reference to the DON-hosted encrypted secrets. This is done in three steps: - Initialize a `SecretsManager` instance from the Functions NPM package, then call the `encryptSecrets` function. - Call the `uploadEncryptedSecretsToDON` function of the `SecretsManager` instance. This function returns an object containing a `success` boolean as long as `version`, the secret version on the DON storage. - Call the `buildDONHostedEncryptedSecretsReference` function of the `SecretsManager` instance and use the slot ID and version to encode the DON-hosted encrypted secrets reference. 5. Encode the request data offchain using the `buildRequestCBOR` function from the Functions NPM package. 6. Making a Chainlink Functions request: - Initialize your functions consumer contract using the contract address, abi, and ethers signer. - Make a [static call](https://docs.ethers.org/v5/api/contract/contract/#contract-callStatic) to the `sendRequestCBOR` function of your consumer contract to return the request ID that Chainlink Functions will generate. - Call the `sendRequestCBOR` function of your consumer contract. **Note**: The encoded data that was generated by `buildRequestCBOR` is passed in the request. 7. Waiting for the response: - Initialize a `ResponseListener` from the Functions NPM package and then call the `listenForResponseFromTransaction` function to wait for a response. By default, this function waits for five minutes. - Upon reception of the response, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.uint256` in this example). ## Get the latest Chainlink content straight to your inbox. Email Address ## Importing Packages Tutorial [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Using Imports with Functions](https://docs.chain.link/chainlink-functions/tutorials/importing-packages\#overview) This tutorial demonstrates how to import modules and use them with your Functions source code. Modules that are imported into Functions source code must meet the following requirements: - Each import must be 10 MB or less in size. - Up to 100 imports total are supported. - Deno supports [ESM compatible NPM imports](https://docs.deno.com/runtime/manual/node/npm_specifiers) and some [standard Node modules](https://docs.deno.com/runtime/manual/node/node_specifiers). See the [Compatibility List](https://docs.deno.com/runtime/manual/node/compatibility) for details. - Third-party modules are imported at runtime, so import statements must use asynchronous logic like the following examples: - Importing from `deno.land`: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const { escape } = await import("https://deno.land/std/regexp/mod.ts") ``` - ESM-compatible packages: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const { format } = await import("npm:date-fns") ``` - Standard Node modules: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const path = await import("node:path") ``` - CDN imports: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const lodash = await import("http://cdn.skypack.dev/lodash") ``` - Imported modules abide by all sandbox restrictions and do not have access to the file system, environment variables, or any other Deno permissions. ## [Prerequisites](https://docs.chain.link/chainlink-functions/tutorials/importing-packages\#prerequisites) ### [Set up your environment](https://docs.chain.link/chainlink-functions/tutorials/importing-packages\#set-up-your-environment) You must provide the private key from a testnet wallet to run the examples in this documentation. Install a Web3 wallet, configure [Node.js](https://nodejs.org/en/download/), clone the [smartcontractkit/smart-contract-examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository, and configure a `.env.enc` file with the required environment variables. Install and configure your Web3 wallet for Ethereum Sepolia: 1. [Install Deno](https://docs.deno.com/runtime/manual/) so you can compile and simulate your Functions source code on your local machine. 2. [Install the MetaMask wallet](https://docs.chain.link/quickstarts/deploy-your-first-contract#install-and-fund-your-metamask-wallet) or other Ethereum Web3 wallet. 3. Set the network for your wallet to the Sepolia testnet. If you need to add Sepolia to your wallet, you can find the chain ID and the LINK token contract address on the [LINK Token Contracts](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) page. - [Sepolia testnet and LINK token contract](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) 4. Request testnet LINK and ETH from [faucets.chain.link/sepolia](https://faucets.chain.link/sepolia). Install the required frameworks and dependencies: 1. [Install the latest release of Node.js 20](https://nodejs.org/en/download/). Optionally, you can use the [nvm package](https://www.npmjs.com/package/nvm) to switch between Node.js versions with `nvm use 20`. **Note**: To ensure you are running the correct version in a terminal, type `node -v`. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node -v ``` ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell $ node -v v20.9.0 ``` 2. In a terminal, clone the [smart-contract examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository and change directories. This example repository imports the [Chainlink Functions Toolkit NPM package](https://www.npmjs.com/package/@chainlink/functions-toolkit). You can import this package to your own projects to enable them to work with Chainlink Functions. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell git clone https://github.com/smartcontractkit/smart-contract-examples.git && \ cd ./smart-contract-examples/functions-examples/ ``` 3. Run `npm install` to install the dependencies. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npm install ``` 4. For higher security, the examples repository encrypts your environment variables at rest. 1. Set an encryption password for your environment variables. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set-pw ``` 2. Run `npx env-enc set` to configure a `.env.enc` file with the basic variables that you need to send your requests to the Sepolia network. - `ETHEREUM_SEPOLIA_RPC_URL`: Set a URL for the Sepolia testnet. You can sign up for a personal endpoint from [Alchemy](https://www.alchemy.com/), [Infura](https://www.infura.io/), or another node provider service. - `PRIVATE_KEY`: Find the private key for your testnet wallet. If you use MetaMask, follow the instructions to [Export a Private Key](https://support.metamask.io/managing-my-wallet/secret-recovery-phrase-and-private-keys/how-to-export-an-accounts-private-key/). **Note**: Your private key is needed to sign any transactions you make such as making requests. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set ``` ### [Configure your onchain resources](https://docs.chain.link/chainlink-functions/tutorials/importing-packages\#configure-your-onchain-resources) After you configure your local environment, configure some onchain resources to process your requests, receive the responses, and pay for the work done by the DON. #### [Deploy a Functions consumer contract on _Sepolia_](https://docs.chain.link/chainlink-functions/tutorials/importing-packages\#deploy-a-functions-consumer-contract-on-sepolia) 1. [Open the FunctionsConsumerExample.sol contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol) in Remix. [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) 2. Compile the contract. 3. Open MetaMask and select the _Sepolia_ network. 4. In Remix under the **Deploy & Run Transactions** tab, select _Injected Provider - MetaMask_ in the **Environment** list. Remix will use the MetaMask wallet to communicate with _Sepolia_. 5. Under the **Deploy** section, fill in the router address for your specific blockchain. You can find both of these addresses on the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks) page. For _Sepolia_, the router address is `0xb83E47C2bC239B3bf370bc41e1459A34b41238D0`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg). 6. Click the **Deploy** button to deploy the contract. MetaMask prompts you to confirm the transaction. Check the transaction details to make sure you are deploying the contract to _Sepolia_. 7. After you confirm the transaction, the contract address appears in the **Deployed Contracts** list. Copy the contract address. #### [Create a subscription](https://docs.chain.link/chainlink-functions/tutorials/importing-packages\#create-a-subscription) Follow the [Managing Functions Subscriptions](https://docs.chain.link/chainlink-functions/resources/subscriptions#create-a-subscription) guide to accept the Chainlink Functions Terms of Service (ToS), create a subscription, fund it, then add your consumer contract address to it. You can find the Chainlink Functions Subscription Manager at [functions.chain.link](https://functions.chain.link/). ## [Tutorial](https://docs.chain.link/chainlink-functions/tutorials/importing-packages\#tutorial) This example imports [ethers](https://www.npmjs.com/package/ethers) and demonstrates how to call a smart contract functions using a JSON RPC provider to call an onchain function. In this example, the source code calls the [`latestRoundData()` function](https://docs.chain.link/data-feeds/api-reference#latestrounddata) from the `AggregatorV3Interface`. Read the [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/importing-packages#examine-the-code) section for a detailed description of the code example. You can locate the scripts used in this tutorial in the [_examples/11-package-imports_ directory](https://github.com/smartcontractkit/smart-contract-examples/tree/main/functions-examples/examples/11-package-imports). To run the example: 1. Open the file `request.js`, which is located in the `11-package-imports` folder. 2. Replace the consumer contract address and the subscription ID with your own values. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x8dFf78B7EE3128D00E90611FBeD20A71397064D9" // REPLACE this with your Functions consumer address const subscriptionId = 3 // REPLACE this with your subscription ID ``` 3. Make a request: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node examples/11-package-imports/request.js ``` The script runs your function in a sandbox environment before making an onchain transaction: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```text $ node examples/11-package-imports/request.js secp256k1 unavailable, reverting to browser version Start simulation... Simulation result { capturedTerminalOutput: 'Fetched BTC / USD price: 6644228390483\n', responseBytesHexstring: '0x0000000000000000000000000000000000000000000000000000060afadf7e53' } ✅ Decoded response to int256: 6644228390483n Estimate request costs... Fulfillment cost estimated to 1.09518769822223 LINK Make request... ✅ Functions request sent! Transaction hash 0xa73d895adb28360d1737a695647390a3a7f000368d976135fcfe9c834ee75ed6. Waiting for a response... See your request in the explorer https://sepolia.etherscan.io/tx/0xa73d895adb28360d1737a695647390a3a7f000368d976135fcfe9c834ee75ed6 ✅ Request 0x5bac800974596113a3013bf788919a6b3df5ea65ec6238a1c98114a60daff6d2 successfully fulfilled. Cost is 0.236901088749168095 LINK.Complete response: { requestId: '0x5bac800974596113a3013bf788919a6b3df5ea65ec6238a1c98114a60daff6d2', subscriptionId: 2303, totalCostInJuels: 236901088749168095n, responseBytesHexstring: '0x0000000000000000000000000000000000000000000000000000060afadf7e53', errorString: '', returnDataBytesHexstring: '0x', fulfillmentCode: 0 } ✅ Decoded response to int256: 6644228390483n ``` The output of the example gives you the following information: - Your request is first run on a sandbox environment to ensure it is correctly configured. - The fulfillment costs are estimated before making the request. - Your request was successfully sent to Chainlink Functions. The transaction in this example is `0xa73d895adb28360d1737a695647390a3a7f000368d976135fcfe9c834ee75ed6` and the request ID is `0x5bac800974596113a3013bf788919a6b3df5ea65ec6238a1c98114a60daff6d2`. - The DON successfully fulfilled your request. The total cost was: `0.236901088749168095 LINK`. - The consumer contract received a response in `bytes` with a value of `0x0000000000000000000000000000000000000000000000000000060afadf7e53`. Decoding it offchain to `int256` gives you a result: `6644228390483`. ## [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/importing-packages\#examine-the-code) ### [FunctionsConsumerExample.sol](https://docs.chain.link/chainlink-functions/tutorials/importing-packages\#functionsconsumerexamplesol) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; /** * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. * DO NOT USE THIS CODE IN PRODUCTION. */ contract FunctionsConsumerExample is FunctionsClient, ConfirmedOwner { using FunctionsRequest for FunctionsRequest.Request; bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; error UnexpectedRequestID(bytes32 requestId); event Response(bytes32 indexed requestId, bytes response, bytes err); constructor( address router ) FunctionsClient(router) ConfirmedOwner(msg.sender) {} /** * @notice Send a simple request * @param source JavaScript source code * @param encryptedSecretsUrls Encrypted URLs where to fetch user secrets * @param donHostedSecretsSlotID Don hosted secrets slotId * @param donHostedSecretsVersion Don hosted secrets version * @param args List of arguments accessible from within the source code * @param bytesArgs Array of bytes arguments, represented as hex strings * @param subscriptionId Billing ID */ function sendRequest( string memory source, bytes memory encryptedSecretsUrls, uint8 donHostedSecretsSlotID, uint64 donHostedSecretsVersion, string[] memory args, bytes[] memory bytesArgs, uint64 subscriptionId, uint32 gasLimit, bytes32 donID ) external onlyOwner returns (bytes32 requestId) { FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); if (encryptedSecretsUrls.length > 0) req.addSecretsReference(encryptedSecretsUrls); else if (donHostedSecretsVersion > 0) { req.addDONHostedSecrets( donHostedSecretsSlotID, donHostedSecretsVersion ); } if (args.length > 0) req.setArgs(args); if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Send a pre-encoded CBOR request * @param request CBOR-encoded request data * @param subscriptionId Billing ID * @param gasLimit The maximum amount of gas the request can consume * @param donID ID of the job to be invoked * @return requestId The ID of the sent request */ function sendRequestCBOR( bytes memory request, uint64 subscriptionId, uint32 gasLimit, bytes32 donID ) external onlyOwner returns (bytes32 requestId) { s_lastRequestId = _sendRequest( request, subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Store latest result/error * @param requestId The request ID, returned by sendRequest() * @param response Aggregated response from the user code * @param err Aggregated error from the user code or from the execution pipeline * Either response or error parameter will be set, but never both */ function fulfillRequest( bytes32 requestId, bytes memory response, bytes memory err ) internal override { if (s_lastRequestId != requestId) { revert UnexpectedRequestID(requestId); } s_lastResponse = response; s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); } } ``` [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) - To write a Chainlink Functions consumer contract, your contract must import [FunctionsClient.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol) and [FunctionsRequest.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol). You can read the API references: [FunctionsClient](https://docs.chain.link/chainlink-functions/api-reference/functions-client) and [FunctionsRequest](https://docs.chain.link/chainlink-functions/api-reference/functions-request). These contracts are available in an NPM package, so you can import them from within your project. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; ``` - Use the FunctionsRequest.sol library to get all the functions needed for building a Chainlink Functions request. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext using FunctionsRequest for FunctionsRequest.Request; ``` - The latest request id, latest received response, and latest received error (if any) are defined as state variables: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; ``` - We define the `Response` event that your smart contract will emit during the callback ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext event Response(bytes32 indexed requestId, bytes response, bytes err); ``` - Pass the router address for your network when you deploy the contract: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext constructor(address router) FunctionsClient(router) ``` - The three remaining functions are: - `sendRequest` for sending a request. It receives the JavaScript source code, encrypted secretsUrls (in case the encrypted secrets are hosted by the user), DON hosted secrets slot id and version (in case the encrypted secrets are hosted by the DON), list of arguments to pass to the source code, subscription id, and callback gas limit as parameters. Then: - It uses the `FunctionsRequest` library to initialize the request and add any passed encrypted secrets reference or arguments. You can read the API Reference for [Initializing a request](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#initializerequestforinlinejavascript), [adding user hosted secrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#addsecretsreference), [adding DON hosted secrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#adddonhostedsecrets), [adding arguments](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#setargs), and [adding bytes arguments](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#setbytesargs). ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); if (encryptedSecretsUrls.length > 0) req.addSecretsReference(encryptedSecretsUrls); else if (donHostedSecretsVersion > 0) { req.addDONHostedSecrets( donHostedSecretsSlotID, donHostedSecretsVersion ); } if (args.length > 0) req.setArgs(args); if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); ``` - It sends the request to the router by calling the `FunctionsClient` `sendRequest` function. You can read the API reference for [sending a request](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#_sendrequest). Finally, it stores the request id in `s_lastRequestId` then return it. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, jobId ); return s_lastRequestId; ``` **Note**: `_sendRequest` accepts requests encoded in `bytes`. Therefore, you must encode it using [encodeCBOR](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#encodecbor). - `sendRequestCBOR` for sending a request already encoded in `bytes`. It receives the request object encoded in `bytes`, subscription id, and callback gas limit as parameters. Then, it sends the request to the router by calling the `FunctionsClient` `sendRequest` function. **Note**: This function is helpful if you want to encode a request offchain before sending it, saving gas when submitting the request. - `fulfillRequest` to be invoked during the callback. This function is defined in `FunctionsClient` as `virtual` (read `fulfillRequest` [API reference](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#fulfillrequest)). So, your smart contract must override the function to implement the callback. The implementation of the callback is straightforward: the contract stores the latest response and error in `s_lastResponse` and `s_lastError` before emitting the `Response` event. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastResponse = response; s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); ``` ### [JavaScript example](https://docs.chain.link/chainlink-functions/tutorials/importing-packages\#javascript-example) #### [source.js](https://docs.chain.link/chainlink-functions/tutorials/importing-packages\#sourcejs) The Decentralized Oracle Network will run the [JavaScript code](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/11-package-imports/source.js). The code is self-explanatory and has comments to help you understand all the steps. The example `source.js` file uses a JSON RPC call to the [`latestRoundData()` function](https://docs.chain.link/data-feeds/api-reference#latestrounddata) of a [Chainlink Data Feed](https://docs.chain.link/data-feeds). The request requires a few modifications to work in the Chainlink Functions environment. For example, the `JsonRpcProvider` class must be inherited to override the JsonRpcProvider [`_send` method](https://docs.ethers.org/v6/api/providers/jsonrpc/#JsonRpcProvider). This customization is necessary because Deno does not natively support Node.js modules like [http](https://nodejs.org/api/http.html) or [https](https://nodejs.org/api/https.html). We override the `_send` method to use the [fetch API](https://docs.deno.com/api/web/~/fetch), which is the standard way to make HTTP(s) requests in Deno. **Note**: The `url` passed in the constructor is the URL of the JSON RPC provider. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript // Chainlink Functions compatible Ethers JSON RPC provider class // (this is required for making Ethers RPC calls with Chainlink Functions) class FunctionsJsonRpcProvider extends ethers.JsonRpcProvider { constructor(url) { super(url) this.url = url } async _send(payload) { let resp = await fetch(this.url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }) return resp.json() } } ``` After the class is extended, you can initialize the provider object with the `RPC_URL` and await the response. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const provider = new FunctionsJsonRpcProvider(RPC_URL) const dataFeedContract = new ethers.Contract(CONTRACT_ADDRESS, abi, provider) const dataFeedResponse = await dataFeedContract.latestRoundData() ``` In this example, the contract returns an `int256` value. Encode the value so request.js can properly decode it. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript return Functions.encodeInt256(dataFeedResponse.answer) ``` #### [request.js](https://docs.chain.link/chainlink-functions/tutorials/importing-packages\#requestjs) This explanation focuses on the [request.js](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/11-package-imports/request.js) script and shows how to use the [Chainlink Functions NPM package](https://github.com/smartcontractkit/functions-toolkit) in your own JavaScript/TypeScript project to send requests to a DON. The code is self-explanatory and has comments to help you understand all the steps. The script imports: - [path](https://nodejs.org/docs/latest/api/path.html) and [fs](https://nodejs.org/api/fs.html) : Used to read the [source file](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/11-package-imports/source.js). - [ethers](https://docs.ethers.org/v5/): Ethers.js library, enables the script to interact with the blockchain. - `@chainlink/functions-toolkit`: Chainlink Functions NPM package. All its utilities are documented in the [NPM README](https://github.com/smartcontractkit/functions-toolkit/blob/main/README.md). - `@chainlink/env-enc`: A tool for loading and storing encrypted environment variables. Read the [official documentation](https://www.npmjs.com/package/@chainlink/env-enc) to learn more. - `../abi/functionsClient.json`: The abi of the contract your script will interact with. **Note**: The script was tested with this [FunctionsConsumerExample contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol). The script has two hardcoded values that you have to change using your own Functions consumer contract and subscription ID: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x91257aa1c6b7f382759c357fbc53c565c80f7fee" // REPLACE this with your Functions consumer address const subscriptionId = 38 // REPLACE this with your subscription ID ``` The primary function that the script executes is `makeRequestSepolia`. This function consists of five main parts: 1. Definition of necessary identifiers: - `routerAddress`: Chainlink Functions router address on the Sepolia testnet. - `donId`: Identifier of the DON that will fulfill your requests on the Sepolia testnet. - `explorerUrl`: Block explorer URL of the Sepolia testnet. - `source`: The source code must be a string object. That's why we use `fs.readFileSync` to read `source.js` and then call `toString()` to get the content as a `string` object. - `args`: During the execution of your function, these arguments are passed to the source code. - `gasLimit`: Maximum gas that Chainlink Functions can use when transmitting the response to your contract. - Initialization of ethers `signer` and `provider` objects. The signer is used to make transactions on the blockchain, and the provider reads data from the blockchain. 2. Simulating your request in a local sandbox environment: - Use `simulateScript` from the Chainlink Functions NPM package. - Read the `response` of the simulation. If successful, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.int256` in this example). 3. Estimating the costs: - Initialize a `SubscriptionManager` from the Functions NPM package, then call the `estimateFunctionsRequestCost`. - The response is returned in Juels (1 LINK = 10\*\*18 Juels). Use the `ethers.utils.formatEther` utility function to convert the output to LINK. 4. Making a Chainlink Functions request: - Initialize your functions consumer contract using the contract address, abi, and ethers signer. - Call the `sendRequest` function of your consumer contract. 5. Waiting for the response: - Initialize a `ResponseListener` from the Functions NPM package and then call the `listenForResponseFromTransaction` function to wait for a response. By default, this function waits for five minutes. - Upon reception of the response, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.int256` in this example). ## Get the latest Chainlink content straight to your inbox. Email Address ## Chainlink Functions Tutorial [iframe](https://www.googletagmanager.com/ns.html?id=GTM-N6DQ47T) Chainlink Rewards: Genesis Starts With SXT. [Learn how to build with SXT.](https://go.chain.link/masterclasses/build-with-space-and-time?utm_medium=referral&utm_source=chainlink-docs&utm_campaign=sxt-linklab) On this page # [Request Computation](https://docs.chain.link/chainlink-functions/tutorials/simple-computation\#overview) This tutorial shows you how to run computations on the Chainlink Functions Decentralized Oracle Network (DON). The example code computes the [geometric mean](https://www.mathsisfun.com/numbers/geometric-mean.html) of numbers in a list. After [OCR](https://docs.chain.link/chainlink-functions/resources/concepts) completes offchain computation and aggregation, it returns the result to your smart contract. ## [Prerequisites](https://docs.chain.link/chainlink-functions/tutorials/simple-computation\#prerequisites) ### [Set up your environment](https://docs.chain.link/chainlink-functions/tutorials/simple-computation\#set-up-your-environment) You must provide the private key from a testnet wallet to run the examples in this documentation. Install a Web3 wallet, configure [Node.js](https://nodejs.org/en/download/), clone the [smartcontractkit/smart-contract-examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository, and configure a `.env.enc` file with the required environment variables. Install and configure your Web3 wallet for Ethereum Sepolia: 1. [Install Deno](https://docs.deno.com/runtime/manual/) so you can compile and simulate your Functions source code on your local machine. 2. [Install the MetaMask wallet](https://docs.chain.link/quickstarts/deploy-your-first-contract#install-and-fund-your-metamask-wallet) or other Ethereum Web3 wallet. 3. Set the network for your wallet to the Sepolia testnet. If you need to add Sepolia to your wallet, you can find the chain ID and the LINK token contract address on the [LINK Token Contracts](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) page. - [Sepolia testnet and LINK token contract](https://docs.chain.link/resources/link-token-contracts#sepolia-testnet) 4. Request testnet LINK and ETH from [faucets.chain.link/sepolia](https://faucets.chain.link/sepolia). Install the required frameworks and dependencies: 1. [Install the latest release of Node.js 20](https://nodejs.org/en/download/). Optionally, you can use the [nvm package](https://www.npmjs.com/package/nvm) to switch between Node.js versions with `nvm use 20`. **Note**: To ensure you are running the correct version in a terminal, type `node -v`. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node -v ``` ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell $ node -v v20.9.0 ``` 2. In a terminal, clone the [smart-contract examples](https://github.com/smartcontractkit/smart-contract-examples.git) repository and change directories. This example repository imports the [Chainlink Functions Toolkit NPM package](https://www.npmjs.com/package/@chainlink/functions-toolkit). You can import this package to your own projects to enable them to work with Chainlink Functions. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell git clone https://github.com/smartcontractkit/smart-contract-examples.git && \ cd ./smart-contract-examples/functions-examples/ ``` 3. Run `npm install` to install the dependencies. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npm install ``` 4. For higher security, the examples repository encrypts your environment variables at rest. 1. Set an encryption password for your environment variables. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set-pw ``` 2. Run `npx env-enc set` to configure a `.env.enc` file with the basic variables that you need to send your requests to the Sepolia network. - `ETHEREUM_SEPOLIA_RPC_URL`: Set a URL for the Sepolia testnet. You can sign up for a personal endpoint from [Alchemy](https://www.alchemy.com/), [Infura](https://www.infura.io/), or another node provider service. - `PRIVATE_KEY`: Find the private key for your testnet wallet. If you use MetaMask, follow the instructions to [Export a Private Key](https://support.metamask.io/managing-my-wallet/secret-recovery-phrase-and-private-keys/how-to-export-an-accounts-private-key/). **Note**: Your private key is needed to sign any transactions you make such as making requests. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell npx env-enc set ``` ### [Configure your onchain resources](https://docs.chain.link/chainlink-functions/tutorials/simple-computation\#configure-your-onchain-resources) After you configure your local environment, configure some onchain resources to process your requests, receive the responses, and pay for the work done by the DON. #### [Deploy a Functions consumer contract on _Sepolia_](https://docs.chain.link/chainlink-functions/tutorials/simple-computation\#deploy-a-functions-consumer-contract-on-sepolia) 1. [Open the FunctionsConsumerExample.sol contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol) in Remix. [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) 2. Compile the contract. 3. Open MetaMask and select the _Sepolia_ network. 4. In Remix under the **Deploy & Run Transactions** tab, select _Injected Provider - MetaMask_ in the **Environment** list. Remix will use the MetaMask wallet to communicate with _Sepolia_. 5. Under the **Deploy** section, fill in the router address for your specific blockchain. You can find both of these addresses on the [Supported Networks](https://docs.chain.link/chainlink-functions/supported-networks) page. For _Sepolia_, the router address is `0xb83E47C2bC239B3bf370bc41e1459A34b41238D0`![Copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg). 6. Click the **Deploy** button to deploy the contract. MetaMask prompts you to confirm the transaction. Check the transaction details to make sure you are deploying the contract to _Sepolia_. 7. After you confirm the transaction, the contract address appears in the **Deployed Contracts** list. Copy the contract address. #### [Create a subscription](https://docs.chain.link/chainlink-functions/tutorials/simple-computation\#create-a-subscription) Follow the [Managing Functions Subscriptions](https://docs.chain.link/chainlink-functions/resources/subscriptions#create-a-subscription) guide to accept the Chainlink Functions Terms of Service (ToS), create a subscription, fund it, then add your consumer contract address to it. You can find the Chainlink Functions Subscription Manager at [functions.chain.link](https://functions.chain.link/). ## [Tutorial](https://docs.chain.link/chainlink-functions/tutorials/simple-computation\#tutorial) This tutorial is configured to get the average (geometric mean) from a list of numbers `1,2,3,4,5,6,7,8,9,10`. Read the [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/simple-computation#examine-the-code) section for a detailed description of the code example. You can locate the scripts used in this tutorial in the [_examples/1-simple-computation_ directory](https://github.com/smartcontractkit/smart-contract-examples/tree/main/functions-examples/examples/1-simple-computation). To run the example: 1. Open the file `request.js`, which is located in the `1-simple-computation` folder. 2. Replace the consumer contract address and the subscription ID with your own values. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x8dFf78B7EE3128D00E90611FBeD20A71397064D9" // REPLACE this with your Functions consumer address const subscriptionId = 3 // REPLACE this with your subscription ID ``` 3. Make a request: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```shell node examples/1-simple-computation/request.js ``` The script runs your function in a sandbox environment before making an onchain transaction: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```text $ node examples/1-simple-computation/request.js secp256k1 unavailable, reverting to browser version Start simulation... Simulation result { capturedTerminalOutput: 'calculate geometric mean of 1,2,3,4,5,6,7,8,9,10\ngeometric mean is: 4.53\n', responseBytesHexstring: '0x00000000000000000000000000000000000000000000000000000000000001c5' } ✅ Decoded response to uint256: 453n Estimate request costs... Fulfillment cost estimated to 1.004325887213695 LINK Make request... ✅ Functions request sent! Transaction hash 0x7df8240d23ef5c951ea73634b2346a459c8cd5b9a0bf76dbe0bb4d912e099b22. Waiting for a response... See your request in the explorer https://sepolia.etherscan.io/tx/0x7df8240d23ef5c951ea73634b2346a459c8cd5b9a0bf76dbe0bb4d912e099b22 ✅ Request 0x91a72a36a94ddedfc9e7bcfe33aaa13dd5747c4e985d9baa8c0c34175ac6c715 successfully fulfilled. Cost is 0.240613623834519812 LINK.Complete response: { requestId: '0x91a72a36a94ddedfc9e7bcfe33aaa13dd5747c4e985d9baa8c0c34175ac6c715', subscriptionId: 2303, totalCostInJuels: 240613623834519812n, responseBytesHexstring: '0x00000000000000000000000000000000000000000000000000000000000001c5', errorString: '', returnDataBytesHexstring: '0x', fulfillmentCode: 0 } ✅ Decoded response to uint256: 453n ``` The output of the example gives you the following information: - Your request is first run on a sandbox environment to ensure it is correctly configured. - The fulfillment costs are estimated before making the request. - Your request was successfully sent to Chainlink Functions. The transaction in this example is [0x7df8240d23ef5c951ea73634b2346a459c8cd5b9a0bf76dbe0bb4d912e099b22](https://sepolia.etherscan.io/tx/0x7df8240d23ef5c951ea73634b2346a459c8cd5b9a0bf76dbe0bb4d912e099b22) and the request ID is `0x91a72a36a94ddedfc9e7bcfe33aaa13dd5747c4e985d9baa8c0c34175ac6c715`. - The DON successfully fulfilled your request. The total cost was: `0.240613623834519812 LINK`. - The consumer contract received a response in `bytes` with a value of `0x00000000000000000000000000000000000000000000000000000000000001c5`. Decoding it offchain to `uint256` gives you a result: `453`. ## [Examine the code](https://docs.chain.link/chainlink-functions/tutorials/simple-computation\#examine-the-code) ### [FunctionsConsumerExample.sol](https://docs.chain.link/chainlink-functions/tutorials/simple-computation\#functionsconsumerexamplesol) ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; /** * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. * DO NOT USE THIS CODE IN PRODUCTION. */ contract FunctionsConsumerExample is FunctionsClient, ConfirmedOwner { using FunctionsRequest for FunctionsRequest.Request; bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; error UnexpectedRequestID(bytes32 requestId); event Response(bytes32 indexed requestId, bytes response, bytes err); constructor( address router ) FunctionsClient(router) ConfirmedOwner(msg.sender) {} /** * @notice Send a simple request * @param source JavaScript source code * @param encryptedSecretsUrls Encrypted URLs where to fetch user secrets * @param donHostedSecretsSlotID Don hosted secrets slotId * @param donHostedSecretsVersion Don hosted secrets version * @param args List of arguments accessible from within the source code * @param bytesArgs Array of bytes arguments, represented as hex strings * @param subscriptionId Billing ID */ function sendRequest( string memory source, bytes memory encryptedSecretsUrls, uint8 donHostedSecretsSlotID, uint64 donHostedSecretsVersion, string[] memory args, bytes[] memory bytesArgs, uint64 subscriptionId, uint32 gasLimit, bytes32 donID ) external onlyOwner returns (bytes32 requestId) { FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); if (encryptedSecretsUrls.length > 0) req.addSecretsReference(encryptedSecretsUrls); else if (donHostedSecretsVersion > 0) { req.addDONHostedSecrets( donHostedSecretsSlotID, donHostedSecretsVersion ); } if (args.length > 0) req.setArgs(args); if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Send a pre-encoded CBOR request * @param request CBOR-encoded request data * @param subscriptionId Billing ID * @param gasLimit The maximum amount of gas the request can consume * @param donID ID of the job to be invoked * @return requestId The ID of the sent request */ function sendRequestCBOR( bytes memory request, uint64 subscriptionId, uint32 gasLimit, bytes32 donID ) external onlyOwner returns (bytes32 requestId) { s_lastRequestId = _sendRequest( request, subscriptionId, gasLimit, donID ); return s_lastRequestId; } /** * @notice Store latest result/error * @param requestId The request ID, returned by sendRequest() * @param response Aggregated response from the user code * @param err Aggregated error from the user code or from the execution pipeline * Either response or error parameter will be set, but never both */ function fulfillRequest( bytes32 requestId, bytes memory response, bytes memory err ) internal override { if (s_lastRequestId != requestId) { revert UnexpectedRequestID(requestId); } s_lastResponse = response; s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); } } ``` [Open in Remix](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol&autoCompile=true) [What is Remix?](https://docs.chain.link/getting-started/conceptual-overview#what-is-remix) - To write a Chainlink Functions consumer contract, your contract must import [FunctionsClient.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol) and [FunctionsRequest.sol](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol). You can read the API references: [FunctionsClient](https://docs.chain.link/chainlink-functions/api-reference/functions-client) and [FunctionsRequest](https://docs.chain.link/chainlink-functions/api-reference/functions-request). These contracts are available in an NPM package, so you can import them from within your project. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol"; import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol"; ``` - Use the FunctionsRequest.sol library to get all the functions needed for building a Chainlink Functions request. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext using FunctionsRequest for FunctionsRequest.Request; ``` - The latest request id, latest received response, and latest received error (if any) are defined as state variables: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext bytes32 public s_lastRequestId; bytes public s_lastResponse; bytes public s_lastError; ``` - We define the `Response` event that your smart contract will emit during the callback ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext event Response(bytes32 indexed requestId, bytes response, bytes err); ``` - Pass the router address for your network when you deploy the contract: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext constructor(address router) FunctionsClient(router) ``` - The three remaining functions are: - `sendRequest` for sending a request. It receives the JavaScript source code, encrypted secretsUrls (in case the encrypted secrets are hosted by the user), DON hosted secrets slot id and version (in case the encrypted secrets are hosted by the DON), list of arguments to pass to the source code, subscription id, and callback gas limit as parameters. Then: - It uses the `FunctionsRequest` library to initialize the request and add any passed encrypted secrets reference or arguments. You can read the API Reference for [Initializing a request](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#initializerequestforinlinejavascript), [adding user hosted secrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#addsecretsreference), [adding DON hosted secrets](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#adddonhostedsecrets), [adding arguments](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#setargs), and [adding bytes arguments](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#setbytesargs). ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext FunctionsRequest.Request memory req; req.initializeRequestForInlineJavaScript(source); if (encryptedSecretsUrls.length > 0) req.addSecretsReference(encryptedSecretsUrls); else if (donHostedSecretsVersion > 0) { req.addDONHostedSecrets( donHostedSecretsSlotID, donHostedSecretsVersion ); } if (args.length > 0) req.setArgs(args); if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); ``` - It sends the request to the router by calling the `FunctionsClient` `sendRequest` function. You can read the API reference for [sending a request](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#_sendrequest). Finally, it stores the request id in `s_lastRequestId` then return it. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastRequestId = _sendRequest( req.encodeCBOR(), subscriptionId, gasLimit, jobId ); return s_lastRequestId; ``` **Note**: `_sendRequest` accepts requests encoded in `bytes`. Therefore, you must encode it using [encodeCBOR](https://docs.chain.link/chainlink-functions/api-reference/functions-request/#encodecbor). - `sendRequestCBOR` for sending a request already encoded in `bytes`. It receives the request object encoded in `bytes`, subscription id, and callback gas limit as parameters. Then, it sends the request to the router by calling the `FunctionsClient` `sendRequest` function. **Note**: This function is helpful if you want to encode a request offchain before sending it, saving gas when submitting the request. - `fulfillRequest` to be invoked during the callback. This function is defined in `FunctionsClient` as `virtual` (read `fulfillRequest` [API reference](https://docs.chain.link/chainlink-functions/api-reference/functions-client/#fulfillrequest)). So, your smart contract must override the function to implement the callback. The implementation of the callback is straightforward: the contract stores the latest response and error in `s_lastResponse` and `s_lastError` before emitting the `Response` event. ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```plaintext s_lastResponse = response; s_lastError = err; emit Response(requestId, s_lastResponse, s_lastError); ``` ### [JavaScript example](https://docs.chain.link/chainlink-functions/tutorials/simple-computation\#javascript-example) #### [source.js](https://docs.chain.link/chainlink-functions/tutorials/simple-computation\#sourcejs) The Decentralized Oracle Network will run the [JavaScript code](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/1-simple-computation/source.js). The code is self-explanatory and has comments to help you understand all the steps. The main steps are: - Read the numbers provided as arguments in the `args` setting. Because `args` is an array of `string`, call `parseInt` to convert from `string` to `number`. **Note**: `args` contains string values that are injected into the JavaScript source code when the Decentralized Oracle Network executes your function. You can access theses values from your JavaScript code using the name `args`. - Calculate the average (geometric mean): First, compute the product of the numbers. Then, calculate the nth root of the product where `n` is the length of `args`. - Return the result as a [buffer](https://nodejs.org/api/buffer.html#buffer) using the `Functions.encodeUint256` helper function. Because Solidity doesn't support decimals, multiply the result by `100` and round the result to the nearest integer. There are other helper functions that you could use depending on the response type: - `Functions.encodeUint256`: Takes a positive JavaScript integer number and returns a Buffer of 32 bytes representing a uint256 type in Solidity. - `Functions.encodeInt256`: Takes a JavaScript integer number and returns a Buffer of 32 bytes representing an int256 type in Solidity. - `Functions.encodeString`: Takes a JavaScript string and returns a Buffer representing a string type in Solidity. **Note**: You are not required to use these encoding functions as long as the JavaScript code returns a Buffer representing the bytes array returned onchain. Read this [article](https://www.freecodecamp.org/news/do-you-want-a-better-understanding-of-buffer-in-node-js-check-this-out-2e29de2968e8/) if you are new to Javascript Buffers and want to understand why they are important. #### [request.js](https://docs.chain.link/chainlink-functions/tutorials/simple-computation\#requestjs) This explanation focuses on the [request.js](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/1-simple-computation/request.js) script and shows how to use the [Chainlink Functions NPM package](https://github.com/smartcontractkit/functions-toolkit) in your own JavaScript/TypeScript project to send requests to a DON. The code is self-explanatory and has comments to help you understand all the steps. The script imports: - [path](https://nodejs.org/docs/latest/api/path.html) and [fs](https://nodejs.org/api/fs.html) : Used to read the [source file](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/1-simple-computation/source.js). - [ethers](https://docs.ethers.org/v5/): Ethers.js library, enables the script to interact with the blockchain. - `@chainlink/functions-toolkit`: Chainlink Functions NPM package. All its utilities are documented in the [NPM README](https://github.com/smartcontractkit/functions-toolkit/blob/main/README.md). - `@chainlink/env-enc`: A tool for loading and storing encrypted environment variables. Read the [official documentation](https://www.npmjs.com/package/@chainlink/env-enc) to learn more. - `../abi/functionsClient.json`: The abi of the contract your script will interact with. **Note**: The script was tested with this [FunctionsConsumerExample contract](https://remix.ethereum.org/#url=https://docs.chain.link/samples/ChainlinkFunctions/FunctionsConsumerExample.sol). The script has two hardcoded values that you have to change using your own Functions consumer contract and subscription ID: ![copy to clipboard](https://docs.chain.link/assets/icons/copyIcon.svg) ```javascript const consumerAddress = "0x8dFf78B7EE3128D00E90611FBeD20A71397064D9" // REPLACE this with your Functions consumer address const subscriptionId = 3 // REPLACE this with your subscription ID ``` The primary function that the script executes is `makeRequestSepolia`. This function consists of five main parts: 1. Definition of necessary identifiers: - `routerAddress`: Chainlink Functions router address on the Sepolia testnet. - `donId`: Identifier of the DON that will fulfill your requests on the Sepolia testnet. - `explorerUrl`: Block explorer URL of the Sepolia testnet. - `source`: The source code must be a string object. That's why we use `fs.readFileSync` to read `source.js` and then call `toString()` to get the content as a `string` object. - `args`: During the execution of your function, These arguments are passed to the source code. - `gasLimit`: Maximum gas that Chainlink Functions can use when transmitting the response to your contract. - Initialization of ethers `signer` and `provider` objects. The signer is used to make transactions on the blockchain, and the provider reads data from the blockchain. 2. Simulating your request in a local sandbox environment: - Use `simulateScript` from the Chainlink Functions NPM package. - Read the `response` of the simulation. If successful, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.uint256` in this example). 3. Estimating the costs: - Initialize a `SubscriptionManager` from the Functions NPM package, then call the `estimateFunctionsRequestCost`. - The response is returned in Juels (1 LINK = 10\*\*18 Juels). Use the `ethers.utils.formatEther` utility function to convert the output to LINK. 4. Making a Chainlink Functions request: - Initialize your functions consumer contract using the contract address, abi, and ethers signer. - Call the `sendRequest` function of your consumer contract. 5. Waiting for the response: - Initialize a `ResponseListener` from the Functions NPM package and then call the `listenForResponseFromTransaction` function to wait for a response. By default, this function waits for five minutes. - Upon reception of the response, use the Functions NPM package `decodeResult` function and `ReturnType` enum to decode the response to the expected returned type ( `ReturnType.uint256` in this example). ## What's next - [\> Try out the Chainlink Functions Tutorials](https://docs.chain.link/chainlink-functions/tutorials) - [\> Read the Architecture to understand how Chainlink Functions operates](https://docs.chain.link/chainlink-functions/resources/architecture)