Skip to content

Latest commit

 

History

History
13 lines (13 loc) · 21.6 KB

Lesson 6.md

File metadata and controls

13 lines (13 loc) · 21.6 KB

Chapter 2, lesson 6

We'll continue the previous kind of theoretical talk about how to scale contracts with a more concrete example of various contracts that people are interested in and show how those principles apply to those examples. We'll talk about the token standard and ERC20 and Ethereum, about multisig, plugins in the words. We'll talk about the staking pool. And we'll finish with a summary that once again kind of highlights the common idea behind this approach.

ERC 20

Now, first example is ERC 20 vs tokens. In Ethereum, as you know, the most popular token standard is called ERC 20. And in tones something similar to it for the custom tokens is the jetten standard that was proposed last summer. Now, what are the crucial differences and what does it teach us about scalability? If you look at the ERC 20 token standard, then each token is effectively a single contract in Ethereum that acts as a smart contract bank. And as any bank, it has its own internal ledger that keeps track of clients balances. So if you take USDT, popular stable coin, USDT is implemented as a single contract with a canonical address that identifies this stable coin. And it has a list of accounts, effectively just two pairs of account identifier and the amount of those coins and his balance. And it has a little bit of code that permits the account holders to do the transcripts. When they come in and say I want to transfer five USDT dollars from my account to someone else's, then the code simply forgets my line in this ledger, checks that I have sufficient balance and then deducts the money from my line and adds it to in other in other accounts line in its internal database. So this is very simple, very straightforward and watching takes care of all the atomicity issues. So the contract itself doesn't have to worry about you know, doing this changes atomically like the whole transaction is atomic, and looks pretty simple and easy. And of course, it doesn't scale. And it doesn't scale again, for the reason that if you have billions of users, then you suddenly invented the blockchain inside your blockchain. And in case of Ethereum, neither the outside blockchain nor, you know, contracts internally have facilities for sharding, like for infinite sharding. And if you try to do the same thing in ton, then you would get the sharding on the outside. So all the individual contracts could live in separate shards happily and communicate with each other efficiently. But our ERC20 contract, within its own shard would not scale and this will be a big problem. So in ton, there is a tip number 74 Jetten standart that specifies a scalable approach to tokens, where instead of storing this table, inside the central contract, instead, we still have a central contract, but we call it a mentor. And this contract acts as this authenticator to issue individual objects for individual user. And whenever you will come into the subject and say, Could you please meant some number of tokens to this account, what they're doing, they're creating a separate, smart contract that is tied to that account to that word, and contains in itself, the number on the balance, and the other user would have the similar thing, but this contract will contain their wallet address and their balance in terms of this tokens. And here's the interesting thing. So whenever you want to say I'd like to transfer tokens from one account to another. What you're actually doing is you're sending the message from your wallet to this a contract that is called Jetton Wallet. However, I prefer to call it slightly differently. Unfortunately, the standard now already uses the term ?jetten? wallet. So this is what we will be going forward with. But think of this is not really a wallet, it's just a kind of balance record, right? So this specific contract that keeps the balance of this specific token. And if you have three different stable coins, like USDT and euro and some breached Bitcoin, or whatever you have, then for each of those, you will have separate contracts. Now, if you look at one of those contracts, that stores the balance for USDT, then first it will receive the message from your wallet saying, Could you please you know, transfer the money to some other address this digital wallet would authenticate requests that comes from its owners. So it will not allow such a message to write from anyone else, obviously. And then what it will do, it will send a message to the similar instance with the same code as itself, but initialized with the another user's wallet address. So it will deterministically construct the contract address for its own sibling effectively. So think of this as all these like jetten balances, they are spread among the sibling contracts that are differing only imbalances and their owners. But otherwise, they have the same code exactly. So we'll construct this other like address for its own sibling, and send a message to this address saying could you please transfer 10 units to yourself. And for itself at the same time atomically, it would decrement its own balance. So it would decrement its own balance by 10 units and then send an outgoing message to its own sibling saying could you increment your balance by 10 points. And when the sibling receives this message, it's called receive tokens message. What they will do, they would check the message sender and reconstruct the sibling address from the information that they know like the sender's wallet address the code of this contract. And it will check that the sender matches this reconstruction. Because if it doesn't, it means that some other random contract told this contract to receive money effectively from nowhere. And we should reject such requests. But if this message was sent from the same code, properly initialized that our own contract that means we can trust that it properly authenticated the user and decremented its own balance, and that in the whole first place, it had the balance to start with. And this balance was properly authenticated, originally. And so we can trust this message and increment our own balance. So you could see that while those two sibling contracts, kind of verify each other and transfer message from one to another. This works in a completely, you know decentralized manner. Because if you have another pair of such contracts for the same token, like same UCC token, for instance, in some other accounts and some other short chains, and they're doing the same thing, those transactions will be completely disconnected from the ones that we just talked about. So these pair of contracts would communicate with each other independently from the other pair of contracts. And this means that if you have a billion of users, using your tokens, all those billions of transactions could be shorted and spread out in the system and will not interfere with each other, it will not create the bottleneck. The only possible bottleneck is the mentor. That would create initial, you know, transfers that would you know, receive the coins and get them out of circulation and create new tokens into circulation. So that would be the only potential bottleneck. So if somehow you design a system that has to go through the mentor all the time, then that would be the bottleneck, but you normally wouldn't have to do that. So you would probably have people rarely go directly to the mentor, and more often can be trading with each other and you always can kind of shut out and scale out your minting facility by meeting to multiple contracts, like you know, hundreds of Intermediate accounts, and then distribute tokens from those individual accounts to individual users. And this is how you could scale up by 100 by a factor of 100. So this is this, how the tokens work, in turn, and there is a great documentation in detail how this works by Tyler Cohen, who is also co author of this course. And you can find it on Tom society, it's been easy to find the anatomy of the jetten wallets and how they scale. It's a great article that goes into all the details how this works.

