Building Minimal DeFi Applications
ETHCC 5 · July 2022 · 46:11
Patrick Collins demonstrates building minimal DeFi applications. The workshop uses examples involving staking, swaps and lending.
Speakers
Topics
From ETHCC 5, hosted by Ethereum France.
Transcript
all right what's going on hello bonjour welcome uh hopefully everybody can hear me everyone online can hear me uh we ran into some technical difficulties so I had some slides here we're uh we're about 9 9 minutes over so we're just not going to do the slides um but I'm just going to basically tell you what we're going to be talking about today so today we're going to be talking about building minimal def applications and if I had some slides I would show you some Wonder pictures but tough luck and with building minimal defi applications we're going to be talking about the current major dii projects some of the major functions that they all use that they all share uh and then we're going to go over um this def5 minimal repo that we've been working on uh and then we're going to do a little code along so since
we have a small enough group here which is great uh we can be pretty interactive so and before we get started how many people here are developers coders oh yes okay how many people here are defi coders and I've worked with defi yes okay excellent all right cool how many people here are are new coders to web 3 brand new to web 3 are no you're not what um okay right cool how many people are are are more experienced intermediate defi developers okay how many people are experienced dii developers so there was a ton of people who were developers but very few defi developers are most people here Web Two developers are you a web two developer raise your hand okay cool all right so that that gives me an
approximation okay cool uh so and again you can't say anything so right now the the major defi applications are projects like maker Dow Lio a Unis swap curve these are all the kind of the big defi applications and they have some similar functions they do some same things some of the the main things that they do um and pretty much most of them share is some type of deposit and withdraw collateral or assets or Etc right so understanding how to uh stake add liquidity deposit these are all basically functions that do essentially the same thing it's going to be taking your ERC token and locking it into your smart contract and then doing
obviously the reverse of that which is going to be withdrawing your erc20 token or your native eth your native polygon your native Avalanche you know your your native blockchain token and then a lot of these protocols will have like a get value maybe a claim reward if if the you're doing staking or yield farming a borrow repay a swap mint burn depending obviously on the defi application so today we're going to be doing a minimal a so a minimal lending application we're going to be coding it live and hopefully my coding goes smoother than our our our av setting up um and since we have a small group uh please raise your hand ask questions uh and we're going to be jumping right into
it so so um what is I have like a couple slides to say what a is but you can't see any of the slides so uh a is a borrowing and lending protocol it's a way for you to put down some collateral and in return you're able to you know borrow assets and why would you ever want to do that well one of the major reasons is to leverage exposure to certain positions um if you're confused on what that means uh do a quick Google search on on like leveraging or short selling um um that'll give you kind of the basic breakdown it's basically a way to say hey I have some money in ethereum I don't want to sell my ethereum so I'm going to put it down as collateral I'm going to borrow some asset and buy more ethereum with that borrowed asset so
that now I have basically doubled my exposure to ethereum if the price goes up I make double the profit if the price goes down I lose twice as much as well approximately and I was going to uh let people choose which framework we were going to work with brownie found or hard hat but um I'm on a setup that I'm not familiar with so I'm just it has yarn so we're going to go with yarn here uh but let's say I was going to ask that question how many people here would be like yes brownie I love brownie let's do brownie all right cool some python people how many people would be like Foundry ah give me those solidity scripts love okay cool didn't you also vote for for brownie and then how many people would
be like hard hat love me some JavaScript okay so JavaScript would have won any anyways all right so this works out well and the hard part of this is since I need to hold the mic while coding we're going to enter a little stance here and see how this works all right good I think this is good how weirdly can I hunch over Tada all right all right let's do this um so we're and I got pull up my code base here so I can see what I'm doing uh yeah everyone's taking photos um let's do this so uh let's get started let's create our our hard hat
project with yarn hard hat hard Hat's not installed so we need to install hard hat yarn at hard hat a thank goodness yarn is working okay cool so we're going to be using hard hat we're not going to actually do a lot of functionality with hard hat um we're just going to be you know using it as our scaffolding for it able to compile if we have time at the end we'll write some tests um but we probably won't because I've already you know wasted 15 minutes setting up so and for anybody who wants to see this uh I don't feel safe going to the internet right now so so I'm just going to tell you um if you go to SM github.com smartcontract kitd minimal we have all the code here
so if you're got confused or if you want to play with this later uh you can go to that repo uh if you're W if you're live watching live you can go to right now follow along with us um and it has a ton of different examples so it's got an A example um synthetic staking example reward token example it's got some uh Ava Unis swap examples you know it's it's a living breathing repo of just really condensed classic uh defi applications so working on a smart on a stable coin one right now um so hopefully that will be out soonish so uh we'll do yarn hard hat we'll get our hard hat project set up create a JavaScript project yep yep yep uh read me already exists oh sorry
because I'm in the middle of a another project J Project yep yep right okay so we're going to do c we're going to CD down one sorry CD down again CD let's just CD let's see if this works all right can I can I like turn off the screen for a second um Stephen can I can I go to your home directory probably not right that's probably it uh okay um I really don't want new workspace okay file new open
workspace is there a new workspace button sorry guys in the worker in the workspace folder go up two go up two directories yeah right everyone's just gonna see all of Steven's files sorry H workspace and then new folder ah okay okay all right here we go you're going to trust me thank you all right cool now we're going to try again and thanks for bearing with us
everybody who's watching and everybody who's here but we're going to be doing some really cool stuff so all right yarn hard hat here we go there we go that this looks more right all right cool so we're downloading hard hat uh again this is just our scaffolding for the the code that we're building um we're barely going to interact with it and we have a little lock. soul which is cute and I'm also going to grab the hardhead solidity extension for those of you who are working with vs code oh never mind we're not going to install
that but for people who are working with vs code the hard hat solidity extension is really really nice it makes your solidity uh get formatted have the code highlighting so that's kind of cool to show anyways but um the Juan uh Blanco one is also really good hey whoa you me see oh this is actually worse cuz now I can't get the mic I think I'm going to use that one we're going to be showing you guys cool stuff I promise this is better much better all right cool now stuff's highlighted all right great so time to actually build our
contract so we're going to go to our contracts folder new file we're going to call it lending. so and let's get rid of lock. Soul delete goodbye lending. so okay so classic setup we'll do um spdx license identify fire MIT pragma solidity 0.8.7 hopefully they can still hear me contract lending all right cool downloading the comp compiler which
is great while that downloads um let's just create the basic functions that we're going to need to do so we're in our contract we have our minimal contract here uh what do we want this to do so we want this to be able to deposit collateral right so we'll do function deposit what else do we wanted to do function withdraw we want to be able to deposit our collateral so that we can borrow we want to be able to withdraw our collateral so we can take it out we're going to want to be able to to borrow because this is going to be a borrowing and lending protocol and then we're going to want to be able to repay so these are going to be the the really Bare Bones functions that we're going to be doing and this deposit and
withdraw um these are going to be kind of the most important functions and understanding how these work and how to use them will help you in pretty much any defi application you make be it borrowing lending being swapping whatever right because you're always going to need to lock some type of asset in your smart contracts right because it's a smart contract that's going to facil fa itate all the Logics of your financial uh assets so let's start with a deposit here so this deposit function and then actually let me add these in here so that uh stuff actually compiles and then we'll make this external make all these
external cool so our deposit function it's going to be an external function right because nobody in our contract is actually going to be calling it and when we deposit what are we going to be depositing well we need an address token what token are we going to be depositing what's the asset is it a uh the we WRA token Etc and then obviously uh you 256 amount now when we're depositing um we want to make sure that we do the uh the transfer call when we transfer the erc20 tokens and for everybody who's here an erc20 token is just another smart contract when we call that uh that transfer that's got to be the last step
uh in this function so I'm just going to go ahead and write it now though so we'll do BU success equals you know something something dot transfer from message. sender address this oops amount and since we're doing anc20 here push this over a little bit okay since we're doing an erc20 here we're going to need an erc20 interface so we're going to import that from open Zeppelin oops
import open Zeppelin SLC contracts C oops token erc20 ic20 do soul I can type much faster when I'm sitting normally I swear um so now we have the interface for an erc20 token and we can just wrap the address of the token ic20 token transfer from message. sender and this will transfer the token to this contract and then we just say um if that transfer was not
successful sorry and the mic is now on a rogue ramp page there we go if the transfer was not successful then we're just going to do a little revert and we'll say transfer failed that means at the top you're going to do a little error code outside of the contract uh we'll do error transfer failed and you know because of my weird setup here we're probably going to just go over these fundamentals and not uh
not everything do a little compile see if that looks okay got to add that yarn add opens up contracts okay cool compile whoops yarn hard hat compile uh
uh what mad about not finding hard hat oops guess we'll just doubly make sure it's installed all right now it's doubly installed I guess but it's compiling successfully yay so all right so now that we have this compiled um we have this kind of very minimal deposit here does anyone see anything wrong with this deposit or are we missing anything if we're building a contract that's going to keep track of people's collateral we now have a way to get the tokens what what are we missing here
balance there's no mapping we're we're actually not keeping track of anyone's collateral here so we're depositing tokens to keep track of collateral and we don't have a way to do that so what we want to do is we're going to create a mapping uh towards the top that's going to uh be a mapping of users accounts to these token addresses to how much assets they actually have so up at the top we'll do a little um mapping and it'll be a mapping of an address to a mapping of an address to 256 we'll make this public that's not the best but it's fine and we'll call it account
to uh token to amount great so before we do the transfer here we'll do account to token to amount of account to token is going to um plus equal amount cool all right so now we're keeping track of of how much uh people are sending is there anything else wrong here or missing so we're keeping track
of the balance we're sending the tokens to this contract we're locking them in here and I spelled a count [Music] wrong account account is not defined yep sure this should be uh yeah message us sender sorry yep is there anything else wrong here does this does this deposit function look okay what do we think we don't worry about that in this contract that's something the front end would do anything else here all right I'll tell you it looks pretty good this is pretty much it
actually there's some additional things that we probably would add if we had more time like we would want we would definitely want to emit an event um saying hey mapping been updated we'd have maybe some modifiers saying you know this token is allowed because we don't want to just be able to accept any erc20 we're not going to have a price feed for every single year C20 um and we might want to do a modifier like non-reentrant to get rid of re entres uh or more than zero but basically this is it right and which is really cool because for all of these defi applications if you want to make one of these deposit collateral stake um add liquidity this is essentially it send the token and keep track of how many tokens are being sent boom you've just
done like 50% of all defi applications and and now someone's going to be like oh Patrick told me this was 50% uh the the second 50 is much harder um so all right so great so next we would add a withdraw um I'm going to skip the withdrawing just to go right into uh right to borrowing uh because withdraw is basically going to be the opposite of that and I can't type very fast down here so let's do borrowing so now we have a way to deposit collateral other people are going to deposit assets into this smart contract and we can say hey like I have collateral I would love to borrow that asset to do stuff with it
so what we're going to do uh basically a check to make sure that you have enough collateral down to borrow the asset right so let's say I put you know one e down as collateral and I want to borrow $50 of usdc one e is going to be plenty but let's say I put one e down as collateral and I want to borrow 10 billion dollar of usdc our protocol should say hey you you can't do that right because your collateral doesn't cover that right your collateral needs to be uh at least uh at least equal to how much you're going to borrow normally it's over collateralized where you want a lot more um but we're going to kind of skip that for now because we have how much time Drive left 20 minutes 10 minutes 25 25 minutes thank you because I have 25
minutes left so we're going to do borrowing now so if I want to borrow something uh obviously we need to give the address of the token and the amount that I want to borrow unit 256 amount uh will make this external ideally we would do some non- re-entrance is the token allowed more than zero modifiers but again we're going to skip that for now and again this is going to be external because nobody in our contract should be calling this so uh the first thing that we're going to need to check for is whether or not our contract has enough of that token right because people are going to be be depositing collateral they're going to deposit like let's say in our example usdc uh we need to check that
does our contract have enough people deposited the US see so um normally I would do kind of this if else revert but require uses less typing so I'm just going to do that here um so I'm going to say require that the I erc20 of the token um balance of address this uh is greater than and amount and if not we're going to say not enough deposited or not enough collateral or something like that want to check that
we have enough of the token that they want to borrow next we would probably emit an event or something like that um then we would do uh we would just send them the token and we're going to have one more really really important step which makes us kind of whole thing to come together so we're going to do bull success again equals ic20 token. transfer to message.
Sender amount and then we're going to say we're just going to do require success uh failed and so this we've basically just done the opposite we're sending tokens to people who are borrowing what are we missing what are we not doing here somebody says hey I would love to borrow you know $100,000 of usdc and we're going yeah sure here you go we're uh we are checking if usdc is in the contract yes collateral we're not we're not checking for collateral we have no idea if this person has enough collateral to take this out they say hey let me borrow that usdc please uh we're right now we're saying yeah here you go
um you know thank you for stealing all of our money uh which is not what we want to do we want to stay solvent so what we're going to need to do is build some type of function called Health factor to check to see um if they have enough collateral down uh normally a calls this uh someone's Health Factor uh and it needs to be above one at all times if it's below one that's when people can come in and liquidate it we're probably not going to have time to make a liquidate function um but we do have time to do a health Factor function so way down here let's do function Health Factor and this is going to be how we're going to make sure that they have enough collateral and there's going to be some really interesting things here because we need to also price their collateral
right if they put down eth um usdc bat uh maker die all these different collaterals have different values so we need to figure out what's their total value first so that we know how much they can borrow so uh we're going to create this get health Factor function do address account this will be a public View and it's going to return a un 256 which we'll call uh HF which stands for health Factor so the first thing that we're going to do is you're going to need to get how much money that they actually have so we're going to create a new function actually called get account
info and going to pass the account and this is going to return a un 256 uh borrowed value in eth and a un 256 collateral in eth because we need to have them have the same unit the um same unit of measure so that we know exactly how much value uh that they have so we'll do a function get account info address
account and this will be uh a public view as well and this is going to return those two numbers it's going to be a un 256 borrowed value in eth and un 256 collateral and eth and I had no idea that my elbow could get so tired from holding this up this long all right cool so get a count
info and basically what we're going to do is we're going to uh loop through all of the possible coll Al and see how much they've they've added up now we don't have uh not going to have time to like add like a you know allow collateral so we're just going to cheat a little bit up at the top um we're just going to do an array um an address array called uh um sore allowed tokens and we're just going to hardcode this um normally we would add like a add alloud token token remove allowed token this is like the the collaterals that we allow on our protocol uh if you go to a
you know most protocols have some type of like hey these are the ones that are not risky enough that will will at will let them be collateral basically um and they have price feeds so um for this uh for now I'm just going to kind of dummy them as address zeros so it's going to be two address zeros but these are going to be like an ec20 token address we could put like the we token address bat token uh Etc and then let me pause here is everyone following along or are there any questions so far who here is is like I'm totally lost I don't know where we are nobody's like that who here is like I'm following I'm with it I know exactly what's happening you're the one who was like
yeah use Brownie and Foundry get screwed um uh because I did the demo in in solidity although I have done a bunch of these in Viper um next time next time I do love Viper just FYI uh okay cool so we're all following along great so we have this array of uh allow tokens so down here we're basically just going to Loop through those in a little for Loop you 256 that was really just a way for me to rest my arm uh un 256 uh index equals zero index is going to be less than S allowed tokens. length uh
index Plus+ oops index Plus+ and now basically we're going to do um un 256 amount equals um s account to token borrows of user account oops sorry it's on account what do we say account to oh yeah account to token amount token amount that's what it
called yep count to token amount uh so we'll do account and this will be sore allowed tokens actually let's make this a little easier address token allow tokens of index and then we got to get the value uint
256 value in eth is going to be we're going to have to create a new function called get eth value of the uh of the token and the amount and then what we're going to do is we're going to do un 256 total collateral oops equals zero and then outside of this or uh excuse me in here we're going to do total collateral equals total collateral plus value in E so we're going through this list of tokens we're going to get um did I spell this wrong Undeclared
identifier there's going to be typles all over the place here yeah thank you count with an N ah well uh it's it it's G to be quicker for me to just keep it spelled wrong a question yes temporary temporary variables create more gas it does yes so if we wanted to optimize for gas we wouldn't do this but I'm optimizing for readability here yeah yeah yeah good great great question really good question yeah um cool so we have this total collateral and E uh and we're getting the value of of our total collateral and then we're going to have to get the value of our total borrows
and basically we're to say okay value of our collateral minus the value of your borrows boom do you have more collateral than you have borrowed that's what we're going for here so now we're going to go down here we're do function and I have what 9 minutes left N9 minutes yes 15 even better all right get e value and then yeah as as this gentleman over here did if you have questions just jump in we have a small enough group and um it gives me a chance to not have my arms up uh which works out really really well so we have we have to create this function get value eth we're going to do the address of the token and then the
amount so we can price their collateral this will be a public views returns uh unit 256 and here is where we where this kind of allow tokens array is really important right uh in order to price our collateral this isn't some information that we're going to find on chain right the price of your assets is something that us humans have just kind of assigned to things right we say the price of eth is you know $1,300 or whatever is right now the price of die is one the price of uh the maker token is you know whatever it is right now that's not like some fundamental thing that lives on chain that's something
that we've assigned so in order for us to work with that we're going to need to work with an oracle so we're going to going to import uh the chain link code in here and we're going to read off of what's called a price feed so if you want to learn more about how these price feeds work how these oracles work they're decentralized network of uh chain link nodes and they deliver data on chain um so that we can use it in our defi applications like this one so at the top we're going to add some chain link code in here we're going to do import at chain link SLC contracts SL srcv 0.8 interfaces inter okay
T V3 interface that's s and with this interface we're able to read from these price feeds right so this price information is already aggregated for us all we got to do is read it off the the contract and this aggregator V3 interface allows us to do so so we'll have to add this at chain link contracts copy while that's being added way down here in this get eth value down here we're now going to say aggregator V3
interface price feed equals and this is where uh whenever we have whenever we add one of these tokens we're going to need to add the price feed associated with it right the price of eth is going to have its own price feed the price of bat is going to have its own price feed price of maker etc etc so normally again we'd have like an add price feed with your tokens we're just going to make it a little uh simpler here we're just going to create a mapping of address to address and we're going to call this um we're going to call this sore um token to price feed
oops talking to press feed and we're just going to assume for this demo that in the Constructor we say Okay um address zero has price feed at address you know XYZ address 2 has price feed at XYZ but again we don't really we're going to run out of time because I'm typing very slow so we're just going to assume we already did that um this will still compile because everything all the addresses will just be zero and all the price dudes will be zero but if you want to get a list you can go to docs. chain. link uh ethereum addresses scroll down and there's a plethora of of data to choose from and price feeds to choose from so we're going to say price feed equals Agra Gator V3 interface of uh sore
token to price feed token so now we have our price feed and then we can just do um this is going to look a little weird I'm going to I'm going to give you the I'm going to tell you why in a second into 256 price feed comma comma comma equals price feed do latest round data oh nice um oops uh price so Price feed. latest round data um latest round data is a function that
returns I think five variables so we just put commas because we're not actually going to use them so once we get this price now what we do is we just say return the amount and then we're going to Times by 1 e 18 um because this amount is going to be uh because we need to divide then by the price divide by un 256 price like so so in the reason we're doing 1 E18 first is because um uh uh price is in units of we as well so it has 18 zos amount will also have 18 zos so uh we
want to just multiply this by 18 zeros first so we don't cancel those out so we get a result that still is in terms of way uh who who is anyone unfamiliar with terms of way is this math like super weird to somebody who who here is confused by the math here okay great wow you guys are all wizards uh all right cool so now we have this function get sorry what's the question price comes no oh really good question so uh we're just in this function get e value we're just returning it as a u 256 but the
chain link price feeds naturally return an INT so we just cast it as a un 256 yeah it doesn't doesn't create any problems um if we had a if we had a negative price that might be weird for sure so if you want it to be super super um uh like if if you were coding this for more uh professional use cases you would you would definitely add some checks to make sure the int wasn't negative before you casted it but really good point though really good point but again this is demo code so we're we're taking a couple Liberties here as youve as you've been seeing um so cool so now we have this get e price now we're reading from those price feeds and boom this function will now return oh once I add a return in here uh down at the bottom we're just
going to do return total collateral boom like so so now now this is going to return uh oops [Music] turn oh okay actually we're just going to do we're going to cheat a little bit again un 256 total borrows because equal zero turn total collateral total borrows thank you um for now we're going to take a little bit of a liberty here um oh actually I
don't even need I don't need this so we would also roll through um all of the borrows as well so we're we're tracking how much collateral we have we would additionally do this exact same process for the borrows and then just do the reverse right uh get how much we have borrowed and every time we we take out a borrow we would track that as well we're going to do that but again in the interest of time I'm just going to skip it because I have five minutes left right okay great so uh now up here in our get account info excuse me we're getting our borrowed first Total borrows total
collateral we're getting our borrow we're getting our collateral and what we would do is we're going to adjust this for some liquid threshold so normally what these protocols do is they say okay you need at least 80 uh um uh uh 80% over collateral or 50% over collateralize or basically you need 120% to borrow 100% or if you have one eth you can borrow up to 08 eth right you can up to borrow up to 80% of your collateral or 50% of your collateral or whatever that is so we're going to do a little adjustment here so we're going to say un 256 um collateral
adjusted equals and then we're going to say collateral value um in eth times some liquidation threshold which for us we're just going to hardcode it into this function normally you'd put it as like a global variable here uh we're going to say it's 80 so we're giving an 80% threshold here so if you have one eth you can borrow up to8 eth here and then and then we're going to divide by 100 to make sure that uh our units of measure are correct and then we just do uh
return collateral adjusted uh times 1 E18 divided by The Borrowed value eth and now we have a health Factor oops divided by excuse me not the borrowed value this one and then we do some checking to like make sure um you know if borrow value to e was Zero for example so we don't have divide by zero but we're going to skip that for now and now up in our borrow now that we've done all that we've pretty much done the vast majority of the work we need to do to have our borrow function so now here we would just do require
oops require um the health factor of message. sender is greater than or equal to some minimum Health factor or we just put one at the top and we're good to go there and the other thing we would do is we would track the borrows kind of same as we did with the deposits um but like the reverse so that below and I'm just going to skip it for now um so this would be like count to token borrowed um so that again below when we do this measuring we just measure how much people have borrowed but because I have three minutes left we're going to skip
it but essentially that's all you need for a borrow right we would add some some modifiers maybe no re-entrant is allowed more than zero uh where we check to see that the amount that we're looking to borrow is more than zero um if the token that we're looking for is actually in our token list um and some nod re-entrance stuff so that people can't finagle with our our stuff but um essentially you have the Bare Bones here right you know how to price your collateral and that's something that you're going to need in a ton of defi applications if you're uh doing some type of staking and you're allowing many different types of tokens you need to understand how much value people are staking if you want to make a Unis swap if you want to make a borrow lending
this is the super minimum amount of code that you need um uh to to do them so uh yeah because uh I'm sitting down here like this I wasn't able to type as quickly so we won't be able to go over the rest of it but those are really The Bare Bones that's kind of the functions there um again if you want to see the Restless code smart contract kitd minimal has all of this and more um it has a test Suite as well some deployment scripts in haret um and yeah any other questions about any of this stuff yes yes you're right the health Factor should definitely be checked before the token is transferred I put it at the end just to to to be like making more sense but yes that is a re-entrancy
risk you would not want to do that excellent point yes Al also updating the the internal the internal status of the of the class it's before trans making a trans defective transaction what's the question Sor so no that actually the same happen with updating the internal dictionary or map in terms of the amount because it comes before the transfer because of the reentrancy attack I understand so updating the the internal state of the object comes before the transactions yes uh 100% correct yeah so these these uh these parts where we call um both of these lines we should do these later yes absolutely we should do these at the end
so so excellent point yes any other questions other than when [Laughter] Viper all right cool well uh we thank you all so much hope you learned something here uh like I said feel free to go to smart Contra kitd and uh it's open source so if you want a specific thing actually feel free to make a uh an issue be like hey I want Viper um and uh yeah or or AP Works uh for for the AP Works team that's here so cool well thank you all so much [Applause]