NEAR Live Contract Review | Episode 33: Fungible Token in Assembly Script
Nothing is loaded from YouTube until you press play, and then without tracking cookies.
About this video
We review standard fungible token implementation in AssemblyScript.
Source code: https://github.com/pixeldapps/near-as...
Follow the latest from NEAR Protocol on: Website: near.org Discord: near.chat Blog: near.org/blog Twitter: / nearprotocol GitHub: github.com/near github.com/nearprotocol #Blockchain #FutureIsNEAR #NEAR #nearprotocol
Transcript
2,431 wordsCaptions as YouTube publishes them, usually machine-generated, so product and people names can be misheard.
- 0:01
hi everyone and this is jin and mike and this is another episode of live contract reviews and today we're going to review a fungible token contract that is written in assembly script so let me present window i'm not sure what's the quality of today's recording going to be because we are recording through ingots because i lost my zoom access and well i try to avoid mirroring um cool so
- 0:51
i actually not super familiar how assembly script works but here's the main index file from where we export a bunch of methods and i guess the public and they call some internal implementation methods which i assume are not public which i'm not 100 confident about this so we have initialization then we have core map 141 which has ft transfer ft transfer call we have the on transfer which is a callback it shouldn't be exported
- 1:50
probably uh if your resolve transfer is our callback and total supply and balance off then storage storage deposit storage withdrawals storage and register storage balance bounce and storage balance off and finally ft metadata so let's actually start with the um this ft transfer implementation so i started looking at this uh first of all this is
- 2:57
file 141 and it has the persistent map this is a key t we have to transfer implementation take sender receiver amount and memo first we verify that receiver is valid and it's called from i have to transfer with the predecessor okay and then get the amount verified that we cannot send to ourself get the amount as positive take the balance of the sender and verify that it's larger than the amount you're trying to send we
- 3:47
check that the balance of the receiver is exist which means it's registered and then we subtract the amount and new balance of the receiver we add and we save them back and uh log a message similarly to the rust implementation so the only thing i think this is missing is one yockton unit that is also required on the ft transfer next is ft transfer call and it takes message and memo so this one is actually verifies one yoktan year
- 4:49
and the predecessor is similarly so we do the standard transfer and then we create a promise on the receiver side to call fgm transfer and uh what's that just real real quick looks like a message is supposed to be the last parameter yeah i think it doesn't matter in this case as a suggestion but yeah good point so we pass sender id amount and message and pass cross contract call gas which is 30k
- 5:39
so that's a bit more than what what the standard trust does i think we actually pass use the amount of gas but doing this like a remaining gas to to the ft call so it's all gas except for 30k or 30 tara gas so given gas but we keep this 30 charges and this one we take five and then it returns the result so send their amount message send their id receive already amount and we don't really need a message
- 6:31
to roll back um argument is ft call and this is ft callback yeah it's all good now ftm transfer implementation right this one result transfer so that happens when we call this method and then so we verify that we get called by ourself that the number of results is one if that failed then we re revert transfer and return that the amount that was
- 7:36
transferred is amount i think this should return the amount transferred it should be zero but maybe i'm missing it because resolve i think it returns the actual amount that was transferred instead of the amount that was returned i think it is like however much you're like are we supposed to return back to the person yeah but that that's a return but for on transfer not for the
- 8:15
internal resolve it should say how much tokens were actually transferred oh maybe it's returned oh i see you're saying you're right no you know you're right if this is on resolve transfer then we tell the end user how many were actually transferred yeah so so this should be zero and this should be used amount instead of unused amount and that should be full amount okay so we're trying to decode
- 8:50
from this result and i wonder what happens if this panics because in the rest we try to gracefully handle it because if you provide some invalid data or like you you ask to return too much then you should handle it so because the the contract can actually provide you maliciously invalid data so one thing it can try to break that one but maybe typescript forum actually gonna handle it fine to decode string
- 9:43
and you may not be able to decode string so that may panic then this may panic because it's not a number and finally it then used amount as more then you should compare it to the given amount because the receiver may say oh actually go re refund twice the amount of money from me which is stupid but that shouldn't be a lot so that should verify that unused amount is at most the amount
- 10:23
and this parsing should be handled in such a way that it doesn't paint or if it does panic then we kind of resolve it again through some different implementation basically we rely that we didn't panic it can be done using the kind of try then and finally all the catch and then during the try we actually call it this during the cat then we call in ourselves and trying to parse data that was given to us and then finally just to be verified that
- 11:15
our parsing succeeded if our parsing failed we just say okay something went wrong give all the money back that's it then we can do a bunch of asserts uh like here we can just oh let's parse the result no matter what then if it failed then it means we need to do full rollback but yeah this is not correct not fully correct so it does roll back um or attempt to roll back also a receiver might register there so
- 12:02
this thing gonna panic again so that's kind of some um undesired behavior but ascender might disappear in this case the original implementation of rust is actually burning it but it's not necessary it has to burn the tokens it's probably okay to to panic but ideally like this method should never panic okay finally uh total supply we get the max supply and balance implementation we get the balance
- 12:51
um which kinda assumes that the balance is given but then that's not correct oh it's with zero yeah that's fine so it is it always returns zero just correct i think um all right so that's only a problem on resolving when the contract that was called acted maliciously or incorrectly or panicked and correctly returned some data invalid data so next is a storage implementation so let's take a look at the storage implementation can by default its predecessor
- 13:44
registration is false okay it assumes one yoktan year so that's not right because storage should actually take the deposit instead of one yokta what is one i'm missing it because i don't have the maybe it's a misc no yeah it's probably near my engine the one the octa-core but yeah storage deposit implementation doesn't really need one doctor instead it should it should verify that it's more than minimum buy bound but one yacht is not necessary
- 14:48
okay we check the balance if the balance total more than zero then we say the account is already registered which does this this is storage registry new balance um so how we do this this one token the simple implementation doesn't really need to have storage registry because the storage cost can be fixed but for json storage it may not be the case so okay let's actually take a look how it's
- 15:33
done so you have a storage balance which has total and available so if total is present and more than zero then we say that it's already registered and we refund it that's actually not right because maybe you want to increase the balance but what is the bounce the bounce uh storage cost from some variable remember it's okay to use it this way but in this case you don't really need a separate storage
- 16:25
you can just rely on account balances otherwise we say the total is this available is zero save storage register for this account id and if the deposit is modern minimum bound we refund our difference ignoring registration only which is fine um probably not a big deal but line 28 is misspelled yeah yeah yeah um what what we need to do here
- 17:52
yeah i think it's it's okay here except to like that that storage balance in them in a map is unnecessary because we can use one from 141 to to safe and right another one we actually didn't register the account itself so this one in nft transfer implementation in token registry is empty so that it that should receive a zero in our storage deposit so when you deposit a storage or given account that should actually verify it
- 18:46
also ideally we should verify the validity of the account id otherwise you can register invalid account so yeah what is missing is actual registering the storage for that is required to to store the the actual balance not the storage balance per token storage withdrawal is we verify that predecessor exists if the amount is zero or the amount is zero not otherwise we do nothing oh that's a bit weird yes it's not
- 19:49
well that one just compares it to zero anyway so again well one yacht is correct here on register implementation wait how we use it withdraw implementation register of course okay so it falls then we delete from storage registry which is correct but probably we need to update total supply in this case by decreasing it in for storage registry yes we delete that amount return true but we should refund the
- 20:41
balance from the storage so this one doesn't refine the balances and well this is not correct because storage balance of implementation actually should be able to return now i think storage on register i'm looking at the spec right now can return false if and only if the account was not registered before right yeah yeah so so this one is not right because you you definitely need to burn the token to decrypt the total
- 21:31
supply as well as refund the storage registration if it was paid for or false if it's not it didn't exist in the past yeah okay and finally and here you can return now in case the account was not registered at least i think that suspect correct so this one also doesn't do this because it forced it it returns it basically total zero which is somewhat similar but i think cleaner is just returned no so just replacing this get some should
- 22:13
be fine but then it's used internally here in a few places so in this places it should get updated okay uh finally ft metadata and that's just metadata that should work and pause it from the storage test no tests okay it doesn't look like we have a a few places in the fundable token metadata that are null like icon reference and reference hash are supposed to be able to be null
- 23:05
yeah yeah so some of them can be known yeah like this and then the ones the two below that too nice uh i think that's it for for this uh contract so basically there are some things oh i guess you need talking is another one in it talking checks that it's called by itself get the initial state sets the metadata and mux supply and gives the full supply to the predecessor measure account storage
- 23:54
so we set the max length max use 128 cool and then we delete it but the problem is um in this case uh that map is unaccounted for so this map is should be removed and we should just rely on on token balance token registry map instead of having a separate storage register at least no not for this particular token um cool and actually uh on thick on this page possibly if you scroll down kind of slowly i think there might be one of these export oh yeah like right on line
- 24:48
29 there's like a extra um underscore ft on transfer underscore yeah i think both of them are not needed actually from this because this one shouldn't be exported from this particular contract but instead it should be implemented on the receiver on the receiver side so that's why here it's just saying not implemented okay okay um i think that's it for for this contract there just need the extra yokta on
- 25:31
on on this call on this call so this one should be one yoga kinda because it doesn't check it um in our solve yeah whatever we commented i guess uh we went through this so let me stop presenting nice this will be a huge addition once we get those in that's great cool but yeah overall it does look correct and like there's might be some complication around the like how to handle invalid transitions
- 26:13
around transfer call where let's say a receiver said go refund all the tokens but the receivable already spent all the tokens and you probably don't want to panic or if receivers say hey uh well i actually received 500 but now i want to return 1000.
- 26:35
in this case you should also say that's not possible yeah or receiver instead of saying a number saying return a word like hey and then it would panic here on the return but instead it should say oh we rewarded because it incorrectly did it and yeah since and that can be solved with one extra step where you kind of have two callbacks one a callback on the receiver and the second callback is on
- 27:22
your own site this might turn it down anyway thanks everyone cool