Multisig

The second example is multisig. So multi-signature contracts are deals that allow a number of users to sign off, on access to value. So if you have three people, and you want to any two of them agree to unlock the funds, then you need something like a multi-signature contract. The way traditionally it is done is that the contract stores the list of signatures and verifies that some subset of them and unlock value. The problem with the 10th implementation is that you're you will have to decide who is actually paying the gas fees for performing this operation. And you have to decide whether you do intermediate storage of your request on chain or the ordered off chain. So if you do off chain, that means that you need to invent some kind of communication channel to do what one person initiate the request and store it somewhere somehow, like send it over email or over telegram to another person, they have to input it into the wallet and add the signature into this thing and then combine everything together in one message and then send it to this contract that will verify it and unlock the money. So this creates a lot of friction and overhead of doing this off chain communication and it's going to less decentralized. Alternatively, you could do this on chain, you can say okay, I initiate the request, I store it in the smart contract. And then the second person can you know, wake up in their timezone come later detect this on chain and then sent their own message. And this simplifies things greatly because you're using Blockchain for the intended purpose of recording overstates your application. And this helps you avoid creating extra centralized infrastructure to keep track of the sticks. And also the incentives are better aligned, because now every person pays the fees to interact with the blockchain individually. And no one is potentially getting hurt by you know, paying for someone else. However, if you're storing the state inside the contract, then you run into the same kind of scalability and denial of service problems, like what if somebody's in sheet, one request, or somebody initiates the request, and the other party initiates a request? Do you keep track of those requests for each party? Do you allow multiple concurrent requests? And if so, like, would it you know, go out of brands? What if someone is kind of trolling the system? You have two honest participants in one dishonest one always sends in repeated requests that, you know, override the other requests? How do you resolve this? So ideally, you would not have to even like, have this problem if you just allowed anyone to create as many requests as they want, and they would not interfere with each other. The only question is, where do we store them? And back to our original principle, the place to store those requests would be the blockchain itself. So you would have to tokenize those requests. So let's say you have the multi-signature contract that specifies the list of participants and then the request comes in says, I want to initiate the transcript. What do we do? We simply create a request contract as a token, so to speak, or like think of this as a, maybe an NFT or something like that, kind of simpler because you don't have to make it transferable. It's just this contract that has has to exist only for you know, 24 hours or something. So the person comes in says, I want to initiate this quest. They are authenticated, the request is created as a contract, and then anyone else could come into this request contract and add their vote into so I other parties could, you know come to this request object and add their vote and request would know the parties because we'll have a copy of the participants would authenticate them and and increment its counter. And at some point, the counter would be reaching the mark will say, two out of three, so twitches two, and it would resolve itself to go back to the multi-signature contract and say, Hey, you could verify me just like we verify tokens, you could verify that you issued me, here's the you know, all the info that you need to do about this request. And at this point, multi-signature contract would do the checks and receive the message that it needs to send out to the network with like the value the parameters, whatever your multi signature contracts, holds, and will satisfy this request and issue this message on behalf of itself. And the beautiful result here is that all these contracts would have constant time operation. So if you have you know, three users, they will have those shortlist of users. And every time you receive the message from a user or friend requests or issue a request, all these operations will be constantly so you know exactly how many fees, you have to pay, and there is no possibility for denial of service. So if any rogue user creates million requests, they would create million contracts funded with their own fees that they have to pay. And no one else has to care or strive to satisfy those requests. That's an example of a scalable multi-signature contract. And this is going to work fine when you have a shortlist of participants. But if you want to create something like a large scale, like for 1000s of people, organization, then it's more like a DAO the decentralized autonomous organization. And then you probably want to tokenize participation. So instead of keeping a list of participants, you would issue voting tokens, and they would vote with those tokens. But then you might also have the same principle of creating those requests. So that's, how you would scale multisig and again, you will see that you have this list of requests and use blockchain to store this list instead of storing it inside the contract.

