The Keep3r Network Experiment
I have been playing recently with the Keep3r network and I wanted to share my findings. I started by reading Andre’s blogposts and documentation but I just didn’t get it. This is my attempt to explain why the Keep3r network is useful for me and I hope it will help you understand the big picture.
Let’s jump directly into it by going through the two use cases I worked on.
Yearn V2 use case
Some weeks ago, we deployed the Hegic vault/strategy with Yearn v2 code.
Before winding it down, the vault had two strategies:
- ETH lot buyer
- WBTC lot buyer
As a strategist, I had to take care of monitoring those two strategies and call harvest() on them when:
- Users deposited Hegic in the vault to the point where another Hegic lot could be purchased. (888k Hegic)
- There was enough profit to warrant a claim from the Hegic protocol
Vaults v2 allows up to 20 strategies per vault. Whenever that happens, a strategist would need to monitor several strategies at the same time. Making sure calls to harvest() are made.
This needs automation!
The Hegic protocol use case
To understand the Hegic use case, let’s go through the lifecycle of an option. Alice buys an ETH call option for 1 ETH with strike price 600 with a 24hs expiration. The Hegic protocol creates an option by locking capital from the pool and stores it. 24 hours go by and Alice couldn’t exercise her option because the eth price stayed below the strike price. At this point, the option inside the system is still active and keeps the ETH locked when it’s no longer needed.
Hegic protocol allows anyone to call unlock(optionID) to free the locked capital and mark the option as expired. But, who is in charge of unlocking Alice’s option to free the locked capital? I would guess this has been done by Molly, manually. If Molly is unavailable, pool participants will not receive their premium immediately. Also, an option might not be created because pool funds are locked, and thus unavailable to be locked by new option contracts.
This needs automation!
The simplest solution
Come on, Carlos! You can create a script!
For the yearn use case, you can create a cron job and call every 24hs.
For the Hegic, use case:
- Listen to Hegic’s Create event
- For every option created set up an alarm for the option’s expiration time
- Call unlock(optionID) when the time comes
Maintaining cron jobs is not an easy task, so let’s see what Keep3r offers.
Enter Keep3r network
There are two things we should clarify before we go through this section:
1) I will not go into the details of how the yearn v2 keep3r works.
You can find the code here: https://github.com/Macarse/GenericKeep3rV2.
2) If you need to understand the basics of keep3r, Ceazor7 did a nice video:
https://www.youtube.com/watch?v=hQFXyiuQGC4.
At first, I didn’t know what I was dealing with.
- Will keepers understand the Hegic code?
- Will I need to offer some helper methods to guide the correct workflow?
- Would the default incentives be enough for them to pick up the work?
I started by creating the most simplistic implementation of a keep3r for Hegic.
You can find the tagged code at https://github.com/Macarse/hegicKeep3r/releases/tag/0.0.1
I will only focus on the ETH options code since it will be the same for WBTC.
The two most important methods in the code are the following:
function ethOptionUnlockable(uint256 _optionId) external override view returns (bool) {
Option memory option = IHegic(ethOptions).options(_optionId);
return option.state == State.Active &&
option.expiration < block.timestamp;
}
which allows a Keeper to check if an option can be unlocked.
To be unlocked, the option needs to be still active, and the expiration time should be in the past.
function ethUnlock(uint256 _optionId) external override paysKeeper {
IHegic(ethOptions).unlock(_optionId);
}
A keeper will call the above function to call unlock() on the Hegic protocol and since the method includes the paysKeeper modifier, it will take care of paying the keeper some kp3r.
Can a keeper call this method with a random optionId?
Yes, but if the optionId can’t be unlocked, the Hegic protocol reverts the tx.
After some local testing, I deployed the contract to https://etherscan.io/txs?a=0x5E6B1Ce8E608D4EEEFA7e403c6f4FfC7AEA022C1.
Since the keep3r gov at the moment is just Andre, I ping him in TG and ask him to add the job to the network. The job started with 10 KP3R credits for keepers to farm.
To my surprise, after a couple of hours, one keeper understood the logic and started calling my contract.
The first unlock was this one https://etherscan.io/tx/0xbe91359b02e6b3fe2e3feacfcb4892611ee8eb80424ead8d4920077228d99bdd
The keeper spent 0.0103094628 ETH (6.07 usd) with a gas price of 58.8 gwei to unlock optionId = 368. If we check in the Hegic protocol, optionId 368 was:
Amount: 15 ETH
Type: PUT
Strike price: 383.07 USD
Expiration: Tuesday, November 24, 2020 9:52:35 PM GMT
Premium: 1.11045 ETH
My keep3r contract paid the keeper 0.070689336476052217 KP3R ($15.12)
That’s cool!
Then we got: https://etherscan.io/tx/0xa433fc5f33a16fde75563274969e729b3f740b90853eaab17f1e337d621e2976
That’s unlocking option ID 885, which was 1 ETH. We also paid around 15 USD for it.
That’s NOT cool!
My job was completely dominated by a unique keeper: 0xfe56
I soon realized that my algorithm was too naive and that 0xfe56 was going to drain my job’s credit. There is no way to remove credits from a job, so I just saw the whole thing to the end.
Some interesting things that happened:
1) 0xfe56 tried to unlock the same option id (925) at the same time!
https://etherscan.io/tx/0x83b2b8a972343f6c7d3bc2245c71019edab1dffd9d7ef58a9b2854fecb04e562
https://etherscan.io/tx/0xf8451c493449a0cf1d56dc1817c68d5c96126099cda06a4b577078acbbb6e777
Cheers to everyone that think running scripts is easy. 🥂
2) At a certain point another keeper joined the race but was owned by 0xfe56:
Loser tx from 0xd8: https://etherscan.io/tx/0xd42ce60199c578cedf436a05bfb1a73fdd09a4e44d8c8ea38c39e2c4200d951e
Winner tx from 0xfe56: https://etherscan.io/tx/0x38eed57ee8787621ffbb97c3af152aaab6d220da4c75da58a1eff2ea0353b847
3) When the job ran out of credits a keeper kept calling, wasting their gas on rejected txs. If the keep3r job can’t pay the keeper, the whole tx is reverted.
Example: https://etherscan.io/tx/0x7010cf128762b5e5a9be245f86c75ee5262c2753b31a1c4c0ac122a4ed8eb4b6
After the credits ran out, I asked Andre to remove the job and started working on v2.
Conclusions after v1 that inspired V2
1) There was no relationship between how much capital was unlocked and the price paid for the work.
A crazy example: A keeper might unlock a 1 ETH option for 2 ETH if gas price is high.
2) Keepers don’t need to consider if gas is high, it even benefits them since they get more rewards.
The max cost of a tx is gas paid * 1.1. This means that if the gas is high, the keepers will get a higher reward, and consequently drain the job KP3R more quickly.
3) There is no consideration of pool usage. In the Hegic protocol, an option cannot be created when the locked ETH is equal to 80% of the total pool size.
Does it make sense to unlock 1 ETH for 15 dollars worth of credits when the pool is at 10% usage?
Enter version 2
Code at https://github.com/Macarse/hegicKeep3r/releases/tag/0.0.2
After v1 I wanted something smarter and after discussing with other Hegic developers I came up with the following algorithm:
Copy and paste from the PR:
Gas usage of a single unlock is around 175k gas.
Pool usage can be calculated with: 100-(pool.availableBalance() * 100 / pool.totalBalance())
We can ask keep3r a quote for the work to be done.
My idea is to have a % of the locked value we want to pay in fees.
Let’s say it’s 10%. If we can free 1 eth, we would like to pay 0.1 eth in fees+gas.
This will be modifiable in the keep3r contract by the owner.The process will be the following:Keeper sends a list of options id
We calculate the call totalCost which is keep3r.quote(175k) * len(optionsList)
we calculate totalUnlock by sum all the options locked value + premium
We calculate unlockValue by doing totalUnlock * 10.0 / 100.0
Finally, we get weightedUnlockValue in based on pool usage with poolUsage * unlockValue / 80.0
if totalCost <= weightedUnlockValue => proceed with the unlocks.
The contract was deployed at https://etherscan.io/address/0x13dAda6157Fee283723c0254F43FF1FdADe4EEd6 and keepers started sending valid txs hours after. 😮
Here’s the tx that interested me the most:
https://etherscan.io/tx/0xca51a2c823df8ffa53dae576d01bf80284cee83da0475275679f6a9b8dd80ea9
The keeper spent 0.00708110079471 ETH (4.16 usd) with a gas price of 13 gwei to unlock 12 options!
The tx unlocked 60.0 ETH + 1.6701 ETH in premium.
The keep3r contract paid them 0.034741623257409949 kp3r, which is 7.423937473875932 usd.
That’s VERY cool!
Conclusion
After doing this Thanksgiving experiment, I learned that Keep3r is not just an automation job framework. Keep3r is a “please, figure this out” tool.
I can specify a problem, and keepers will find a solution for a fee.
I have no idea how they are organizing the options list and satisfying my algorithm, but they are doing it!
A possible next step would be customizing the reward prize. Perhaps a Hegic reward instead of KP3R? 🤔
Thanks for reading!
Acknowledgments
Thanks to all the people who helped me through this journey ❤