New Ethereum talks, every Monday. The week's conference uploads by event, in your inbox.

Loading player…

Yearn 🛠 Build and Profit with Yearn Vaults

ETHGlobalSun, Oct 9, 2022, 12:00 AM

Join skeletor spaceman of Yearn Finance for a workshop titled, "Build and Profit with Yearn Vaults." Leverage the power of Yearn by learning how to create a money making integration on top of v2 vaults by taking advantage of the brand new EIP-4626: Tokenized Vault Standard! We'll guide you through creating a B2B/business router for yearn v2 vaults, which complies with the new EIP-4626. Choose from multiple fee strategies for your users to maximize your profit. This workshop is part of ETHAmsterdam, the first in-person hackathon for ETHGlobal since ETHLondon in 2019. Join over 800 likeminded engineers, designers, and creators to build and learn over one full weekend at the Beurs Van Berlage in Amsterdam. ETHAmsterdam is taking place as part of Devconnect, the week-long in-person gathering in Amsterdam. We're back to build, we hope you'll join us. ---------------------------------------------------- Follow us: https://twitter.com/ETHGlobal​ Check us out: https://ethglobal.co​m Email us at: hello@ethglobal.com

Transcript

Then you have some functions to let's say push money into the vault or like the either like deposit or mint. Deposit is meant for so it basically does the same thing but one you specify how much underlying amount you want to deposit and the other one you specify how much how much sorry how many shares do you want to get from your deposit and then the kind of the logic takes care of how much underlying to take from your allowance on the ERC-20. Withdraw is practically the same. So you have withdraw and redeem. Withdraw is for your underlying.

So you say hey I want to withdraw let's say 10 die or if you hit redeem you say hey I want to redeem I don't know nine YV die shares which is the vault share token. Then you have a lot of utility or view functions which are here defined as external but we the ERC like they the vault wrapper or the 4626 use then uses them as well. Uh like inside the code so you will probably have to redefine them as public variables sorry functions. But yeah it's basically how do you convert shares to assets how like some internal accounting or everything is pretty flexible. So if you do have like well you'll see as we as we go through but here you can add like specific logic depending on what you are wrapping in this case obviously we'll see an example of the V2 vaults of yearn.

And then there are some functions either for user facing or for integration contracts which are okay let's say I want to deposit 100 die how many shares would I get so I can check. Or I want to withdraw I don't know or yeah I want to redeem X amount of shares how many underlying or assets would I be getting. Then we'll have some kind of functions that set some yeah well here it says limit logic. Sometimes you might have a vault that doesn't really want your money per se. We usually have vaults that do not have or have like a big deposit limit.

Uh but in some cases you want to just limit a vault or some integration to a certain amount of money either one uh because you don't feel comfortable holding I don't know billions or millions of TVL in a single contract because you are not going to effectively use them so they will probably dilute the APY for the the users that are already in or for any other reason you might find. There is also the same kind of functionality but adapted to vault shares which is max amount of mintable shares. And the same with withdraw. Sometimes you might have a vault that uh let's say it doesn't have the possibility to give the underlying back or does require some other mechanism for you to get your withdrawals. Let's say in the case of yearn we do have some vaults that have a big buffer but let's say if you're a really really big whale or you are in a vault that most of the assets are being utilized in locking strategies you might either want if you're an integrator and you're probably like in the partners program for yearn you probably will ping us and say hey we are planning on withdrawing I don't know 500 million how can we coordinate and we would unwind the strategies for you to be able to get out.

But if you're a user this can also be useful for let's say knowing how much can you withdraw one either without incurring any losses because there are a possibility that when you withdraw if you hit a strategy so if you go out of the buffer that the vault has and you need to go into a strategy that might be a lossy strategy you might incur in some losses. We'll go into this over. And then obviously it's the same function for redeem. So basically you have just really few functions one for each one for share management one for underlying management. So you will see a lot of like internal accounting but most of these yeah should should be like yeah quite common for you guys if any of you have been working around yearn or yield bearing tokens.

