Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add documentation for source imported packages #1682

Merged
merged 17 commits into from
Dec 15, 2023
Merged
4 changes: 4 additions & 0 deletions src/config/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,10 @@ export const SIDEBAR: Partial<Record<Sections, SectionEntry[]>> = {
title: "Automate your Functions (Custom Logic Automation)",
url: "chainlink-functions/tutorials/automate-functions-custom-logic",
},
{
title: "Using Imports with Functions",
url: "chainlink-functions/tutorials/importing-packages",
},
],
},
{
Expand Down
6 changes: 6 additions & 0 deletions src/content/chainlink-functions/resources/release-notes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ title: "Chainlink Functions Release Notes"

import { Aside } from "@components"

## Module import support on testnets - 2023-12-15

You can use module imports with Chainlink Functions source code on testnet networks. See the [Using Imports with Functions](/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.

## Open Beta - 2023-09-29

- Chainlink Functions is available as an open beta on the following blockchains:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ To run the example:

#### source.js

The Decentralized Oracle Network will run the [JavaScript code](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/3-custom-response/source.js). The code is self-explanatory and has comments to help you understand all the steps. **Note**: The custom source code you want to execute in a Functions request can use vanilla [deno](https://deno.land/) but cannot use any require statements or imported modules.
The Decentralized Oracle Network will run the [JavaScript code](https://github.com/smartcontractkit/smart-contract-examples/blob/main/functions-examples/examples/3-custom-response/source.js). The code is self-explanatory and has comments to help you understand all the steps.

<ChainlinkFunctions section="deno-importe-notes" />

This JavaScript source code uses [Functions.makeHttpRequest](/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](/chainlink-functions/api-reference/javascript-source#http-requests) documentation, you see that you must provide the following parameters:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,9 @@ To run the example:

#### source.js

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. **Note**: The custom source code you want to execute in a Functions request can use vanilla [deno](https://deno.land/) but cannot use any require statements or imported modules.
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.

<ChainlinkFunctions section="deno-importe-notes" />

This JavaScript source code uses [Functions.makeHttpRequest](/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.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,9 @@ To run the example:

#### source.js

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. **Note**: The custom source code you want to execute in a Functions request can use vanilla [deno](https://deno.land/) but cannot use any require statements or imported modules.
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.

<ChainlinkFunctions section="deno-importe-notes" />

This JavaScript source code uses [Functions.makeHttpRequest](/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](/chainlink-functions/api-reference/javascript-source#http-requests) documentation, you see that you must provide the following parameters:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ To run the example:

#### source.js

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. **Note**: The custom source code you want to execute in a Functions request can use vanilla [deno](https://deno.land/) but cannot use any require statements or imported modules.
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.

<ChainlinkFunctions section="deno-importe-notes" />

This JavaScript source code uses [Functions.makeHttpRequest](/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](/chainlink-functions/api-reference/javascript-source#http-requests) documentation, you see that you must provide the following parameters:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,9 @@ To run the example:

#### source.js

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. **Note**: The custom source code you want to execute in a Functions request can use vanilla [Deno](https://deno.land/) but cannot use any require statements or imported modules.
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.

<ChainlinkFunctions section="deno-importe-notes" />

This JavaScript source code uses [Functions.makeHttpRequest](/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](/chainlink-functions/api-reference/javascript-source#http-requests) documentation, you see that you must provide the following parameters:

Expand Down
222 changes: 222 additions & 0 deletions src/content/chainlink-functions/tutorials/importing-packages.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
---
section: chainlinkFunctions
date: Last Modified
title: "Using Imports with Functions"
metadata:
linkToWallet: true
whatsnext:
{
"Try out the Chainlink Functions Tutorials": "/chainlink-functions/tutorials",
"Read the Architecture to understand how Chainlink Functions operates": "/chainlink-functions/resources/architecture",
}
---

import { Aside, CopyText } from "@components"
import { Tabs } from "@components/Tabs"
import ChainlinkFunctions from "@features/chainlink-functions/common/ChainlinkFunctions.astro"

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 20 imports total are supported.
dwightjl marked this conversation as resolved.
Show resolved Hide resolved
- 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 [Compatability 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`:

```javascript
const { escape } = await import("https://deno.land/std/regexp/mod.ts")
```

- ESM-compatible packages:

```javascript
const { format } = await import("npm:date-fns")
```

- Standard Node modules:

```javascript
const path = await import("node:path")
```

- CDN imports:

```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.

<Aside type="caution">
Using module imports as part of your Functions source code is supported only on testnets at this time. Running the same code on mainnet will not succeed.

Users are fully responsible for any code that they import. Chainlink Functions provides no guarantees of the validity, availability, or security of any code that a user chooses to import. For any use cases seeking to secure value, fully vet any dependencies that are being used or completely avoid importing dependencies to avoid risk from a compromised dependency or repository.

</Aside>

<ChainlinkFunctions section="prerequisites-guides" />

## 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 on-chain function. In this example, the source code calls the [`latestRoundData()` function](/data-feeds/api-reference#latestrounddata) from the `AggregatorV3Interface`. Read the [Examine the code](#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.
1. Replace the consumer contract address and the subscription ID with your own values.

```javascript
const consumerAddress = "0x8dFf78B7EE3128D00E90611FBeD20A71397064D9" // REPLACE this with your Functions consumer address
const subscriptionId = 3 // REPLACE this with your subscription ID
```

1. Make a request:

```shell
node examples/11-package-imports/request.js
```

The script runs your function in a sandbox environment before making an on-chain transaction:

```text
$ node examples/11-package-imports/request.js
secp256k1 unavailable, reverting to browser version
Start simulation...
Simulation result {
capturedTerminalOutput: 'Fetched BTC / USD price: 4367193987453\n',
responseBytesHexstring: '0x000000000000000000000000000000000000000000000000000003f8d10bd97d'
}
✅ Decoded response to int256: 4367193987453n

Estimate request costs...
Fulfillment cost estimated to 0.20243353895715 LINK

Make request...

✅ Functions request sent! Transaction hash 0xed3d0419189c012ce852b37b51d47bdcd80f06a4749b4c01a81a3f5fb06139e3. Waiting for a response...
See your request in the explorer https://mumbai.polygonscan.com/tx/0xed3d0419189c012ce852b37b51d47bdcd80f06a4749b4c01a81a3f5fb06139e3

✅ Request 0xa8a7bec42edc16cf549f69e734161f2f2550a1057bb4060611a8043253ee61ef successfully fulfilled. Cost is 0.200014890551438381 LINK.Complete reponse: {
requestId: '0xa8a7bec42edc16cf549f69e734161f2f2550a1057bb4060611a8043253ee61ef',
subscriptionId: 38,
totalCostInJuels: 200014890551438381n,
responseBytesHexstring: '0x000000000000000000000000000000000000000000000000000003f8d10bd97d',
errorString: '',
returnDataBytesHexstring: '0x',
fulfillmentCode: 0
}

✅ Decoded response to int256: 4367193987453n
```

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 `0xed3d0419189c012ce852b37b51d47bdcd80f06a4749b4c01a81a3f5fb06139e3` and the request ID is `0xdfb161de5a6ad34e58bb115dd07651a11d4cf4739652f509ecad78a1bf506e82`.

- The DON successfully fulfilled your request. The total cost was: `0.200435783655508510 LINK`.
- The consumer contract received a response in `bytes` with a value of `0xa8a7bec42edc16cf549f69e734161f2f2550a1057bb4060611a8043253ee61ef`. Decoding it off-chain to `int256` gives you a result: `4367193987453`.

## Examine the code

### FunctionsConsumerExample.sol

<ChainlinkFunctions section="functions-consumer" />

### JavaScript example

#### source.js

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.

<ChainlinkFunctions section="deno-importe-notes" />

The example `source.js` file uses an Ethers JSON RPC call to the [`latestRoundData()` function](/data-feeds/api-reference#latestrounddata) of a [Chainlink Data Feed](/data-feeds). The request requires a few modifications to work in the Chainlink Functions environment. For example, the `JsonRpcProvider` class must be modified to handle the request asynchronously.

```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 and await the response.

```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.

```javascript
return Functions.encodeInt256(dataFeedResponse.answer)
```

#### request.js

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:

```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 `makeRequestMumbai`. This function can be broken into five main parts:

1. Definition of necessary identifiers:

- `routerAddress`: Chainlink Functions router address on Polygon Mumbai.
- `donId`: Identifier of the DON that will fulfill your requests on Polygon Mumbai.
- `explorerUrl`: Block explorer url of Polygon Mumbai.
- `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.

1. 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).

1. 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.

1. 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.

1. 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).
Loading
Loading