From 62cc3675e481cac2d04443e2aa10cf324880c293 Mon Sep 17 00:00:00 2001 From: Morgan Kuphal <87319522+KuphJr@users.noreply.github.com> Date: Fri, 24 Nov 2023 08:53:05 -0600 Subject: [PATCH] Use try-catch for sending Functions requests (#195) --- README.md | 2 +- contracts/AutomatedFunctionsConsumer.sol | 22 ++++++++++++-- .../Functions-consumer/performManualUpkeep.js | 30 ++++++++++++++----- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index e12fc42f..b6973de9 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ For other detailed tutorials and examples, check out the [Chainlink Functions Tu Install **both** of the following: -- Node.js version [18.18.0](https://nodejs.org/en/download/) (or the latest release of Node.js v18 if a later one is available) +- Node.js version [20](https://nodejs.org/en/download/) - Deno version [1.36](https://deno.land/manual@v1.36.4/getting_started/installation) (or the latest release of Deno v1 if a later one is available) ## Steps on live testnet diff --git a/contracts/AutomatedFunctionsConsumer.sol b/contracts/AutomatedFunctionsConsumer.sol index ce26609e..23c06620 100644 --- a/contracts/AutomatedFunctionsConsumer.sol +++ b/contracts/AutomatedFunctionsConsumer.sol @@ -26,9 +26,12 @@ contract AutomatedFunctionsConsumer is FunctionsClient, ConfirmedOwner, Automati uint256 public s_updateInterval; uint256 public s_lastUpkeepTimeStamp; uint256 public s_upkeepCounter; + uint256 public s_requestCounter; uint256 public s_responseCounter; event OCRResponse(bytes32 indexed requestId, bytes result, bytes err); + event RequestRevertedWithErrorMsg(string reason); + event RequestRevertedWithoutErrorMsg(bytes data); /** * @notice Executes once when a contract is created to initialize state variables @@ -86,8 +89,23 @@ contract AutomatedFunctionsConsumer is FunctionsClient, ConfirmedOwner, Automati s_lastUpkeepTimeStamp = block.timestamp; s_upkeepCounter = s_upkeepCounter + 1; - bytes32 requestId = _sendRequest(s_requestCBOR, s_subscriptionId, s_fulfillGasLimit, donId); - s_lastRequestId = requestId; + try + i_router.sendRequest( + s_subscriptionId, + s_requestCBOR, + FunctionsRequest.REQUEST_DATA_VERSION, + s_fulfillGasLimit, + donId + ) + returns (bytes32 requestId) { + s_requestCounter = s_requestCounter + 1; + s_lastRequestId = requestId; + emit RequestSent(requestId); + } catch Error(string memory reason) { + emit RequestRevertedWithErrorMsg(reason); + } catch (bytes memory data) { + emit RequestRevertedWithoutErrorMsg(data); + } } /** diff --git a/tasks/Functions-consumer/performManualUpkeep.js b/tasks/Functions-consumer/performManualUpkeep.js index d141b7e0..cd7d5bec 100644 --- a/tasks/Functions-consumer/performManualUpkeep.js +++ b/tasks/Functions-consumer/performManualUpkeep.js @@ -16,22 +16,36 @@ task("functions-perform-upkeep", "Manually call performUpkeep in an Automation c // Call performUpkeep const performData = taskArgs.data ?? [] + const autoConsumerContractFactory = await ethers.getContractFactory("AutomatedFunctionsConsumer") + const autoConsumerContract = await autoConsumerContractFactory.attach(taskArgs.contract) + console.log( - `Calling performUpkeep for Automation consumer contract ${taskArgs.contract} on network ${network.name}${ + `\nCalling performUpkeep for Automation consumer contract ${taskArgs.contract} on network ${network.name}${ taskArgs.data ? ` with data ${performData}` : "" }` ) - const autoConsumerContractFactory = await ethers.getContractFactory("AutomatedFunctionsConsumer") - const autoConsumerContract = await autoConsumerContractFactory.attach(taskArgs.contract) - - const checkUpkeep = await autoConsumerContract.performUpkeep(performData, overrides) + const performUpkeepTx = await autoConsumerContract.performUpkeep(performData, overrides) console.log( - `Waiting ${networks[network.name].confirmations} blocks for transaction ${checkUpkeep.hash} to be confirmed...` + `\nWaiting ${networks[network.name].confirmations} blocks for transaction ${ + performUpkeepTx.hash + } to be confirmed...` ) - await checkUpkeep.wait(networks[network.name].confirmations) + const events = (await performUpkeepTx.wait(networks[network.name].confirmations)).events + + const requestRevertedWithErrorMsg = events.find((e) => e.event === "RequestRevertedWithErrorMsg") + if (requestRevertedWithErrorMsg) { + console.log(`\nRequest reverted with error message: ${requestRevertedWithErrorMsg.args.reason}`) + return + } - console.log(`\nSuccessfully called performUpkeep`) + const requestRevertedWithoutErrorMsg = events.find((e) => e.event === "RequestRevertedWithoutErrorMsg") + if (requestRevertedWithoutErrorMsg) { + console.log( + `\nRequest reverted without error message. Ensure your request has been set correctly, the subscription is funded and the consumer contract is authorized.\n(Raw data: ${requestRevertedWithoutErrorMsg.data})` + ) + return + } const reqId = await autoConsumerContract.s_lastRequestId() console.log("\nLast request ID received by the Automation Consumer Contract...", reqId)