So what we did here what we did here is vault wrapper which is basically a contract on top of a yearn V2 vault which is written in viper that basically is kind of a proxy for your deposits or withdrawals or for your interaction. This contract per se is not an ERC-20 so it's not it doesn't have a token itself it's just routing funds in and out both underlying and shares for the depositors and let's say if you also want to let's say add a fee or whatever it can also route the fees into another separate contract. The idea of this contract is not to not hold any value at all. Um So we started constructing the contract we yeah right now it's like pretty simple this was hacked quite very quickly so there might be some incongruencies we checked it and it looked fine but if you guys see anything that's wrong ping me on Twitter or whatever. We'll open up the source code for this so you'll yeah you can open up issues whenever the repo comes up.

So since this is one contract right now we have a constructor for the vault this can be also a contract that has clone functionality so you don't have to deploy the contract again and again and it's a little bit cheaper to deploy. Obviously you might really want to customize this wrapper contracts for yourself but if you do customize them and you want to tackle different vaults or multiple vaults it's also recommended to have some sort of this cloning mechanism to be basically not waste that mega cash on yeah deploying the same bytecode over and over again. So here we define vault token and decimals. These decimals are defined just to avoid having to do one extra call you'll see this in a moment. We and now here comes the tricky part where we have to comply with all the interfaces required by this new beautiful EIP.

So it's quite similar to what we have on vaults V2 but there are some naming and some since now we are required to both handle deposits via let's say deposit which takes shares and mint which uh takes sorry which deposit takes underlying and mint that takes shares we'll have to do some tricks around. But yeah so first this is the first example asset we used to have it as token. So for us it's basically the same but this is an easy way to kind of rename it. Um And then okay into the fun part. So deposit here I takes an amount of assets so let's say 100 die and a receiver.

The receiver doesn't necessarily has to be the message sender in the case of you wanting to or I don't know whatever wanting to to deposit for another person but the deposit does take the internal deposit function does take message sender so if we go here which is that just below the like at the bottom of the contract is an internal function that takes the depositor so the message sender is our depositor in this case which is the person that we are going to take the tokens from. There is no logic obviously to take the let's say for you as a message sender to set a depositor into another for another address because obviously you will be kind of draining the allowance for another person. So here it's quite simple. We set some values in memory just to avoid having to reaccess the same storage slot over and over again. If we do have uint 256 max which is like basically try to deposit as much as possible we do check either which is like the minimum amount between the user balance or the allowance.

The user might have infinite allowance as well but the actual balance might not be obviously infinite uint 256 number or the other way around the user might have a ton of balance but only allow the vault to access like specific amount like 100 die. If not we will take the amount as a predefined amount by the user which is might be also correct and if it's not correct either we'll have a revert here trying to transfer from a user that doesn't have allowance etc. or that doesn't have the actual balance. So the first thing we do is we drain the we drain we pull the funds from the user which is it's from the depositor yeah let's say correct to the to the phrasing here from the depositor into the vault wrapper so we are not actually sending this directly into the vault because we we we require to have these funds in the vault wrapper for us to be able to call the deposit function later. This is weird one but we need to check So you have two options here.

One you initialize when you initialize the vault wrapper you set allowance infinite to your vault which I think it's okay or second set which is kind of easier but you are just screwing your first depositor is you have your first depositor approve like give the max allowance into the into the vault. So yeah you probably want to be the first depositor. This might not ever run out possibly. Not sure how it will run out, but there is a check for if it's not enough, you can like re-approve, etc. But should be okay to take this outside just to one, save some gas on deposits, and secondly, to have yeah, basically more control over the the allowance from the wrapper to the vault.

