This tutorial shows you how to run computations on the Chainlink Functions Decentralized Oracle Network (DON). The example code computes the geometric mean of numbers in a list. After OCR completes off-chain computation and aggregation, it returns the result to your smart contract.
Before you begin
Complete the setup steps in the Getting Started guide: The Getting Started Guide shows you how to set up your environment with the necessary tools for these tutorials. You can re-use the same consumer contract for each of these tutorials.
Make sure your subscription has enough LINK to pay for your requests. Read Get Subscription details to learn how to check your subscription balance. If your subscription runs out of LINK, follow the Fund a Subscription guide.
Check out the correct branch before you try this tutorial: Each tutorial is stored in a separate branch of the Chainlink Functions Starter Kit repository.
git checkout tutorial-1
This tutorial is configured to get the average (geometric mean) from a list of numbers. For a detailed explanation of the code example, read the Explanation section.
Functions-request-config.js. Note that the
["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"], so the source code will calculate the average (geometric mean) of “1,2,3,4,5,6,7,8,9,10”. You can change the
argsvalue to compute another set’s average. Read the request config explanation for more information about the request config file.
The Chainlink Functions hardhat starter kit includes a simulator to test your Functions code on your local machine. The
functions-simulate command will execute your code in a local runtime environment and simulate an end-to-end fulfillment, helping you fix any issues before submitting your functions to a Decentralized Oracle Network.
functions-simulate task to run the source code locally and make sure
Functions-request-source.js are correctly written:
npx hardhat functions-simulate
Reading the output of the example above, you can note that the geometric mean was correctly computed:
4.53. Because Solidity does not support decimals, we move the decimal point so that the value looks like an integer
453 before returning the
bytes encoded value
0x00000000000000000000000000000000000000000000000000000000000001c5 in the callback. Note: Read the source code explanation for a more detailed explanation.
Send a request to the Decentralized Oracle Network to compute the average (geometric mean). Run the
functions-request task with the
subid (subscription ID) and
executeRequest function. Read the functionsConsumer section for more details about the consumer contract.
npx hardhat functions-request --subid REPLACE_SUBSCRIPTION_ID --contract REPLACE_CONSUMER_CONTRACT_ADDRESS --network REPLACE_NETWORK
$ npx hardhat functions-request --subid 6 --contract 0xa9b286E892d579dc727c79D3be9b01949796240A --network mumbai secp256k1 unavailable, reverting to browser version Simulating Functions request locally... __Console log messages from sandboxed code__ calculate geometric mean of 1,2,3,4,5,6,7,8,9,10 geometric mean is: 4.53 __Output from sandboxed source code__ Output represented as a hex string: 0x00000000000000000000000000000000000000000000000000000000000001c5 Decoded as a uint256: 453 If all 100000 callback gas is used, this request is estimated to cost 0.000052353682260389 LINK Continue? (y) Yes / (n) No y Requesting new data for FunctionsConsumer contract 0xa9b286E892d579dc727c79D3be9b01949796240A on network mumbai Waiting 2 blocks for transaction 0xa282664fc12c1cecca3607b506f7d4074cce102ae991101b88f4f32c412a56a4 to be confirmed... Request 0x6ec358f19476daf07dba0f786f49f043b10449855c8a0b6a197776460db8bfc1 initiated Waiting for fulfillment... Request 0x6ec358f19476daf07dba0f786f49f043b10449855c8a0b6a197776460db8bfc1 fulfilled! Response returned to client contract represented as a hex string: 0x00000000000000000000000000000000000000000000000000000000000001c5 Decoded as a uint256: 453 Transmission cost: 0.000080952063590393 LINK Base fee: 0.0 LINK Total cost: 0.000080952063590393 LINK
The output of the example gives you the following information:
executeRequestfunction was successfully called in the
FunctionsConsumercontract. The transaction in this example is 0xa282664fc12c1cecca3607b506f7d4074cce102ae991101b88f4f32c412a56a4.
- The request ID is
- The DON successfully fulfilled your request. The total cost was:
- The consumer contract received a response in
byteswith a value of
0x00000000000000000000000000000000000000000000000000000000000001c5. Decoding it off-chain to
uint256give you a result:
At any time, you can run the
functions-read task with the
contract parameter to read the latest received response.
npx hardhat functions-read --contract REPLACE_CONSUMER_CONTRACT_ADDRESS --network REPLACE_NETWORK
$ npx hardhat functions-read --contract 0xa9b286E892d579dc727c79D3be9b01949796240A --network mumbai secp256k1 unavailable, reverting to browser version Reading data from Functions client contract 0xa9b286E892d579dc727c79D3be9b01949796240A on network mumbai On-chain response represented as a hex string: 0x00000000000000000000000000000000000000000000000000000000000001c5 Decoded as a uint256: 453
To write a Chainlink Functions consumer contract, your contract must import FunctionsClient.sol. You can read the API reference: FunctionsClient.
This contract is not available in an NPM package, so you must download and import it from within your project.
Use the Functions.sol library to get all the functions needed for building a Chainlink Functions request. You can read the API reference: Functions.
using Functions for Functions.Request;
The latest request id, latest received response, and latest received error (if any) are defined as state variables. Note
latestErrorare encoded as dynamically sized byte array
bytes, so you will still need to decode them to read the response or error:
bytes32 public latestRequestId; bytes public latestResponse; bytes public latestError;
We define the
OCRResponseevent that your smart contract will emit during the callback
event OCRResponse(bytes32 indexed requestId, bytes result, bytes err);
Pass the oracle address for your network when you deploy the contract:
constructor(address oracle) FunctionsClient(oracle)
At any time, you can change the oracle address by calling the
The two remaining functions are:
It uses the
Functionslibrary to initialize the request and add any passed encrypted secrets or arguments. You can read the API Reference for Initializing a request, adding secrets, and adding arguments.
It sends the request to the oracle by calling the
sendRequestfunction. You can read the API reference for sending a request. Finally, it stores the request id in
bytes32 assignedReqID = sendRequest(req, subscriptionId, gasLimit); latestRequestId = assignedReqID;
fulfillRequestto be invoked during the callback. This function is defined in
fulfillRequestAPI reference). 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
latestErrorbefore emitting the
latestResponse = response; latestError = err; emit OCRResponse(requestId, response, err);
Read the Request Configuration section for a detailed description of each setting. In this example, the settings are the following:
secretsLocation: Location.Inline: The encrypted secrets are provided within the request.
source: fs.readFileSync("./Functions-request-source.js").toString(): The source code must be a script object. That’s why we use
Functions-request-source.jsand then call
toString()to get the content as a
args: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]: These arguments are passed to the source code. This example computes the average(geometric mean) of
expectedReturnType: ReturnType.uint256: The response received by the DON is encoded in
bytes. Because the average (geometric mean) is a
ReturnType.uint256to inform users how to decode the response received by the DON.
- Read the numbers provided as arguments in the
argsis an array of
parseIntto convert from
- Calculate the average (geometric mean): First, compute the product of the numbers. Then, calculate the nth root of the product where
nis the length of
- Return the result as a buffer using the
Functions.encodeUint256helper function. Because solidity doesn’t support decimals, multiply the result by