This project is a simple implementation of a CR (collateral ratio) monitor for Liquity Protocol using the Liquity SDK.
It lets you receive push-notifications whenever the TCR (total collateral ratio) of the Liquity system, or the individual CR of any Trove in a selected list falls below a configurable threshold.
The project is made up of a dependency-minimized core, and an example that integrates it with Tenderly Actions.
The minimalistic and dependency-minimized core of Liquity CR Monitor. It is designed as a one-shot task, executed by calling the function checkPriceAndDispatchNotifications.
import { connectToLiquity } from "./core/connection";
import { checkPriceAndDispatchNotifications } from "./core/monitoring";
import coingeckoPrice from "./core/price/sources/coingecko";
import liquityPrice from "./core/price/sources/liquity";
import slackNotification from "./core/notification/targets/slack";
connectToLiquity(myEthereumRpcUrl).then(liquity => {
checkPriceAndDispatchNotifications({
liquity,
storage: myStorageImplementation, // Implement interface Storage from "./core/storage"
tcrThreshold: 2.0, // 200%
troveCrThreshold: 1.5, // 150%
monitoredTroves: [
{ name: "Trove #1", address: "0x24fC9b59F159F6FD28F01Af892a70173A59dEd7d" },
{ name: "Trove #2", address: "0xf0439213A6236d7eDb8CBE0a036d280D058FAB6c" },
{ name: "Trove #3", address: "0xAA541196481db150cC71FaF658999831a2EABCB7" }
],
priceSources: {
CoinGecko: coingeckoPrice,
"Liquity PriceFeed": liquityPrice(liquity)
},
notificationTargets: [slackNotification(mySlackWebhookUrl)]
});
});
- core/connection: Establishing a connection with Liquity Protocol through Ethereum JSON-RPC.
- core/monitoring: Querying blockchain data and calculating collateral ratios, invoking the notification dispatcher. Contains the entry point of the monitoring core.
- core/notification: Dispatching notifications to targets. Uses storage to ensure notifications are only sent out once every time a threshold is crossed.
- core/notification/targets: Modules implementing various notification methods, e.g. Slack (currently the only implementation).
- core/price: Ether:USD price aggregation. Fetches Ether price (quoted in USD) from a number of sources and chooses the lowest one.
- core/price/sources: Modules implementing various Ether price sources (e.g. Liquity PriceFeed contract, CoinGecko API).
Example that shows how the monitoring core can be configured and integrated into Tenderly Actions.
- tenderly.yaml: Tenderly Actions configuration defining a single periodic task to call the entry point of the monitor.
- src/tenderlyFunctions.ts: source file containing the entry point function referenced by
tenderly.yaml
. Configures and invokes the monitoring core. - src/tenderly: Tenderly Actions-specific code for accessing secrets and persistent storage.
In this example, we will set up Liquity CR Monitor to send us notifications through a Slack channel and deploy it to Tenderly Actions.
We will need:
- a Tenderly account,
- access to an Ethereum node, e.g. by creating an Alchemy app,
- a webhook to our Slack channel.
The first thing we need to do once we have the above prerequisites is to install Tenderly CLI and log into our account:
tenderly login
After cloning this repo, we need to edit tenderly.yaml and replace liquity/cr-monitor
with our Tenderly username and project ID. We can simply use the default project that Tenderly created for us when we signed up, which is named project
. In this case, our tenderly.yaml
should look something like this:
actions:
myusername/project:
runtime: v1
# ... more stuff ...
After navigating to the directory containing tenderly.yaml
, we should be able to build and deploy our action with:
tenderly actions deploy
Before we do this, we might want to take a look at src/tenderlyFunctions.ts and customize our configuration, such as the list of Troves we want to monitor.
At this stage, we should be able to navigate to the Actions page on our Tenderly dashboard and see our new action periodicallyCheckPrice
being executed every 5 minutes. However, we'll notice that it keeps failing with Error: SecretNotFound
.
To fix this, we need to select the Secrets tab under Actions, and add the following items:
- Name:
ethereumRpcUrl
, value: JSON-RPC URL of an Ethereum node. For example if we're using Alchemy, this will look like"https://eth-mainnet.alchemyapi.io/v2/..."
. - Name:
slackWebhookUrl
, value: the URL of a webhook that lets us post to our Slack channel. This should look like"https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX"
.
Once we've set these up, we should see subsequent executions of our action be successful and we should start receiving alerts in our Slack channel whenever the TCR or any of our Troves crosses its CR threshold!