Gas Optimization using TrueCurrencies with William Morriss
ETHGlobal·Fri, Oct 9, 2020, 12:00 AM
Gas Optimization using TrueCurrencies with William Morriss from TrustToken
Transcript
okay so I'm will Morris I'm blockchain engineer charts token we have five tokenized currencies the biggest by market cap is true USD at a hundred and seventy five million dollars the rest of these were hoping to build up over time but they work in the same way these are tokenized currencies which represent dollars you can send to your bank account or in the case of the British the pounds that you can send to your pound account I don't know but the way that it works is that we have an app and we assign you an address and when you send it to that address it burns it and you get it in your bank account usually within the same day but if you're outside of banking hours in your own country then you will get it the next day it's basically as soon as we can get it to your account we get it to your account and we have sort of metrics to make sure that we don't regress in that category okay so how do I do I have to click ah there we go alright so we have hackathon prizes we're giving up 6,500 t CAD which is worth about five thousand US dollars that's the most amount they would let us give up we would have loved to give up more money but we love to incentivize people to build on our products and so it's 5,000 T CAD for the best use of true parents ease and 1500 T CAD for the runner-up and I'll be evaluating that based on utility the use of true currency features and user experience so you don't have to use true currency features you can just use er C 20 but if somebody else comes along and makes great use of them then hello then all the preference for that so that's these are substantial prizes but there's only two of them and I'll be judging and also need your aetherium address because these are cryptocurrency prizes and not like physical money prizes that also helped me get past a border security on my way in is if you came in with a bag full of cash they they're gonna ask more questions than if you come in with a bag full of cryptocurrency so currency's use very little guess in fact we're very confident that they use the less least guests of any ERC 20 token on maintenance but you can see the case breakdown here it's really for major cases for ERC 20 tokens based on the preconditions for transfer and in most of those cases were less than everyone else in particular the worst case which is called reducing the nu which is when you reduce one account and creates a new account these these cases that's the case in which we beat everyone out of the water it's also the case that's fairly relevant for withdrawals okay so the way that we got that good is by profiling and I encourage everyone to profile for guess when developing smart contracts the way that you do that is you create a test suite and truffle or whatever framework that are using that evaluates the many different cases that you might have we have 46 cases for our own contract and there's also preconditions to consider you want to control as many variables as possible such as the time stamp little things like the time stamp parameter in the call data having one zero byte can cause variance in your test so you want to control that using techniques such as truffle time machine developed by my friend Ethan Wetzel who did you work to air swap you want to measure gas used as returned by the transaction receipts so that's the when you do awaits transaction in truffle that returns a dictionary and one of the fields in the dictionary is gas used and if you evaluate that you can compare it to the previous time that you ran it by writing results to a file and see that if you got a regression or if you got an improvement you want to see that and also include that in any pull requests you make and we recommend measuring as many different possible cases so that you can see even edge cases that might be much more expensive than the regular cases and controlling for those so first we're going to talk about high-level guidelines don't use external storage contracts for data that you'll read often that's because if you call into those contracts there's overhead and that overhead is only going to increase with E - E - so just keep all your storage internal don't externalize it there's no reason to like it well good object-oriented programming often says you should have a different class that representated you don't really want to do that on chain in the case of having a different contract that has the data because of the overhead you there's a contract called Gemini USD that has a very bad behavior here that it stores its token balances on another contract so first it reads the token balance then it adds it then it writes it and each of these is a different call and they didn't even consolidate it it's pretty inefficient so also if you use a custom storage layout using solidity assembly then you have to be aware of existing storage that might be in your contract for catch act mappings or erase so there's also a thing called upgradeable proxies that we use and that you may use but our recommendations first is to not use upgradeable proxies does everyone here know what in gradable proxies does anyone do you know what an upgradeable proxy is okay do you know what end up great people proxy is you know yeah you can change the code yep using delegate call so the way that it works is that you have a proxy contract that tells you where the code is and it delegate calls into that code so the data remains in the proxy contract but the implementation is in the implementation contract this allows you to if the EVM changes how much gas things cost you can do an upgrade and if the EVM like if something breaks you can actually fix it before the hard fork but without actually changing your address now this is important for some things more than it is for others if you're a major token and you don't want to break exchanges like ever and you don't want to tell them to change their address you don't want to have to do a community announcement and get everyone to use your new token or migrate using a redeemer then you can use this and said but my first recommendation here is to not use that that only use it unless it's absolutely necessary if you're developing defy just allow people to move their money out like for example with unit swap you can pull your liquidity you don't so that people have a way out if things are going to break in an upgrade that's slightly better than having a proxy but if you do have a proxy don't put many methods in the fallback country proxy contract that's because the delegate call happens in what's called the fallback function do you all know what fallback functions are in solidity okay yeah so if you have many methods in your fallback proxy then the proxy has to check for each of those methods before it delegate calls and so the more methods you have the higher the overhead of your proxy will be so you don't want to have more methods you want to have as few as possible you should also consider writing your proxies in assembly if you don't have methods that's great certain factories use proxies for example the eunice watt Factory creates proxies those proxies are written an assembly but they don't have any methods so it's ideal matches all these recommendations and beware storage conflicts so if you have an implementation address and storage make sure that doesn't conflict with anything in your implementation because you don't want to override that and over time when you're developing way the proxy if you have a storage proxy you have your storage layout and then you change it use the variables don't move the all the storage is gonna stay where it was at the time that you upgraded so you want to deprecate slots that you're not using so that you don't go back and reuse them you wouldn't want to have any conflicts of that kind those are guidelines related to proxies so now sharing data so suppose you were you have a bunch of contracts that want to refer to the same data and that data doesn't change very often so suppose it's a blacklist for example of addresses that are not allowed to receive your token then you don't want to have to call into a contract because that would be overhead you don't want like every time you do a transfer to call into another contract and an earlier implementation of true USD we did because of the object-oriented paradigm which is the one that we were raised on that if you keep your data in one place then it's seems to be more efficient but actually you want it to be in ten different places so that you don't have to call into those contracts if you're not writing very often like if writing is an admin functionality for example or something that only happens every five minutes or every hour but people are going to do transfers much more often than that then you wouldn't want to call into an external contract because there's considerable overhead to doing that and so it's better to instead have a right through like controller so you control the writing you write into one contract and then you have subscribers to that that so that's when you when you write it it writes through to those other contracts so that they get the data they need and it's internal to them so that they don't have to external call into it external call I already said I expect the cost of it to increase over time currently it's 700 but there's also the call data and the overhead of figuring out what method you're calling and loading data of course and returning it all this is not free it can add a few thousand gas to your transaction and that's not friendly you can save several percent by in keeping that internal so that's our recommendation for if you write rarely we adopted this and it saved considerable gas we adopted it in February so next multilevel mappings so between the left and the right which one do you think is cheaper have a look at it there's a constant deposit address and there's a mapping but the only thing that's different is that the keys for the mapping are flipped so the first key is bytes the constant and the second key is the address or vice versa on the right side where the address comes first followed by the mapping and what you're doing is you're calling attributes sub deposit address which is a constant and 2 which is a variable so the result is shown in the bullet point below so which one is cheaper the say left or right yeah so the left one is cheaper that's correct and that's because chechik of constant can be simplified by the compiler so if you have a registry of attributes per address as we do then if simply flipping the order of the keys it saves gas because you don't have to compute the the the catch act twice you only have to do it once so that's a cool little trick I discovered in the bathtub one day cool yes because of the order of the catch hack and if you ever forget this you can look up the solidity read the docs in the miscellaneous section it lays out how the storage works for a multi-level erase and then you Reid arrived this but yes the constant first if you can get constants first in your mappings multi-level mappings then that will save gas cool arrays so the if you wanted to clear an array the one on the left might be a very naive solution you set the thing to zero then you decrease the size the length until there's nothing left but actually you can just do the thing on the right and it does exactly the same thing but in substantially less gas so if a concept of how inefficient the first one is first it would set the value to zero and then it would set the value to zero and then it so it so it would do it twice the compiler does not know not to set it to zero twice it just does it anyway and then it doesn't optimize the fact that you're actually going to decrease the length each time it would it doesn't optimize that so if you want it to clear a bunch of elements and then reduce the length of the array you should just change the length of the array so here it says I equals zero and then but the length minus minus also sets it to zero yeah so that's not good but that's what happens it's not something you'd expect just looking at it that changing the length of the array would set it to zero you might do this to save gas for example when you change ones to zeros it reduces the it gives a gas refund to the people operating the people executing so if you're done with space you should clear it but be careful about how you do it because if you did it on the way on the Left it would actually not save gas because the overhead would be so substantial so at the end of execution if you've cleared state you get gas back based on how much state you cleared if you clear a nest or slot which is storage slot of 32 bytes you get back 15 15,000 gas which is a lot of gas and if you delete a contract if you call self-destruct that refunds 24,000 gas which is a lot of gas for reference a transfer is 21,000 gas and at store creating a new slot is to that 20,000 so that's all for this slide and now we're going to talk about true currency features and if you use these features you'll have an edge in the competition so first we have a feature called deposit addresses so in one transaction you can create two to the twenty which is about a million deposit addresses that all forward tokens to your central wallet you can save gas on your deposits to your exchange or centralized service while tracking the originator so a common paradigm in exchanges is that they wants to accept an address hello and so they wants to they want to accept at an address they knew who sent it they give everyone their own address and if you send to that address then they know that the money came from you but then they have to sweep it which is a separate transaction and it costs them money there's overhead to that it it's sometimes passed on to the customer in the form of a fee but if you use deposit addresses then you don't have to charge that fee at all what we called it auto sweep and we tried to get that trademarked but they said that it was too accurate of a name for what it did that it was too close to the actual description of the thing that it didn't qualify as a u.s. trademark so that was annoying but being able to create a million addresses in one transaction that all forward to your centralized well it it can be useful if you're an OTC desk or if you are a centralized exchange if you it omits to transfer events when you do this it omits the transfer to the deposit address and then the transfer to the to the centralized wallet and but it only does the S store once so it's considerably cheaper than sweeping like more than 50% cheaper we also have Redemption addresses which are the feature that lets you send to your bank account if you send an address if you send it to your Redemption address we burn the funds immediately in the same transaction so we don't sweep a few of our competitors do suite including circle and PACs and this costs them overhead but we can do it and operate much cheaper because we do it automatically here is an example of a Redemption address it's has many many zeros in it because we're issuing them upwards numerically so as you if you create a new account you can get a really short address we're still in 3 digits right now though we're now out of the Oh x9 so the next I think we're currently in a if you get a new account it'll start with an A I'm gonna actually open this URL if I can but I'm gonna OH nice first try so here you can see this person's activity all their redemptions here they redeemed a million dollars five million dollars two million dollars three million dollars down here 16 million dollars which is our largest ever redemption we gave them the money very quickly because they were on a network called subrogate which recently IP owed by the way you can invest in them now silver gate is a very cheap bank that is that charge is nothing for internal transfers and a lot of crypto traders use it so it's very popular and that's why we're on it so like transfers to another silver gate account yeah and they have a good API and it's their internal transfers settle programmatically in less than a second so when people redeemed through silver they get their money in less than 15 seconds we only wait because we want to make sure that that was the block but currently none of our clients are minors so we aren't super worried about 51% attacks on the Theo theorem network okay the next page is recipient callbacks so if you all are familiar with our c2 23 there's a callback function so you're able to get a callback when you receive money this could be useful in a variety of ways but mostly for developers that wants to know when they received money and their contract so it's opt-in so you have to call into a registry to get this callback and we evaluate that you are in fact a smart contract before you get this and if you and you actually get it from ERC 20 transfers instead of from a or C to 23 we're considering adopting to 23 one difference between 223 and this is an additional parameter bytes which would be useful if you wanted to provide more data but we don't support that right now mostly because ERC 223 is not standard yet so it's actually EIP 223 but we find this as useful for contracts we've gotten feedback from several depths that they'd like something like this and we're working with Eunice WAP right now to use this they're probably going to be the first customer of this feature but it's also somewhat useful for if you are doing an IC o---- then it changes the experience from first approving the contract and then transfer from C it replaces approve transfer from for a lot of context to just transferring money to the contract which is a considerably better user experience we also do gas sponsorship so if you so far we have 25 billion gas which is a lot of gas for context each block has 8 million gas so this corresponds to about a month of blockchain activity it's very similar to gas token if you know how that works but we without the overhead and of calling into the gas token contract we have a bye wall for guess we are often during periods of low activity true USD it represents like 5% of all network activity because we buy gas when its cheap and it would be higher but higher than 5% during law activity but many miners do not mind below one gig away so you don't you have to pander to the miners that will accept low gas prices and when we have more guests and Reserve we use a lower gas price so this means that we have a nice equilibrium that if if we got low we'd pay more and we pay less when we have more which results in a long-term equilibrium we wouldn't want to have super equilibrium because that would mean that we're paying too much we want to pay precisely as much as we need for there to be a large reserve there was for the entire month of September a something called a fair win that was like eating up the etherium Network and causing gas prices to not fall below 1 gig away for the entire month in fact for the most of September they were at 10 gig away so we didn't buy anything and we were fine because we have such large reserves of gas the atera one would have had to have been an attack on true USD for our for us to run out of gas and because we buy at a lower gas price than when the gas is refunded we get a really nice arbitrage because we buy gas 0.20 one gig away but most transfers happen around 10 gig away finances transfers for example happen at 40 so because of that difference we get a net gain of about 50 X and we spend on average $1.00 per day on this so it's a very good investment from our founders perspective I was actually able to actually convince them that this was a good idea [Laughter] so last feature is blacklisted contracts so we prevent certain contracts from receiving our currencies and it prevents the surprisingly common mistakes so now for the giggle time look at all these people losing their money by sending it to the token contract so here's died someone's sending 500 die to the die contract here's tether someone's sending 51,000 tether to the tether contract there's USD see someone's sending 45,000 US DC to the US DC contract can't happen with true USD you can't send sure us to do the true USD contract so you can never be superset nothing yep they get rekt yes so that's fine questions okay I'll pull up the code it's open source trust token true currencies and contracts gasps refund token I'm gonna try to make this bigger but I don't know so this is first so we have two kinds of gasps sponsorship we sponsor for s store and we sponsor for contracts so the S store first this is our contract sponsorship so we'll we deploy what's called a sheep a sheep kills itself when its master calls to it so the way that this works here's the assembly it's so that first when you deploy a contract it invokes the constructor which returns the data in the contract so the contract the called a that we passed that a constructor first pushes 27 which is the length of the sheep it duplicates it so now 27 s there twice and we push the number 9 which is the offset return datasize which is the which is the easiest way to push 0 onto the stack it's so you cheaper than push the zero return data size and code copy which copies the yeah it takes the the it takes the the code that was passed to the constructor it copies it into memory at the parameters that were previously passed nine and twenty seven so it offsets the sheep at which because this is offset 9 and 27 is the length of the cheap and then it returns so because the Sheep is now in memory it returns it and the rest of the code is the Sheep which pushes 0 on the stack the collar is the the person that called the contracts then we push ourselves so this is the expectation then XOR to figure out if it's invalid because if the caller differs from me which is the issuer then I don't want you to be able to destroy my sheep then I do jumpy which is the conditional jump and that's so that if if someone else tries to suicide our keeper then it's then it fails and then we do self destruct so that destroys the contract so the other one is much simpler it's the gas refund 40 here's 15 for example we load the length of the array if it's greater than 1 that is then we're able to refund 15,000 gas then we store 0 in that location and then we change the length of the array so there's an array that's full of gas and we refund it gas 15 fifth there's an overhead to refund and gas so gas refund 15 only Nets about four thousand gas but the larger ones are more efficient such as 30 the most common when we use for example for transfer from is gas refund 39 which does both suicided contract and it also sets a 1 to a zero so here's the the other sponsor gas one it just populates an array we do nine at a time so it creates nine slots sets them to one and that's all yeah we did this in assembly because we weren't satisfied it actually resulted in an improvement over not doing it in assembly and its effects our cost savings and if we had done this sheep in code instead of in assembly the cost and overhead would have been substantially higher something like nine times higher so we decide whether or not to refund fifteen or or not conditionally and so if if you are setting if your transfer like creates a new account then we're gonna give you more gas back than if it doesn't because we know during execution how much gas we're gonna use we know how much we're gonna refund yep and that's all open source in our trust token true currencies github which also contains the instructions for getting rinkeby tokens for this guy I'm gonna set up Kovan during this hackathon yeah which is always a scary thing to do cool I'm out of time thank you
Automatic transcript — names and jargon may be misspelled.