Plugins in the woods

Third example is plugins in the woods. So every word is effectively authentication device for the user. So it has a public key and issues messages on its behalf to control tokens, NFTs, like DNS and all sorts of liquidity pools. But also the wallet can be I can delegate access to additional code. And number one reason is to use this delegation is subscription payments. So if you have a subscription payment, and you want to create a contract that has full access to the world, and implements the subscription logic, like allows some third party to take some amount of money every time period, like every month, and this logic will be hard coded into the subscription contract. And the contract itself from the world's perspective, it will be a plugin, and the world would fully trust it because delegates to the trust to this contract. And this contract would be instantiated by the users client application like a timekeeper, wallet. And in so this means that the users preferences will be kind of spread out between the core wallets so it's just the public key and all these plugins that implement their own limits like authorization conditions inside themselves, for instance, that subscription plugin would know the amount of money and the time period, but also know the recipient who is allowed to receive the money. And then it's not a problem of the user to keep around this contract, it will be messaged by some other, you know, third party system to draw money from that account. And at any point, the user could come in and remove this plugin. And the way to you need to make it scalable is actually like three faults. First step is you probably don't have to make it scalable. If you imagine that the user has a limited amount of subscriptions, maybe up to you know, 10 or 20. They could just keep this list in the wallet and this is what the wallets version for does today. One way to make it more scalable is to especially if you want to make the plugins much more powerful and allow the users to extend their wallet in more interesting ways to just subscriptions then you probably would have, you know, maybe up to 100 of contracts. And you also would like to have other you know, parties to for whom these plugins are created to pay the rent fees and not bother user with them. And to do that you would you can imagine the wallet architecture where the list of plugins doesn't store the individual contract addresses, but instead stores the contract code. So if you wallet supports a feature called subscription, then you don't need to list all the 20 subscriptions that you do, you could just have a list of just one piece of code that says subscription. And then anytime you receive a request from any subscription, then you can just check whether you deploy this code. And whether you trust that code. And you then don't have to worry about how many subscriptions are out there, someone else will be paying for them. So there could be no hundreds, but you will only keep the information about the coder to trust not the actual contents. You just need to remember, like, you just need to have this code authenticate itself and not initialize itself if it's not properly authenticated by the user as well. And this allows you to dramatically scale this list of plugins by just keeping the list of supported codes. And if you support subscription version one, and then subscription version two, and then maybe some other plugin that you know does another thing, then you may have you know, hundreds of particular contracts are to use this code, but you would only keep a list of three items in your world, which would save a lot on on rent and gas for you, as a user. And finally, the third, like the third, make the most radical options to have this one more level of indirection and have either like signed pieces of code, and you will just receive a message from arbitrary contract and check whether, you know, their operation is actually authorized by the user signature before and so you don't have to store anything in the world. But that would create some overhead for checking the signature, but would be totally infinitely scalable. Or you would have a more kind of jet on like system where you would have a like a meta code that just as an indication then allows to be extended with arbitrary URL like user specified code embedded in it. And he would just do the authentication once and then say, okay, if I deployed that thing with the customized code that I don't even know about, but you know, the outer code, check the traditional logic, and therefore I can trust this plugin, and then I don't have to store anything inside my own world. So this is how you can make like fully, perfectly scalable wallet architecture. But it will probably have some kind of complicated architecture just to make it a whole working kind of harder to audit. So that's probably not the way we'll want to go. But that's an illustration of the approach.