Um Uh here we need to check if the vault wrapper has some dust in the underlying. So, we check, let's say somebody mistakenly uh mistakenly send one die into the vault wrapper instead of doing an allowance and calling deposit. It will up Sorry, it will mess up somewhat with the account internal accounting of this function. So, we check pre and post balance. In the meanwhile, in the middle we call deposit, so vault deposit should be here.

Uh vault deposit So, this is in Viper, but it's it's pretty easily and self-explanatory. You can check that as well in the Yearn Vaults repo if you want to. We check how much tokens we have left. So, there is a possibility that the deposit doesn't really take all of No, actually no. The deposit will take all of the amount that you sent, but this is done just for avoiding to Yeah, give give some gas.

And then, if there is anything that might be refundable, uh you send that back to the to the depositor. Uh here in the vault deposit, you set the receiver. So, this can be either yourself or it can be a third So, yourself not the depositor itself or a third party that the depositor choose. Um Let's go back up. Uh so, for mint, this practically the same.

Oh, well, obviously the deposit function returns both the assets that it used and the new minted shares. It For mint, it's the same. The only difference is that the user specify specifies numbers of shares. For the withdraw, which is a little bit tricky, and it really depends on uh kind of how and at in which state you are hitting the vault. So, we have a a bunch of different kind of scenarios that might happen.

So, yeah, you As I said, the depositor right now or the withdraw Let me check what's the actual name here. Okay, the sender for some reason is the the one that has the vulture tokens. So, remember this sender doesn't actually So, since vault wrapper is not an ERC-20, you are still interacting with the vault as an as it being the behaving as the vault API. So, the that has the deposit withdraw all done functions. But since also the vault is an ERC-20 because it it has its own shares, so it does the the accounting of its own share.

It behaves like an ERC-20. Obviously, in Viper you don't have the open separate ERC-20. So, probably here you have like transfer, blah blah blah. So, everything is kind of implemented internally. Um Uh which I've heard is more gas optimized, so shout-outs to Viper.

And then, yeah, it's basically kind of similar, but the other way around. So, we do need to calculate how much available shares does the vault has or does the user No, sorry, does the user has um uh basically to withdraw. Um then we calculate depending on the PPS of the vault. So, this is the price per share. Let's say you enter in a new vault, probably the PPS or not probably, but the PPS will be one.

If that vault through a strategy receives profit, uh the PPS will increase. If it receives losses, the PPS will decrease. So on and so forth. Uh Yeah, basically some internal accounting, which if you really want to go deep into it, you can, but it's pretty straightforward. Then we take the vault share tokens from the sender into this address.

So, because as you remember, you need to hold these first to be able to interact with the vault. And differentiation with the deposit function is that the withdraw function doesn't really need allowance because when you're interacting with the vault, the vault uh doesn't really need you to give allowance for its own token to itself because it will be done. So, you don't need to to handle that. You just hold your tokens so you can interact with whatever like internal vault functions that you want without giving it allowance. And here we also do check pre and post balances to one.

Uh Okay, and here comes the kind of the different scenario. So, there's a possibility that when you withdraw, you might not get all the amount of say underlying that you wished for. One, because of the offered we talked about, maybe you go over that and there are no other uh withdrawal strategies. So, we have something called a withdrawal queue where we set the more easy uh or liquid to withdraw strategies on top. Those strategies also might not have any withdrawal liquidity or withdrawal underlying on them.

So, as you go into the queue, you might end up without fulfilling your full amount. Obviously, if you withdraw less, it will be possible to like for you for a month. But if you withdraw a ton of underlying, it might get trickier on the more illiquid vaults. Uh So, yeah, here we withdraw, and so we have to do some checks to know uh either um how many actual shares were were burned because obviously, if you say, "Hey, I want to withdraw 100 shares." And this is also a differentiation between deposit and withdraw.

