├── .gitignore ├── LICENSE ├── README.md ├── connection.js ├── contracts ├── FunctionsConsumer.sol └── abi │ └── FunctionsConsumer.json ├── env.example ├── functions-request-config.js ├── listen.js ├── networks.js ├── package-lock.json ├── package.json ├── scripts ├── 01_deployConsumers.js ├── 02_createAndFundSub.js ├── 03_secrets.js ├── 04_request.js └── 05_readResponse.js └── source.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | coverage.json 4 | typechain 5 | typechain-types 6 | 7 | # Secrets 8 | .env.enc 9 | *.env 10 | 11 | #Hardhat files 12 | cache 13 | artifacts 14 | 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 SmartContract Chainlink Limited SEZC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chainlink Constellation Hackathon, Fall 2023 - Demonstrating the Power of Chainlink Functions 2 | 3 | This workshop demonstrates Chainlink Functions. The key dependency used is the [Chainlink Functions Toolkit NPM Package](https://github.com/smartcontractkit/functions-toolkit) 4 | 5 | In this workshop, we will make an on-chain prompt to the OpenAPI ChatGPT API and get a decentralized response delivered back on chain -- all done via a single Smart Contract and some custom JavaScript that we supply that is executed by the Chainlink Decentralized Oracle Network! 6 | 7 | The custom JS code that makes HTTP requests can receive dynamic arguments (the prompt we want answered) and access encrypted API keys (a.k.a secrets) to access the OpenAI API. 8 | 9 | The source code that will be executed by Chainlink Functions is in `./source.js`. This is the code that gets sent on-chain and then onto the Chainlink Decentralized Oracle Network for decentralized execution. 10 | 11 | ## Prerequisites 12 | 13 | 1. Metamask funded with LINK tokens - [fund here.](faucets.chain.link). Also ensure you have enough test Mumbai Matic or Sepolia Eth. Network-specific configs are in `./networks.js` but we set the `NETWORK` variable each of the files in `./scripts` so that you can choose which one you want to use. 14 | 15 | 2. Install NPM and Node > v 17. If you wish to simulate the execution of your Chainlink Functions Locally using the in-built simulator (done in the `./scripts/simulateScript.ts` script) you will also need to install [Deno](https://deno.land/manual/getting_started/installation). 16 | 17 | 3. The following environment variables should be readily available (check the `networks.js` file to see which ones you will need and what name they are given): 18 | 19 | ``` 20 | The following ENV VARIABLE values 21 | GPT_API_KEY --> get from https://platform.openai.com and then https://platform.openai.com/account/api-keys. 22 | PRIVATE_KEY --> Wallet private key 23 | 24 | POLYGON_MUMBAI_RPC_URL 25 | ## OR ## 26 | ETHEREUM_SEPOLIA_RPC_URL 27 | ``` 28 | 29 | Set your environment variables using the `env-enc` package included. 30 | 1. Set password with `npx env-enc set-pw`. Remember this password otherwise you will have to set the env vars each time! 31 | 2. Set the above-mentioned env vars with `npx env-enc set`...and then follow the prompts. 32 | 3. After you set all the env vars, you can view the decrypted, human-readable version by running `npx env-enc view` 33 | 34 | **Note** each time you open a fresh terminal or restart a terminal session you will need to run `npx env-enc set-pw` but not the other steps. 35 | 36 | ## Steps 37 | 38 | 1. Go to the [Functions Subscriptions App](https://functions.chain.link). This is the subscription management UI for functions. Connect your wallet to Polygon Mumbai/Sepolia on the Functions web app. 39 | 40 | Create your first subscription. This include two transactions: 41 | - one to accept the Terms of Service that adds your wallet address to the Allowlist, and 42 | - the other to create your Functions Subscription on-chain. 43 | 44 | Take a note of your Subscription Id as you will need it when using Chainlink Functions programmatically. 45 | 46 | Once a Functions Subscription is created you can manage it from the UI. 47 | 48 |
49 | 50 | 2. Please add at least 3 LINK to your subscription to run this project's code. This can be done from the ACTIONS button when your wallet is connected. 51 |
52 | 53 | 3. Follow along on the workshop! 54 | 55 | 56 | 57 | ## Disclaimer 58 | 59 | This tutorial offers educational examples of how to use a Chainlink system, product, or service and is provided to demonstrate how to interact with Chainlink’s systems, products, and services to integrate them into your own. This template is provided “AS IS” and “AS AVAILABLE” without warranties of any kind, it has not been audited, and it may be missing key checks or error handling to make the usage of the system, product, or service more clear. Do not use the code in this example in a production environment without completing your own audits and application of best practices. Neither Chainlink Labs, the Chainlink Foundation, nor Chainlink node operators are responsible for unintended outputs that are generated due to errors in code. -------------------------------------------------------------------------------- /connection.js: -------------------------------------------------------------------------------- 1 | require("@chainlink/env-enc").config(); 2 | // require('dotenv').config() 3 | 4 | const { providers, Wallet } = require("ethers"); 5 | 6 | const RPC_URL = process.env.RPC_URL; 7 | 8 | if (!RPC_URL) { 9 | throw new Error("Please set the RPC_URL environment variable"); 10 | } 11 | 12 | const provider = new providers.JsonRpcProvider(RPC_URL); 13 | const wallet = new Wallet(process.env.PRIVATE_KEY || "UNSET"); 14 | const signer = wallet.connect(provider); 15 | 16 | module.exports = { provider, wallet, signer }; 17 | -------------------------------------------------------------------------------- /contracts/FunctionsConsumer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.19; 3 | 4 | import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/dev/v1_0_0/FunctionsClient.sol"; 5 | import {ConfirmedOwner} from "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; 6 | import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/dev/v1_0_0/libraries/FunctionsRequest.sol"; 7 | 8 | /** 9 | * @title Chainlink Functions example on-demand consumer contract example 10 | */ 11 | contract FunctionsConsumer is FunctionsClient, ConfirmedOwner { 12 | using FunctionsRequest for FunctionsRequest.Request; 13 | 14 | bytes32 public donId; // DON ID for the Functions DON to which the requests are sent 15 | 16 | bytes32 public s_lastRequestId; 17 | bytes public s_lastResponse; 18 | bytes public s_lastError; 19 | 20 | constructor(address router, bytes32 _donId) FunctionsClient(router) ConfirmedOwner(msg.sender) { 21 | donId = _donId; 22 | } 23 | 24 | /** 25 | * @notice Set the DON ID 26 | * @param newDonId New DON ID 27 | */ 28 | function setDonId(bytes32 newDonId) external onlyOwner { 29 | donId = newDonId; 30 | } 31 | 32 | /** 33 | * @notice Triggers an on-demand Functions request using remote encrypted secrets 34 | * @param source JavaScript source code 35 | * @param secretsLocation Location of secrets (only Location.Remote & Location.DONHosted are supported) 36 | * @param encryptedSecretsReference Reference pointing to encrypted secrets 37 | * @param args String arguments passed into the source code and accessible via the global variable `args` 38 | * @param bytesArgs Bytes arguments passed into the source code and accessible via the global variable `bytesArgs` as hex strings 39 | * @param subscriptionId Subscription ID used to pay for request (FunctionsConsumer contract address must first be added to the subscription) 40 | * @param callbackGasLimit Maximum amount of gas used to call the inherited `handleOracleFulfillment` method 41 | */ 42 | function sendRequest( 43 | string calldata source, 44 | FunctionsRequest.Location secretsLocation, 45 | bytes calldata encryptedSecretsReference, 46 | string[] calldata args, 47 | bytes[] calldata bytesArgs, 48 | uint64 subscriptionId, 49 | uint32 callbackGasLimit 50 | ) external onlyOwner { 51 | FunctionsRequest.Request memory req; // Struct API reference: https://docs.chain.link/chainlink-functions/api-reference/functions-request 52 | req.initializeRequest(FunctionsRequest.Location.Inline, FunctionsRequest.CodeLanguage.JavaScript, source); 53 | req.secretsLocation = secretsLocation; 54 | req.encryptedSecretsReference = encryptedSecretsReference; 55 | if (args.length > 0) { 56 | req.setArgs(args); 57 | } 58 | if (bytesArgs.length > 0) { 59 | req.setBytesArgs(bytesArgs); 60 | } 61 | s_lastRequestId = _sendRequest(req.encodeCBOR(), subscriptionId, callbackGasLimit, donId); 62 | } 63 | 64 | /** 65 | * @notice Store latest result/error 66 | * @param requestId The request ID, returned by sendRequest() 67 | * @param response Aggregated response from the user code 68 | * @param err Aggregated error from the user code or from the execution pipeline 69 | * Either response or error parameter will be set, but never both 70 | */ 71 | function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal override { 72 | s_lastResponse = response; 73 | s_lastError = err; 74 | } 75 | } -------------------------------------------------------------------------------- /contracts/abi/FunctionsConsumer.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-artifact-1", 3 | "contractName": "FunctionsConsumer", 4 | "sourceName": "contracts/FunctionsConsumer.sol", 5 | "abi": [ 6 | { 7 | "inputs": [ 8 | { 9 | "internalType": "address", 10 | "name": "router", 11 | "type": "address" 12 | }, 13 | { 14 | "internalType": "bytes32", 15 | "name": "_donId", 16 | "type": "bytes32" 17 | } 18 | ], 19 | "stateMutability": "nonpayable", 20 | "type": "constructor" 21 | }, 22 | { 23 | "inputs": [], 24 | "name": "EmptyArgs", 25 | "type": "error" 26 | }, 27 | { 28 | "inputs": [], 29 | "name": "EmptySource", 30 | "type": "error" 31 | }, 32 | { 33 | "inputs": [], 34 | "name": "NoInlineSecrets", 35 | "type": "error" 36 | }, 37 | { 38 | "inputs": [], 39 | "name": "OnlyRouterCanFulfill", 40 | "type": "error" 41 | }, 42 | { 43 | "anonymous": false, 44 | "inputs": [ 45 | { 46 | "indexed": true, 47 | "internalType": "address", 48 | "name": "from", 49 | "type": "address" 50 | }, 51 | { 52 | "indexed": true, 53 | "internalType": "address", 54 | "name": "to", 55 | "type": "address" 56 | } 57 | ], 58 | "name": "OwnershipTransferRequested", 59 | "type": "event" 60 | }, 61 | { 62 | "anonymous": false, 63 | "inputs": [ 64 | { 65 | "indexed": true, 66 | "internalType": "address", 67 | "name": "from", 68 | "type": "address" 69 | }, 70 | { 71 | "indexed": true, 72 | "internalType": "address", 73 | "name": "to", 74 | "type": "address" 75 | } 76 | ], 77 | "name": "OwnershipTransferred", 78 | "type": "event" 79 | }, 80 | { 81 | "anonymous": false, 82 | "inputs": [ 83 | { 84 | "indexed": true, 85 | "internalType": "bytes32", 86 | "name": "id", 87 | "type": "bytes32" 88 | } 89 | ], 90 | "name": "RequestFulfilled", 91 | "type": "event" 92 | }, 93 | { 94 | "anonymous": false, 95 | "inputs": [ 96 | { 97 | "indexed": true, 98 | "internalType": "bytes32", 99 | "name": "id", 100 | "type": "bytes32" 101 | } 102 | ], 103 | "name": "RequestSent", 104 | "type": "event" 105 | }, 106 | { 107 | "inputs": [], 108 | "name": "acceptOwnership", 109 | "outputs": [], 110 | "stateMutability": "nonpayable", 111 | "type": "function" 112 | }, 113 | { 114 | "inputs": [], 115 | "name": "donId", 116 | "outputs": [ 117 | { 118 | "internalType": "bytes32", 119 | "name": "", 120 | "type": "bytes32" 121 | } 122 | ], 123 | "stateMutability": "view", 124 | "type": "function" 125 | }, 126 | { 127 | "inputs": [ 128 | { 129 | "internalType": "bytes32", 130 | "name": "requestId", 131 | "type": "bytes32" 132 | }, 133 | { 134 | "internalType": "bytes", 135 | "name": "response", 136 | "type": "bytes" 137 | }, 138 | { 139 | "internalType": "bytes", 140 | "name": "err", 141 | "type": "bytes" 142 | } 143 | ], 144 | "name": "handleOracleFulfillment", 145 | "outputs": [], 146 | "stateMutability": "nonpayable", 147 | "type": "function" 148 | }, 149 | { 150 | "inputs": [], 151 | "name": "owner", 152 | "outputs": [ 153 | { 154 | "internalType": "address", 155 | "name": "", 156 | "type": "address" 157 | } 158 | ], 159 | "stateMutability": "view", 160 | "type": "function" 161 | }, 162 | { 163 | "inputs": [], 164 | "name": "s_lastError", 165 | "outputs": [ 166 | { 167 | "internalType": "bytes", 168 | "name": "", 169 | "type": "bytes" 170 | } 171 | ], 172 | "stateMutability": "view", 173 | "type": "function" 174 | }, 175 | { 176 | "inputs": [], 177 | "name": "s_lastRequestId", 178 | "outputs": [ 179 | { 180 | "internalType": "bytes32", 181 | "name": "", 182 | "type": "bytes32" 183 | } 184 | ], 185 | "stateMutability": "view", 186 | "type": "function" 187 | }, 188 | { 189 | "inputs": [], 190 | "name": "s_lastResponse", 191 | "outputs": [ 192 | { 193 | "internalType": "bytes", 194 | "name": "", 195 | "type": "bytes" 196 | } 197 | ], 198 | "stateMutability": "view", 199 | "type": "function" 200 | }, 201 | { 202 | "inputs": [ 203 | { 204 | "internalType": "string", 205 | "name": "source", 206 | "type": "string" 207 | }, 208 | { 209 | "internalType": "enum FunctionsRequest.Location", 210 | "name": "secretsLocation", 211 | "type": "uint8" 212 | }, 213 | { 214 | "internalType": "bytes", 215 | "name": "encryptedSecretsReference", 216 | "type": "bytes" 217 | }, 218 | { 219 | "internalType": "string[]", 220 | "name": "args", 221 | "type": "string[]" 222 | }, 223 | { 224 | "internalType": "bytes[]", 225 | "name": "bytesArgs", 226 | "type": "bytes[]" 227 | }, 228 | { 229 | "internalType": "uint64", 230 | "name": "subscriptionId", 231 | "type": "uint64" 232 | }, 233 | { 234 | "internalType": "uint32", 235 | "name": "callbackGasLimit", 236 | "type": "uint32" 237 | } 238 | ], 239 | "name": "sendRequest", 240 | "outputs": [], 241 | "stateMutability": "nonpayable", 242 | "type": "function" 243 | }, 244 | { 245 | "inputs": [ 246 | { 247 | "internalType": "bytes32", 248 | "name": "newDonId", 249 | "type": "bytes32" 250 | } 251 | ], 252 | "name": "setDonId", 253 | "outputs": [], 254 | "stateMutability": "nonpayable", 255 | "type": "function" 256 | }, 257 | { 258 | "inputs": [ 259 | { 260 | "internalType": "address", 261 | "name": "to", 262 | "type": "address" 263 | } 264 | ], 265 | "name": "transferOwnership", 266 | "outputs": [], 267 | "stateMutability": "nonpayable", 268 | "type": "function" 269 | } 270 | ], 271 | "bytecode": "0x60a06040523480156200001157600080fd5b50604051620019f1380380620019f1833981016040819052620000349162000183565b6001600160a01b0382166080523380600081620000985760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000cb57620000cb81620000d8565b50505060025550620001bf565b336001600160a01b03821603620001325760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200008f565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080604083850312156200019757600080fd5b82516001600160a01b0381168114620001af57600080fd5b6020939093015192949293505050565b60805161180f620001e26000396000818161018501526109c3015261180f6000f3fe608060405234801561001057600080fd5b50600436106100be5760003560e01c806379ba5097116100765780638dbe7b9d1161005b5780638dbe7b9d14610147578063b1e217491461015e578063f2fde38b1461016757600080fd5b806379ba5097146101245780638da5cb5b1461012c57600080fd5b80633944ea3a116100a75780633944ea3a146100eb5780634b0795a81461010957806378ca5de71461011157600080fd5b80630ca76175146100c3578063231c1619146100d8575b600080fd5b6100d66100d13660046110b5565b61017a565b005b6100d66100e63660046111f0565b610217565b6100f361036a565b604051610100919061132d565b60405180910390f35b6100f36103f8565b6100d661011f366004611340565b610405565b6100d6610412565b6000546040516001600160a01b039091168152602001610100565b61015060025481565b604051908152602001610100565b61015060035481565b6100d6610175366004611359565b6104d5565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101dc576040517fc6829f8300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101e78383836104e9565b60405183907f85e1543bf2f84fe80c6badbce3648c8539ad1df4d2b3d822938ca0538be727e690600090a2505050565b61021f610508565b6102606040805160e0810190915280600081526020016000815260200160008152602001606081526020016060815260200160608152602001606081525090565b6102a76000808e8e8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250879594939250506105649050565b602081018a60028111156102bd576102bd611382565b908160028111156102d0576102d0611382565b8152505088888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505050608082015285156103295761032961032287896113bc565b82906105fb565b83156103435761034361033c8587611449565b8290610625565b61035961034f8261064f565b84846002546109be565b600355505050505050505050505050565b60048054610377906114b1565b80601f01602080910402602001604051908101604052809291908181526020018280546103a3906114b1565b80156103f05780601f106103c5576101008083540402835291602001916103f0565b820191906000526020600020905b8154815290600101906020018083116103d357829003601f168201915b505050505081565b60058054610377906114b1565b61040d610508565b600255565b6001546001600160a01b031633146104715760405162461bcd60e51b815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b600080543373ffffffffffffffffffffffffffffffffffffffff19808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6104dd610508565b6104e681610a90565b50565b60046104f5838261153b565b506005610502828261153b565b50505050565b6000546001600160a01b031633146105625760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610468565b565b805160000361059f576040517f22ce3edd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b838360028111156105b2576105b2611382565b908160028111156105c5576105c5611382565b905250604084018280156105db576105db611382565b908180156105eb576105eb611382565b9052506060909301929092525050565b805160000361061d5760405163fe936cb760e01b815260040160405180910390fd5b60a090910152565b80516000036106475760405163fe936cb760e01b815260040160405180910390fd5b60c090910152565b6060600061065e610100610b46565b90506106a86040518060400160405280600c81526020017f636f64654c6f636174696f6e000000000000000000000000000000000000000081525082610b6790919063ffffffff16565b82516106c69060028111156106bf576106bf611382565b8290610b85565b60408051808201909152600881527f6c616e67756167650000000000000000000000000000000000000000000000006020820152610705908290610b67565b604083015161071c9080156106bf576106bf611382565b60408051808201909152600681527f736f757263650000000000000000000000000000000000000000000000000000602082015261075b908290610b67565b606083015161076b908290610b67565b60a083015151156108105760408051808201909152600481527f617267730000000000000000000000000000000000000000000000000000000060208201526107b5908290610b67565b6107be81610bc2565b60005b8360a0015151811015610806576107fe8460a0015182815181106107e7576107e76115fb565b602002602001015183610b6790919063ffffffff16565b6001016107c1565b5061081081610be6565b608083015151156109115760008360200151600281111561083357610833611382565b0361086a576040517fa80d31f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051808201909152600f81527f736563726574734c6f636174696f6e000000000000000000000000000000000060208201526108a9908290610b67565b6108c2836020015160028111156106bf576106bf611382565b60408051808201909152600781527f73656372657473000000000000000000000000000000000000000000000000006020820152610901908290610b67565b6080830151610911908290610c04565b60c083015151156109b65760408051808201909152600981527f6279746573417267730000000000000000000000000000000000000000000000602082015261095b908290610b67565b61096481610bc2565b60005b8360c00151518110156109ac576109a48460c00151828151811061098d5761098d6115fb565b602002602001015183610c0490919063ffffffff16565b600101610967565b506109b681610be6565b515192915050565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663461d27628688600188886040518663ffffffff1660e01b8152600401610a16959493929190611611565b6020604051808303816000875af1158015610a35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a59919061165b565b60405190915081907f1131472297a800fee664d1d89cfa8f7676ff07189ecc53f80bbb5f4969099db890600090a295945050505050565b336001600160a01b03821603610ae85760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610468565b6001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b610b4e610fc1565b8051610b5a9083610c11565b5060006020820152919050565b610b748260038351610c8b565b8151610b809082610dac565b505050565b8151610b929060c2610dd4565b50610bbe8282604051602001610baa91815260200190565b604051602081830303815290604052610c04565b5050565b610bcd816004610e3d565b600181602001818151610be0919061168a565b90525050565b610bf1816007610e3d565b600181602001818151610be0919061169d565b610b748260028351610c8b565b604080518082019091526060815260006020820152610c316020836116b0565b15610c5957610c416020836116b0565b610c4c90602061169d565b610c56908361168a565b91505b602080840183905260405180855260008152908184010181811015610c7d57600080fd5b604052508290505b92915050565b60178167ffffffffffffffff1611610cb25782516105029060e0600585901b168317610dd4565b60ff8167ffffffffffffffff1611610cf4578251610cdb906018611fe0600586901b1617610dd4565b5082516105029067ffffffffffffffff83166001610e54565b61ffff8167ffffffffffffffff1611610d37578251610d1e906019611fe0600586901b1617610dd4565b5082516105029067ffffffffffffffff83166002610e54565b63ffffffff8167ffffffffffffffff1611610d7c578251610d6390601a611fe0600586901b1617610dd4565b5082516105029067ffffffffffffffff83166004610e54565b8251610d9390601b611fe0600586901b1617610dd4565b5082516105029067ffffffffffffffff83166008610e54565b604080518082019091526060815260006020820152610dcd83838451610ed9565b9392505050565b6040805180820190915260608152600060208201528251516000610df982600161168a565b905084602001518210610e1a57610e1a85610e158360026116d2565b610faa565b8451602083820101858153508051821115610e33578181525b5093949350505050565b8151610b8090601f611fe0600585901b1617610dd4565b6040805180820190915260608152600060208201528351516000610e78828561168a565b90508560200151811115610e9557610e9586610e158360026116d2565b60006001610ea5866101006117cd565b610eaf919061169d565b90508651828101878319825116178152508051831115610ecd578281525b50959695505050505050565b6040805180820190915260608152600060208201528251821115610efc57600080fd5b8351516000610f0b848361168a565b90508560200151811115610f2857610f2886610e158360026116d2565b855180518382016020019160009180851115610f42578482525b505050602086015b60208610610f825780518252610f6160208361168a565b9150610f6e60208261168a565b9050610f7b60208761169d565b9550610f4a565b51815160001960208890036101000a0190811690199190911617905250849150509392505050565b8151610fb68383610c11565b506105028382610dac565b6040518060400160405280610fe9604051806040016040528060608152602001600081525090565b8152602001600081525090565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561103557611035610ff6565b604052919050565b600067ffffffffffffffff83111561105757611057610ff6565b61106a601f8401601f191660200161100c565b905082815283838301111561107e57600080fd5b828260208301376000602084830101529392505050565b600082601f8301126110a657600080fd5b610dcd8383356020850161103d565b6000806000606084860312156110ca57600080fd5b83359250602084013567ffffffffffffffff808211156110e957600080fd5b6110f587838801611095565b9350604086013591508082111561110b57600080fd5b5061111886828701611095565b9150509250925092565b60008083601f84011261113457600080fd5b50813567ffffffffffffffff81111561114c57600080fd5b60208301915083602082850101111561116457600080fd5b9250929050565b80356003811061117a57600080fd5b919050565b60008083601f84011261119157600080fd5b50813567ffffffffffffffff8111156111a957600080fd5b6020830191508360208260051b850101111561116457600080fd5b803567ffffffffffffffff8116811461117a57600080fd5b803563ffffffff8116811461117a57600080fd5b600080600080600080600080600080600060e08c8e03121561121157600080fd5b67ffffffffffffffff808d35111561122857600080fd5b6112358e8e358f01611122565b909c509a5061124660208e0161116b565b99508060408e0135111561125957600080fd5b6112698e60408f01358f01611122565b909950975060608d013581101561127f57600080fd5b61128f8e60608f01358f0161117f565b909750955060808d01358110156112a557600080fd5b506112b68d60808e01358e0161117f565b90945092506112c760a08d016111c4565b91506112d560c08d016111dc565b90509295989b509295989b9093969950565b6000815180845260005b8181101561130d576020818501810151868301820152016112f1565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000610dcd60208301846112e7565b60006020828403121561135257600080fd5b5035919050565b60006020828403121561136b57600080fd5b81356001600160a01b0381168114610dcd57600080fd5b634e487b7160e01b600052602160045260246000fd5b600067ffffffffffffffff8211156113b2576113b2610ff6565b5060051b60200190565b60006113cf6113ca84611398565b61100c565b80848252602080830192508560051b8501368111156113ed57600080fd5b855b8181101561143d57803567ffffffffffffffff81111561140f5760008081fd5b870136601f8201126114215760008081fd5b61142f36823586840161103d565b8652509382019382016113ef565b50919695505050505050565b60006114576113ca84611398565b80848252602080830192508560051b85013681111561147557600080fd5b855b8181101561143d57803567ffffffffffffffff8111156114975760008081fd5b6114a336828a01611095565b865250938201938201611477565b600181811c908216806114c557607f821691505b6020821081036114e557634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610b80576000816000526020600020601f850160051c810160208610156115145750805b601f850160051c820191505b8181101561153357828155600101611520565b505050505050565b815167ffffffffffffffff81111561155557611555610ff6565b6115698161156384546114b1565b846114eb565b602080601f83116001811461159e57600084156115865750858301515b600019600386901b1c1916600185901b178555611533565b600085815260208120601f198616915b828110156115cd578886015182559484019460019091019084016115ae565b50858210156115eb5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052603260045260246000fd5b67ffffffffffffffff8616815260a06020820152600061163460a08301876112e7565b61ffff9590951660408301525063ffffffff92909216606083015260809091015292915050565b60006020828403121561166d57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610c8557610c85611674565b81810381811115610c8557610c85611674565b6000826116cd57634e487b7160e01b600052601260045260246000fd5b500690565b8082028115828204841417610c8557610c85611674565b600181815b8085111561172457816000190482111561170a5761170a611674565b8085161561171757918102915b93841c93908002906116ee565b509250929050565b60008261173b57506001610c85565b8161174857506000610c85565b816001811461175e576002811461176857611784565b6001915050610c85565b60ff84111561177957611779611674565b50506001821b610c85565b5060208310610133831016604e8410600b84101617156117a7575081810a610c85565b6117b183836116e9565b80600019048211156117c5576117c5611674565b029392505050565b6000610dcd838361172c56fea2646970667358221220b88da1a37f47a41d67747f093d4336251e77dc860a00150af843d1ed2da23a2f64736f6c63430008160033", 272 | "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100be5760003560e01c806379ba5097116100765780638dbe7b9d1161005b5780638dbe7b9d14610147578063b1e217491461015e578063f2fde38b1461016757600080fd5b806379ba5097146101245780638da5cb5b1461012c57600080fd5b80633944ea3a116100a75780633944ea3a146100eb5780634b0795a81461010957806378ca5de71461011157600080fd5b80630ca76175146100c3578063231c1619146100d8575b600080fd5b6100d66100d13660046110b5565b61017a565b005b6100d66100e63660046111f0565b610217565b6100f361036a565b604051610100919061132d565b60405180910390f35b6100f36103f8565b6100d661011f366004611340565b610405565b6100d6610412565b6000546040516001600160a01b039091168152602001610100565b61015060025481565b604051908152602001610100565b61015060035481565b6100d6610175366004611359565b6104d5565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101dc576040517fc6829f8300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101e78383836104e9565b60405183907f85e1543bf2f84fe80c6badbce3648c8539ad1df4d2b3d822938ca0538be727e690600090a2505050565b61021f610508565b6102606040805160e0810190915280600081526020016000815260200160008152602001606081526020016060815260200160608152602001606081525090565b6102a76000808e8e8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250879594939250506105649050565b602081018a60028111156102bd576102bd611382565b908160028111156102d0576102d0611382565b8152505088888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505050608082015285156103295761032961032287896113bc565b82906105fb565b83156103435761034361033c8587611449565b8290610625565b61035961034f8261064f565b84846002546109be565b600355505050505050505050505050565b60048054610377906114b1565b80601f01602080910402602001604051908101604052809291908181526020018280546103a3906114b1565b80156103f05780601f106103c5576101008083540402835291602001916103f0565b820191906000526020600020905b8154815290600101906020018083116103d357829003601f168201915b505050505081565b60058054610377906114b1565b61040d610508565b600255565b6001546001600160a01b031633146104715760405162461bcd60e51b815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b600080543373ffffffffffffffffffffffffffffffffffffffff19808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6104dd610508565b6104e681610a90565b50565b60046104f5838261153b565b506005610502828261153b565b50505050565b6000546001600160a01b031633146105625760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610468565b565b805160000361059f576040517f22ce3edd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b838360028111156105b2576105b2611382565b908160028111156105c5576105c5611382565b905250604084018280156105db576105db611382565b908180156105eb576105eb611382565b9052506060909301929092525050565b805160000361061d5760405163fe936cb760e01b815260040160405180910390fd5b60a090910152565b80516000036106475760405163fe936cb760e01b815260040160405180910390fd5b60c090910152565b6060600061065e610100610b46565b90506106a86040518060400160405280600c81526020017f636f64654c6f636174696f6e000000000000000000000000000000000000000081525082610b6790919063ffffffff16565b82516106c69060028111156106bf576106bf611382565b8290610b85565b60408051808201909152600881527f6c616e67756167650000000000000000000000000000000000000000000000006020820152610705908290610b67565b604083015161071c9080156106bf576106bf611382565b60408051808201909152600681527f736f757263650000000000000000000000000000000000000000000000000000602082015261075b908290610b67565b606083015161076b908290610b67565b60a083015151156108105760408051808201909152600481527f617267730000000000000000000000000000000000000000000000000000000060208201526107b5908290610b67565b6107be81610bc2565b60005b8360a0015151811015610806576107fe8460a0015182815181106107e7576107e76115fb565b602002602001015183610b6790919063ffffffff16565b6001016107c1565b5061081081610be6565b608083015151156109115760008360200151600281111561083357610833611382565b0361086a576040517fa80d31f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051808201909152600f81527f736563726574734c6f636174696f6e000000000000000000000000000000000060208201526108a9908290610b67565b6108c2836020015160028111156106bf576106bf611382565b60408051808201909152600781527f73656372657473000000000000000000000000000000000000000000000000006020820152610901908290610b67565b6080830151610911908290610c04565b60c083015151156109b65760408051808201909152600981527f6279746573417267730000000000000000000000000000000000000000000000602082015261095b908290610b67565b61096481610bc2565b60005b8360c00151518110156109ac576109a48460c00151828151811061098d5761098d6115fb565b602002602001015183610c0490919063ffffffff16565b600101610967565b506109b681610be6565b515192915050565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663461d27628688600188886040518663ffffffff1660e01b8152600401610a16959493929190611611565b6020604051808303816000875af1158015610a35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a59919061165b565b60405190915081907f1131472297a800fee664d1d89cfa8f7676ff07189ecc53f80bbb5f4969099db890600090a295945050505050565b336001600160a01b03821603610ae85760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610468565b6001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b610b4e610fc1565b8051610b5a9083610c11565b5060006020820152919050565b610b748260038351610c8b565b8151610b809082610dac565b505050565b8151610b929060c2610dd4565b50610bbe8282604051602001610baa91815260200190565b604051602081830303815290604052610c04565b5050565b610bcd816004610e3d565b600181602001818151610be0919061168a565b90525050565b610bf1816007610e3d565b600181602001818151610be0919061169d565b610b748260028351610c8b565b604080518082019091526060815260006020820152610c316020836116b0565b15610c5957610c416020836116b0565b610c4c90602061169d565b610c56908361168a565b91505b602080840183905260405180855260008152908184010181811015610c7d57600080fd5b604052508290505b92915050565b60178167ffffffffffffffff1611610cb25782516105029060e0600585901b168317610dd4565b60ff8167ffffffffffffffff1611610cf4578251610cdb906018611fe0600586901b1617610dd4565b5082516105029067ffffffffffffffff83166001610e54565b61ffff8167ffffffffffffffff1611610d37578251610d1e906019611fe0600586901b1617610dd4565b5082516105029067ffffffffffffffff83166002610e54565b63ffffffff8167ffffffffffffffff1611610d7c578251610d6390601a611fe0600586901b1617610dd4565b5082516105029067ffffffffffffffff83166004610e54565b8251610d9390601b611fe0600586901b1617610dd4565b5082516105029067ffffffffffffffff83166008610e54565b604080518082019091526060815260006020820152610dcd83838451610ed9565b9392505050565b6040805180820190915260608152600060208201528251516000610df982600161168a565b905084602001518210610e1a57610e1a85610e158360026116d2565b610faa565b8451602083820101858153508051821115610e33578181525b5093949350505050565b8151610b8090601f611fe0600585901b1617610dd4565b6040805180820190915260608152600060208201528351516000610e78828561168a565b90508560200151811115610e9557610e9586610e158360026116d2565b60006001610ea5866101006117cd565b610eaf919061169d565b90508651828101878319825116178152508051831115610ecd578281525b50959695505050505050565b6040805180820190915260608152600060208201528251821115610efc57600080fd5b8351516000610f0b848361168a565b90508560200151811115610f2857610f2886610e158360026116d2565b855180518382016020019160009180851115610f42578482525b505050602086015b60208610610f825780518252610f6160208361168a565b9150610f6e60208261168a565b9050610f7b60208761169d565b9550610f4a565b51815160001960208890036101000a0190811690199190911617905250849150509392505050565b8151610fb68383610c11565b506105028382610dac565b6040518060400160405280610fe9604051806040016040528060608152602001600081525090565b8152602001600081525090565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561103557611035610ff6565b604052919050565b600067ffffffffffffffff83111561105757611057610ff6565b61106a601f8401601f191660200161100c565b905082815283838301111561107e57600080fd5b828260208301376000602084830101529392505050565b600082601f8301126110a657600080fd5b610dcd8383356020850161103d565b6000806000606084860312156110ca57600080fd5b83359250602084013567ffffffffffffffff808211156110e957600080fd5b6110f587838801611095565b9350604086013591508082111561110b57600080fd5b5061111886828701611095565b9150509250925092565b60008083601f84011261113457600080fd5b50813567ffffffffffffffff81111561114c57600080fd5b60208301915083602082850101111561116457600080fd5b9250929050565b80356003811061117a57600080fd5b919050565b60008083601f84011261119157600080fd5b50813567ffffffffffffffff8111156111a957600080fd5b6020830191508360208260051b850101111561116457600080fd5b803567ffffffffffffffff8116811461117a57600080fd5b803563ffffffff8116811461117a57600080fd5b600080600080600080600080600080600060e08c8e03121561121157600080fd5b67ffffffffffffffff808d35111561122857600080fd5b6112358e8e358f01611122565b909c509a5061124660208e0161116b565b99508060408e0135111561125957600080fd5b6112698e60408f01358f01611122565b909950975060608d013581101561127f57600080fd5b61128f8e60608f01358f0161117f565b909750955060808d01358110156112a557600080fd5b506112b68d60808e01358e0161117f565b90945092506112c760a08d016111c4565b91506112d560c08d016111dc565b90509295989b509295989b9093969950565b6000815180845260005b8181101561130d576020818501810151868301820152016112f1565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000610dcd60208301846112e7565b60006020828403121561135257600080fd5b5035919050565b60006020828403121561136b57600080fd5b81356001600160a01b0381168114610dcd57600080fd5b634e487b7160e01b600052602160045260246000fd5b600067ffffffffffffffff8211156113b2576113b2610ff6565b5060051b60200190565b60006113cf6113ca84611398565b61100c565b80848252602080830192508560051b8501368111156113ed57600080fd5b855b8181101561143d57803567ffffffffffffffff81111561140f5760008081fd5b870136601f8201126114215760008081fd5b61142f36823586840161103d565b8652509382019382016113ef565b50919695505050505050565b60006114576113ca84611398565b80848252602080830192508560051b85013681111561147557600080fd5b855b8181101561143d57803567ffffffffffffffff8111156114975760008081fd5b6114a336828a01611095565b865250938201938201611477565b600181811c908216806114c557607f821691505b6020821081036114e557634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610b80576000816000526020600020601f850160051c810160208610156115145750805b601f850160051c820191505b8181101561153357828155600101611520565b505050505050565b815167ffffffffffffffff81111561155557611555610ff6565b6115698161156384546114b1565b846114eb565b602080601f83116001811461159e57600084156115865750858301515b600019600386901b1c1916600185901b178555611533565b600085815260208120601f198616915b828110156115cd578886015182559484019460019091019084016115ae565b50858210156115eb5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052603260045260246000fd5b67ffffffffffffffff8616815260a06020820152600061163460a08301876112e7565b61ffff9590951660408301525063ffffffff92909216606083015260809091015292915050565b60006020828403121561166d57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610c8557610c85611674565b81810381811115610c8557610c85611674565b6000826116cd57634e487b7160e01b600052601260045260246000fd5b500690565b8082028115828204841417610c8557610c85611674565b600181815b8085111561172457816000190482111561170a5761170a611674565b8085161561171757918102915b93841c93908002906116ee565b509250929050565b60008261173b57506001610c85565b8161174857506000610c85565b816001811461175e576002811461176857611784565b6001915050610c85565b60ff84111561177957611779611674565b50506001821b610c85565b5060208310610133831016604e8410600b84101617156117a7575081810a610c85565b6117b183836116e9565b80600019048211156117c5576117c5611674565b029392505050565b6000610dcd838361172c56fea2646970667358221220b88da1a37f47a41d67747f093d4336251e77dc860a00150af843d1ed2da23a2f64736f6c63430008160033", 273 | "linkReferences": {}, 274 | "deployedLinkReferences": {} 275 | } -------------------------------------------------------------------------------- /env.example: -------------------------------------------------------------------------------- 1 | RPC_URL= 2 | GPT_API_KEY= 3 | PRIVATE_KEY -------------------------------------------------------------------------------- /functions-request-config.js: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import { 3 | Location, 4 | ReturnType, 5 | CodeLanguage, 6 | } from "@chainlink/functions-toolkit"; 7 | 8 | // Configure the request by setting the fields below 9 | export const requestConfig = { 10 | // String containing the source code to be executed 11 | source: fs.readFileSync("./API-request-example.js").toString(), 12 | // Location of source code (only Inline is currently supported) 13 | codeLocation: Location.Inline, 14 | // Optional. Secrets can be accessed within the source code with `secrets.varName` (ie: secrets.apiKey). The secrets object can only contain string values. 15 | secrets: { apiKey: process.env.COINMARKETCAP_API_KEY ?? "" }, 16 | // Optional if secrets are expected in the sourceLocation of secrets (only Remote or DONHosted is supported) 17 | secretsLocation: Location.DONHosted, 18 | // Args (string only array) can be accessed within the source code with `args[index]` (ie: args[0]). 19 | args: ["1", "bitcoin", "btc-bitcoin", "btc", "1000000", "450"], 20 | // Code language (only JavaScript is currently supported) 21 | codeLanguage: CodeLanguage.JavaScript, 22 | // Expected type of the returned value 23 | expectedReturnType: ReturnType.uint256, 24 | }; 25 | 26 | 27 | -------------------------------------------------------------------------------- /listen.js: -------------------------------------------------------------------------------- 1 | const { 2 | ResponseListener, 3 | decodeResult, 4 | ReturnType, 5 | } = require("@chainlink/functions-toolkit"); 6 | 7 | require("@chainlink/env-enc").config("../.env.enc"); 8 | 9 | const { networks } = require("./networks.js"); 10 | const { provider } = require("./connection.js"); 11 | 12 | const NETWORK = "polygonMumbai"; 13 | const subscriptionId = "718"; 14 | 15 | const responseListener = new ResponseListener({ 16 | provider, 17 | functionsRouterAddress: networks[NETWORK].functionsRouter, 18 | }); 19 | 20 | console.log("\nListening...."); 21 | responseListener.listenForResponses(subscriptionId, response => { 22 | if (!response.errorString) { 23 | console.log( 24 | "\nFunctions response decodes to a string value of: ", 25 | decodeResult(response.responseBytesHexstring, ReturnType.string) 26 | ); 27 | } else { 28 | console.log("\nError during functions execution: ", response.errorString); 29 | } 30 | }); 31 | 32 | // Remove existing listener 33 | process.on("SIGINT", ()=>{ 34 | console.log("Removing Listeners...") 35 | responseListener.stopListeningForResponses(); 36 | }) 37 | -------------------------------------------------------------------------------- /networks.js: -------------------------------------------------------------------------------- 1 | require("@chainlink/env-enc").config() 2 | // require('dotenv').config() 3 | 4 | const DEFAULT_VERIFICATION_BLOCK_CONFIRMATIONS = 2; 5 | const PRIVATE_KEY = process.env.PRIVATE_KEY; 6 | 7 | const networks = { 8 | ethereumSepolia: { 9 | gasPrice: undefined, 10 | nonce: undefined, 11 | accounts: [PRIVATE_KEY], 12 | verifyApiKey: process.env.ETHERSCAN_API_KEY || "UNSET", 13 | chainId: 11155111, 14 | confirmations: DEFAULT_VERIFICATION_BLOCK_CONFIRMATIONS, 15 | nativeCurrencySymbol: "ETH", 16 | linkToken: "0x779877A7B0D9E8603169DdbD7836e478b4624789", 17 | linkPriceFeed: "0x42585eD362B3f1BCa95c640FdFf35Ef899212734", // LINK/ETH 18 | functionsRouter: "0xb83E47C2bC239B3bf370bc41e1459A34b41238D0", 19 | donId: "fun-ethereum-sepolia-1", 20 | gatewayUrls: [ 21 | "https://01.functions-gateway.testnet.chain.link/", 22 | "https://02.functions-gateway.testnet.chain.link/", 23 | ], 24 | }, 25 | polygonMumbai: { 26 | gasPrice: 20_000_000_000, 27 | nonce: undefined, 28 | accounts: [PRIVATE_KEY], 29 | verifyApiKey: process.env.POLYGONSCAN_API_KEY || "UNSET", 30 | chainId: 80001, 31 | confirmations: DEFAULT_VERIFICATION_BLOCK_CONFIRMATIONS, 32 | nativeCurrencySymbol: "MATIC", 33 | linkToken: "0x326C977E6efc84E512bB9C30f76E30c160eD06FB", 34 | linkPriceFeed: "0x12162c3E810393dEC01362aBf156D7ecf6159528", // LINK/MATIC 35 | functionsRouter: "0x6E2dc0F9DB014aE19888F539E59285D2Ea04244C", 36 | donId: "fun-polygon-mumbai-1", 37 | gatewayUrls: [ 38 | "https://01.functions-gateway.testnet.chain.link/", 39 | "https://02.functions-gateway.testnet.chain.link/", 40 | ], 41 | } 42 | }; 43 | 44 | module.exports = { 45 | networks, 46 | }; 47 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chainlink/constellation2023-functions-demo", 3 | "author": { 4 | "name": "Zubin Pratap" 5 | }, 6 | "scripts": { 7 | "listen": "nodemon scripts/06_listen.ts" 8 | }, 9 | "dependencies": { 10 | "@chainlink/contracts": "^0.8.0", 11 | "@chainlink/env-enc": "^1.0.5", 12 | "@chainlink/functions-toolkit": "^0.2.6", 13 | "@types/node": "^20.6.2", 14 | "dotenv": "^16.3.1", 15 | "nodemon": "^3.0.1", 16 | "typescript": "^5.2.2" 17 | }, 18 | "devDependencies": { 19 | "@nomicfoundation/hardhat-verify": "^2.0.0", 20 | "@nomiclabs/hardhat-etherscan": "^3.1.7", 21 | "hardhat": "^2.19.0", 22 | "ts-node": "^10.9.1" 23 | } 24 | } -------------------------------------------------------------------------------- /scripts/01_deployConsumers.js: -------------------------------------------------------------------------------- 1 | const { abi, bytecode } = require("../contracts/abi/FunctionsConsumer.json"); 2 | const { wallet, signer } = require("../connection.js"); 3 | const { networks } = require("../networks.js"); 4 | const { ContractFactory, utils } = require("ethers"); 5 | 6 | const NETWORK = "polygonMumbai"; 7 | 8 | const routerAddress = networks[NETWORK].functionsRouter; 9 | const donIdBytes32 = utils.formatBytes32String(networks[NETWORK].donId); 10 | 11 | const deployFunctionsConsumerContract = async () => { 12 | const contractFactory = new ContractFactory(abi, bytecode, wallet); 13 | 14 | console.log( 15 | `\nDeploying FunctionsConsumer contract on network ${NETWORK}...` 16 | ); 17 | const functionsConsumerContract = await contractFactory 18 | .connect(signer) 19 | .deploy(routerAddress, donIdBytes32); 20 | 21 | await functionsConsumerContract.deployed(); 22 | console.log(`\nDeployed at address ${functionsConsumerContract.address}`) 23 | }; 24 | 25 | deployFunctionsConsumerContract().catch(err => { 26 | console.log("Error deploying the Consumer Contract ", err); 27 | }); 28 | -------------------------------------------------------------------------------- /scripts/02_createAndFundSub.js: -------------------------------------------------------------------------------- 1 | const { SubscriptionManager } = require("@chainlink/functions-toolkit"); 2 | const { utils } = require("ethers"); 3 | 4 | const { signer } = require("../connection"); 5 | const { networks } = require("../networks"); 6 | 7 | const NETWORK = "polygonMumbai"; 8 | 9 | const functionsRouterAddress = networks[NETWORK].functionsRouter; 10 | const linkTokenAddress = networks[NETWORK].linkToken; 11 | const consumerAddress = "0x01568F134A64b8c525E468908a3850B6c6A55F54"; 12 | const LINK_AMOUNT = "3.3" 13 | 14 | const createAndFundSub = async () => { 15 | const subscriptionManager = new SubscriptionManager({ 16 | signer, 17 | linkTokenAddress, 18 | functionsRouterAddress, 19 | }); 20 | 21 | await subscriptionManager.initialize(); 22 | 23 | // Create Subscription 24 | const subscriptionId = await subscriptionManager.createSubscription(); 25 | console.log(`\n Subscription ${subscriptionId} created.`); 26 | 27 | // add consumer to subscription 28 | const receipt = await subscriptionManager.addConsumer({ 29 | subscriptionId, 30 | consumerAddress, 31 | }); 32 | 33 | console.log( 34 | `\n Subscription ${subscriptionId} now has ${consumerAddress} as a consumer.)` 35 | ); 36 | 37 | // Fund Subscription 38 | const juelsAmount = utils.parseUnits(LINK_AMOUNT, 18).toString() 39 | subscriptionManager.fundSubscription({ 40 | subscriptionId, 41 | juelsAmount 42 | }) 43 | 44 | console.log(`\n Subscription ${subscriptionId} funded with ${LINK_AMOUNT} LINK.`) 45 | }; 46 | 47 | createAndFundSub().catch(err => { 48 | console.log("Error creating/funding Subscription ", err); 49 | }); 50 | -------------------------------------------------------------------------------- /scripts/03_secrets.js: -------------------------------------------------------------------------------- 1 | const { SecretsManager } = require("@chainlink/functions-toolkit"); 2 | const fs = require("fs"); 3 | const path = require("path"); 4 | 5 | const { signer } = require("../connection.js"); 6 | const { networks } = require("../networks.js"); 7 | 8 | require("@chainlink/env-enc").config(); 9 | // require('dotenv').config() 10 | 11 | const NETWORK = "polygonMumbai"; 12 | 13 | const functionsRouterAddress = networks[NETWORK].functionsRouter; 14 | const donId = networks[NETWORK].donId; 15 | 16 | const encryptAndUploadSecrets = async () => { 17 | const secretsManager = new SecretsManager({ 18 | signer, 19 | functionsRouterAddress, 20 | donId, 21 | }); 22 | 23 | await secretsManager.initialize(); 24 | 25 | if (!process.env.GPT_API_KEY) { 26 | throw Error("GPT_API_KEY not found in .env.enc file"); 27 | } 28 | 29 | const secrets = { 30 | apiKey: process.env.GPT_API_KEY, 31 | }; 32 | 33 | const encryptedSecretsObj = await secretsManager.encryptSecrets(secrets); 34 | 35 | const gatewayUrls = networks[NETWORK].gatewayUrls; 36 | const slotId = 0; 37 | const minutesUntilExpiration = 75; 38 | 39 | const { 40 | version, // Secrets version number (corresponds to timestamp when encrypted secrets were uploaded to DON) 41 | success, // Boolean value indicating if encrypted secrets were successfully uploaded to all nodes connected to the gateway 42 | } = await secretsManager.uploadEncryptedSecretsToDON({ 43 | encryptedSecretsHexstring: encryptedSecretsObj.encryptedSecrets, 44 | gatewayUrls, 45 | slotId, 46 | minutesUntilExpiration, 47 | }); 48 | 49 | if (success){ 50 | console.log("\nUploaded secrets to DON...") 51 | const encryptedSecretsReference = secretsManager.buildDONHostedEncryptedSecretsReference({ 52 | slotId, 53 | version 54 | }) 55 | 56 | console.log(`\nMake a note of the encryptedSecretsReference: ${encryptedSecretsReference} `) 57 | } 58 | 59 | }; 60 | 61 | encryptAndUploadSecrets().catch(err => { 62 | console.log("Error encrypting and uploading secrets: ", err); 63 | }); 64 | -------------------------------------------------------------------------------- /scripts/04_request.js: -------------------------------------------------------------------------------- 1 | const { Contract } = require("ethers"); 2 | const fs = require("fs"); 3 | const path = require("path"); 4 | const { Location } = require("@chainlink/functions-toolkit"); 5 | require("@chainlink/env-enc").config(); 6 | // require('dotenv').config() 7 | 8 | const { signer } = require("../connection.js"); 9 | const { abi } = require("../contracts/abi/FunctionsConsumer.json"); 10 | 11 | const consumerAddress = "0x01568F134A64b8c525E468908a3850B6c6A55F54"; 12 | const subscriptionId = "718"; 13 | const encryptedSecretsRef = "0xa266736c6f744964006776657273696f6e1a65540efa"; 14 | 15 | const sendRequest = async () => { 16 | if (!consumerAddress || !encryptedSecretsRef || !subscriptionId) { 17 | throw Error("Missing required environment variables."); 18 | } 19 | const functionsConsumer = new Contract(consumerAddress, abi, signer); 20 | 21 | const source = fs 22 | .readFileSync(path.resolve(__dirname, "../source.js")) 23 | .toString(); 24 | 25 | const prompt = "Describe what a blockchain is in 15 words or less"; 26 | const args = [prompt]; 27 | const callbackGasLimit = 300_000; 28 | 29 | console.log("\n Sending the Request....") 30 | const requestTx = await functionsConsumer.sendRequest( 31 | source, 32 | Location.DONHosted, 33 | encryptedSecretsRef, 34 | args, 35 | [], // bytesArgs can be empty 36 | subscriptionId, 37 | callbackGasLimit 38 | ); 39 | 40 | const txReceipt = await requestTx.wait(1); 41 | const requestId = txReceipt.events[2].args.id; 42 | console.log( 43 | `\nRequest made. Request Id is ${requestId}. TxHash is ${requestTx.hash}` 44 | ); 45 | }; 46 | 47 | sendRequest().catch(err => { 48 | console.log("\nError making the Functions Request : ", err); 49 | }); 50 | -------------------------------------------------------------------------------- /scripts/05_readResponse.js: -------------------------------------------------------------------------------- 1 | const { decodeResult, ReturnType } = require("@chainlink/functions-toolkit"); 2 | const { Contract } = require("ethers"); 3 | 4 | const { signer } = require("../connection.js"); 5 | const { abi } = require("../contracts/abi/FunctionsConsumer.json"); 6 | 7 | const consumerAddress = "0x01568F134A64b8c525E468908a3850B6c6A55F54" 8 | const readResponse = async () => { 9 | const functionsConsumer = new Contract(consumerAddress, abi, signer); 10 | 11 | const responseBytes = await functionsConsumer.s_lastResponse() 12 | console.log("\nResponse Bytes : ", responseBytes) 13 | 14 | const decodedResponse = decodeResult(responseBytes, ReturnType.string) 15 | 16 | console.log("\nDecoded response from OpenAI/ChatGPT:", decodedResponse) 17 | }; 18 | 19 | readResponse().catch(err => { 20 | console.log("Error reading response: ", err); 21 | }); 22 | -------------------------------------------------------------------------------- /source.js: -------------------------------------------------------------------------------- 1 | const gptPrompt = args[0]; 2 | 3 | const postData = { 4 | model: "gpt-3.5-turbo", 5 | messages: [{ role: "user", content: gptPrompt }], 6 | temperature: 0, 7 | }; 8 | 9 | const openAIResponse = await Functions.makeHttpRequest({ 10 | url: "https://api.openai.com/v1/chat/completions", 11 | method: "POST", 12 | headers: { 13 | Authorization: `Bearer ${secrets.apiKey}`, 14 | "Content-Type": "application/json", 15 | }, 16 | data: postData, 17 | }); 18 | 19 | if (openAIResponse.error) { 20 | throw new Error(JSON.stringify(openAIResponse)); 21 | } 22 | 23 | const result = openAIResponse.data.choices[0].message.content; 24 | 25 | console.log(result); 26 | return Functions.encodeString(result); --------------------------------------------------------------------------------