Ethan Bennett ~ Out-of-the-box UX Upgrades: Dai.js and DSProxy
Ethereum Denver·Wed, Oct 9, 2019, 12:00 AM
Ethan Bennett Presents Out-of-the-box UX Upgrades: Dai.js and DSProxy
Transcript
foreign [Music] everybody uh this is thanks I haven't earned that yet um we're gonna look at uh die JS which uh some of you may have experienced before it's our JavaScript SDK at maker um so we're going to do it slightly differently than some of the workshops in the past um and part of the benefit of that is you're going to walk away with a Dye react template which already has die configured to work with metamask um and then on top of that it's just a create react app so what we're going to do in this is uh we're gonna walk through just a few introductory slides then I'll show you the react template then we'll talk about the little toy app that we're going to look at in the context of this Workshop to kind of serve as an example of how to use some of these features um then we will walk through that code and then we'll take some questions so uh just a brief introduction to die JS it's our JavaScript SDK um it serves a few purposes for us at maker first of all it serves as like as a place for all of our middleware blockchain uh logic to sort of be centralized this allows us to not have to repeat this logic within all of our different user interfaces like governance the CDP portal Etc it also serves as a really easy tool set for developers to use to build on top of maker so if any of you have ever tried to interact with the maker contracts you may have found that there was some basically a lot of new terminology to learn a lot of logic to wrap your head around using the JavaScript SDK is much much easier so especially at hackathons people find it pretty useful I think um so we have some built-in Dev tools on top of the general functionality for maker um some of the really the coolest ones I think and the ones we're going to talk about here is our transaction manager which watches the state of a transaction we have a token service which we can use to check allowances on the tokens and also to interact with the tokens easily and we have a DS proxy service which I will explain in a bit more detail um so on the subject of that DS proxy this is uh this is going to come into play when we look at the specific app that uh is going to be the example for our library but one of the uh most common design patterns in our maker front-end apps lately has been using uh these proxy contracts to sort of uh make several transactions Atomic so if you've ever used the newest CDP portal that came out around Devcon or if you used Oasis direct you've probably experienced this where uh either in the case of the CDP portal you might lock eth and then draw die in the same transaction or in the case of Oasis direct you might Grant approval convert eath to West sell the West for die convert it back to eth send it back Etc so it's really nice uh obviously for ux reasons because it's way uh way less cumbersome for a user to approve a single transaction than five of them but it's all also really good just for General Security because if you're executing all these transactions atomically and one of them in the middle fails then the whole thing will revert and you don't have to deal with like stranded States or anything like that um so I will look at some specific examples of this later when we start looking at the actual code but I just kind of wanted to introduce it first because the language gets a little confusing uh specifically because there's actually two things that we call a proxy here and they're both directly related to what we're doing so the first proxy is what we kind of refer to as like a forwarding proxy um and it's essentially a contract that exists a level above the core contract of your dap and it's there only to run these transactions uh in a row right so that it executes atomically on chain this is important to be in a separate contract many times because if you're designing a smart contract your top priority probably isn't how many combination or how many transactions you can combine but rather how safe your contract should be so in this case we can just make a super simple contract right on top of it run those transactions in a row and call that function instead but if we want to make it as simple as possible in order to avoid creating new attack vectors and stuff like that we actually want to use something called a DS proxy or a profile proxy which is essentially uh it's there are many instances of it it's deployed for the user when they first start using the app and when you have it you can use the execute function on that proxy to execute the call data within the uh the forwarding proxy so that everything actually executes in the context of this contract that you own not in the context of this forwarding proxy so that has many advantages Beyond just being owned by the user it means that the user can recover funds if it ever gets lost and it also means that allowances that a user sets in one app can follow the user into another app so all of this might seem kind of vague right now but I think it'll make more sense as we start looking at code um I covered a lot of that uh so now just to kind of introduce this react template um die JS can be configured to interact with many different provider types this I've made uh default to metamask just because it seemed easier to get it up and running uh for hackers at the hackathon but you can easily change that to run on inferior or on a local node whatever you want to do the documentation is actually linked as you'll see in the template but just to give you an idea when you're uh when you're working on this later the master branch is the Clean Slate that you can use to create your own product project and uh the East Denver Branch you can look at to reference how some of this code can be used so now I'm going to show you that a react template um so basically it's a create react app um there's not a whole lot to walk through before we actually get the real code in here but a few things to note I've also created here um some directories yes good call how's that probably a little small still foreign okay I think that's good um so just a couple things to point out before we actually pull in like the that real project um I've created some directories here that just make it easier um by no means are they required to be organized in this way but essentially what we're looking at here is a maker JS file which has just the very basic configuration um in fact this doesn't need to be here and will only confuse um so you'll see we don't really need to pass in any extra settings or anything like that for the basic functionality but if you look at the documentation you'll notice other configuration settings are passed in and this object right here also this first parameter is what's telling it to use metamask um otherwise I've created a Services directory which we'll get into uh when we pull in the code and I'll show you how you can inject a service into the Plugin or I'm sorry into the SDK and use your own application specific logic with all of the built-in logic so real quick I'll just kind of show you also what it looks like this is a loading screen okay so it's a it's a pretty basic like create react app as I said but just something else to point out I'm showing the current address just so you have sort of a confirmation that it is connected to metamask um also die JS docs are linked right here so if you forget how to find them they're on the create react app so now I'm going to check out the finished project and we'll talk about what exactly it does okay foreign okay so uh this sort of example app that I I want to look at here is uh it's have can I get like a show of hands who used Oasis direct when it was up and running cool so a lot of you have um as uh some of you know then I when you buy die with eth on Oasis direct it was a single transaction uh that was executed without any accounts or anything through metamask so we're going to look at doing the same thing uh in that create react app only for the case of buying die with eth and also some of the like more necessary functionality like setting the slippage rate stuff like that isn't here it's really just for the sake of showing how it works uh but in the context of atomic transactions these are the ones we're looking at all right first this contract wraps the eth which turns it into West then we Grant allowances for the uh contracts to send with on the user's behalf uh we buy die from the maker OTC contract we unwrap the remaining eth because we actually have to send a little more eth than we than the pay amount in order to make sure that it covers slippage and then we return that remaining each to the user so what normally be five transactions in this case will be one transaction and we're going to do it by creating a new service and injecting it into the SDK the buy die service so the Oasis direct proxy I did not write this is the same contract that we were using for Oasis direct it simply makes transactions like those atomic for all of the buy and sell you know combinations so I just kind of want to point out a little bit about what's going on here um pretty much exactly what I said in pseudocode just a second ago but we'll see here West token dot deposit the value that's turning message.value which is the eth into F we're checking if it has allowance if the user has already granted allowance to the OTC contract to transact with on our behalf if it doesn't we're approving it and then we are getting the weth amount by calling otcs by function by the way the OTC function is the core or sorry the OTC contract is the core contract behind Oasis and our decentralized exchanges in general so that means also the new ease to die service and the coming improvements to Oasis so um here we are finally doing uh the buy uh we're buying dye for the west then we're returning the um uh buy token to the message dot Cinder and uh withdrawing it back oh and sending it there actually um so yeah do I think we should do questions at the end because of the microphone situation actually but if anybody has a burning question you can shout it out I won't be offended um okay so now we'll look at the actual code so you'll see here this new directory that I pointed out before Services um so there's a few uh just basic things you need to do to connect the your new service to the running SDK instance so I'm just going to walk you through some of the format here uh first of all uh makerdow Slash die is the npm package and we're importing the maker object from that so this is the same maker object actually that we see in uh this maker.js file where we create the maker instance that we actually use in this case however we're not creating a maker instance we're getting an instance of the defined services within the SDK so there are a few different service options there's local Service public service and private service for the moment it's not too critical to note know or care about the difference you can default to the local the main difference is built into the private it in the Public Services there are other life cycle functions that happen basically when they're connected so the private service or sorry the public service has a Connect function the private service has both the connect and the authenticate function so personally I only use that when I want to execute some functionality right at the moment that the contract or I'm sorry the service is injected into the SDK um and yeah so reach out if you have any questions about using that you feel that you would need to for the moment we don't need to so we're just using the local service we create our own class by extending the local service which is a property on maker and then after that uh we do have a little bit and the Constructor to look at we Define a name here this name is how we're going to refer to the service from other services and also from our other code um so I've just called this by die here we're passing name into Super and we're also defining all of the other services that this service depends on so this can be added as needed and you'll see some of these services are documented in the documentation others are not because some of them are more under the hood so again if there's anything that you find in the code that you think would be useful and it's not documented or something like that feel free to reach out the token service for instance I I know isn't on there but it's been on my list for weeks to do so that will happen soon otherwise after this all we have is the application specific logic so uh why would you want to use a service in the first place I think that at the very least it serves as a nice Organization for your app um so yeah on like in this case it's part of the app right it's living in a directory within the same react app but for many of our services for instance for the governance dashboard we actually published that plugin independently on npm and pull it into the UI so not only can you separate this logic from your component logic but you can also separate it from your UI entirely so it helps to not bog down your UI with the complex blockchain logic keeps everything readable so that's a really good reason in itself another good reason is it can access some of these under the hood features of the library so some of these features we'll look at here as we walk through this code others I'll just kind of point out for instance right now I'll mention that the smart contracts in our system are wrapped and have some extra functionality that get sort of injected into them this is primarily for things like the transaction manager so we can listen to the transactions as they go through it also happens for the DS proxy you'll notice I'm getting ahead of myself we'll get there actually so here is an example of how you use a service within another service so we're all we're doing is calling this dot get that's the way you do it for all of them and then you use that name where does the name come from it's just defined in each of these services so for any of these services that are defined here you can call this docket and it will work you can also chain them of course so if one is a dependency of a dependency then you can access it that way um so uh here we're getting the exchange service which actually I'm using in order to get the max pay amount from the OTC contracts that's a bit out of scope for this talk I think but um the high level of what's happening there is it's just um asking the contract for the pay amounts and then taking a slippage rate into account and setting that is a maximum amount that will be paid this is just so that users don't end up placing an order to buy tin die and then some weird stuff happens on the decks and all of a sudden the user's paying like 20 eth for that 10 die so the max pay amount is Paxton as the value and then we're getting the contract from the smart contract Service so that it will be wrapped here we're gonna get into the DS proxy stuff so I mentioned before that we have a proxy that's you can't really read that uh a proxy that's deployed on behalf of the user when they first visit the app so when a user has that proxy then it uh they pass the call data or more accurately the SDK passes the call data for those atomic transactions through a function on the DS proxy so that it all executes within the context of that proxy that's owned by the user so normally there would be a lot of uh leg work to do to make that work first of all you would need to query the proxy registry to find the proxy that belongs to the user's account you would also need to call or use web 3 or ethers to get the call data for a transaction and then pass that through the execute function and it wouldn't be very readable and it definitely requires a lot more contract interaction so in this case the DS proxy is handled by a service within the SDK so all we do here is we're calling ensure proxy which checks if a user has a proxy if they do we move on if they don't we deploy a proxy for them so that's all you really need to worry about here then at that point we can pass DS proxy in as a property in the options object that you can pass into any ethereum transaction which at first might seem a little weird because it's not an option that you're used to seeing for ethereum transactions but it's intercepted by the smart contract Service and it signals to the smart contract Service that instead of just calling the contract what we actually want to do is get the call data for that method and then pass that to the DS proxy owned by the user one more thing to point out here we're using the allowance service to require allowance for the proxy this cannot be looped into the proxy itself because it is for the the proxy itself so in some cases you have more than one transaction on the first visit the maximum would be if you didn't have a proxy you would see another transaction here and if you didn't already have allowance for that proxy you would see a transaction here and some of that should also be probably familiar to those of you who used Oasis direct because in some cases there would be a few transactions and then you would return and it would just be one so that's what's Happening Here a brief note though you actually can wrap the creation of a proxy into the forwarding proxy the complication here though is uh well there's two actually the first is it only works if you're paying eth because you can't make a function payable and die for instance and if you're calling this forwarding proxy which then creates a profile proxy and then sends the rest of the call data to that then it would have to first accept your die and then send it back so there could be ways to work around that but for Oasis direct at least they decided not to integrate that for many of the functions um another uh another reason that you can't do it um well for the allowance at least is then we need to allow the specific proxy allowance to transact and especially if the proxy doesn't exist yet then you couldn't do that yet so um you'll see some different states represented uh depending on whether a user has used the app before um what else should we look at the contracts actually will return to the contracts in just a moment let's look at the configuration so now we have this service right how do we inject the service into the running instance of maker so that's pretty straightforward as well uh first of all let me mention that this exchange property on the configuration that exists in this example Branch but does not exist in the master branch is not critical for you to like put in your own plugin that's actually there just for the functionality within the plugin so here we see we're also adding a property called plugins and we're passing in this array which is defined up here so the array is a function which returns an object we're going to take any existing config and combine it with the config that we're defining here uh you'll see here we're giving it its name by die we're also defining the buy die service which we've imported up here just from that JavaScript script file we were just looking at and then we pass in the smart contracts with another property here so the smart contracts can obviously they can be any application specific contracts that you need to build in the course of your hack here but you can also so a note on that and I kind of mentioned this in the beginning um I think that it's really important to not build your smart contracts with atomic transactions as your top priority I think you're much better off building your smart contract with security in mind and with your you know application specific priorities in mind and then coming back and building a second layer proxy on top of that to make the transactions Atomic so in this case you'll notice we're adding this Oasis proxy even though the maker OTC contract is already in the SDK the reason we're doing that is because that contract is the forwarding proxy it's not critical to the core logic of maker it exists at another level between that logic and the UI logic right so you can do that with any uh any contract really so maybe you want to build an app that interacts with some existing DAP in the ecosystem whether it's maker or auger whatever you could still build a forwarding proxy in this exact same way and add it to the library you can also do this if you're building a hackathon project and you want to you know write out your entire like core smart contract logic and inject it in so you can do this for an arbitrary number of contracts with arbitrary complexity and all that um so uh we're passing the contract in here uh the addresses and abis are defined in this folder here and um I think a lot of this will probably be a little easier to retain when you're like looking through it but I wanted to give a walk through of it just so that it's not um confusing what you're looking at and instead is helpful to uh you know serve as an example of how to use this functionality so now let's look at app JS which is where we're actually pulling in the service and we're calling it right so this is not an impressive user interface at all it's very similar to the user interface you already saw with create react app with a text box which allows you to enter an amount and a button which allows you to buy the die so um in this case uh we're you know we're just capturing the value here on click we're calling a function defined here in the component by die the reason that we're not just calling that service directly is is because that's so annoying um the reason we're not calling it directly is because maker isn't defined right away um in fact you have to await maker authentication before it can be available to use so uh that can cause problems sometimes because the app will of course render before that's done um it's also worth pointing out just so that you're aware when you're using the library that you need to await authenticate um and I I mean you'll see it if you don't but it's something it's a good gotcha to know about um so instead of calling it directly we're calling it here in this function and otherwise we're just calling maker.service you'll notice that when we're accessing the service externally we're not calling dot get we're calling dot service otherwise it's the same we're calling this function that we just looked at we're passing in an amount and then we're once it's mined it's going to show us a little notification that's mined if it doesn't mine or if it's uh reverts or anything we're going to see an error message so what I could have done and if I spent a little more time making this a fancy UI is showed a loading screen when we're waiting for the transaction to mine or any other kind of you know reactive sort of UI in this case there's there's not too much of that but um we'll see here it looks very very similar to what it looked like before but we have this really well designed input feels here um so now I'll show you how it works um in this case I'm using a mainnet my metamask account attached to mainnet and I have already built a DS proxy I have also already given allowance so in this case we're going to see um just one transaction and here we go you'll also notice just to point out all we had to do was call a contract function in order to trigger metamask popping up that comes with just the the maker configuration that's already built into that template that you can fork and use yourself so that should take away some of the overhead for building a Dap in this case we're just going to confirm and we're gonna wait this is on Main net so it'll be a second eventually we're going to see it pop up in the meantime uh let me first point you to some resources uh the first link here is the react template that you can fork and use yourself we also have the dye JS documentation that is also linked on the app.js page of the create react app dap Seth and hdvm just some cool adapt tools for interacting with the chain from the command line are linked here we have a graphql API that allows you to do read operations on certain maker specific data such which is CDP State you know that sort of thing and the docs are all here we also have a really really helpful glossary that's still under development for multi-collateral dye but this if any of you have read the maker contracts before you'll know its language of its own um it's pretty I've grown to like it a lot as I think a lot of maker people have but it is off-putting sometimes for people who don't know it so having a really easily accessible glossary is like I cannot overstate how helpful that has been so please look to that and we also have this really cool uh chat server it's basically like an open source slack but you can go to it chat.
makerdow.com uh it uh we're all in it all the devs and everything so if you have any questions you can't find any of us around at the booth or anything look for us there we're remote so there are people all over the world so somebody is online anytime pretty much and the dev Channel is a good place to go to look at um hey look at mind and so yeah I don't know if you can tell but there's an obnoxious number of exclamation points there uh so I think that pretty much covers it uh if you want a copy of the slides I'm not sure the best way to distribute that but I will try to do that otherwise if you search for me on GitHub or search for Diary act template that's the easiest way to find that and now we have about five minutes for questions if anybody hasn't uh also there's a microphone I think for questions yeah right over here cool come up to the mic but everybody can hear you in the room and on stream a developer wants to use dive by service outside of the react template context is that something that you'd recommend doing and is it only available in the die react template repository right now that's a good question um so that specific one is only available in the repository but uh actually this exchange service that I injected here the um if to die direct actually has that functionality as well as other functionalities so you can sell for you know erc20 to erc20 you can buy ether you can pay eth and it also has integrated the atomic create and execute functions for the ones that pay Eve so I kind of cheated because the functionality was already done but you can access it this way I would recommend pulling in this this service here rather than copying the code that's in in this app just because it's more extensive but yeah thanks hi can you quickly go through the part where you made the whole transaction atomic like where you show it like oh yeah yeah um so I should also specify that it's Atomic by like the it's inherently Atomic because it's in a smart contract right so uh here basically all we're doing is compiling different transactions uh or sorry different contract calls into one single contract function so these are all functions that are defined on other contracts within the maker ecosystem there's three in fact and actually you'll notice that uh We've like explicitly avoided having any logic in here pretty much everything you need is passed in as a parameter and most of those things are just addresses for the contracts they're interacting with thank you no problem any other questions cool thanks everyone hey everybody uh coming up next and we're just gonna go straight into this one uh is Andreas and Chris from kauri they're talking about focusing on the dev so this is developer relations developer experience so you're going to want to stick around thank you
Automatic transcript — names and jargon may be misspelled.