-
Notifications
You must be signed in to change notification settings - Fork 20
New Template: Vault Harvester #39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ejacquier
wants to merge
5
commits into
main
Choose a base branch
from
new-vault-harvester-template
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
5b31d36
created vault harvester template
ejacquier 97fff0d
Updated template metadata and readme
ejacquier db25a53
Add disclaimer
ejacquier 3f8e9c5
Added template link in readme.md
ejacquier 0bcde04
Added receiverContractExecutionStatus check after the TX success check
ejacquier File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
starter-templates/vault-harvester/vault-harvester-ts/.cre/template.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| kind: starter-template | ||
| id: vault-harvester-ts | ||
| projectDir: . | ||
| title: "Vault Harvester (TypeScript)" | ||
| description: "Automated DeFi vault harvesting — check if yield is profitable, then harvest and compound." | ||
| language: typescript | ||
| category: workflow | ||
| tags: | ||
| - vault | ||
| - harvester | ||
| - yield | ||
| - compounder | ||
| - defi | ||
| - cron | ||
| - on-chain-read | ||
| - on-chain-write | ||
| workflows: | ||
| - dir: my-workflow | ||
| postInit: | | ||
| A demo VaultHarvester contract is pre-deployed on Sepolia. See README.md for details. |
1 change: 1 addition & 0 deletions
1
starter-templates/vault-harvester/vault-harvester-ts/.gitignore
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| *.env |
153 changes: 153 additions & 0 deletions
153
starter-templates/vault-harvester/vault-harvester-ts/README.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,153 @@ | ||
| # Vault Harvester — CRE Starter Template (TypeScript) | ||
|
|
||
| Automated DeFi vault harvesting — check if yield is profitable, then harvest and compound. | ||
|
|
||
| **⚠️ DISCLAIMER** | ||
|
|
||
| This template is an educational example to demonstrate how to interact with Chainlink systems, products, and services. It is provided **"AS IS"** and **"AS AVAILABLE"** without warranties of any kind, has **not** been audited, and may omit checks or error handling for clarity. **Do not use this code in production** without performing your own audits and applying best practices. Neither Chainlink Labs, the Chainlink Foundation, nor Chainlink node operators are responsible for unintended outputs generated due to errors in code. | ||
|
|
||
| --- | ||
|
|
||
| ## Overview | ||
|
|
||
| This template demonstrates the **cron -> read -> check profitability -> harvest** pattern using Chainlink CRE (Compute Runtime Environment). Same cron -> read -> check -> write pattern as the Keeper Bot, but with a DeFi-specific vault contract. | ||
|
|
||
| ### Use Cases | ||
|
|
||
| - **Vault harvesting** (primary): Check if `timeSinceLastHarvest > threshold` AND `yield > minThreshold`, then harvest | ||
| - **Yield compounding**: Harvest + swap + redeposit accumulated rewards | ||
| - **Protocol revenue collection**: Claim and redistribute protocol fees on schedule | ||
| - **Target protocols**: Beefy, Yearn, Alchemix, and any vault with a `harvest()` function | ||
|
|
||
| ## Architecture | ||
|
|
||
| ``` | ||
| ┌─────────────────────────────────────────────────────────────┐ | ||
| │ CRE DON │ | ||
| │ │ | ||
| │ ┌──────────┐ ┌───────────────┐ ┌──────────────────┐ │ | ||
| │ │ CRON │───>│ Read Vault │───>│ Profitable to │ │ | ||
| │ │ Trigger │ │ State │ │ harvest? │ │ | ||
| │ │ (5 min) │ │ (EVMClient) │ │ (time + yield) │ │ | ||
| │ └──────────┘ └───────────────┘ └────────┬─────────┘ │ | ||
| │ │ │ | ||
| │ ┌──────────v──────────┐ │ | ||
| │ │ Profitable? │ │ | ||
| │ │ YES -> Write report│ │ | ||
| │ │ NO -> Log & skip │ │ | ||
| │ └──────────┬──────────┘ │ | ||
| │ │ │ | ||
| └────────────────────────────────────────────────┼────────────┘ | ||
| │ | ||
| ┌──────────v──────────────┐ | ||
| │ KeystoneForwarder │ | ||
| │ -> Vault._processReport│ | ||
| │ (harvest + compound) │ | ||
| └─────────────────────────┘ | ||
| ``` | ||
|
|
||
| ## Components | ||
|
|
||
| ### CRE Workflow (`my-workflow/`) | ||
|
|
||
| The TypeScript workflow runs off-chain inside CRE DON: | ||
|
|
||
| 1. **Cron trigger** fires every 5 minutes (configurable) | ||
| 2. **Reads** `shouldHarvest()`, `pendingYield()`, `totalHarvested()`, `harvestCount()` from the on-chain `VaultHarvester` contract | ||
| 3. **If profitable**: sends a signed report to trigger harvest on-chain | ||
| 4. **If not profitable**: logs and skips | ||
|
|
||
| ### Consumer Contract (`contracts/evm/src/VaultHarvester.sol`) | ||
|
|
||
| A DeFi vault contract extending `ReceiverTemplate`: | ||
|
|
||
| - `shouldHarvest()` — view function that checks if `harvestInterval` has elapsed AND `pendingYield >= minYieldThreshold` | ||
| - `_processReport(bytes)` — called by CRE Forwarder, harvests pending yield, resets state, emits event | ||
| - `accrueYield(uint256)` — simulates yield accrual (in production, yield comes from the underlying strategy) | ||
| - `pendingYield`, `totalHarvested`, `harvestCount`, `lastHarvest` — public state variables | ||
|
|
||
| ## Getting Started | ||
|
|
||
| A demo `VaultHarvester` contract is pre-deployed on Sepolia with simulated yield — this template works out of the box. | ||
|
|
||
| ### Prerequisites | ||
|
|
||
| - [Bun](https://bun.sh/) runtime installed | ||
| - [CRE CLI](https://docs.chain.link/cre) installed | ||
|
|
||
| ### 1. Install Dependencies | ||
|
|
||
| ```bash | ||
| cd my-workflow && bun install && cd .. | ||
| cd contracts && bun install && cd .. | ||
| ``` | ||
|
|
||
| ### 2. Run Tests | ||
|
|
||
| ```bash | ||
| cd my-workflow && bun test | ||
| ``` | ||
|
|
||
| ### 3. Simulate | ||
|
|
||
| ```bash | ||
| # Dry run (no broadcast) | ||
| cre workflow simulate my-workflow --target staging-settings | ||
|
|
||
| # With actual on-chain transaction | ||
| cre workflow simulate my-workflow --target staging-settings --broadcast | ||
| ``` | ||
|
|
||
| ### 4. Deploy Your Own Contract (Optional) | ||
|
|
||
| To use your own contract, deploy `contracts/evm/src/VaultHarvester.sol` to Sepolia using [Remix](https://remix.ethereum.org/) or Foundry. Constructor arguments: | ||
|
|
||
| - `forwarder`: CRE KeystoneForwarder address on Sepolia (`0x15fc6ae953e024d975e77382eeec56a9101f9f88`) | ||
| - `_harvestInterval`: Seconds between allowed harvests (e.g., `300` for 5 minutes) | ||
| - `_minYieldThreshold`: Minimum yield in wei to justify harvest (e.g., `1000000000000000000` for 1 token) | ||
|
|
||
| Then update the `contractAddress` in `my-workflow/config.staging.json` with your deployed address. | ||
|
|
||
| To simulate yield accrual on your contract: | ||
| ```bash | ||
| cast send <YOUR_CONTRACT> "accrueYield(uint256)" 2000000000000000000 \ | ||
| --private-key <YOUR_KEY> --rpc-url https://ethereum-sepolia-rpc.publicnode.com | ||
| ``` | ||
|
|
||
| ## Customization | ||
|
|
||
| - **Change the schedule**: Edit `schedule` in `config.staging.json` (cron syntax) | ||
| - **Change the profitability check**: Modify `shouldHarvest()` in `VaultHarvester.sol` | ||
| - **Change the harvest logic**: Modify `_processReport()` to implement your vault's harvest + compound strategy | ||
|
|
||
| ## Migration Guides | ||
|
|
||
| ### Coming from Gelato? | ||
|
|
||
| This template replaces Gelato's vault harvesting Web3 Functions with CRE cron triggers. Gelato shut down Web3 Functions in March 2026. | ||
|
|
||
| | Gelato | CRE | | ||
| |--------|-----| | ||
| | `Web3Function.onRun()` | CRE cron callback (`onCronTrigger`) | | ||
| | `multiChainProvider` | `EVMClient` | | ||
| | `userArgs` | `config.json` | | ||
|
|
||
| ### Coming from Chainlink Automation? | ||
|
|
||
| This replaces the Beefy/Yearn `checkUpkeep + performUpkeep` pattern. Off-chain profitability check means no wasted gas. | ||
|
|
||
| | Chainlink Automation | CRE | | ||
| |---------------------|-----| | ||
| | `checkUpkeep()` on-chain | `shouldHarvest()` read via `EVMClient` (off-chain) | | ||
| | `performUpkeep()` | `_processReport()` via KeystoneForwarder | | ||
| | LINK funding | No per-call LINK costs | | ||
|
|
||
| ## Security | ||
|
|
||
| - The `VaultHarvester.sol` contract is a **demo** — audit and customize before production use | ||
| - The `ReceiverTemplate` base contract validates that only CRE Forwarder can call `onReport()` | ||
| - Never commit `.env` files or secrets | ||
|
|
||
| ## License | ||
|
|
||
| MIT | ||
11 changes: 11 additions & 0 deletions
11
starter-templates/vault-harvester/vault-harvester-ts/contracts/abi/VaultHarvester.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import { parseAbi } from "viem" | ||
|
|
||
| export const VaultHarvesterAbi = parseAbi([ | ||
| "function shouldHarvest() view returns (bool harvestNeeded)", | ||
| "function totalHarvested() view returns (uint256)", | ||
| "function lastHarvest() view returns (uint256)", | ||
| "function harvestCount() view returns (uint256)", | ||
| "function pendingYield() view returns (uint256)", | ||
| "function harvestInterval() view returns (uint256)", | ||
| "function minYieldThreshold() view returns (uint256)", | ||
| ]) |
1 change: 1 addition & 0 deletions
1
starter-templates/vault-harvester/vault-harvester-ts/contracts/abi/index.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export * from './VaultHarvester' |
27 changes: 27 additions & 0 deletions
27
starter-templates/vault-harvester/vault-harvester-ts/contracts/evm/src/IERC165.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| // OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol) | ||
|
|
||
| pragma solidity >=0.4.16; | ||
|
|
||
| /** | ||
| * @dev Interface of the ERC-165 standard, as defined in the | ||
| * https://eips.ethereum.org/EIPS/eip-165[ERC]. | ||
| * | ||
| * Implementers can declare support of contract interfaces, which can then be | ||
| * queried by others ({ERC165Checker}). | ||
| * | ||
| * For an implementation, see {ERC165}. | ||
| */ | ||
| interface IERC165 { | ||
| /** | ||
| * @dev Returns true if this contract implements the interface defined by | ||
| * `interfaceId`. See the corresponding | ||
| * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] | ||
| * to learn more about how these ids are created. | ||
| * | ||
| * This function call must use less than 30 000 gas. | ||
| */ | ||
| function supportsInterface( | ||
| bytes4 interfaceId | ||
| ) external view returns (bool); | ||
| } |
18 changes: 18 additions & 0 deletions
18
starter-templates/vault-harvester/vault-harvester-ts/contracts/evm/src/IReceiver.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity ^0.8.0; | ||
|
|
||
| import {IERC165} from "./IERC165.sol"; | ||
|
|
||
| /// @title IReceiver - receives keystone reports | ||
| /// @notice Implementations must support the IReceiver interface through ERC165. | ||
| interface IReceiver is IERC165 { | ||
| /// @notice Handles incoming keystone reports. | ||
| /// @dev If this function call reverts, it can be retried with a higher gas | ||
| /// limit. The receiver is responsible for discarding stale reports. | ||
| /// @param metadata Report's metadata. | ||
| /// @param report Workflow report. | ||
| function onReport( | ||
| bytes calldata metadata, | ||
| bytes calldata report | ||
| ) external; | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could link to this template from the README one level up https://github.com/smartcontractkit/cre-templates/blob/main/starter-templates/README.md?plain=1#L38.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good suggestion, will do for all templates.