diff --git a/public/images/data-streams/getting-started/solidity-compiler.webp b/public/images/data-streams/getting-started/solidity-compiler.webp
index 25c0fd9ed85..1c29cc4a57f 100644
Binary files a/public/images/data-streams/getting-started/solidity-compiler.webp and b/public/images/data-streams/getting-started/solidity-compiler.webp differ
diff --git a/public/samples/DataStreams/StreamsUpkeep.sol b/public/samples/DataStreams/StreamsUpkeep.sol
index 8cd0e0d782a..0b9b698136f 100644
--- a/public/samples/DataStreams/StreamsUpkeep.sol
+++ b/public/samples/DataStreams/StreamsUpkeep.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.16;
+pragma solidity 0.8.19;
import {Common} from "@chainlink/contracts/src/v0.8/llo-feeds/libraries/Common.sol";
import {StreamsLookupCompatibleInterface} from "@chainlink/contracts/src/v0.8/automation/interfaces/StreamsLookupCompatibleInterface.sol";
diff --git a/public/samples/DataStreams/StreamsUpkeepRegistrar.sol b/public/samples/DataStreams/StreamsUpkeepRegistrar.sol
index 33ea55feb88..8e36542a7f8 100644
--- a/public/samples/DataStreams/StreamsUpkeepRegistrar.sol
+++ b/public/samples/DataStreams/StreamsUpkeepRegistrar.sol
@@ -1,12 +1,12 @@
// SPDX-License-Identifier: MIT
-pragma solidity 0.8.16;
+pragma solidity 0.8.19;
-import {Common} from "@chainlink/contracts/src/v0.8/libraries/Common.sol";
+import {Common} from "@chainlink/contracts/src/v0.8/llo-feeds/libraries/Common.sol";
import {StreamsLookupCompatibleInterface} from "@chainlink/contracts/src/v0.8/automation/interfaces/StreamsLookupCompatibleInterface.sol";
import {ILogAutomation, Log} from "@chainlink/contracts/src/v0.8/automation/interfaces/ILogAutomation.sol";
import {IRewardManager} from "@chainlink/contracts/src/v0.8/llo-feeds/interfaces/IRewardManager.sol";
import {IVerifierFeeManager} from "@chainlink/contracts/src/v0.8/llo-feeds/interfaces/IVerifierFeeManager.sol";
-import {IERC20} from "@chainlink/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC20.sol";
+import {IERC20} from "@chainlink/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC20.sol";
import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol";
/**
@@ -154,6 +154,22 @@ contract StreamsUpkeepRegistrar is
}
}
+ /**
+ * @notice this is a new, optional function in streams lookup. It is meant to surface streams lookup errors.
+ * @return upkeepNeeded boolean to indicate whether the keeper should call performUpkeep or not.
+ * @return performData bytes that the keeper should call performUpkeep with, if
+ * upkeep is needed. If you would like to encode data to decode later, try `abi.encode`.
+ */
+ function checkErrorHandler(
+ uint256 /*errCode*/,
+ bytes memory /*extraData*/
+ ) external pure returns (bool upkeepNeeded, bytes memory performData) {
+ return (true, "0");
+ // Hardcoded to always perform upkeep.
+ // Read the StreamsLookup error handler guide for more information.
+ // https://docs.chain.link/chainlink-automation/guides/streams-lookup-error-handler
+ }
+
// This function uses revert to convey call information.
// See https://eips.ethereum.org/EIPS/eip-3668#rationale for details.
function checkLog(
diff --git a/src/features/data-streams/common/gettingStarted.mdx b/src/features/data-streams/common/gettingStarted.mdx
index 8b9e951fcbe..1b0047dd453 100644
--- a/src/features/data-streams/common/gettingStarted.mdx
+++ b/src/features/data-streams/common/gettingStarted.mdx
@@ -25,7 +25,9 @@ This example uses a [Chainlink Automation Log Trigger](/chainlink-automation/gui
- Testnet LINK is available for Arbitrum Sepolia at [faucets.chain.link](https://faucets.chain.link/arbitrum-sepolia).
- Learn how to [Fund your contract with LINK](/resources/fund-your-contract).
-## Deploy the Chainlink Automation upkeep contract
+## Tutorial
+
+### Deploy the Chainlink Automation upkeep contract
Deploy an upkeep contract that is enabled to retrieve data from Data Streams. For this example, you will read from the ETH/USD stream with ID `0x00027bbaff688c906a3e20a34fe951715d1018d262a5b66e38eda027a674cd1b` on Arbitrum Sepolia. See the [Stream Identifiers](/data-streams/stream-ids) page for a complete list of available assets, IDs, and verifier proxy addresses.
@@ -33,7 +35,7 @@ Deploy an upkeep contract that is enabled to retrieve data from Data Streams. Fo
-1. Select the `0.8.16` Solidity compiler and the `StreamsUpkeep.sol` contract in the **Solidity Compiler** tab.
+1. Select the `StreamsUpkeep.sol` contract in the **Solidity Compiler** tab.
-## Deploy the emitter contract
+### Deploy the emitter contract
This contract emits logs that trigger the upkeep. This code can be part of your dApp. For example, you might emit log triggers when your users initiate a trade or other action requiring data retrieval. For this Getting Started guide, use a very simple emitter so you can test the upkeep and data retrieval.
@@ -121,7 +123,7 @@ This contract emits logs that trigger the upkeep. This code can be part of your
style="max-width: 70%;"
/>
-## Register the upkeep
+### Register the upkeep
Register a new **Log trigger** upkeep. See [Automation Log Triggers](/chainlink-automation/guides/log-trigger) to learn more about how to register Log Trigger upkeeps.
@@ -151,7 +153,7 @@ Register a new **Log trigger** upkeep. See [Automation Log Triggers](/chainlink-
1. Leave the **Check data** value and other fields blank for now, and click **Register Upkeep**. MetaMask prompts you to confirm the transaction. Wait for the transaction to complete.
-## Fund the upkeep contract
+### Fund the upkeep contract
In this example, the upkeep contract pays for onchain verification of reports from Data Streams. The Automation subscription does not cover the cost.
@@ -163,7 +165,7 @@ Open MetaMask and send 1 testnet LINK on _Arbitrum Sepolia_ to the upkeep contra
style="max-width: 70%;"
/>
-## Emit a log
+### Emit a log
Now, you can use your emitter contract to emit a log and initiate the upkeep, which retrieves data for the specified Data Streams asset ID.
@@ -181,7 +183,7 @@ After the transaction is complete, the log is emitted, and the upkeep is trigger
-## View the retrieved price
+### View the retrieved price
The retrieved price is stored as a variable in the contract and emitted in the logs.
@@ -199,8 +201,32 @@ Alternatively, you can view the price emitted in the logs for your upkeep transa
## Examine the code
-The example code you deployed has all the interfaces and functions required to work with Chainlink Automation as an upkeep contract. It follows a similar flow to the trading flow in the [Architecture](/data-streams#example-trading-flow) documentation but uses a basic log emitter to simulate the client contract that would initiate a `StreamsLookup`. After the contract receives and verifies the report, `performUpkeep` stores the price from the report in the `last_retrieved_price` and emits a `PriceUpdate` log message with the price. You could modify this to use the data in a way that works for your specific use case and application.
-
-The code example uses `revert` with `StreamsLookup` to convey call information about what streams to retrieve. See the [EIP-3668 rationale](https://eips.ethereum.org/EIPS/eip-3668#rationale) for more information about how to use `revert` in this way.
+The example code you deployed has all the interfaces and functions required to work with Chainlink Automation as an upkeep contract. It follows a similar flow to the trading flow in the [Architecture](/data-streams#example-trading-flow) documentation but uses a basic log emitter to simulate the client contract that would initiate a `StreamsLookup`. The code example uses `revert` with `StreamsLookup` to convey call information about what streams to retrieve. See the [EIP-3668 rationale](https://eips.ethereum.org/EIPS/eip-3668#rationale) for more information about how to use `revert` in this way.
+
+### Initializing the upkeep contract
+
+When deploying the contract, you define the verifier proxy address for the Data Streams feed you want to read from. You can find this address on the [Data Streams Feed IDs](/data-streams/stream-ids) page. The verifier proxy address provides functions that are required for this example:
+
+- The `s_feeManager` function to estimate the verification fees.
+- The `verify` function to verify the report onchain.
+
+### Emitting a log, retrieving, and verifying the report
+
+After registering your upkeep contract with Chainlink Automation with a log trigger, you can emit a log with the `emitLog` function from your emitter contract.
+
+ 1. The emitted log triggers the Chainlink Automation upkeep.
+ 2. Chainlink Automation then uses `StreamsLookup` to retrieve a signed report from the Data Streams Engine, returns the data in a callback (`checkCallback`), and runs the `performUpkeep` function on your registered upkeep contract.
+ 3. The `performUpkeep` function calls the `verify` function on the verifier contract to verify the report onchain.
+ 4. In this example, the `performUpkeep` function also stores the price from the report in the `last_retrieved_price` state variable and emits a `PriceUpdate` log message with the price.
+
+### Viewing the retrieved price
+
+The `last_retrieved_price` getter function of your upkeep contract retrieves the last price stored by the `performUpkeep` function in the `last_retrieved_price` state variable of the `StreamsUpkeep` contract. Additionally, the `performUpkeep` function emits a `PriceUpdate` log message with the retrieved price.
+
+### Optional: Handle Data Streams fetching errors offchain with `checkErrorHandler`
+
+When Automation detects the triggering event, it runs the `checkLog` function of your upkeep contract, which includes a `StreamsLookup` revert custom error. The `StreamsLookup` revert enables your upkeep to fetch a report from Data Streams. If the report is fetched successfully, the `checkCallback` function is evaluated offchain. Otherwise, the `checkErrorHandler` function is evaluated offchain to determine what Automation should do next.
+
+In this example, the `checkErrorHandler` is set to always return `true` for `upkeepNeeded`. This implies that the upkeep is always triggered, even if the report fetching fails. You can modify the `checkErrorHandler` function to handle errors offchain in a way that works for your specific use case. Read more about [using the StreamsLookup error handler](/chainlink-automation/guides/streams-lookup-error-handler).
diff --git a/src/features/data-streams/common/gettingStartedHardhat.mdx b/src/features/data-streams/common/gettingStartedHardhat.mdx
index 6418d318dfd..daa91e61f8e 100644
--- a/src/features/data-streams/common/gettingStartedHardhat.mdx
+++ b/src/features/data-streams/common/gettingStartedHardhat.mdx
@@ -166,9 +166,7 @@ You can find the upkeep transaction hash at [Chainlink Automation UI](https://au
## Examine the code
-The example code you deployed has all the interfaces and functions required to work with Chainlink Automation as an upkeep contract. It follows a similar flow to the trading flow in the [Architecture](/data-streams#example-trading-flow) documentation but uses a basic log emitter to simulate the client contract that would initiate a `StreamsLookup`. After the contract receives and verifies the report, `performUpkeep` stores the price from the report in the `s_last_retrieved_price` and emits a `PriceUpdate` log message with the price. You could modify this to use the data in a way that works for your specific use case and application.
-
-The code example uses `revert` with `StreamsLookup` to convey call information about what streams to retrieve. See the [EIP-3668 rationale](https://eips.ethereum.org/EIPS/eip-3668#rationale) for more information about how to use `revert` in this way.
+The example code you deployed has all the interfaces and functions required to work with Chainlink Automation as an upkeep contract. It follows a similar flow to the trading flow in the [Architecture](/data-streams#example-trading-flow) documentation but uses a basic log emitter to simulate the client contract that would initiate a `StreamsLookup`. The code example uses `revert` with `StreamsLookup` to convey call information about what streams to retrieve. See the [EIP-3668 rationale](https://eips.ethereum.org/EIPS/eip-3668#rationale) for more information about how to use `revert` in this way.
@@ -212,4 +210,10 @@ You can use the [`emitLog` task](https://github.com/smartcontractkit/smart-contr
### Viewing the retrieved price
-The [`getLastRetrievedPrice`](https://github.com/smartcontractkit/smart-contract-examples/blob/main/data-streams/getting-started/hardhat/tasks/getLastRetrievedPrice.js) Hardhat task retrieves the last price updated by the `performUpkeep` function in the `s_last_retrieved_price` state variable of the `StreamsUpkeep` contract.
+The [`getLastRetrievedPrice`](https://github.com/smartcontractkit/smart-contract-examples/blob/main/data-streams/getting-started/hardhat/tasks/getLastRetrievedPrice.js) Hardhat task retrieves the last price updated by the `performUpkeep` function in the `s_last_retrieved_price` state variable of the `StreamsUpkeepRegistrar` contract.
+
+### Optional: Handle Data Streams fetching errors offchain with `checkErrorHandler`
+
+When Automation detects the triggering event, it runs the `checkLog` function of your upkeep contract, which includes a `StreamsLookup` revert custom error. The `StreamsLookup` revert enables your upkeep to fetch a report from Data Streams. If the report is fetched successfully, the `checkCallback` function is evaluated offchain. Otherwise, the `checkErrorHandler` function is evaluated offchain to determine what Automation should do next.
+
+In this example, the `checkErrorHandler` is set to always return `true` for `upkeepNeeded`. This implies that the upkeep is always triggered, even if the report fetching fails. You can modify the `checkErrorHandler` function to handle errors offchain in a way that works for your specific use case. Read more about [using the StreamsLookup error handler](/chainlink-automation/guides/streams-lookup-error-handler).