Skip to content
by Unity Nodes
NEAR Protocol

NEAR Live Contract Review | Episode 6: STAKE fungible token

about 1:09:59 long

Nothing is loaded from YouTube until you press play, and then without tracking cookies.

About this video

In this video we'll discuss having locked Ⓝ represented as a STAKE token. This is the first live contract review of a community contribution. Follow along with this repository: https://github.com/oysterpack/oysterp...

Follow the latest from NEAR Protocol on,

Website: near.org Discord: near.ai/discord Medium: near.ai/medium Twitter: near.ai/twitter GitHub: near.ai/github

#WhiteboardSeries #Blockchain #FutureIsNEAR

Transcript

6,709 words

Captions as YouTube publishes them, usually machine-generated, so product and people names can be misheard.

  1. 0:02

    hey everybody um this is another episode of Live contract reviews and today we actually get a review from a external contributor and let's jump to contract okay um so it's called near stake token and I haven't looked at the code or any details so it would be fun to do this live together um the idea is to introduce a token that is backed by state near tokens and then you can just uh transfer it and trade it and I assume it

  2. 0:56

    will uh supposed to receive a reward similar to how compound R tokens appreciate in price and later can be redeemed back to the original asset except uh in this case asset is near and um or stake near and then it collects uh more rewards okay so stake is back to near token and stake earnings EX sense um deposits near specify stake inol to delegate in Exchange customer receives a stake token storage

  3. 1:44

    fees any applicable storage piece I deducted from deposit this is kind of cool um and then they refunded when you withdraw right so State token value is total stake near balance divided by total stake token Supply um that's actually depends if all of the stake tokens are stayed to the same pool if not then it might be an issue because different pool may have different rewards and let's say you deposit somewhere to 100% reward pool then

  4. 2:42

    while you appreciate from other people reward you can also keep all the reward if you own the pool and state near not available yes this is a problem um if another is submitted then everything is locked all right um so yeah the problem is because they can pull relocks everything after another un staken action then if multiple people through this contract St into the same pool then

  5. 3:25

    they will need to either wait for unstaking to happen until they can send another one for four EPO or they will um break the withdrawal for the previous person so it's not easy um to work around un staken request will be held until a previous and taking request is complete that works yeah that's fine usually you don't need to unstake uh because you already have a stake in token which you can trade and

  6. 4:09

    like exchange for me or somewhere else potentially quick quick question um I remember looking at some of the core contracts and we had like an enum that was like the status was idle or like a transaction was like idle or busy basically is there there is something similar with staking where you have like a a status associated with it where it's like withdraw in prog in process of withdrawing or whatever or does that not

  7. 4:41

    exist so I think it was um for duration of the transaction so it was like if you it's for the lockup contract if you issue a transaction from a lockup contract then um we prevent you from issuing any other transaction from the lockup contract until this one completes and that it's done through this you I'm kind of locking the state of the lockup um except like in some rare cases um cool let let's jump into the

  8. 5:25

    contract so star in with lip and um so there are a bunch of modules um import and Global allocator oh let's start with THL so it uses near SDK to and some interesting uh dependencies so premi types allows to use like uint and stuff um and deflate I don't know what is the deflate crate isn't that like G gzip like compression Z yeah ZB or gzip or something um not sure can I go there yeah

  9. 6:33

    def B that's interesting so like to compress data you basically Exchange in storage which is more expensive towards um towards the computer but at the same time contract is more is larger so you paying for the like dictionary common dictionary of deflate once so if I try to build it um un unnown I wonder how large the contract

  10. 7:34

    is it has a rust Flags in in carg so that should be fine by building it without passing that rust flag for optimization all right let's continue for now um okay so this is the main structure it has a operator ID so some kind of admin role configuration config updated on block index um okay yeah the block time stamp is not needed so long as you have block

  11. 8:35

    accounts and um staking tools and order it set hey Chad hi sorry I'm late yeah so we reviewing a new contract that allows you to stake um to convert your delegated tokens into aupt p ible token and that is provided by Our Community member oyster Puck okay um failed use of and clar module your blockchain um where I don't see

  12. 9:37

    doesn't need nightly it doesn't need nightly yeah that's weird um I'm going to do quick search in a project and I cannot find near blockchain I think I maybe did something wrong maybe Target no Target is correct um not sure maybe I should have tried to build it okay let's see if there's test and I can try run test locally instead so cine allows to run

  13. 10:41

    test and let's see if it compiles so default is bent state is already initialized so you take operator d and the config so you is pass a config or not and the cool part about this is if you're because we use Json then if you pass config then it will be just present in adjacent but if you just ignore it completely this argument then it's still going to be valid so you can just pass operator D an account so it does compile locally just

  14. 11:38

    for some reason didn't compile for me um when I did cargo build releas all right yes so not sure why I didn't compile and complained about um wi and target maybe I don't have was Target for this target let's try

  15. 12:39

    near B engine cannot be found that's super weird um because it's imported here okay let's see on the left yeah I'm getting the same error here what's the file size also doesn't tell you oh it doesn't tell you which file doesn't comp oh account okay let's see account maybe it's just not imported in account no um okay let's try to move all parts

  16. 13:44

    up and um it shouldn't affect anything and use Imports and Ed variabl that doesn't yeah near blockchain from maybe nearest DEC is broken for some reason or something like this because some dependency was published let's see if I can still compile something um okay while I'm checking let's continue this all right so to we

  17. 14:49

    initialize operator with check operator ID it basically verifies that operator is not a current contract and it's a valid operator oh it's valid account cool um so config is either default or it can be passed updated to an index so we basically just record a current index accounts is default which is a lookup map is a prefix um zero cool that works and no accounts um and we have another set of stti in puls which we use dat

  18. 15:41

    ID uh two so this is a different way of doing prefixes but it's kind of cool as well it um allows you to just have one module so from rust like thing it is um it basically just means a slice of size one of u8 and this is a zero so it's pretty much the same that you can write as something like this I'm pretty sure you can do um like this um but this is going to but this gives you not a reference even so both of them going to be static

  19. 16:39

    so one way of doing this is kind of like this but it's um this is fine too okay so all of this is initialized they all um they all unique so all prefixes are unique so then it right States so this is not needed because you're going to use in it and it just can be Rewritten like this so you just return it and you write it at the end of the new because of the init um okay so just a two Getters that return

  20. 17:29

    operator ID and a block index use do you need the state right I remember no it it will happen it will happen automatically after init completes so this is not needed because of the innit decorator right right so it just writes to State whatever you returned yep um so this is not decorated with near Buon uh which means this methods are not going to be exposed plus they they have a private visibility which is also going to

  21. 18:18

    be so I'm going to remove cargo log and try to rebuild to see if a log file used something different from what I expect but it's strange um so this yeah this is the check that verifies is so and this check asserts that the oops that operator that the color is operator already then we have test a unit test that um initializes a contract verifies the default config block index that was passed from the context and checks it through the view

  22. 19:19

    call then this T passes a custom config verifies that um the the operator is different so this test actually can be also re written in more um precise way so for now you can see that the test is decorated with should Panic it means the test should throw a panic at the at some point of the execution but you can also add a message that should match uh what Panic it is so I'm compiling this test right

  23. 20:13

    now because I deleted loog file it has to rebuild everything and my terminal still compiles it as well I guess my CPU is pretty slow um so this just in valid account ID and as you can see there's some module from test mode that gives um helpers let's take a look your accounted is just cust to account using um a string okay so test completed and it basically said panicked because left not equal right so you can see this helper message that we can

  24. 21:09

    assert here I don't remember the syntax that's like expect it like this so you can Mark a module or a test with a specific message and then when you rewrite the test it will verify that the Panic contain CH this message so now if I modified something like oh no then it should fail because the Panic is different so the Panic was like Hey operator ID must B um where's my oh no uh I guess this is the assert message

  25. 21:59

    so it doesn't match the one that we put here that's why the test failed so if for example something fail at initialization that is different then uh then the test will not complete similar how if Point invalid account ID if you put it there then it's saying operator ID is not a valid account ID so we can just past this message here this is what we expect and then when I rewrite it it complet so this unit test make it more

  26. 22:36

    precise because they verify something otherwise um it can be a nasty bug with something like I can Panic here oh no and it never gets to the actual Panic so it still completes and succeeds while we never verified it but if we would put it here then uh the test would fail so this uh a good way of making sure that the test actually verifies the Panic you want there's was another way of how you can do this you can basically catch a panic using a custom Panic

  27. 23:27

    Handler and and later work something with this Panic or like you can ignore it in continue so if you want to check multiple panics on the way what's that syntax look like I haven't seen that uh we had it in really old unit tests you basically put something like STD custom pic Handler you pass the closure that just puts the Panic into some variable and returns it instead of unwrapping it and then returns you back to the execution then you restore the

  28. 24:09

    Panic Handler and continue the process and you can parse the Panic using assert it should be in a r book somewhere in the like a helper okay empty operator is also just not a valid account ID and this is also not a valid account ID and finally multiple initializations um so that's interesting because this p is actually panics um this contract already initialized which is actually

  29. 24:51

    correct um but unit tests are not really a good way of testing it because the state is somewhat weird without for example this right so without this in this test will not panic it's because unit test do not really store into the state um it just calls this method so that may be why this pieces here but if you do a simulation test then this uh method would fail okay um let's go to some other

  30. 25:39

    place I think take um St or account count is has some logic so this is good I'm just quickly scroll through this and take also has some logic uh let's start with take RS so let's see if terminal was able to build no Trails for some reason maybe I used the older contract um all right so State token service is what we reviewed St in service so trade

  31. 26:44

    is like an interface let's read the comment so so contract enable stake owner to earn reward while be able to trade yes contract rules customer can deposit in stake near and exchange for stake tokens stake tokens are issued for near tokens that are delegated to staking pul Sten near mean stake stake tokens implements the allowance free VA based token standards so this kind of cool um except um yeah it uses saves probably

  32. 27:35

    and we should update it to VA but it's saying VA so it depends on the interface um stake tokens Can Be redeemed for near which triggers near to be unstaked amount of near turn stake for the next schedule and St in transaction storage fees are paid by the customer so this pretty cool contract with like a lot of uh Concepts around both storage fees data charge to the user as well as um unstaking that is delayed so it's a

  33. 28:19

    lot of logic that it's supposed to do so your global storage fees are paid by this contract okay St in service so first method called deposit on stake um it takes the attach deposit to the specific staking pool Returns the promise uh if there's any storage fees then they will be deducted from the deposit um so what it does is checks taking pool account ID panics if the account ID is not valid

  34. 29:21

    right deposit attached uh dat customer account check if customer account fees needs to be applied so removes that deposit and stake with the staking pool updates total balance St with Stak in pool comput take token value in near okay creit account with stake tokens Lo the event okay all right let's look at the method and it's implementation okay if it's there I see so it's possible that not all of

  35. 30:20

    these methods are implemented and not not all of the logic is completed yet uh and that's why maybe it doesn't compile but because it's not fully completed uh let's see taking oh okay it's here no okay yeah so I guess not the contract is not fully complete um and I was asked to look at the account so let's look at the account for now all right so when a new account is registered it's assign to the next sequence value

  36. 31:20

    sure uh remove account comput hash so hash is 32 bytes and it basically just hashes this value into a fix size T size is cool because um when you do bch you realize on top of the hash it doesn't put the length of the value so it only takes like 32 bytes if you would put a vector there then it would put um 36 bytes so it's removes if there was already an account then it decreases the account and returns this

  37. 32:07

    account uh default we talked about default okay so account has the following it has a storage escr in a balance stake balances so stake token is different for every stake in pool and available near balance this probably the balance that is already withdrawn and available to either deposit or or withdraw so it looks like it does early on you were wondering if people had multiple staking pools but it looks like that's taken into account here yeah it basically does a stake token for every

  38. 33:03

    pull cool so you can essentially stti with multiple PS I would probably rewrite it where you have a one contract per staking pool so if you have a Stak in pool then maybe there's a factory that deploys a contract that only works with one staking pool it has a bunch of benefits one of them is um you just have a single token to worry about and a single balance to worry about it makes it work nicer with sharding because let's say you have two

  39. 33:51

    different accounts that trades heavily they don't have to go through one contract they can be done in parallel considering there can be multiple shirs uh downside of this is you will have to deploy multiple contracts and currently it's expensive because our contract is fairly large after compilation Um this can be addressed with two ways uh one of them is we will eventually have replicatable contracts

  40. 34:22

    which means the code is deployed once and paid once and everybody just has a link to the code basically just a hash of the contract code um so that wouldn't be that wouldn't be using cross contract calls that would be like actually yeah could you explain that a little bit more right so we have a nap for this uh that explains this so the technical side we can ignore for now the

  41. 34:53

    way it works you deploy a contract code to a specific account so similar how evm is a custom account they're going to be like a global contracts registry or something like this or Library you call deploy code on this account um and you have to transfer balance for this entire deployment to this account so it takes your balance if the contract doesn't exist and it puts it into a code base where every chart has access to

  42. 35:35

    now when you have an account then there may be a new way of deploying a code such as deploy by hash or if you already deployed the code before the same code then the next time you touch this account it will release the storage under this contract and credit it back to you so it will delete the local copy of this contract code from your account and just use the remote one because every shart has access to this and they will be indexed by hash so or you can

  43. 36:18

    imagine yeah I could imagine we might be able to generalize that so that if the same contract gets deployed to a different account chain can say like oh this is already over on this account in this Shard and then The Shard where this account lives knows that it needs to like store it in store it locally in its own database whoever is running this Shard so yeah that that way you need like to be able to address like when you delete a code

  44. 36:52

    on one account you need to charge or like yeah charge the other account and then when you rebalance or like reshuffle accounts yeah sh them okay okay let's continue um so this well you were saying there were two ways that was one way that we could make it cheaper to deploy multiple to do a factory pattern what's the second way second way is uh no STD so there's some work to make contract

  45. 37:24

    smaller it will not make it completely cheap but it will definitely make it like maybe like six to eight times cheaper comparing to STD version that's a lot so STD contains a lot of debugging information um collections like hash map and stuff like this um noise TD first of all we'll need different Json work that works with nod even so also works uh then borch no STD and then yeah nod just like much smaller

  46. 38:03

    comparing to STD um binaries plus we can strip all a lot of debugging info out then it will also make it okay so trade account registry so it has a register account so I assume it works similarly how you do um uh VA based fible to so you have one kind of registration endpoint because it's fixed size per account then you have a register account and number of accounts register account register is a um

  47. 38:58

    because it implements trade uh this is doesn't need to be public so all trade methods are considered public by default and near Buon actually works fine with this we verify that so account register this is the view call in a russh way rust doesn't have gets it usually just um just the getter accounts do accounts so self here is a token register accounts is a lookup map and contains key hash of

  48. 39:42

    this remind me what accounts why accounts. accounts is needed uh so one of them is from contract structure that just has a accounts sub structure here so instead of a map and this account also has a number of accounts just thanks okay so I just verified if account already exist um register account well that's interesting so it's a that's said functions huh yeah uh check is that common no not really what's it do I I'm aware I'm

  49. 40:38

    familiar with the implications functions in JavaScript but not in rest it has a context of the local local function access to mute s it's a closure kind of like a closure um except there's like different types of closures in Rust once mutable and like um reusable closures it doesn't look like it's being used here no reference a bunch of declarations first I assume it's used below here

  50. 41:24

    right so check cars it will basically validates arguments so deposit is positive um account is not a current account that's probably doesn't need to be tested because the current accounts should not have keys eventually so that cannot really happen and it just returns account and deposit but it also doesn't yeah that's fine uh second method is called apply storage Fe it it's kind of interesting because

  51. 42:16

    you can move this out of this um method they it doesn't use any local context so you can reuse it for someone else some other method if you want to but if you're not using it anywhere else it's kind of a nice way to create a clear mental model of what this function does right okay apply storage fees it takes s this is kind of s um so capital letter self is just a alas for the current structure initial storage so this is similar to

  52. 43:03

    this method from fible token original fible token. refund P um it basically takes a current storage after modification and you pass initial storage then you calculate the difference whether you allocated more storage or leas storage and then it takes the attach deposit and it return refunds you the difference from what you attached and what's uh required deposit and uh it would Panic here if you didn't attach enough and tries to increase

  53. 43:44

    storage more but it also returns um how much it needed for storage can I go back one second and like what's the what's the difference between lowercase self and capital S self exactly so lower case is an instance and capital is a class okay kind it also this method assumes that the storage has increased or at least didn't decrease because it does this check here which is both of them are U 128 or u64

  54. 44:34

    so it would Panic if if it underflows okay so next we get a hash for the account we check if the account is already registered then it Returns the result um already registered or registered and here's the fee cool um I guess this is fine another way of doing this would be some kind of rust way of doing this is would be result using actual STD result I'm result um P or uh registration error and then registration error so in

  55. 45:37

    this case you can potentially return error registration error already registered um and in case of success you would return okay storage fee for example or if you want to be explicit then you can do storage B like this or registration success of registration so basically you can separate whether it's success or failure so I guess in this case it kind of success but the problem you just consume the deposit so if I would attach balance here to

  56. 46:34

    registration and my account already exist then this method just uh took my money because it returned okay so correct way of do this going to be is better to like Panic here say like hey already registered in this case it would not take the attached deposit um here okay I I guess I didn't know that so so Panic you don't have to do extra work to refund when someone attaches a deposit

  57. 47:21

    yeah yeah pic pretty much going to revert entire transaction so if you did anything before or not transaction TI receipt so if there was like for example you can deploy a contract then do something else and then do function call for initialization and then function call fails entire thing going to deploy from creation of account to deployment to access keys to to attach deposit and stuff like this and transfer even though it might have

  58. 47:52

    spanned several blocks or if you do it like that only for one one block that this batched actions okay um account needs to pay for its storage so we get the storage we create the default account we insert the account by hash we incremented account um a storage fee um things so we discussed this with Chad in some other contract about the way of doing this um and like if you want to optimize a

  59. 48:40

    few a few gas pieces you can do the following so we don't really need to check that the account is um does not exist what we can do we can insert um insert and verify that it doesn't has the doesn't have a previous value so then we can Panic here but it requires you to panic actually because if you are not going to panic then it actually going to insert the new value and return so what this happens is we basically try to insert

  60. 49:27

    and if there is already a previous value exist for this hash then we panic and it's all going to roll it back so you don't need to verify plus I it a little uh I still find it a bit surprising I don't love that but but this we do two serialization of the keys and two lookups pretty much so you pay fees twice if if you do this like million times not million times but like 100 times then it totally would make sense to optimize this as much as possible for this pattern is totally fine as well so

  61. 50:08

    long as you refund um are you just saying Chad that you don't like the the syntax of like if blah blah blah is some it's like I don't like I don't like that kind of like uh Elite mode version that Eugene does just in terms of like expressivity I find it surprising right like when I read that I don't I it it takes some like Insider knowledge to understand what the code is doing it also assumes that it will be rewarded so like it assumes it will this place because

  62. 50:48

    the insert already happened but you may don't want to do the insert so you rely on Panic to revert the state and this is what what's confusing well this one is cleaner in terms of like well we didn't modify the state up to this point so here we are ready to modify the State per perhaps just like Elite mode stuff just needs a comment above it to you know make it read better yeah I mean I guess there's still the like possibility in the future perhaps that the behavior of how things are averted

  63. 51:22

    right you're like relying on implementation details of the blockchain itself versus like writing code that uh this is would work even if it were changed to here right we actually do explicit assert and like often we do if this then panics because we can just ignore this piece and uh this line will overflow and panic so that would be fine as well right okay so storage fee uh we refunded now we say we store this

  64. 52:12

    because this is a new account um we have to reinsert it because we first need to record how much the account cost um that actually can be avoided if we do this once when we calculate how much account cost uh in Rust well you you also have a key so this makes it a little challenging you need to know inner working of the blockchain and it might change right if the Fe a change it change then so that's some work the and

  65. 52:56

    necessary work that we have to reinsert the account after modifying the storage um anyway so and then we return the result that it was insert de um boom okay so it doesn't include deposit of the balance it just takes the stores this balance that it was paid and what's interesting also here is um if in the future config changes then you do not rely on the actual storage that being used by the account but instead have this explicitly given here so if the storage

  66. 53:51

    becomes cheaper you do not start to refund at cheaper price but you will keep refunding at the correct price when you assume on register account so it's 11 I missed how they're calculating the storage fees can we look at that briefly like yes where're saying apply storage fees yes so you basically take the difference between oh it's passed in in the config when you initialize the contract yeah storage okay

  67. 54:27

    default which is kind my net fee for one B right I was wondering like at some point we might add the ability to look up configs like that yep from the environment MH so on register account um so if it's not registered then we just return it and this is a rusty match so it's a final match the value of this result will be returned from the method and if it was registered then if the account is not

  68. 55:15

    empty um oh it's an ordered map yeah this is the issue uh where because there's multiple accounts they may have a conflict on their balances because every map needs to be visin its own sub suix right now they all already use the same map so unless um unless we store them separately so yeah it's probably a bug so the bug here is because if you created two accounts they will reuse the same map and they will have conflicts in

  69. 56:07

    their balances because the key going to be the same because this is just a prefix so the way to address this is to pass a cash so remove default to something like in account make it you and then take uh hash and then you do something like conat hash um Pass State probably the other way around but yeah sure yeah one way or another I think this way is somewhat fine two maybe yeah doesn't

  70. 57:06

    matter because the length is going to be unique um so what it does it basically con Cates the unique hash of the account with the key um and then it creates a key of 32 or 33 bytes that will be unique for every account instance based on their account ID so your balances are not going to intersect this is the same pattern we saw in the funable token example I believe right yep okay so it verifies that you don't have any balances then

  71. 57:47

    um it is safe to transfer a syn that's fine because you will just delete this record here um again the pattern that I would use is use a remove instead of get um and then I don't need to do remove here because if nothing is removed that's fine if something is removed this is fine and then I would have to panic here but if you want to return not a panic but actual value then you cannot rely on a contract P panicked because we don't really have a revert and a

  72. 58:42

    return um cool and um yeah it returns you how much money it refunded here I think like if I can give like a general comment about this whole project this is like extremely interesting like besides the like in-depth rust here like just the idea of tokenizing staked near is really cool and I I feel like there is like a Eureka moment that I haven't fully had yet but people are tokenizing multiple different things

  73. 59:22

    just in blockchain and um I like kind of get it and I think it's just so awesome that someone from the community did this um and we're seeing this in like you know basic attention token is like tokenizing attention um and there's this one site I think it's called gas token.io where people are like like tokenizing like fluctuating gas prices and I totally don't get that yet but this is another one of those examples and um yeah I just want to applaud this

  74. 59:47

    this person for implementing it okay I need to reverse some stuff around account logic if you want to test check test okay so there is an interesting test about um registering new account um so what it does it basically saying we're going to attach them near um but at the initialization so this succeeds um but in theory you should not reuse the same context and instead clone it because context can be modified and then you you

  75. 1:00:51

    don't really need a deposited start because you're just initializing the contract it should fail okay I didn't pay for the fees so before doing this you would say something like okay then y now these two methods are view calls so you may want to do change context to view is VI true so this a micro that uh takes a context and initialize the blockchain and passes the storage back all right I need to change view back to not

  76. 1:01:49

    view okay it works so it just allows you to also verify that you don't require balances in some places um it's unclear why this didn't Panic this attach deposit it seems like in near SDK we don't verify that the Constructor doesn't take payable which is probably okay because Constructor usually only called once um then you call register account and you expect that it's going to be registered and not if it's reg then it's

  77. 1:02:36

    a panic then we again need to switch to the view call without deposit um and rerun it so it works so register pre-existing account um so you can see that there is uh already a bug that we spotted before so it's just not verified there because context is simply reused um so if we move it here again switch to clone um and we will original balance

  78. 1:03:43

    um we basically take the original balance after this initialization happened and the call match registered so we registered the account so count balance should be increased by account balance should be equal original balance plus uh storage fee so this is how we can verify that the contract only took uh required amount of storage what else we can verify is we can do um storage

  79. 1:04:43

    usage we can say here is original storage usage and we can verify that the I'm like storage usage increased as well by storage fee divided by config default what the name of this config um aage per B okay let's try to one uh what is y oh right zero expected 64 so let's cast it to

  80. 1:05:50

    64 what did the point Z do uh it returns adjacent and I just take inner inner value so it's similar how to write um storage Fe balance storage Fe into it will cast it to balance then we can REM this to balance so generally Chad like Capital u128 if you have one of those you can do zero and it'll give you lowercase u128 wow what a trick uh it basically the way this internally um well that's not super easy

  81. 1:06:46

    it is a structure that has a topple inside so unnam structure has two you want uh yeah whatever it doesn't matter we don't need to get that I didn't know Happ next what happens next is um we have to do this again and okay we we check the balance again we already have it so original balance is account balance and um storage usage is this attach deposit we attach to tokens again but also we

  82. 1:07:26

    need to say account balance is account balance and context Storage US storage so we just need to update St context as well because now we call it again um now we call it oops it's still where f well while you're thinking about that like I I feel like these kind of tests would be better in simulations instead of like constantly changing the Contex right because yeah because you have to

  83. 1:08:13

    um oh weird um so for some reason oh no yeah the problem is I didn't change the context yeah that that's much better in simulation and it would actually cut the bug that we don't refund the storage or don't refund the money uh and just keep it so so we out of time and let's finish it quickly okay so it still works but now what should happen is this is expected Behavior but if you would verify this

  84. 1:09:06

    stuff so what we expect is um we expect that the account balance uh doesn't change and we expect the storage usage does didn't change so if we verify the storage usage it works but um when we verified that the balance didn't change it fails so it means that we took the token s um okay so we out of time um but that was very interesting contract I like the idea of it and like overall the implementation is super nice so we definitely should come back to this

  85. 1:09:59

    later once there is more to the contract add it and that great thanks for everyone who attended and thanks for oyster pack for this contract and allowing us to review it live have a good day yes thank you see right