Staking pool

And finally, the staking, I would rather get to here like copy paste the discussion of the staking pool from the previous doc and put it right here, where we will be talking about this example where you have the validation cycles, and you want to remember, not just the shares of the pools tokens, but you also want to track individual deposit and withdrawal requests as like NFT, like receipt tokens. So anytime the money comes in or request comes in to exchange money, and we cannot process it right away, we would remember this data as a token, keep it at the user's hands and not keep a list of those things, and then process them separately when the time comes. And to make it more secure. For each end of the validation cycle, we would issue another token that represents the state of the validation cycle where we would offload all the money that we have to do all the money that has to participate in with deposits and withdrawals for this cycle. So imagine that you have this staking pool where you have validation cycles. And in every cycle, you know, the total amount of deposits and withdrawals to process and you put them all together in one helper contract. And I always do individual per user deposit tickets, and receipts they all go in and get exchanged for actual money with those payout objects. And you do this payout object for every validation cycle, and you have them like once a day, something like that. And so you would have any number of pending deposits or withdrawals from a number of users. It could be Millions, you would have this payout object every day, just once per cycle. And you would have one central object that would do this, you know, central state transitions, authorized withdrawals, deposits and stuff, and process, the beginning and the end of the validation cycle. And in that architecture, you would have a number of contract type like kinds, and all of them would have fixed storage and fixed execution cost. And that would be fully scalable. Sticking pool around a single validator. And this also would be using the blockchain as a way to express the list of things in different contexts. And not necessarily you know, tokens or things of value, but just you know, pieces of data that you need to track at different levels. So that's one of the most complicated examples of how to make the scalable applications and talk.

Conclusion

So to summarize all the above. In turn, you'll think of this as you're not allowed to use lists, or dictionaries, or databases. Instead, you use the blockchain itself, and you turn your items of data into individual contracts, and keep the state and value within those countries. It could be per user or per unit of time. It could be long term storage, it could be short term, like transient state. But in all of these cases, you would put them around and we would use the tricks like child parent authentication where the parent knows that he should this child and child verifies the parent, or the sibling sibling authentication, like and in Jettens were to contract share the same code and know how to identify themselves so they can trust that the other contract actually fulfilled their part of the part of computation.