# Automation Architecture
Source: https://docs.chain.link/chainlink-automation/concepts/automation-architecture
The following diagram describes the architecture of the Chainlink Automation Network. The Chainlink Automation Registry governs the actors on the network and compensates Automation Nodes for performing successful upkeeps. Developers can register their Upkeeps, and Node Operators can register as Automation Nodes.
## How it works
Automation Nodes form a peer-to-peer network using Chainlink's OCR3 protocol. Nodes use the `Registry` to know which Upkeeps to service and **simulate** `checkUpkeep` functions on their own block nodes to determine when upkeeps are eligible to be performed.
Using Chainlink's OCR3 protocol, nodes then get consensus on which upkeeps to perform and sign a report. The signed report contains the performData that will be executed onchain and the report is validated on the `Registry` before execution to provide cryptographic guarantees. The network has built-in redundancy and will still perform your upkeep even if some nodes are down.
Chainlink Automation use the same battle-tested transaction manager mechanism built and used by Chainlink Data Feeds. This creates a hyper-reliable automation service that can execute and confirm transactions even during intense gas spikes or on chains with significant reorgs.
## Internal monitoring
Internally, Chainlink Automation also uses its own monitoring and alerting mechanisms to maintain a healthy network and ensure developers get the industry leading reliability and performance.
## Supported networks and costs
For a list of blockchains that is supported by Chainlink Automation, please review the [supported networks page](/chainlink-automation/overview/supported-networks). To learn more about the cost of using Chainlink Automation, please review the [Automation economics](/chainlink-automation/overview/automation-economics) page.
---
# Automation Concepts
Source: https://docs.chain.link/chainlink-automation/concepts/automation-concepts
Before you explore how Chainlink Automation works on the [architecture](/chainlink-automation/concepts/automation-architecture) page, you should explore core concepts.
**Prerequisites**:
- [Smart contracts](https://chain.link/education/smart-contracts#:~:text=DEFINITION,executed%20on%20a%20blockchain%20network.)
- [ERC-677 Token standard](/resources/link-token-contracts)
## Upkeeps and triggers
These are the jobs or tasks that you execute onchain. For example, you can call a smart contract function if a specific set of conditions are met. These specific conditions are called *triggers*. There are currently three types of triggers that the Chainlink Automation Network supports including:
- [**Time-based trigger**](/chainlink-automation/guides/job-scheduler): Use a [time-based trigger](/chainlink-automation/guides/job-scheduler) to execute your function according to a time schedule. This feature is also called the Job Scheduler and it is a throwback to the Ethereum Alarm Clock. Time-based trigger contracts do not need to be [compatible](/chainlink-automation/guides/compatible-contracts) with the `AutomationCompatibleInterface` contract.
- [**Custom logic trigger**](/chainlink-automation/guides/register-upkeep): Use a [custom logic trigger](/chainlink-automation/guides/register-upkeep) to provide custom solidity logic that Automation Nodes evaluate (offchain) to determine when to execute your function onchain. Your contract must meet the requirements to be [compatible](/chainlink-automation/guides/compatible-contracts) with the `AutomationCompatibleInterface` contract. Custom logic examples include checking the balance on a contract, only executing limit orders when their levels are met, any one of our [coded examples](/chainlink-automation/util-overview), and many more.
- [**Log trigger**](/chainlink-automation/guides/log-trigger): Use log data as both trigger and input. Your contract must meet the requirements to be [compatible](/chainlink-automation/guides/compatible-contracts) with the `AutomationCompatibleInterface` contract.
## Automation nodes
Automation Nodes in the Chainlink Automation Network provide service to upkeeps that are funded and registered in the Automation registry. Automation Nodes use the same Node Operators as Chainlink Data Feeds.
---
# Automation Best Practices
Source: https://docs.chain.link/chainlink-automation/concepts/best-practice
This guide outlines the best practices when using Chainlink Automation. These best practices are important for using Chainlink Automation securely and reliably when you [create Automation-compatible contracts](/chainlink-automation/guides/compatible-contracts).
### Use the latest version of Chainlink Automation
To get the best reliability and security guarantees for your upkeep, use the latest version of Chainlink Automation.
### Make registry and registrar addresses configurable
Where your upkeep calls the registry or the registrar, you must make the address configurable so you can migrate your upkeep easily with the one-click migration capability. If you don't make the address configurable, you must redeploy the upkeep for migrations.
Alternatively, set the forwarder address when your upkeep is deployed and read the registry from the forwarder during your execution to simplify it.
### Use the Forwarder
If your upkeep performs **sensitive** functions in your protocol, consider using the `Forwarder` to lock it down so `performUpkeep` can only be called by the `Forwarder`. Add other permissible addresses if you need to call it yourself. Note the forwarder is only determined after registration so make this a mutable variable and ensure you add a setter function with permissions for you to set it.
### Verify Data Streams reports fetched with StreamsLookup
If your upkeep uses [StreamsLookup](/chainlink-automation/reference/automation-interfaces#streamslookupcompatibleinterface), ensure you use the [verification interface](/data-streams/streams-trade/interfaces) to verify your reports onchain.
### Avoid "flickering" custom logic upkeeps
The Automation DON evaluates your upkeep regularly. When your upkeep is eligible, the DON attempts to perform the upkeep. For best results, ensure that `checkUpkeep` remains true until execution.
If the state of your upkeep "flickers" by rapidly alternating between true and false, then your upkeep is at risk of not being performed. "Flickering" upkeeps might cause unintended consequences because there is latency between observing the state of the chain, getting consensus (v2 and later) on what needs to happen, and confirming the transaction onchain.
### Always test your contracts
As with all smart contract testing, it is important to test the boundaries of your smart contract in order to ensure it operates as intended. Similarly, it is important to make sure the compatible contract operates within the parameters of the `Registry`.
Test all of your mission-critical contracts, and stress-test the contract to confirm the performance and correct operation of your use case under load and adversarial conditions. The Chainlink Automation Network will continue to operate under stress, but so should your contract. For a list of supported testnet blockchains, please review the [supported networks page](/chainlink-automation/overview/supported-networks).
### Using ERC-677 tokens
For registration on Mainnet, you need ERC-677 LINK. Many token bridges give you ERC-20 LINK tokens. Use PegSwap to [convert Chainlink tokens (LINK) to be ERC-677 compatible](https://pegswap.chain.link/). To register on a supported testnet, get [LINK](/resources/link-token-contracts) for the testnet that you want to use from our faucet.
### Automation v1 upkeep revalidation
If your upkeep is on Automation v1, we recommend that you revalidate the conditions specified in `checkUpkeep` in your `performUpkeep` function. Automation v1 uses a turn taking system where nodes rotate to monitor your upkeep. It does not use consensus.
---
# Create Automation-Compatible Contracts
Source: https://docs.chain.link/chainlink-automation/guides/compatible-contracts
Learn how to make smart contracts that are compatible with `Automation`.
## Automation compatible contracts
A contract is Automation-compatible when it follows a specified interface that allows the Chainlink Automation Network to determine if, when, and how the contract should be automated.
The interface you use will depend on the type of trigger you want to use:
- If you want a log event to trigger your upkeep, use the [`ILogAutomation`](/chainlink-automation/reference/automation-interfaces/#ilogautomation) interface.
- If you want to use onchain state in a custom calculation to trigger your upkeep, use [`AutomationCompatibleInterface`](/chainlink-automation/reference/automation-interfaces/#automationcompatibleinterface) interface.
- If you want to call a function just based on time, you don't need an interface. Consider instead using a [time-based upkeep](/chainlink-automation/guides/job-scheduler).
- If you want to use Automation with Data Streams, use [`StreamsLookupCompatibleInterface`](/chainlink-automation/reference/automation-interfaces/#streamslookupcompatibleinterface) interface.
You can learn more about these interfaces [here](/chainlink-automation/reference/automation-interfaces).
## Example Automation-compatible contract using custom logic trigger
Custom logic Automation compatible contracts must meet the following requirements:
- Import `AutomationCompatible.sol`. You can refer to the [Chainlink Contracts](https://github.com/smartcontractkit/chainlink/tree/contracts-v1.3.0/contracts/src) on GitHub to find the latest version.
- Use the [`AutomationCompatibleInterface`](/chainlink-automation/reference/automation-interfaces) from the library to ensure your `checkUpkeep` and `performUpkeep` function definitions match the definitions expected by the Chainlink Automation Network.
- Include a `checkUpkeep` function that contains the logic that will be executed offchain to see if `performUpkeep` should be executed. `checkUpkeep` can use onchain data and a specified `checkData` parameter to perform complex calculations offchain and then send the result to `performUpkeep` as `performData`.
- Include a `performUpkeep` function that will be executed onchain when `checkUpkeep` returns `true`.
Use these elements to create a compatible contract that will automatically increment a counter after every `updateInterval` seconds. After you register the contract as an upkeep, the Chainlink Automation Network frequently simulates your `checkUpkeep` offchain to determine if the `updateInterval` time has passed since the last increment (timestamp). When `checkUpkeep` returns true, the Chainlink Automation Network calls `performUpkeep` onchain and increments the counter. This cycle repeats until the upkeep is cancelled or runs out of funding.
Compile and deploy your own Automation Counter onto a [supported Testnet](/chainlink-automation/overview/supported-networks).
1. In the Remix example, select the compile tab on the left and press the compile button. Make sure that your contract compiles without any errors. Note that the Warning messages in this example are acceptable and will not block the deployment.
2. Select the **Deploy** tab and deploy the `Counter` smart contract in the `injected web3` environment. When deploying the contract, specify the `updateInterval` value. For this example, set a short interval of 60. This is the interval at which the `performUpkeep` function will be called.
3. After deployment is complete, copy the address of the deployed contract. This address is required to register your upkeep in the [Automation UI](https://automation.chain.link/). The example in this document uses [custom logic](/chainlink-automation/guides/register-upkeep) automation.
To see more complex examples, go to the [Quick Starts](/quickstarts/eth-balance-monitor) page.
Now register your [upkeep](/chainlink-automation/guides/register-upkeep).
## Vyper example
You can find a `KeepersConsumer` example [here](https://github.com/smartcontractkit/apeworx-starter-kit/blob/main/contracts/KeepersConsumer.vy). Read the ***apeworx-starter-kit*** [README](https://github.com/smartcontractkit/apeworx-starter-kit) to learn how to run the example.
---
# Create Flexible, Secure, and Low-Cost Smart Contracts
Source: https://docs.chain.link/chainlink-automation/guides/flexible-upkeeps
In this guide, you will learn how the flexibility of [Chainlink Automation](https://chain.link/automation) enables important design patterns that reduce gas fees, enhance the resilience of dApps, and improve end-user experience. Smart contracts themselves cannot self-trigger their functions at arbitrary times or under arbitrary conditions. Transactions can only be initiated by another account.
Start by integrating an example contract to Chainlink Automation that has not yet been optimized. Then, deploy a comparison contract that shows you how to properly use the flexibility of Chainlink Automation to perform complex computations without paying high gas fees.
## Prerequisites
This guide assumes you have a basic understanding of [Chainlink Automation](https://chain.link/automation). If you are new to Automation, complete the following guides first:
- Learn how to [deploy solidity contracts using Remix and Metamask](/quickstarts/deploy-your-first-contract)
- Learn how to make [compatible contracts](/chainlink-automation/guides/compatible-contracts)
- [Register Upkeep for a smart contract](/chainlink-automation/guides/register-upkeep)
Chainlink Automation is supported on several [networks](/chainlink-automation/overview/supported-networks).
## Problem: Onchain computation leads to high gas fees
In the guide for [Creating Compatible Contracts](/chainlink-automation/guides/compatible-contracts), you deployed a basic [counter contract](/chainlink-automation/guides/compatible-contracts/#example-automation-compatible-contract-using-custom-logic-trigger) and verified that the counter increments every 30 seconds. However, more complex use cases can require looping over arrays or performing expensive computation. This leads to expensive gas fees and can increase the premium that end-users have to pay to use your dApp. To illustrate this, deploy an example contract that maintains internal balances.
The contract has the following components:
- A fixed-size(1000) array `balances` with each element of the array starting with a balance of 1000.
- The `withdraw()` function decreases the balance of one or more indexes in the `balances` array. Use this to simulate changes to the balance of each element in the array.
- Automation Nodes are responsible for regularly re-balancing the elements using two functions:
- The `checkUpkeep()` function checks if the contract requires work to be done. If one array element has a balance of less than `LIMIT`, the function returns `upkeepNeeded == true`.
- The `performUpkeep()` function to re-balances the elements. To demonstrate how this computation can cause high gas fees, this example does all of the computation within the transaction. The function finds all of the elements that are less than `LIMIT`, decreases the contract `liquidity`, and increases every found element to equal `LIMIT`.
Test this example using the following steps:
1. Deploy the contract using Remix on the [supported testnet](/chainlink-automation/overview/supported-networks) of your choice.
2. Before registering the upkeep for your contract, decrease the balances of some elements. This simulates a situation where upkeep is required. In Remix, Withdraw 100 at indexes 10,100,300,350,500,600,670,700,900. Pass `100,[10,100,300,350,500,600,670,700,900]` to the withdraw function:
(Image: Withdraw 100 at 10,100,300,350,500,600,670,700,900)
You can also perform this step after registering the upkeep if you need to.
3. Register the upkeep for your contract as explained [here](/chainlink-automation/guides/register-upkeep). Because this example has high gas requirements, specify the maximum allowed gas limit of `2,500,000`.
4. After the registration is confirmed, Automation Nodes perform the upkeep.
(Image: BalancerOnChain Upkeep History)
5. Click the transaction hash to see the transaction details in Etherscan. You can find how much gas was used in the upkeep transaction.
(Image: BalancerOnChain Gas)
In this example, the `performUpkeep()` function used **2,481,379** gas. This example has two main issues:
- All computation is done in `performUpkeep()`. This is a state modifying function which leads to high gas consumption.
- This example is simple, but looping over large arrays with state updates can cause the transaction to hit the gas limit of the [network](/chainlink-automation/overview/supported-networks), which prevents `performUpkeep` from running successfully.
To reduce these gas fees and avoid running out of gas, you can make some simple changes to the contract.
## Solution: Perform complex computations with no gas fees
Modify the contract and move the computation to the `checkUpkeep()` function. This computation *doesn’t consume any gas* and supports multiple upkeeps for the same contract to do the work in parallel. The main difference between this new contract and the previous contract are:
- The `checkUpkeep()` function receives [`checkData`](/chainlink-automation/reference/automation-interfaces/#checkdata), which passes arbitrary bytes to the function. Pass a `lowerBound` and an `upperBound` to scope the work to a sub-array of `balances`. This creates several upkeeps with different values of `checkData`. The function loops over the sub-array and looks for the indexes of the elements that require re-balancing and calculates the required `increments`. Then, it returns `upkeepNeeded == true` and `performData`, which is calculated by encoding `indexes` and `increments`. Note that `checkUpkeep()` is a view function, so computation does not consume any gas.
- The `performUpkeep()` function takes [performData](/chainlink-automation/reference/automation-interfaces/#performdata) as a parameter and decodes it to fetch the `indexes` and the `increments`.
Run this example to compare the gas fees:
1. Deploy the contract using Remix on the [supported testnet](/chainlink-automation/overview/supported-networks) of your choice.
2. Withdraw 100 at 10,100,300,350,500,600,670,700,900. Pass `100,[10,100,300,350,500,600,670,700,900]` to the withdraw function the same way that you did for the [previous example](#problem-onchain-computation-leads-to-high-gas-fees).
3. Register three upkeeps for your contract as explained [here](/chainlink-automation/guides/register-upkeep). Because the Automation Nodes handle much of the computation offchain, a gas limit of 200,000 is sufficient. For each registration, pass the following `checkData` values to specify which balance indexes the registration will monitor. **Note**: You must remove any breaking line when copying the values.
| Upkeep Name | CheckData(base16) | Remark: calculated using [`abi.encode()`](https://docs.soliditylang.org/en/develop/abi-spec.html#strict-encoding-mode) |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| balancerOffChainSubset1 | 0x000000000000000000000000 00000000000000000000000000 00000000000000000000000000 00000000000000000000000000 0000000000000000000000014c | lowerBound: 0 upperBound: 332 |
| balancerOffChainSubset2 | 0x000000000000000000000000 00000000000000000000000000 0000000000014d000000000000 00000000000000000000000000 0000000000000000000000029a | lowerBound: 333 upperBound: 666 |
| balancerOffChainSubset3 | 0x000000000000000000000000 00000000000000000000000000 0000000000029b000000000000 00000000000000000000000000 000000000000000000000003e7 | lowerBound: 667 upperBound: 999 |
4. After the registration is confirmed, the three upkeeps run:
(Image: BalancerOffChain1 History)
(Image: BalancerOffChain2 History)
(Image: BalancerOffChain3 History)
5. Click each transaction hash to see the details of each transaction in Etherscan. Find the gas used by each of the upkeep transactions:
(Image: BalancerOffChain1 Gas)
(Image: BalancerOffChain2 Gas)
(Image: BalancerOffChain3 Gas)
In this example the total gas used by each `performUpkeep()` function was 133,464 + 133,488 + 133,488 = **400,440**. This is an improvement of about 84% compared to the previous example, which used **2,481,379** gas.
## Conclusion
Using Chainlink Automation efficiently not only allows you to reduce the gas fees, but also keeps them within predictable limits. That's the reason why [several Defi protocols](https://chainlinktoday.com/prominent-founders-examine-chainlink-keepers-role-in-defis-evolution/) outsource their maintenance tasks to Chainlink Automation.
---
# Secure Upkeeps Using the Forwarder
Source: https://docs.chain.link/chainlink-automation/guides/forwarder
This tutorial explains how to use the `Forwarder` to add additional security to your Automation upkeeps. To learn how other Chainlink Automation contracts work, click [here](/chainlink-automation/reference/automation-contracts).
## What is a Forwarder? When is it used?
Each registered upkeep under the Chainlink Automation network has its own unique `Forwarder` contract. The `Forwarder` address becomes available only after upkeep registration, as we deploy a new forwarder for each upkeep. The `Forwarder` contract is the intermediary between the Automation Registry and your Upkeep contract, so you make it the `msg.Sender` for your upkeep.
If you don't use the forwarder address, your contract's `performUpkeep` function is open and callable by anyone. If your contract is without risk of accepting unintentional external data, you don't need to use the forwarder address.
## Securing your upkeep
If your upkeep's perform function needs to be permissioned, please consider setting `msg.sender` as your forwarder address at the top of your `performUpkeep` function.
To make this work you will need to:
- Create `forwarder` as a mutable address variable on your contract that only *you* can update. `forwarder` is a unique value that cannot change for your upkeep.
- Create a `setForwarder` function in your contract so you can update the `forwarder` address.
- Register your upkeep and then retrieve its forwarder address from the Chainlink Automation App or programmatically.
- Call the `setForwarder` function, passing the forwarder address as an input argument.
### Finding the forwarder address
After you register an upkeep, its forwarder address is available in the Chainlink Automation App. Alternatively, you can fetch it programmatically using `registry.getForwarder(upkeepID)` from the Registry interface.
## Code example
The code sample below uses the Forwarder:
---
# Set a gas price threshold on your upkeep
Source: https://docs.chain.link/chainlink-automation/guides/gas-price-threshold
You can set a gas price threshold for your upkeep to prevent it from being serviced when gas prices exceed the *maximum gas price* you specify. You can set a maximum gas price on conditional upkeeps and log trigger upkeeps.
**Note:** This is a different gas setting than the upkeep gas limit, which limits the *amount* of gas used.
After you set your maximum gas price, it takes a few minutes to go into effect as it syncs with the nodes. Updating your maximum gas price does not impact any upkeep where the execution is in-flight.
## Limitations
Do not set a gas price threshold when speed of execution is important. The gas price threshold can significantly delay the execution of conditional upkeeps and prevent execution entirely for log trigger upkeeps.
### Gas prices spike after your transaction is in flight
Due to the decentralized nature of the Automation network and its transaction manager, your upkeep may be performed at a gas price higher than the maximum gas price you set. This edge case can happen when:
1. The Automation network determines that the upkeep should be performed while the onchain gas price is below your threshold. After that check occurs, the `performUpkeep` transaction is in flight (in the mempool).
2. After the transaction is already in flight, gas prices start spiking and move above your threshold. To ensure that the node's sending key nonce does not become blocked, the node automatically increases the gas to confirm the transaction and prevent the nonce from blocking subsequent transactions.
To avoid this edge case, increase the buffer in your gas price threshold.
### Log trigger upkeeps are not retried
If a log trigger upkeep is triggered by a log event, and is declared ineligible to perform the upkeep because gas prices are above your gas price threshold, the upkeep is not retried.
## Choose your maximum gas price
Each node compares the specified threshold to its estimate of onchain gas price. A quorum is needed before upkeeps are performed. Nodes may bid aggressively on gas prices to ensure transactions go through. If the node's gas price bid is above your maximum gas price, the node will not perform your upkeep. For example, if you set a gas price threshold of 3 gwei, your upkeep's execution may stop as soon as the node's gas price bid hits 3 gwei, even if the actual gas price is only 2 gwei. To adjust for this, you may need to set a higher gas price threshold.
## Set the maximum gas price on an existing upkeep
Set the maximum gas price using the `offchainConfig` field in your upkeep. Only the upkeep admin can set gas controls for an upkeep. This setting is not yet available in the Chainlink Automation App, so it must be done programmatically.
To set the maximum gas price on an upkeep, follow these steps:
1. [Format and encode your offchain config](#format-and-encode-your-offchain-config). The offchain config is where you set your maximum gas price.
2. Run `setUpkeepOffchainConfig` on the registry using your upkeep ID and the encoded value of your offchain config.
### Run the script
The [Automation gas threshold](https://github.com/smartcontractkit/smart-contract-examples/tree/main/automation-gas-threshold) script encodes and sets your offchain config, which includes the maximum gas price in wei.
1. To run this example, clone the repo and install its dependencies:
```sh
git clone https://github.com/smartcontractkit/smart-contract-examples.git && cd smart-contract-examples/automation-gas-threshold
```
```sh
npm install
```
2. Set the following variables:
- `YOUR_RPC_URL`: The RPC URL for your provider (such as Alchemy or Infura)
- `YOUR_PRIVATE_KEY`: Your wallet's private key
- `YOUR_UPKEEP_ID`: The ID of the Automation upkeep you want to configure.
- Within the `offchainConfig` variable, set your `maxGasPrice` in wei. Do not use quotation marks around the value you set for `maxGasPrice`. If this string is formatted incorrectly, the feature does not work. Here's an example of correct formatting: `{"maxGasPrice":2000000000}`
3. Run the script:
```sh
node index.js
```
### Remove the maximum gas price
To remove the maximum gas price from your upkeep, set the value of your `offchainConfig` back to `0x00`:
- Encode this request with CBOR encoding.
- Run `setUpkeepOffchainConfig` on the registry using your upkeep ID and the CBOR encoded value for `0x00`.
If you're using [the gas threshold script](#run-the-script), set the `offchainConfig` variable in the script to `0`:
```js
// Change this value from `{"maxGasPrice":2000000000}` to `0`:
const offchainConfig = 0
```
## Create a new upkeep with a gas price threshold
To create a new upkeep with a gas threshold in place, you can [create a conditional upkeep or log trigger upkeep programmatically](/chainlink-automation/guides/register-upkeep-in-contract#register-the-upkeep). **Note:** The [Chainlink Automation App](https://automation.chain.link/) does not yet support setting a gas price threshold when creating a new upkeep.
You need to format and encode your offchain config before you set the `offchainConfig` parameter. You can adjust [the gas threshold script](#run-the-script) to get the encoded value for your offchain config and set that as the `offchainConfig` variable when [creating your new upkeep](/chainlink-automation/guides/register-upkeep-in-contract#register-the-upkeep), or you can encode your config using the Solidity or Go examples below.
### Format and encode your offchain config
Currently, the only parameter that you can set in your upkeep's offchain config is `maxGasPrice`. You need to format your offchain config as a JSON object and CBOR encode it before you update it on the registry.
1. Format your offchain config as JSON. For example: `{"maxGasPrice": 100000000000}`.
Use quotation marks only around the key, `"maxGasPrice"`. Do not use quotation marks around the value of the maximum gas price you are setting.
2. Encode the JSON object using CBOR encoding:
---
# Create a Time-Based Upkeep
Source: https://docs.chain.link/chainlink-automation/guides/job-scheduler
Create powerful automation for your smart contract using time schedules without having to create Automation-compatible contracts. This guide explains how to register time-based upkeeps.
(Image: Job Scheduler animation)
## Using the Chainlink Automation app
In the [Chainlink Automation App](https://automation.chain.link/), click the blue **Register new Upkeep** button.
### Connecting your wallet
If you do not already have a wallet connected with the Chainlink Automation network, the interface will prompt you to do so. Click the **Connect Wallet** button and follow the remaining prompts to connect your wallet to one of the [Automation supported blockchain networks](/chainlink-automation/overview/supported-networks).
## Trigger selection
Select **Time-based** trigger.
## Using time-based triggers
When you select the time-based trigger, you are prompted to enter a *contract address*. Provide the address of the contract you want to automate. If you did not verify the contract on chain, you will need to paste the [Application Binary Interface](https://docs.soliditylang.org/en/develop/abi-spec.html) (ABI) of the deployed contract into the corresponding text box. Select the function name that you want to execute and provide any static inputs. If you want to use dynamic inputs please see [Custom logic Upkeeps](/chainlink-automation/guides/register-upkeep)
### Specifying the time schedule
After you have successfully entered your contract address and ABI, specify your time schedule in the form of a [CRON expression](https://en.wikipedia.org/wiki/Cron). CRON expressions provide a shorthand way of creating a time schedule. You can use the provided example buttons in the Automation app to experiment with different schedules. Then, create your own time schedule.
```
Cron jobs are interpreted according to this format:
┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of the month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday)
│ │ │ │ │
│ │ │ │ │
│ │ │ │ │
* * * * *
All times are in UTC.
- can be used for range e.g. "0 8-16 * * *"
/ can be used for interval e.g. "0 */2 * * *"
, can be used for list e.g. "0 17 * * 0,2,4"
Special limitations:
* there is no year field
* no special characters: ? L W #
* lists can have a max length of 26
* no words like JAN / FEB or MON / TUES
```
After entering your CRON expression, click **Next**.
## Entering upkeep details
Provide the following information in the Automation app:
- **Upkeep name**: This will be visible in the Chainlink Automation app.
- **Gas limit**: This is the maximum amount of gas that your transaction requires to execute on chain. This limit cannot exceed the `performGasLimit` value configured on the [registry](/chainlink-automation/overview/supported-networks).
- **Starting balance (LINK)**: Specify a LINK starting balance to fund your upkeep. See the [LINK Token Contracts](/resources/link-token-contracts) page to find the correct contract address and access faucets for testnet LINK. This field is required. You must have LINK before you can use the Chainlink Automation service.
- **Your email address (optional)**: This email address will be used to send you an email notification when your upkeep is underfunded.
## Complete upkeep registration
Click **Register upkeep** and confirm the transaction in MetaMask.
(Image: Upkeep Registration Success Message)
Your upkeeps will be displayed in your list of **Active Upkeeps**. You must monitor the balance of your upkeep. If the balance drops below the **minimum balance**, the Chainlink Automation Network will not perform the Upkeep. See [Managing Upkeeps](/chainlink-automation/guides/manage-upkeeps) to learn how to manage your upkeeps.
---
# Register a Log Trigger Upkeep
Source: https://docs.chain.link/chainlink-automation/guides/log-trigger
Create powerful smart contracts that use log data as both trigger and input. This guide explains how to create log-trigger upkeeps.
## Understanding maximum logs processed
Chainlink Automation processes a limited number of logs per block per upkeep. See the [Service Limits](/chainlink-automation/overview/service-limits) page to learn about how logs are processed and how many logs you can expect to be processed per block on the chain you're using.
## Emit a log
1. Open `CountEmitLog.sol` in Remix. This contract contains an event `WantsToCount` that keeps track of the address of the message sender. The function `emitCountLog` emits this event.
{" "}
1. Under *Environment*, select the option **Injected Provider** to connect to your cryptocurrency wallet.
2. Deploy the contract and confirm the transaction.
3. You can view the contract on Etherscan by clicking the message in the terminal. You an view the address of the created contract and the original contract in Etherscan.
4. Navigate to the *Contract* tab. If the contract is already verified, you will see options to **Read Contract** and **Write Contract**. If your contract isn't verified, follow the prompts in Etherscan to verify the contract.
5. Click **Write Contract** and click the **emitCountLog** button to emit a log.
6. Navigate back to Etherscan and locate the *Events* tab. You should see the event of emitting a log recorded in this section.
## Using `ILogAutomation` Interface
1. Open `CountWithLog.sol` in Remix. This contract contains a struct to account for the log structure and uses the [ILogAutomation interface](/chainlink-automation/reference/automation-interfaces#ilogautomation) for log automation. The interface contains the `checkLog` and `performUpkeep` functions. The contract contains an event `CountedBy`. The `counted` variable will be incremented when `performUpkeep` is called.
{" "}
1. Deploy the contract and confirm your transaction.
2. Under *Deployed Contracts*, expand `CountWithLog`. Click the **count** button to view the value of the count variable. It should be 0.
3. Copy the address of this contract either via Remix or Etherscan to register it on the Chainlink Automation app.
## Using the Chainlink Automation App
**Click the Register New Upkeep button.**
### Connecting your wallet
If you do not already have a wallet connected with the Chainlink Automation network, the interface will prompt you to do so. Click the **Connect Wallet** button and follow the remaining prompts to connect your wallet to one of the [Automation supported blockchain networks](/chainlink-automation/overview/supported-networks).
## Trigger selection
Select **Log Trigger**.
## Using log triggers
1. **Provide the address of your [Automation-compatible contract](/chainlink-automation/guides/compatible-contracts)** that you want to automate. In this case, we will paste the address of `CountWithLog.sol`. This contract must follow the format of the [ILogAutomation interface](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/automation/interfaces/ILogAutomation.sol) to ensure Automation nodes can interact with your contract as expected.
2. **Provide the address of the contract that will be emitting the log.** In this case, this is the address of `CountEmitLog.sol`. If the contract is not validated you will need to provide the ABI.
To find the ABI of your contract in Remix, navigate to the Compiler view using the left side icons. Then, copy the ABI to your clipboard using the button at the bottom of the panel.
3. **Use the dropdown to select the triggering event.** This is **WantsToCount**. You can also provide one optional filter per any of the indexed events in the log, but you don't have to. When this combination of filters are matched the upkeep will trigger.
## Entering upkeep details
Provide the following information in the Automation app:
- **Upkeep name**: This will be visible in the Chainlink Automation app.
- **Gas limit**: This is the maximum amount of gas that your transaction requires to execute on chain. This limit cannot exceed the `performGasLimit` value configured on the [registry](/chainlink-automation/overview/supported-networks).
- **Starting balance (LINK)**: Specify a LINK starting balance to fund your upkeep. See the [LINK Token Contracts](/resources/link-token-contracts) page to find the correct contract address and access faucets for testnet LINK. This field is required. You must have LINK before you can use the Chainlink Automation service.
{" "}
{" "}
- **Check data**: Optional input field that you may use depending on whether you are using it in your contract.
- **Your email address (optional)**: This email address will be used to send you an email notification when your upkeep is underfunded.
## Complete upkeep registration
Click **Register upkeep** and confirm the transaction in MetaMask.
(Image: Upkeep Registration Success Message)
Your upkeeps will be displayed in your list of **Active Upkeeps**. You must monitor the balance of your upkeep. If the balance drops below the **minimum balance**, the Chainlink Automation Network will not perform the Upkeep. See [Managing Upkeeps](/chainlink-automation/guides/manage-upkeeps) to learn how to manage your upkeeps.
## Performing upkeep
Navigate back to the Etherscan page for `CountEmitLog.sol`. Under *Write Contract*, click the button to **emitCountLog**. Refresh the upkeep details page. You may have to wait a few moments. Under *History*, you should see the upkeep has been performed.
---
# Managing Upkeeps
Source: https://docs.chain.link/chainlink-automation/guides/manage-upkeeps
Manage your Upkeeps to get the best performance.
## Fund your upkeep
You must monitor the balance of your Upkeep. If the Upkeep LINK balance drops below the [minimum balance](/chainlink-automation/overview/automation-economics#minimum-balance), the Chainlink Automation Network will not perform the Upkeep.
Follow these steps to fund your Upkeep:
1. **Click `View Upkeep`** or go to the [Chainlink Automation App](https://automation.chain.link) and click on your recently registered Upkeep under My Upkeeps.
2. **Click the `Add funds` button**
3. **Approve the LINK spend allowance**
(Image: Approve LINK Spend Allowance)
4. **Confirm the LINK transfer** by sending funds to the Chainlink Automation Network Registry
(Image: Confirm LINK Transfer)
5. **Receive a success message** and verify that the funds were added to the Upkeep
(Image: Funds Added Successful Message)
## Maintain a minimum balance
Each Upkeep has a [minimum balance](/chainlink-automation/overview/automation-economics#minimum-balance) to ensure that an Upkeeps will still run should a sudden spike occur. If your Upkeep LINK balance drops below this amount, the Upkeep will not be performed.
To account for Upkeep execution over time and possible extended gas spikes, maintain an Upkeep LINK balance that is 3 to 5 times the minimum balance. Note if you have an upkeep that performs frequently you may want to increase the buffer to ensure a reasonable interval before you need to fund again. Developers also have the ability to update `performGasLimit` for an upkeep.
## Withdraw funds
To withdraw funds, the Upkeep administrator have to cancel the Upkeep first. There is delay once an Upkeep has been cancelled before funds can be withdrawn. The number of blocks delay varies by network and once the delay has passed, you can **Withdraw funds**.
## Interacting directly with the Chainlink Automation Registry
After registration, you can interact directly with the [registry contract](/chainlink-automation/overview/supported-networks) functions such as `cancelUpkeep` and `addFunds` using your **Upkeep ID**. The Registry Address might change when new contracts are deployed with new functionality.
---
# Migrate to v2.1
Source: https://docs.chain.link/chainlink-automation/guides/migrate-to-v2
Chainlink Automation 2.1 is a consensus-driven Automation solution that allows you to cut onchain gas costs by using cryptographically verified offchain compute. Automation 2.1 provides 10M gas worth of offchain compute, which is significantly more than previous versions. Additionally, Automation 2.1 provides increased reliability, performance, log trigger capability, and the ability to use `StreamsLookup` to retrieve Data Streams.
You can migrate most upkeeps that use Automation version 1.2 and later in the [Chainlink Automation App](https://automation.chain.link/) or [in the block scanner](#migrating-upkeeps-using-block-scanner). When you migrate upkeeps through the registry, you retain the Upkeep ID. Before you migrate, read the [migration checklist](#migration-checklist) to maximize your benefits from Automation 2.1.
For upkeeps on older registry versions 1.0 (Ethereum Mainnet), and 1.1 (BNB Mainnet and Polygon Mainnet), you must migrate manually by cancelling and re-registering your upkeep in the [Chainlink Automation App](https://automation.chain.link/). After you do this manual migration, future migrations will be easier because your new upkeeps will be eligible for the simpler migration process.
## Migrating using the Chainlink Automation App
The Chainlink Automation App offers a streamlined migration process for upkeeps using registry versions 1.2 and later. To migrate upkeeps with older versions, follow the [manual migration process](#migrating-older-upkeeps-manually) instead.
1. Navigate to the Chainlink Automation App, select the supported blockchain you're using, and connect your wallet.
2. To start migrating a specific upkeep, select the upkeep. In the **Details** page, expand the **Actions** menu and select **Migrate upkeep**.
If you have multiple upkeeps to migrate, start the migration using the link in your upkeeps dashboard. This link displays only if you have one or more upkeeps to migrate:
3. Follow the prompts to approve and confirm the transactions in your wallet to migrate your upkeeps.
Upkeeps that are successfully migrated will show the following [transaction logs](https://testnet.bscscan.com/tx/0x85b3a147518719d3c9b1dd6b80e5f39d53d18c177ebc10d1bfb8890eaab8900a#eventlog):
4. If your upkeep restricts `msg.sender` to the previous registry address, [update your contract](#update-permissions) to use the new forwarder address.
After the migration is complete:
- Your balance is transferred to the new registry automatically.
- The new forwarder address becomes available.
- Read the [migration checklist](#migration-checklist) to understand further updates you might need to make in your contracts.
### Migrating upkeeps on paused registries
If you have any upkeeps that are not yet migrated to v2.1, using older registries that are paused, the only action you can take is either to migrate these upkeeps or to cancel them. Affected upkeeps will show a **Deprecated** label in the Chainlink Automation App. When you hover over this label, it displays a link you can click to begin the migration process for the upkeep:
## Migrating upkeeps using block scanner
To migrate one or more upkeeps using the scanner:
1. Navigate to the blockscanner for the desired chain to the Automation registry containing your upkeeps. You can find the registry address in the Chainlink Automation App under **Upkeep details**.
2. Under **Contract/Write contract** expand the `migrateUpkeeps` function.
Enter a list of upkeep IDs. For example: `[99297446083125056953495436926707926113001699970195513612134585638496630959874,63026166139768298778579034679995711427803187091626268721992534052921779884688]`.
3. Enter the destination registry address, which is the latest registry address on this chain. You can find this address on the [Supported Networks](/chainlink-automation/overview/supported-networks) page, or at the top of the Chainlink Automation App with the desired chain selected.
4. Execute the `migrateUpkeeps` function and confirm the transaction. When this transaction is confirmed, your upkeeps will be migrated to the latest registry, and each upkeep will have a [unique forwarder](#unique-forwarder) address.
5. If your upkeep restricts `msg.sender` to the previous registry address, [update your contract](#update-permissions) to use the new forwarder address.
After the migration is complete:
- Your balance is transferred to the new registry automatically.
- The new forwarder address becomes available.
- Read the [migration checklist](#migration-checklist) to understand further updates you might need to make in your contracts.
## Migrating older upkeeps manually
For upkeeps on registry versions 1.0 and 1.1, you must migrate upkeeps manually:
1. Navigate to the Upkeep in the Chainlink Automation App.
2. In the **Details** section, navigate to the center **Upkeep** card. Copy the **Upkeep address** - you need this for Step 5.
3. Expand the **Actions** menu and select **Cancel upkeep**.
4. Approve the transaction in your wallet. When this transaction is confirmed, you must wait 50 blocks before you can withdraw funds.
5. Return to the main [Chainlink Automation App](https://automation.chain.link/) landing page. Register a new upkeep, providing the **Upkeep address** of your old upkeep.
6. If your upkeep restricts `msg.sender` to the previous registry address, [update your contract](#update-permissions) to use the new forwarder address.
After migration, you have a new upkeep on Automation 2.1 with the same interface as your old upkeep. Future migrations are eligible for the simpler migration process.
After the migration is complete:
- Your balance is transferred to the new registry automatically.
- The new forwarder address becomes available.
- Read the [migration checklist](#migration-checklist) to understand further updates you might need to make in your contracts.
## Update permissions
Your new upkeep has a new [unique forwarder](#unique-forwarder) to increase security for your upkeep. This address will be the unique `msg.sender` for your upkeep. If your upkeep restricts `msg.sender` to the previous registry address, you must give permission to the forwarder address. Otherwise, Automation will no longer be able to execute your function.
1. The forwarder address becomes available after migrating your upkeep. You can find this in the Chainlink Automation App, within the upkeep's **Details** section:
2. Update your contract to use the forwarder address by following the instructions on the [Forwarder](/chainlink-automation/guides/forwarder) page.
### Forwarders by upkeep type
This diagram shows the flow of different contracts that Automation 2.1 deploys for new and migrated upkeeps. Compared to custom logic and log trigger upkeeps, time-based upkeeps have an additional contract:
- For custom logic and log trigger upkeeps, the `msg.sender` in relation to your contract is the unique forwarder that Automation deploys when you migrate your upkeep.
- For time-based upkeeps, Automation deploys a unique forwarder and a unique CRON upkeep contract. In this case, the CRON upkeep contract is the `msg.sender` in relation to your contract.
## Migration checklist
Before you migrate, be aware of several important changes listed here.
### Unique forwarder
Automation 2.1 upkeeps are called from a unique forwarder per upkeep and not from the registry. If your upkeep restricts `msg.sender` to the previous registry address, you must update it to the newly created [forwarder address](/chainlink-automation/guides/forwarder). The forwarder address becomes available only after the upkeep has been migrated. This forwarder address will remain constant in future migrations.
### Update programmatic upkeeps
Note that migration moves upkeeps from one registry to another. If you interact with your upkeep programmatically using Solidity or other interfaces, you must update your code to make sure that you are referencing the correct registry and registrar for your migrated upkeeps:
- Update the registry and registrar addresses.
- Ensure you use the latest version of the ABI for the registry and registrar.
#### Get the latest ABI
The latest ABI for Automation 2.1 is in the [@chainlink npm package](https://www.npmjs.com/package/@chainlink/contracts?activeTab=code):
- Registry ABI: `@chainlink/contracts/abi/v0.8/IKeeperRegistryMaster.json`
- Registrar ABI: `@chainlink/contracts/abi/v0.8/AutomationRegistrar2_1.json`
After updating to the latest ABI, you will able to execute `registry.getForwarder(upkeepID)` to get the forwarder address in Solidity.
#### Check function signatures
If your contract makes function calls to the registry from your upkeep contract, follow the latest ABI.
### Funding is moved with migration
When you migrate, your LINK funding is moved from one registry to the next automatically.
### Migration questions and feedback
If you have questions or feedback, contact us in the [#automation channel](https://discord.com/channels/592041321326182401/821350860302581771) on the [Chainlink Discord server](https://discord.gg/qj9qarT).
---
# Register Upkeeps Programmatically
Source: https://docs.chain.link/chainlink-automation/guides/register-upkeep-in-contract
This guide explains how to register an upkeep from within your smart contract, also called programmatic upkeep creation. Your contract can then interact with it via the registry to get its balance, fund it, edit it, or cancel it using the `upkeepID`.
## Before you begin
Before beginning this process, complete the following tasks:
1. Ensure the smart contract you want to automate is [Automation Compatible](/chainlink-automation/guides/compatible-contracts). To learn more about the contracts Chainlink Automation uses, click [here](/chainlink-automation/reference/automation-contracts).
2. Ensure you have sufficient LINK in the contract that will be registering the Upkeep. Use [faucets.chain.link](https://faucets.chain.link/) to get testnet LINK.
3. Ensure you have the addresses for the LINK token you are using, and the correct registry/registrar. You can find these values on the [Supported Networks](/chainlink-automation/overview/supported-networks) page. *Note*: You can retrieve the LINK token address by calling the function `getLinkAddress` on the registry .
4. Use variables for the registry and registrar addresses that your admin can change as new versions of Chainlink Automation are released.
5. The interface for LINK and Registrar for registration, interface for Registry for subsequent actions
6. Interface is like the API specification of interacting with the contract.
## Register the upkeep
Programmatically registering an upkeep happens in two steps:
1. Call the LINK token to give allowance to the Automation registrar for the amount of LINK you will fund your upkeep with at registration time, e.g.
Pizza code to do
2. Call `registerUpkeep` on the Registrar contract using the `RegistrationParams` struct. You will receive the `upkeepID` if successful.
| Var type | Var Name | Example value | Description |
| -------- | -------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| String | name | "Test upkeep" | Name of upkeep that will be displayed in the UI. |
| bytes | encryptedEmail | 0x | Can leave blank. If registering via UI we will encrypt email and store it here. |
| address | upkeepContract | | Address of your Automation-compatible contract |
| uint32 | gasLimit | 500000 | The maximum gas limit that will be used for your txns. Rather over-estimate gas since you only pay for what you use, while too low gas might mean your upkeep doesn't perform. Trade-off is higher gas means higher minimum funding requirement. |
| address | adminAddress | | The address that will have admin rights for this upkeep. Use your wallet address, unless you want to make another wallet the admin. |
| uint8 | triggerType | 0 or 1 | 0 is Conditional upkeep, 1 is Log trigger upkeep |
| bytes | checkData | 0x | checkData is a static input that you can specify now which will be sent into your checkUpkeep or checkLog, see interface. |
| bytes | triggerConfig | 0x | The configuration for your upkeep. 0x for conditional upkeeps, or see next section for log triggers. |
| bytes | offchainConfig | 0x | Leave as 0x, or use this field to set a [gas price threshold](/chainlink-automation/guides/gas-price-threshold) for your upkeep. Must be a JSON object and CBOR encoded - see [more details and examples on formatting](/chainlink-automation/guides/gas-price-threshold#format-and-encode-your-offchain-config). |
| uint96 | amount | 1000000000000000000 | Ensure this is less than or equal to the allowance just given, and needs to be in WEI. |
## Upkeep registration parameters and examples
Depending on the trigger you are using, the `triggerConfig` will be different. Browse the triggers below to understand how to set up `triggerConfig`.
### Custom logic upkeeps
#### Parameters
For upkeeps with triggers using onchain state only, the following parameters are needed:
#### Code sample
### Log trigger upkeeps
#### Parameters
For upkeeps with triggers using emitted logs, the following parameters are needed:
```solidity
struct LogTriggerConfig {
address contractAddress; // must have address that will be emitting the log
uint8 filterSelector; // must have filtserSelector, denoting which topics apply to filter ex 000, 101, 111...only last 3 bits apply
bytes32 topic0; // must have signature of the emitted event
bytes32 topic1; // optional filter on indexed topic 1
bytes32 topic2; // optional filter on indexed topic 2
bytes32 topic3; // optional filter on indexed topic 3
}
```
where filterSelector is a bitmask mapping and value is set depending on the selection of filters
| filterSelector | Topic 1 | Topic 2 | Topic 3 |
| -------------- | ------- | ------- | ------- |
| 0 | Empty | Empty | Empty |
| 1 | Filter | Empty | Empty |
| 2 | Empty | Filter | Empty |
| 3 | Filter | Filter | Empty |
| 4 | Empty | Empty | Filter |
| 5 | Filter | Empty | Filter |
| 6 | Empty | Filter | Filter |
| 7 | Filter | Filter | Filter |
#### Code sample
---
# Register a Custom Logic Upkeep
Source: https://docs.chain.link/chainlink-automation/guides/register-upkeep
Create powerful automation for your smart contract that leverages custom logic to trigger specified actions. This guide explains how to register a custom logic upkeep that uses a [compatible contract](/chainlink-automation/guides/compatible-contracts). You can register it using the Chainlink Automation App or from within a contract that you deploy.
{" "}
## Using the Chainlink Automation App
**Click the Register New Upkeep button**
{" "}
### Connecting your wallet
If you do not already have a wallet connected with the Chainlink Automation network, the interface will prompt you to do so. Click the **Connect Wallet** button and follow the remaining prompts to connect your wallet to one of the [Automation supported blockchain networks](/chainlink-automation/overview/supported-networks).
## Trigger selection
Select **Custom Logic** trigger.
{" "}
## Using custom logic triggers
Provide the address of your [compatible contract](/chainlink-automation/guides/compatible-contracts). You do not need to verify the contract onchain, but it must be [compatible](/chainlink-automation/guides/compatible-contracts) with the `AutomationCompatibleInterface` contract.
## Entering upkeep details
Provide the following information in the Automation app:
- **Upkeep name**: This will be publicly visible in the Chainlink Automation app.
- **Gas limit**: This is the maximum amount of gas that your transaction requires to execute on chain. This limit cannot exceed the `performGasLimit` value configured on the [registry](/chainlink-automation/overview/supported-networks). Before the network executes your transaction on chain, it simulates the transaction. If the gas required to execute your transaction exceeds the gas limit that you specified, your transaction will not be confirmed. Developers also have the ability to update `performGasLimit` for an upkeep. Consider running your function on a testnet to see how much gas it uses before you select a gas limit. This can be changed afterwards.
- **Starting balance (LINK)**: Specify a LINK starting balance to fund your upkeep. See the [LINK Token Contracts](/resources/link-token-contracts) page to find the correct contract address and access faucets for testnet LINK. This field is required. You must have LINK before you can use the Chainlink Automation service.
{" "}
{" "}
- **Check data**: This field is provided as an input for when your `checkUpkeep` function is simulated. Either leave this field blank or specify a hexadecimal value starting with `0x`. To learn how to make flexible upkeeps using `checkData`, see the [Flexible Upkeeps](/chainlink-automation/guides/flexible-upkeeps) guide.
- **Your email address (optional)**: This email address will be used to send you an email notification when your upkeep is underfunded.
## Complete upkeep registration
Click **Register upkeep** and confirm the transaction in MetaMask.
(Image: Upkeep Registration Success Message)
Your upkeeps will be displayed in your list of **Active Upkeeps**. You must monitor the balance of your upkeep. If the balance drops below the **minimum balance**, the Chainlink Automation Network will not perform the Upkeep. See [Managing Upkeeps](/chainlink-automation/guides/manage-upkeeps) to learn how to manage your upkeeps.
---
# Using the StreamsLookup error handler
Source: https://docs.chain.link/chainlink-automation/guides/streams-lookup-error-handler
---
# Access Data Streams Using Automation
Source: https://docs.chain.link/chainlink-automation/guides/streams-lookup
## Debugging StreamsLookup
Read our [debugging section](/chainlink-automation/reference/debugging-errors) to learn how to identify and resolve common errors when using `StreamsLookup`.
---
# Chainlink Automation
Source: https://docs.chain.link/chainlink-automation
Automate your smart contracts using a secure and hyper-reliable decentralized network that uses the same external network of node operators that secures billions in value. Building on Chainlink Automation will accelerate your innovation, save you time and money, and help you get to market faster so you don't have to deal with the setup cost, ongoing maintenance, and risks associated with a centralized automation stack.
To learn more about how the Chainlink Automation Network automates your smart contracts, visit the [Concepts](/chainlink-automation/concepts/automation-concepts) and [Architecture](/chainlink-automation/concepts/automation-architecture) pages. You can also learn more through our [additional Automation resources](https://chain.link/automation#masterclass).
## Supported networks and costs
For a list of blockchains that are supported by Chainlink Automation, see the [Supported Networks](/chainlink-automation/overview/supported-networks) page. To learn more about the cost of using Chainlink Automation, see the [Automation Economics](/chainlink-automation/overview/automation-economics) page.
## Contact us
For help with your specific use case, [contact us](https://chain.link/contact?ref_id=Automation) to connect with one of our Solutions Architects. You can also ask questions about Chainlink Automation on [Stack Overflow](https://stackoverflow.com/questions/ask?tags=chainlink) or the [#automation channel](https://discord.com/channels/592041321326182401/821350860302581771) in our [Discord server](https://discord.gg/qj9qarT). For all developers resources, check out the [Developer Resource Hub](https://dev.chain.link).
---
# Automation Billing and Costs
Source: https://docs.chain.link/chainlink-automation/overview/automation-economics
## Cost of using Chainlink Automation
Chainlink Automation requires only an execution fee for transactions onchain. This fee includes the transaction cost, a node operator percentage fee, and a small fixed gas overhead accounting for gas between the network and the registry.
The percentage fee compensates the Automation Network for monitoring and performing your upkeep. The Automation percentage fee varies by chain and is listed on our [Supported Networks](/chainlink-automation/overview/supported-networks) page.
The fee calculation for upkeeps that are configured for LINK payments (or other non-native payments as applicable) have a conversion from native tokens to LINK (or other non-native payments as applicable).
This conversion is not performed in the fee calculation for upkeeps that are configured for native token payments. Otherwise, the fee formula is the same for both payment types:
There is no registration fee or other fees for any offchain computation.
### Fee calculation example
An upkeep transaction was [performed](https://polygonscan.com/tx/0x19309782e15952c90dcadcc02cbf34f331daaeee369d3e3acca43bade02af105) on *Polygon mainnet*. It used *110,051* gas at a gas price of *182,723,799,380 wei*.
The node operator percentage on Polygon was *70%* at the time of this transaction, and this fee [varies by network](/chainlink-automation/overview/supported-networks).
The tables below show how the fees are calculated for upkeeps configured for LINK payments:
The LINK/MATIC exchange rate for this transaction was *7,308,290,731,273,610,000 wei*. The upkeep's LINK balance was reduced by a fee of *0.008077 LINK*. The preceding information and calculation can be found in the table below:
| Variable | Description | Value |
| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------- |
| tx.gasPriceNative WEI | Gas price of the transaction | 182, 723, 799,380 |
| gasUsed | Gas used for performUpkeep calculated in solidity | 110,051 |
| gasOverhead | Fixed gas amount used for transaction call from node to Registry | 80,000 |
| premium% | Current premium on Polygon which can be found on the [Supported Networks page](/chainlink-automation/overview/supported-networks) | 70% |
| LINK/NativeRate in WEI | Exchange rate fetched from Chainlink Oracle | 7,308,290,731,273,610,000 |
0.008077 = [182,723,799,380 \* (110,051 + 80,000) \* (1 + 70%)]/[7,308,290,731,273,610,000]
## How funding works
Upkeeps have a LINK (ERC-677) balance. Every time an onchain transaction is performed for your upkeep, its LINK balance will be reduced by the LINK fee.
Your upkeep's balance must exceed the [minimum balance](#minimum-balance). If this requirement is not met, the Automation Network will not perform onchain transactions. You can add funds using the [Chainlink Automation App](https://automation.chain.link/) or by directly calling the `addFunds()` function on the `AutomationRegistry` contract. Anyone can call the `addFunds()` function.
## Withdrawing funds
To withdraw a LINK balance, you must cancel your upkeep first. Any upkeep that has not spent more than an aggregated amount of 0.1 LINK fees over the span of its lifetime is subject to a *0.1 LINK* fee. This cancellation fee protects node operators from spammers who register jobs that never perform.
**Example 1**: Your upkeep has spent *4.8 LINK* over its lifetime and has a balance of *5 LINK*. When it is cancelled, I will receive *5 LINK*.
**Example 2**: Your upkeep has spent *0 LINK* over its lifetime and has a balance of *5 LINK*. When it is cancelled, I will receive *4.9 LINK*.
## No node competition
Individual Automation Nodes do not compete with one another, but rather work together to ensure all registered upkeeps are performed. This makes costs more predictable upfront, enabling you to estimate costs based on the expected gas consumption.
## Minimum balance
The Chainlink Automation Network is designed to perform your upkeep even when gas prices spike. The minimum balance in LINK reflects the best estimate of the cost to perform your upkeep when gas prices spike. To ensure your upkeep is monitored and performed, ensure that your upkeep's balance is above this minimum balance.
The minimum balance is calculated using the current fast gas price, the gas limit you entered for your upkeep, the max gas multiplier, and the LINK/NativeRate in WEI for conversion to LINK. To find the latest value for the `gasCeilingMultiplier`, see the [Registry Configuration](/chainlink-automation/overview/supported-networks) page.
Follow [maintain a minimum balance](/chainlink-automation/guides/manage-upkeeps/#maintain-a-minimum-balance) to ensure that your upkeep is funded.
## Price selection and gas bumping
Automation Nodes select the gas price dynamically based on the prices of transactions within the last several blocks. This optimizes the gas price based on current network conditions. Automation Nodes are configured to select a price based on a target percentile.
If the Automation Node does not see the `performUpkeep` transaction get confirmed within the next few blocks, it automatically replaces the transaction and bumps the gas price. This process repeats until the transaction is confirmed.
## ERC-677 LINK
For funding on mainnet, you will need ERC-677 LINK. Many token bridges give you ERC-20 LINK tokens. Use PegSwap to [convert Chainlink tokens (LINK) to be ERC-677 compatible](https://pegswap.chain.link/). Use [faucets.chain.link](https://faucets.chain.link/) to get testnet LINK.
---
# Getting Started with Chainlink Automation
Source: https://docs.chain.link/chainlink-automation/overview/getting-started
Chainlink Automation will reliably execute smart contract functions using a variety of triggers. Explore the examples below to see how Chainlink Automation works for each type of trigger. Before you begin, you will need an active cryptocurrency wallet such as Metamask.
- **Time-based trigger**: Use a time-based trigger to execute your function according to a time schedule.
- **Custom logic trigger**: Use a custom logic trigger to provide custom solidity logic that Automation Nodes evaluate (offchain) to determine when to execute your function onchain.
- **Log trigger**: Use log data as both trigger and input.
## Try out Chainlink Automation
Click the tabs below to use Chainlink Automation with each type of trigger:
## Supported networks and costs
For a list of blockchains that are supported by Chainlink Automation, see the [Supported Networks](/chainlink-automation/overview/supported-networks) page. To learn more about the cost of using Chainlink Automation, see the [Automation Economics](/chainlink-automation/overview/automation-economics) page.
## Contact us
For help with your specific use case, [contact us](https://chain.link/contact?ref_id=Automation) to connect with one of our Solutions Architects. You can also ask questions about Chainlink Automation on [Stack Overflow](https://stackoverflow.com/questions/ask?tags=chainlink) or the [#automation channel](https://discord.com/channels/592041321326182401/821350860302581771) in our [Discord server](https://discord.gg/qj9qarT). [Utility contracts](/chainlink-automation/tutorials/eth-balance) can also help you get started quickly.
---
# Chainlink Automation Service Limits
Source: https://docs.chain.link/chainlink-automation/overview/service-limits
## Maximum logs processed for log trigger upkeeps
Chainlink Automation nodes look back over a limited range of the latest blocks on any particular chain. During this process, the nodes process a limited number of logs per block per upkeep, using a minimum dequeue method to ensure that the latest logs are processed first. After this, the nodes may process additional remaining logs on a best effort basis, but this is not guaranteed. If you need all the remaining logs to be processed, configure a manual trigger as backup.
Expect the following numbers of logs to be processed:
| Chain | Logs per block per upkeep |
| --------- | ------------------------------------------ |
| Ethereum | 20 |
| BSC (BNB) | 4 |
| Polygon | 4 |
| Avalanche | 4 |
| Gnosis | 1 |
| OP | 4 |
| BASE | 4 |
| Arbitrum | 1 log every 2 blocks, or 2 logs per second |
Note: Log triggers are not supported on Fantom.
---
# Supported Networks
Source: https://docs.chain.link/chainlink-automation/overview/supported-networks
To use Chainlink Automation on certain networks, you may need to conduct token transfers. You can transfer tokens by using [Chainlink CCIP](/ccip/tutorials/evm/transfer-tokens-from-contract), [Transporter](https://www.transporter.io/) or third-party applications such as [XSwap](https://xswap.link/).
## Parameters
- **Payment Premium %** (`paymentPremiumPPB`): This percentage premium compensates the Chainlink Automation Network for monitoring and performing your upkeep. Every time a transaction is submitted for your upkeep, your LINK balance is reduced by the transaction cost plus this percentage premium.
- **Flat Fee Micro Link** (`flatFeeMicroLink`): A flat fee charged per transaction on all testnets and OP Mainnet.
- **Maximum Check Data Size** (`maxCheckDataSize`): The maximum size, in bytes, that can be sent to your `checkUpkeep` function.
- **Check Gas Limit** (`checkGasLimit`): The maximum amount of gas that can be used by your `checkUpkeep` function for offchain computation.
- **Perform Gas Limit** (`performGasLimit`): The maximum amount of gas that can be used by the client contract's `performUpkeep` function for the onchain transaction. You can set an upper limit on your upkeep during registration, but this number must not exceed the `maxPerformGas` on the `Registry`.
- **maximum Perform Data Size** (`maxPerformDataSize`): The maximum size in bytes that can be sent to your `performUpkeep` function.
- **Gas Ceiling Multiplier** (`gasCeilingMultiplier`): Establishes a ceiling for the maximum price based on the onchain fast gas feed.
- **Minimum Upkeep Spend (LINK)**: The minimum amount of LINK an upkeep must spend over its lifetime. If the lifetime (or total) upkeep spend is below this amount, then at cancellation this amount will be held back.
## Arbitrum
### Arbitrum One
| Item | Value |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Registry Address |
|
| Registrar Address | |
| Payment Premium % | 50 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 2,000 |
| Gas Ceiling Multiplier | 5 |
| Minimum Upkeep Spend (LINK) | 0.1 |
### Arbitrum Sepolia
| Item | Value |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 50 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 2,000 |
| Gas Ceiling Multiplier | 5 |
| Minimum Upkeep Spend (LINK) | 0.1 |
## Avalanche
### Avalanche Mainnet
| Item | Value |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 40 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 5,000 |
| Gas Ceiling Multiplier | 2 |
| Minimum Upkeep Spend (LINK) | 0.1 |
### Avalanche Fuji Testnet
| Item | Value |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 40 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 5,000 |
| Gas Ceiling Multiplier | 2 |
| Minimum Upkeep Spend (LINK) | 0.0 |
## Base
### Base Mainnet
| Item | Value |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 50 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 2,000 |
| Gas Ceiling Multiplier | 5 |
| Minimum Upkeep Spend (LINK) | 0.1 |
### Base Sepolia Testnet
| Item | Value |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 50 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 1,000 |
| Gas Ceiling Multiplier | 2 |
| Minimum Upkeep Spend (LINK) | 0.1 |
## BNB Chain
### BNB Chain Mainnet
| Item | Value |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 30 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 5,000 |
| Gas Ceiling Multiplier | 3 |
| Minimum Upkeep Spend (LINK) | 0.1 |
### BNB Chain Testnet
| Item | Value |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 30 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 5,000 |
| Gas Ceiling Multiplier | 3 |
| Minimum Upkeep Spend (LINK) | 0.0 |
## Ethereum
### Ethereum Mainnet
| Item | Value |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 20 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 2,000 |
| Gas Ceiling Multiplier | 2 |
| Minimum Upkeep Spend (LINK) | 0.1 |
### Ethereum Sepolia Testnet
| Item | Value |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 20 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 2,000 |
| Gas Ceiling Multiplier | 3 |
| Minimum Upkeep Spend (LINK) | 0.0 |
## Gnosis
### Gnosis Mainnet
| Item | Value |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 100 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 5,000 |
| Gas Ceiling Multiplier | 3 |
| Minimum Upkeep Spend (LINK) | 0.1 |
### Gnosis Chiado Testnet
| Item | Value |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 30 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 5,000 |
| Gas Ceiling Multiplier | 3 |
| Minimum Upkeep Spend (LINK) | 0.1 |
## OP
### OP Mainnet
| Item | Value |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 50 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 5,000 |
| Gas Ceiling Multiplier | 5 |
### OP Sepolia Testnet
| Item | Value |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 50 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 5,000 |
| Gas Ceiling Multiplier | 5 |
| Minimum Upkeep Spend (LINK) | 0.1 |
## Polygon
### Polygon Mainnet
| Item | Value |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 70 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 5,000 |
| Gas Ceiling Multiplier | 3 |
| Minimum Upkeep Spend (LINK) | 0.1 |
### Polygon Amoy Testnet
| Item | Value |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 30 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 5,000 |
| Gas Ceiling Multiplier | 3 |
| Minimum Upkeep Spend (LINK) | 0.1 |
## Polygon zkEVM
### Polygon zkEVM Mainnet
| Item | Value |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 56 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 5,000 |
| Gas Ceiling Multiplier | 2 |
| Minimum Upkeep Spend (LINK) | 0.0004 |
### Polygon zkEVM Cardona Testnet
| Item | Value |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 50 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 5,000 |
| Gas Ceiling Multiplier | 2 |
| Minimum Upkeep Spend (LINK) | 0.0004 |
## Scroll
### Scroll Mainnet
| Item | Value |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 56 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 5,000 |
| Gas Ceiling Multiplier | 2 |
| Minimum Upkeep Spend (LINK) | 0.0004 |
### Scroll Sepolia Testnet
| Item | Value |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 50 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 5,000 |
| Gas Ceiling Multiplier | 2 |
| Minimum Upkeep Spend (LINK) | 0.1 |
## ZkSync
### ZkSync Mainnet
| Item | Value |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 50 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 5,000 |
| Gas Ceiling Multiplier | 2 |
| Minimum Upkeep Spend (LINK) | 0.0004 |
### ZkSync Sepolia Testnet
| Item | Value |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Registry Address | |
| Registrar Address | |
| Payment Premium % | 30 |
| Block Count per Turn | Not Applicable |
| Maximum Check Data Size | 5,000 |
| Check Gas Limit | 10,000,000 |
| Perform Gas Limit | 5,000,000 |
| Maximum Perform Data Size | 5,000 |
| Gas Ceiling Multiplier | 2 |
| Minimum Upkeep Spend (LINK) | 0.0004 |
---
# Automation Contracts
Source: https://docs.chain.link/chainlink-automation/reference/automation-contracts
Automation Nodes use the following contracts. You can find them in the [Chainlink repository](https://github.com/smartcontractkit/chainlink/tree/contracts-v1.3.0/contracts/src/v0.8/automation). For details about how to use them, visit the [Creating Compatible Contracts](/chainlink-automation/guides/compatible-contracts) guide. To understand the logic behind these contracts, visit the [Architecture](/chainlink-automation/concepts/automation-architecture) page.
- [`AutomationCompatible.sol`](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/automation/AutomationCompatible.sol): Imports the following contracts:
- [`AutomationBase.sol`](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/automation/AutomationBase.sol): Enables the use of the `cannotExecute` modifier. Import this contract if you need for this modifier. See the [`checkUpkeep` function](/chainlink-automation/reference/automation-interfaces#checkupkeep-function) for details.
- [`AutomationCompatibleInterface.sol`](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/automation/interfaces/AutomationCompatibleInterface.sol): The interface to be implemented in order to make your contract compatible. Import this contract for type safety.
## AutomationRegistry.sol
[`AutomationRegistry2_1.sol`](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/automation/v2_1/KeeperRegistry2_1.sol): The registry contract that tracks all registered Upkeeps and the Automation Nodes that can perform them. *Note*: As Chainlink Automation continues adding new functionalities, a new **Automation Registry** is deployed and the contract address may change.
## AutomationRegistrar.sol
[`AutomationRegistrar2_1.sol`](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/automation/v2_1/AutomationRegistrar2_1.sol): The Registrar contract governs the registration of new Upkeeps on the associated `AutomationRegistry` contract. Users who want to register Upkeeps by directly calling the deployed contract have to call the Transfer-and-Call function on the respective ERC-677 LINK contract configured on the Registrar and ensure they pass the correct encoded function call and inputs.
## UpkeepTranscoder.sol
[`UpkeepTranscode4_0.sol`](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/automation/v2_1/UpkeepTranscoder4_0.sol) allows the conversion of upkeep data from previous Automation registry versions 1.2, 1.3, and 2.0 to registry 2.1.
## AutomationForwarder.sol
[`AutomationForwarder.sol`](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/automation/AutomationForwarder.sol) is a relayer that sits between the registry and the customer's target contract. The purpose of the forwarder is to give customers a consistent address to authorize against that stays consistent between migrations. The Forwarder also exposes the registry address, so that users who want to programmatically interact with the registry can do so. The `forward` function in this contract is called by the registry and forwards the call to the target.
## CronUpkeepFactory.sol
[`CronUpkeepFactory.sol`](https://github.com/smartcontractkit/chainlink/blob/f6256c3b6ea64a91aadc9ac7df30e9bf35dca557/contracts/src/v0.8/automation/upkeeps/CronUpkeepFactory.sol) serves as a delegate for all instances of `CronUpkeep`. Those contracts delegate their checkUpkeep calls onto this contract. Utilizing this pattern reduces the size of the `CronUpkeep` contracts. You can use this contract when creating a time-based upkeep programmatically. You can learn more about creating upkeeps programmatically [here](/chainlink-automation/guides/register-upkeep-in-contract).
---
# Automation Interfaces
Source: https://docs.chain.link/chainlink-automation/reference/automation-interfaces
Your Automation-compatible contracts may use the following interfaces. You can find them in the [Chainlink repository](https://github.com/smartcontractkit/chainlink/tree/contracts-v1.3.0/contracts/src/v0.8/automation). To understand how to implement these contracts, visit the [Compatible Contracts page](/chainlink-automation/guides/compatible-contracts).
- If you want a log event to trigger your upkeep, use the [`ILogAutomation`](#ilogautomation) interface.
- If you want to use onchain state (excluding logs) in a custom calculation to trigger your upkeep, use [`AutomationCompatibleInterface`](#automationcompatibleinterface) interface.
- If you want to call a function just based on time, consider using a [time-based upkeep](/chainlink-automation/guides/job-scheduler).
- If you want to use Automation with Data Streams, use [`StreamsLookupCompatibleInterface`](#streamslookupcompatibleinterface) interface.
## ILogAutomation
## AutomationCompatibleInterface
Custom logic upkeeps need to use the [`AutomationCompatibleInterface.sol`](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/automation/interfaces/AutomationCompatibleInterface.sol) interface. Click on one of the functions below to understand its parameters and limits.
| Function Name | Description |
| --------------- | ------------------------------------------------------------------------------------ |
| `checkUpkeep` | Runs offchain to determine if the `performUpkeep` function should be called onchain. |
| `performUpkeep` | Contains the logic that should be executed onchain when `checkUpkeep` returns true. |
### checkUpkeep function
This view function contains the logic that runs offchain during every block as an [`eth_call`](https://eth.wiki/json-rpc/API#eth_call) to determine if `performUpkeep` should be executed onchain. To reduce onchain gas usage, attempt to do your gas intensive calculations offchain in `checkUpkeep` and pass the result to `performUpkeep` onchain. It is a best practice to import the [`AutomationCompatible.sol`](https://github.com/smartcontractkit/chainlink/blob/contracts-v1.3.0/contracts/src/v0.8/automation/AutomationCompatible.sol) contract and use the `cannotExecute` modifier to ensure that the method can be used only for simulation purposes.
```solidity
function checkUpkeep(
bytes calldata checkData
) external view override returns (bool upkeepNeeded, bytes memory performData);
```
Below are the parameters and return values of the `checkUpkeep` function. Click each value to learn more about its design patterns and best practices:
**Parameters:**
- `checkData`: Fixed and specified at upkeep registration and used in every `checkUpkeep`. Can be empty (0x).
**Return Values:**
- `upkeepNeeded`: Boolean that when True will trigger the onchain `performUpkeep` call.
- `performData`: Bytes that will be used as input parameter when calling `performUpkeep`. If you would like to encode data to decode later, try `abi.encode`.
#### checkData
You can pass information into your `checkUpkeep` function from your [upkeep registration](/chainlink-automation/guides/register-upkeep) to execute different code paths. For example, to check the balance on a specific address, set the `checkData` to abi encode the address. To learn how to create flexible upkeeps with checkData, please see our [flexible upkeeps](/chainlink-automation/guides/flexible-upkeeps) page.
Tips on using `checkData`:
- **Managing unbounded upkeeps**: Limit the problem set of your onchain execution by creating a range bound for your upkeep to check and perform. This allows you to keep within predefined gas limits, which creates a predictable upper bound gas cost on your transactions. Break apart your problem into multiple upkeep registrations to limit the scope of work.
**Example**: You could create an upkeep for each subset of addresses that you want to service. The ranges could be 0 to 49, 50 to 99, and 100 to 149.
- **Managing code paths**: Pass in data to your `checkUpkeep` to make your contract logic go down different code paths. This can be used in creative ways based on your use case needs.
**Example**: You could support multiple types of upkeep within a single contract and pass a function selector through the `checkData` function.
#### performData
The response from `checkUpkeep` is passed to the `performUpkeep` function as `performData`. This allows you to perform complex and gas intensive calculations as a simulation offchain and only pass the needed data onchain.
You can create a highly flexible offchain computation infrastructure that can perform precise actions onchain by using `checkData` and `performData`. Both of these computations are entirely programmable.
### performUpkeep function for custom logic triggers
When `checkUpkeep` returns `upkeepNeeded == true`, the Automation node broadcasts a transaction to the blockchain to execute your `performUpkeep` function onchain with `performData` as an input.
Ensure that your `performUpkeep` is *idempotent*. Your `performUpkeep` function should change state such that `checkUpkeep` will not return `true` for the same subset of work once said work is complete. Otherwise the Upkeep will remain eligible and result in multiple performances by the Chainlink Automation Network on the exactly same subset of work. As a best practice, always check conditions for your upkeep at the start of your `performUpkeep` function.
```solidity
function performUpkeep(bytes calldata performData) external override;
```
**Parameters:**
- `performData`: Data which was passed back from the `checkData` simulation. If it is encoded, it can easily be decoded into other types by calling `abi.decode`. This data should always be validated against the contract's current state.
#### performData
You can perform complex and broad offchain computation, then execute onchain state changes on a subset that meets your conditions. This can be done by passing the appropriate inputs within `performData` based on the results from your `checkUpkeep`. This pattern can greatly reduce your onchain gas usage by narrowing the scope of work intelligently in your own Solidity code.
- **Identify a list of addresses that require work**: You might have a number of addresses that you are validating for conditions before your contract takes an action. Doing this onchain can be expensive. Filter the list of addresses by validating the necessary conditions within your `checkUpkeep` function. Then, pass the addresses that meet the condition through the `performData` function.
For example, if you have a "top up" contract that ensures several hundred account balances never decrease below a threshold, pass the list of accounts that meet the conditions so that the `performUpkeep` function validates and tops up only a small subset of the accounts.
- **Identify the subset of states that must be updated**: If your contract maintains complicated objects such as arrays and structs, or stores a lot of data, you should read through your storage objects within your `checkUpkeep` and run your proprietary logic to determine if they require updates or maintenance. After that is complete, you can pass the known list of objects that require updates through the `performData` function.
## StreamsLookupCompatibleInterface
---
# Debugging and Troubleshooting Upkeeps
Source: https://docs.chain.link/chainlink-automation/reference/debugging-errors
Given an upkeep ID, this page contains different methods of understanding and fixing issues with Upkeeps.
## Automation debugging script
You can use the [Automation debugging script](https://github.com/smartcontractkit/chainlink/blob/develop/core/scripts/chaincli/DEBUGGING.md) to debug and diagnose possible issues with registered upkeeps in Automation 2.1 registries. The script can debug custom logic upkeeps, log trigger upkeeps, and upkeeps that use `StreamsLookup`.
## Underfunded upkeeps
In the Chainlink Automation app, you can see the registration details of the upkeep, alongside the balance required and `performUpkeep` history. If the upkeep is underfunded, you will see a warning on top of the page. Underfunded upkeeps will not be performed.
## Insufficient perform gas
If your performGasLimit is too low, the Automation Network will not execute your upkeep as it will fail in simulation. Consider increasing your perform upkeep gas limit in the UI. See [supported Blockchain Networks](/chainlink-automation/overview/supported-networks) for limits.
## Insufficient check gas
If the amount of computation in your checkUpkeep exceeds our checkGasLimit, your upkeep will not be performed. You will have to reduce the amount of compute in checkUpkeep to bring the gas below the applicable limits. See [supported Blockchain Networks](/chainlink-automation/overview/supported-networks) for limits.
## Paused upkeeps
If your upkeep is paused, your upkeep will not be performed. Please unpause it in the [Chainlink Automation app](https://automation.chain.link/).
## StreamsLookup
### Upkeep has not been allowlisted
Once you registered your upkeep, you need to [ask the Data Streams team to allowlist your upkeepID](https://chainlinkcommunity.typeform.com/datastreams?#ref_id=docs) and specify the feeds you will need to access. If your upkeepID has not been added to the allow list it will not perform an upkeep.
### Requesting multiple feeds where one is not valid
It is possible to request multiple feeds by specifying the feeds in a string array. However, if one of the reports is invalid or not available then Automation will not return any values to your `checkCallback` function. This is to ensure correct execution of your contract.
### StreamsLookup ErrorHandler
Handle the StreamsLookup upkeep [error codes](/chainlink-automation/guides/streams-lookup-error-handler#error-codes) by using the StreamsLookup ErrorHandler.
## Etherscan
You can view the registry or user's upkeep address on [Etherscan](https://etherscan.io/) to view transaction history. There are three types of information you can find on Etherscan:
- **All transactions on registry**: This shows all the perform upkeeps on the registry. You can view a specific `performUpkeep` transaction to debug more.
- **Specific `performUpkeep` transaction**: By diving deep in the logs, you can check the upkeep ID within the UpkeepPerformed log.
- **Target's internal transactions**: For a particular target contract, you can view its internal transactions which contains `performUpkeep` transactions for that contract by using the registry address as the filter for *from* address. *Note*: internal transactions are only visible on Etherscan.
## Tenderly
You can use [Tenderly](https://tenderly.co/) to simulate `checkUpkeep` and/or `performUpkeep` on different blocks. Before following the steps below, make sure you have a Tenderly account.
1. Enter the address of your selected registry. You can find this on the [Supported Networks](/chainlink-automation/overview/supported-networks) page.
2. Select your network.
3. Click **Fetch ABI** to automatically fetch the registry ABI.
4. Select the `checkUpkeep` function or `performUpkeep` function.
5. Enter the ID of your Upkeep. You can find this in the [Chainlink Automation app](https://automation.chain.link/).
6. You can either enter a block number to simulate a past action or use a pending block number to view the current state of an action and view the end result of an of an action.
7. Once the simulation is complete, you will see the result. This will be either a *success* or an *error*. To understand errors, view information under the **Debug** tab. **Note**: if the `performUpkeep` is failing while the check is succeeding, Chainlink Automation will not broadcast transactions.
---
# Counting dNFT
Source: https://docs.chain.link/chainlink-automation/tutorials/counting-dnft
View the template [here](https://github.com/smartcontractkit/smart-contract-examples/tree/main/counting-svg).
This repository houses an example that automates counting with a dynamic SVG. The main contract is `counting-svg.sol` which is automated to create an entirely onchain SVG.
```solidity
// SPDX-License-Identifier: MIT
// An example of a consumer contract that relies on a subscription for funding.
pragma solidity 0.8.17;
// Imports
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/Base64.sol";
contract CountSVG is ERC721, ERC721URIStorage, Ownable {
// Setup counters, we use the OpenZeppelin Counters library
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
// Initialize the counter to 0
uint256 count = 0;
// Constructor for the contract
constructor() ERC721("Counting SVG", "cSVG") {}
// Mint a new NFT and update the URI
function safeMint(address to) public onlyOwner {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
updateURI();
}
// Update the URI for the NFT
function updateURI() internal {
// Build the SVG
string memory finalSVG = buildSVG();
//Encode the SVG and add the metadata
string memory json = Base64.encode(
bytes(
string(
abi.encodePacked(
'{"name": "Counting SVG",',
'"description": "An Automated Counting SVG",',
'"image": "data:image/svg+xml;base64,',
Base64.encode(bytes(finalSVG)),
'"}'
)
)
)
);
// Set the URI string
string memory finalTokenURI = string(abi.encodePacked("data:application/json;base64,", json));
// Update the URI
// NOTE: This is hardcoded to the first SVG only
_setTokenURI(0, finalTokenURI);
}
// Create the SVG
function buildSVG() internal view returns (string memory) {
string
memory headSVG = "";
string memory bodySVG = string(
abi.encodePacked(
"",
Strings.toString(count),
""
)
);
// Concatenate the SVG parts
string memory _finalSVG = string(abi.encodePacked(headSVG, bodySVG, tailSVG));
return _finalSVG;
}
// Increment the counter
function addToCount() public {
count = count + 1;
updateURI();
}
function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
super._burn(tokenId);
}
function tokenURI(uint256 tokenId) public view override(ERC721, ERC721URIStorage) returns (string memory) {
return super.tokenURI(tokenId);
}
}
```
---
# Vault Harvester
Source: https://docs.chain.link/chainlink-automation/tutorials/vault-harvester
Harvesting and compounding is key to maximize yield in DeFi yield aggregators. Automate harvesting and compounding using Chainlink Automation's decentralized automation network.
View the template [here](https://github.com/smartcontractkit/chainlink-automation-templates/tree/main/vault-harvester#chainlink-keepers-template-vault-harvester).
Below is the main contract `KeeperCompatibleHarvester.sol`:
```solidity
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "../libraries/UpkeepLibrary.sol";
import "../interfaces/IKeeperRegistry.sol";
import "../interfaces/IHarvester.sol";
abstract contract KeeperCompatibleHarvester is IHarvester, Ownable {
using SafeERC20 for IERC20;
// Contracts.
IKeeperRegistry public keeperRegistry;
// Configuration state variables.
uint256 public performUpkeepGasLimit;
uint256 public performUpkeepGasLimitBuffer;
uint256 public vaultHarvestFunctionGasOverhead; // Estimated average gas cost of calling harvest()
uint256 public keeperRegistryGasOverhead; // Gas cost of upstream contract that calls performUpkeep(). This is a private variable on KeeperRegistry.
uint256 public chainlinkUpkeepTxPremiumFactor; // Tx premium factor/multiplier scaled by 1 gwei (10**9).
address public callFeeRecipient;
// State variables that will change across upkeeps.
uint256 public startIndex;
constructor(
address _keeperRegistry,
uint256 _performUpkeepGasLimit,
uint256 _performUpkeepGasLimitBuffer,
uint256 _vaultHarvestFunctionGasOverhead,
uint256 _keeperRegistryGasOverhead
) {
// Set contract references.
keeperRegistry = IKeeperRegistry(_keeperRegistry);
// Initialize state variables from initialize() arguments.
performUpkeepGasLimit = _performUpkeepGasLimit;
performUpkeepGasLimitBuffer = _performUpkeepGasLimitBuffer;
vaultHarvestFunctionGasOverhead = _vaultHarvestFunctionGasOverhead;
keeperRegistryGasOverhead = _keeperRegistryGasOverhead;
// Initialize state variables derived from initialize() arguments.
(, OnchainConfig memory config, , , ) = keeperRegistry.getState();
chainlinkUpkeepTxPremiumFactor = uint256(config.paymentPremiumPPB);
}
/* */
/* checkUpkeep */
/* */
function checkUpkeep(
bytes calldata _checkData // unused
)
external
view
override
returns (
bool upkeepNeeded,
bytes memory performData // array of vaults +
)
{
_checkData; // dummy reference to get rid of unused parameter warning
// get vaults to iterate over
address[] memory vaults = _getVaultAddresses();
// count vaults to harvest that will fit within gas limit
(HarvestInfo[] memory harvestInfo, uint256 numberOfVaultsToHarvest, uint256 newStartIndex) = _countVaultsToHarvest(
vaults
);
if (numberOfVaultsToHarvest == 0) return (false, bytes("No vaults to harvest"));
(address[] memory vaultsToHarvest, uint256 heuristicEstimatedTxCost, uint256 callRewards) = _buildVaultsToHarvest(
vaults,
harvestInfo,
numberOfVaultsToHarvest
);
uint256 nonHeuristicEstimatedTxCost = _calculateExpectedTotalUpkeepTxCost(numberOfVaultsToHarvest);
performData = abi.encode(
vaultsToHarvest,
newStartIndex,
heuristicEstimatedTxCost,
nonHeuristicEstimatedTxCost,
callRewards
);
return (true, performData);
}
function _buildVaultsToHarvest(
address[] memory _vaults,
HarvestInfo[] memory _willHarvestVaults,
uint256 _numberOfVaultsToHarvest
)
internal
view
returns (address[] memory vaultsToHarvest, uint256 heuristicEstimatedTxCost, uint256 totalCallRewards)
{
uint256 vaultPositionInArray;
vaultsToHarvest = new address[](_numberOfVaultsToHarvest);
// create array of vaults to harvest. Could reduce code duplication from _countVaultsToHarvest via a another function parameter called _loopPostProcess
for (uint256 offset; offset < _vaults.length; ++offset) {
uint256 vaultIndexToCheck = UpkeepLibrary._getCircularIndex(startIndex, offset, _vaults.length);
address vaultAddress = _vaults[vaultIndexToCheck];
HarvestInfo memory harvestInfo = _willHarvestVaults[offset];
if (harvestInfo.willHarvest) {
vaultsToHarvest[vaultPositionInArray] = vaultAddress;
heuristicEstimatedTxCost += harvestInfo.estimatedTxCost;
totalCallRewards += harvestInfo.callRewardsAmount;
vaultPositionInArray += 1;
}
// no need to keep going if we're past last index
if (vaultPositionInArray == _numberOfVaultsToHarvest) break;
}
return (vaultsToHarvest, heuristicEstimatedTxCost, totalCallRewards);
}
function _countVaultsToHarvest(
address[] memory _vaults
) internal view returns (HarvestInfo[] memory harvestInfo, uint256 numberOfVaultsToHarvest, uint256 newStartIndex) {
uint256 gasLeft = _calculateAdjustedGasCap();
uint256 vaultIndexToCheck; // hoisted up to be able to set newStartIndex
harvestInfo = new HarvestInfo[](_vaults.length);
// count the number of vaults to harvest.
for (uint256 offset; offset < _vaults.length; ++offset) {
// _startIndex is where to start in the _vaultRegistry array, offset is position from start index (in other words, number of vaults we've checked so far),
// then modulo to wrap around to the start of the array, until we've checked all vaults, or break early due to hitting gas limit
// this logic is contained in _getCircularIndex()
vaultIndexToCheck = UpkeepLibrary._getCircularIndex(startIndex, offset, _vaults.length);
address vaultAddress = _vaults[vaultIndexToCheck];
(bool willHarvest, uint256 estimatedTxCost, uint256 callRewardsAmount) = _willHarvestVault(vaultAddress);
if (willHarvest && gasLeft >= vaultHarvestFunctionGasOverhead) {
gasLeft -= vaultHarvestFunctionGasOverhead;
numberOfVaultsToHarvest += 1;
harvestInfo[offset] = HarvestInfo(true, estimatedTxCost, callRewardsAmount);
}
if (gasLeft < vaultHarvestFunctionGasOverhead) {
break;
}
}
newStartIndex = UpkeepLibrary._getCircularIndex(vaultIndexToCheck, 1, _vaults.length);
return (harvestInfo, numberOfVaultsToHarvest, newStartIndex);
}
function _willHarvestVault(address _vaultAddress) internal view returns (bool willHarvestVault, uint256, uint256) {
(bool shouldHarvestVault, uint256 estimatedTxCost, uint256 callRewardAmount) = _shouldHarvestVault(_vaultAddress);
bool canHarvestVault = _canHarvestVault(_vaultAddress);
willHarvestVault = canHarvestVault && shouldHarvestVault;
return (willHarvestVault, estimatedTxCost, callRewardAmount);
}
function _canHarvestVault(address _vaultAddress) internal view virtual returns (bool canHarvest);
function _shouldHarvestVault(
address _vaultAddress
) internal view virtual returns (bool shouldHarvestVault, uint256 txCostWithPremium, uint256 callRewardAmount);
/* */
/* performUpkeep */
/* */
function performUpkeep(bytes calldata _performData) external override {
(
address[] memory vaultsToHarvest,
uint256 newStartIndex,
uint256 heuristicEstimatedTxCost,
uint256 nonHeuristicEstimatedTxCost,
uint256 estimatedCallRewards
) = abi.decode(_performData, (address[], uint256, uint256, uint256, uint256));
_runUpkeep(
vaultsToHarvest,
newStartIndex,
heuristicEstimatedTxCost,
nonHeuristicEstimatedTxCost,
estimatedCallRewards
);
}
function _runUpkeep(
address[] memory _vaults,
uint256 _newStartIndex,
uint256 _heuristicEstimatedTxCost,
uint256 _nonHeuristicEstimatedTxCost,
uint256 _estimatedCallRewards
) internal {
// Make sure estimate looks good.
if (_estimatedCallRewards < _nonHeuristicEstimatedTxCost) {
emit HeuristicFailed(
block.number,
_heuristicEstimatedTxCost,
_nonHeuristicEstimatedTxCost,
_estimatedCallRewards
);
}
uint256 gasBefore = gasleft();
// multi harvest
require(_vaults.length > 0, "No vaults to harvest");
(uint256 numberOfSuccessfulHarvests, uint256 numberOfFailedHarvests, uint256 calculatedCallRewards) = _multiHarvest(
_vaults
);
// ensure _newStartIndex is valid and set startIndex
uint256 vaultCount = _getVaultAddresses().length;
require(_newStartIndex >= 0 && _newStartIndex < vaultCount, "_newStartIndex out of range.");
startIndex = _newStartIndex;
uint256 gasAfter = gasleft();
uint256 gasUsedByPerformUpkeep = gasBefore - gasAfter;
// split these into their own functions to avoid `Stack too deep`
_reportProfitSummary(
gasUsedByPerformUpkeep,
_nonHeuristicEstimatedTxCost,
_estimatedCallRewards,
calculatedCallRewards
);
_reportHarvestSummary(_newStartIndex, gasUsedByPerformUpkeep, numberOfSuccessfulHarvests, numberOfFailedHarvests);
}
function _reportHarvestSummary(
uint256 _newStartIndex,
uint256 _gasUsedByPerformUpkeep,
uint256 _numberOfSuccessfulHarvests,
uint256 _numberOfFailedHarvests
) internal {
emit HarvestSummary(
block.number,
// state variables
startIndex,
_newStartIndex,
// gas metrics
tx.gasprice,
_gasUsedByPerformUpkeep,
// summary metrics
_numberOfSuccessfulHarvests,
_numberOfFailedHarvests
);
}
function _reportProfitSummary(
uint256 _gasUsedByPerformUpkeep,
uint256 _nonHeuristicEstimatedTxCost,
uint256 _estimatedCallRewards,
uint256 _calculatedCallRewards
) internal {
uint256 estimatedTxCost = _nonHeuristicEstimatedTxCost; // use nonHeuristic here as its more accurate
uint256 estimatedProfit = UpkeepLibrary._calculateProfit(_estimatedCallRewards, estimatedTxCost);
uint256 calculatedTxCost = _calculateTxCostWithOverheadWithPremium(_gasUsedByPerformUpkeep);
uint256 calculatedProfit = UpkeepLibrary._calculateProfit(_calculatedCallRewards, calculatedTxCost);
emit ProfitSummary(
// predicted values
estimatedTxCost,
_estimatedCallRewards,
estimatedProfit,
// calculated values
calculatedTxCost,
_calculatedCallRewards,
calculatedProfit
);
}
function _multiHarvest(
address[] memory _vaults
)
internal
returns (uint256 numberOfSuccessfulHarvests, uint256 numberOfFailedHarvests, uint256 cumulativeCallRewards)
{
bool[] memory isSuccessfulHarvest = new bool[](_vaults.length);
for (uint256 i = 0; i < _vaults.length; ++i) {
(bool didHarvest, uint256 callRewards) = _harvestVault(_vaults[i]);
// Add rewards to cumulative tracker.
if (didHarvest) {
isSuccessfulHarvest[i] = true;
cumulativeCallRewards += callRewards;
}
}
(address[] memory successfulHarvests, address[] memory failedHarvests) = _getSuccessfulAndFailedVaults(
_vaults,
isSuccessfulHarvest
);
emit SuccessfulHarvests(block.number, successfulHarvests);
emit FailedHarvests(block.number, failedHarvests);
numberOfSuccessfulHarvests = successfulHarvests.length;
numberOfFailedHarvests = failedHarvests.length;
return (numberOfSuccessfulHarvests, numberOfFailedHarvests, cumulativeCallRewards);
}
function _harvestVault(address _vault) internal virtual returns (bool didHarvest, uint256 callRewards);
function _getSuccessfulAndFailedVaults(
address[] memory _vaults,
bool[] memory _isSuccessfulHarvest
) internal pure returns (address[] memory successfulHarvests, address[] memory failedHarvests) {
uint256 successfulCount;
for (uint256 i = 0; i < _vaults.length; i++) {
if (_isSuccessfulHarvest[i]) {
successfulCount += 1;
}
}
successfulHarvests = new address[](successfulCount);
failedHarvests = new address[](_vaults.length - successfulCount);
uint256 successfulHarvestsIndex;
uint256 failedHarvestIndex;
for (uint256 i = 0; i < _vaults.length; i++) {
if (_isSuccessfulHarvest[i]) {
successfulHarvests[successfulHarvestsIndex++] = _vaults[i];
} else {
failedHarvests[failedHarvestIndex++] = _vaults[i];
}
}
return (successfulHarvests, failedHarvests);
}
/* */
/* Set */
/* */
function setPerformUpkeepGasLimit(uint256 _performUpkeepGasLimit) external override onlyOwner {
performUpkeepGasLimit = _performUpkeepGasLimit;
}
function setPerformUpkeepGasLimitBuffer(uint256 _performUpkeepGasLimitBuffer) external override onlyOwner {
performUpkeepGasLimitBuffer = _performUpkeepGasLimitBuffer;
}
function setHarvestGasConsumption(uint256 _harvestGasConsumption) external override onlyOwner {
vaultHarvestFunctionGasOverhead = _harvestGasConsumption;
}
/* */
/* View */
/* */
function _getVaultAddresses() internal view virtual returns (address[] memory);
function _getVaultHarvestGasOverhead(address _vault) internal view virtual returns (uint256);
function _calculateAdjustedGasCap() internal view returns (uint256 adjustedPerformUpkeepGasLimit) {
return performUpkeepGasLimit - performUpkeepGasLimitBuffer;
}
function _calculateTxCostWithPremium(uint256 _gasOverhead) internal view returns (uint256 txCost) {
return UpkeepLibrary._calculateUpkeepTxCost(tx.gasprice, _gasOverhead, chainlinkUpkeepTxPremiumFactor);
}
function _calculateTxCostWithOverheadWithPremium(
uint256 _totalVaultHarvestOverhead
) internal view returns (uint256 txCost) {
return
UpkeepLibrary._calculateUpkeepTxCostFromTotalVaultHarvestOverhead(
tx.gasprice,
_totalVaultHarvestOverhead,
keeperRegistryGasOverhead,
chainlinkUpkeepTxPremiumFactor
);
}
function _calculateExpectedTotalUpkeepTxCost(
uint256 _numberOfVaultsToHarvest
) internal view returns (uint256 txCost) {
uint256 totalVaultHarvestGasOverhead = vaultHarvestFunctionGasOverhead * _numberOfVaultsToHarvest;
return
UpkeepLibrary._calculateUpkeepTxCostFromTotalVaultHarvestOverhead(
tx.gasprice,
totalVaultHarvestGasOverhead,
keeperRegistryGasOverhead,
chainlinkUpkeepTxPremiumFactor
);
}
function _estimateSingleVaultHarvestGasOverhead(
uint256 _vaultHarvestFunctionGasOverhead
) internal view returns (uint256 totalGasOverhead) {
totalGasOverhead = _vaultHarvestFunctionGasOverhead + keeperRegistryGasOverhead;
}
/* */
/* Misc */
/* */
/**
* @dev Rescues random funds stuck.
* @param _token address of the token to rescue.
*/
function inCaseTokensGetStuck(address _token) external onlyOwner {
IERC20 token = IERC20(_token);
uint256 amount = token.balanceOf(address(this));
token.safeTransfer(msg.sender, amount);
}
}
```
This is an abstract contract that iterates vaults from a provided list and fits vaults within upkeep gas limit. The contract also provides helper functions to calculate gas consumption and estimate profit and contains a trigger mechanism can be time-based, profit-based or custom. Finally, the contract reports profits, successful harvests, and failed harvests.