On Vault V2, you deposit underlying, but when you withdraw, you withdraw with your shares. Uh since in the vault wrapper we are accommodating for both withdrawing saying, "Hey, I want to withdraw 100 die and or I want to withdraw 100 or 99 vault shares." We do accommodate for both. but here, the Vault V2 might not really need to burn all your shares because it obviously, if it can only give you 50% uh of the estimated underlying that you that those shares are worth uh are Sorry, are worth depending on the PPS, so the price per share, it will only give you it will only burn 50% of your shares obviously because if not, we are basically robbing everybody. Uh so, you send the let's say the estimated amount of shares per the amount that you kind of want to get.

Uh you specify a receiver as well. And then, this vault withdraw will return you. So, Vault V2 call will give you how much underlying you got for those shares. And here, this is why we calculate how many shares were burnt. And if we do have any unused shares, unused shares still, we do return them to the sender.

Uh So, that's that's practically it. Then we do have some obviously the same functionality with redeem. So, in this case, this uh kind of is the more native approach or the one the wrappers that is more similar to V2. And this is the weird one which uses assets instead of shares. And on deposit, it's the other way around.

We usually take assets as deposit and mint is this. So, this is why you see different uh accounting prior to called calling deposit or withdraw. Uh then you have some asset sets here, some accounting logic. It's really simple. So, you really need to know the total assets that the vault really has.

Uh This is just like proxy in the call the call to the same function in V2. You need to know Well, you we went through the same EIP. So, everything is pretty like the same here. We just accommodate for for the decimals and the price per share, etc. etc.

We also have max deposit function, so the limit function that we we talked before, which might be useful for one, avoiding reverts on the UI. Uh And secondly, and I think it's most important to also let say integrators know the exact max amount they need to get. So, probably you would call max deposit and then deposit that max amount. That might be in some cases the max uint. Um A max Sorry, uint 256.

Uh same for mint, same for withdraw, same for redeem. Uh So, yeah. So, let's go into the more interesting stuff. This is kind of boring and an introduction, but I think it's good to know. Um So, I think I wrote a to-do here.

Let me check. Uh Okay, so yeah, on max deposit, let's say the EIP 4626 kind of lets you do whatever you want inside. So, if you want to take fees on top of the deposits, you you can. If you want to limit uh deposits or to block deposits for certain users, etc. etc.

, you also can. Same for withdraw. You can add both fees on deposit on withdraw. You can add fees depending on the amount being deposited or withdrawn or depending on the uh difference of the PPS increase. So, let's say you don't really want to make your users lose money, but you want to take a percentage of their profit.

So, and this might get tricky, but you can kind of save how much uh kind of relative PPS a depositor has and then take a percentage out of it. so like a percentage out of their API increase or PB PBS increase. Uh let's say a way to do this, I think it should be pretty easy to do so. Uh you would define, let's say fee receiver here that uh let's say it's C4 address. Uh uh Uh and obviously this won't compile.

Uh it's just for a little bit of laughs. And here on deposit you can uh basically rug some percentage of it. Uh Let's say you want to Oh sorry, this is a weird computer. Uh So you get the token you want to do. And let's say you want to uh transfer uh from Or yeah, okay, let's do this on deposit.

So we we can uh both rug deposits on uh shares and on underlying. Um So here where we're transferring uh let's say we can do something similar. Uh let's copy this. Uh let's say we want to uh send from to Well, but you know, you get the gist. So maybe we can do this to do amount.

So we get a tiny percent from the user and then we do Sorry, amount. So we update. So uh it's quite uh easy to add a different type of uh fee mechanisms for you to earn on top of uh what the depositors have. Obviously it's uh always a good practice to be transparent with your users. So if you're doing this, uh like make them know uh that you're taking a small cut either on withdrawal or on deposit.

Um and then yeah, or or if you also want to uh build up some more complex stuff around the PBS increase, uh just for you um yeah, not to have your users lose money on either deposit or withdrawal. Uh but yeah, that's it. I don't know if you any of you guys have any specific questions that we uh that you might want to to tackle or We good? Okay. Awesome.

Thank you guys.

Automatic transcript — names and jargon may be misspelled.