NEAR Live Contract Review | Episode 27: NFT SDK Standards Example
Nothing is loaded from YouTube until you press play, and then without tracking cookies.
About this video
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
4,857 wordsCaptions as YouTube publishes them, usually machine-generated, so product and people names can be misheard.
- 0:01
oh we are recording cool we're recording now so you've given your consent uh hi everyone welcome to live contract review guest hosts matt mike austin jim figuring it out for the first time on our own without eugene hi this is eugene and uh we're going over another live contract review today um this time we're going over the non-fungible token and this is pretty interesting because
- 0:32
unlike some other examples that we've shown we are going to be using near contract standards which as you can see highlighted right here is actually in a different crate at the moment so typically what happens is if you want to take an example and build off of it you would copy paste the whole thing and we've seen that in number of different cases like let's just take a look at status message for instance this is a very simple example so a typical use case might be
- 1:03
you think this is pretty close to what you want to do you just copy the whole thing paste it blah blah so that's not really great for scalability obviously and so we created this thing near contract standards that has a few different uh standards that you can actually implement so we have storage management functional token and then the most recent one is non-fundable token so this we'll get into a little bit later actually but this has like the
- 1:32
implementation code but what is the actual example itself so the actual example itself will have like way less boilerplate and it's going to be saying hey i want to grab a bunch of logic from near contract standards crate and that's going to make things a lot a lot easier this is not totally set in stone how we are going to do this but this is the current iteration of how the contract standards work should mention that so non-fungible token nft uh you'll note that there's a few other
- 2:03
projects in here this is mostly for simulation tests to make sure that like we can transfer nfts and and all the expected behaviors happening as normal we have our source lib file first let's go in the cargo tunnel and when we're inside the near sdk rs uh project this is also a really good way for our continuous integration to make sure that like any changes we made at sdk are still
- 2:31
kind of working so here we'll use relative paths so for the most part if you are trying to take this example uh copy it out and then make a standalone example you're going to want to change this so it's actually using uh versions instead of relative paths and this is something that we do for all of these is we say basically this is a lib which makes it say hey i'm going to look in lib.rs
- 2:56
so let me close the panel on the left oh yeah much better let's add word wrapping much better so what i like to do usually is just scroll all the way to the bottom just to see like how big this thing is that i'm looking at um so digestible 331 lines of code and how much of this is tests uh a whole lot so at the end of the day we're talking about 114 lines for to make an nft i got it down to like 88 lines somehow maybe i maybe i cut the comments did you add comment okay well
- 3:33
more comments the better it should be longer um so back at the top now that we know that it's like 114 uh it's it's doesn't seem too scary i like to always start with that then at the top as usual we've got these these imports this is kind of like boilerplate if you're using an ide like c lion like we have here a lot of these you can just start typing and it'll automatically import them uh this is actually something that will be a relic of the past soon thanks to
- 4:00
austin who's on this call and so there's nothing nothing special at the top we have uh our kind of main contract struct this is the one that we use the near bindron macro for and we're storing tokens and we're storing uh metadata you won't get too much into this guy but essentially we really want nfts which are especially right now in the zeitgeist um big in the art scene and so being able
- 4:33
to have like thumbnails of like what nfts do you own uh makes a lot of sense so this is a u r i image i can't remember actually the exact turn term for this but we can look at nomicon if we wish and this is something that isn't that worth going over too much but essentially when you have collections like say like a hash map except better just like a map between key and value and then you want to have like
- 5:05
key and then the value is also a collection that has a key in value things can get kind of interesting in terms of how we write state in blockchain so this storage key sort of helps to make sure that when you have collections inside collections that it's it works smoothly and there aren't any sort of conflicts and overlaps okay this is this is something that i think i hadn't really
- 5:36
seen before so notice that we've got we're implementing our contract struct here and we've got this init macro twice here so init usually means like hey i'm gonna be calling this method uh don't worry about what's in state don't take what's in state and try to shove it into the the primary struct that we're talking about which is this uh so this is typically called once uh these these new methods and the most common way is you check to see if it's already initialized so this
- 6:16
can't keep uh getting called multiple times so this in this particular case we have two ways to initialize one's called new default meta and this the other one is called new if you look at all of our examples on near.dev the website you'll see that this second one that i'm highlighting here is the most uh common pattern but this is sort of an easy way to just say hey just give me kind of the a basic nft metadata
- 6:46
nft with metadata initialization this one you can get more granular with it where you pass in an actual nft contract metadata object here this is probably what you'll be using in real life and we will get to metadata in a bit because there's kind of two kinds of metadata um but that doesn't matter when you're initializing an nft contract of course you're going to be putting in the nft contract metadata so this just
- 7:18
initializes this uh and then this is a basically like a customization this does not exist in the the standards necessarily uh nft mint now here's where things get much more interesting and again i don't know if this is going to stay this way forever but this is how it works now as we're saying hey there's this crate called near contract standards and there's a macro that goes through in there that will implement
- 7:52
the essentially the interface functions for the non-functional token core so this is for instance like the the core methods like nft transfer to another person nft transfer call which is similar to the fungible token standard that we have if you've seen that video uh so someone someone might just have this like they they may not even want anything else and this is this is fine the the way that we want to deal with like extension standards is being able to
- 8:23
have a person add just one line of code that says hey it's cool that you know we have these kind of standard the core standard methods but i i'm pretty used to the idea of saying like hey i have an nft um matt i want to allow you to take that from me like let's say it's like christmas time and i'm an artist and i say hey matt i'm going to let you take one of uh these three paintings uh that that i've made into an nft i can like allow him to like take it on my behalf
- 8:56
uh this is becoming a little bit of a old pattern um but nonetheless there are good use cases this is sort of a similar way of like thinking that happens in developer communities so you can add this and then enumeration very important but not like required in the token functional non-fundable token core standard enumeration is basically like uh hey how many nfts does jim have um please like give me a list of
- 9:28
of the nfts that he's got and how many do we have in in total and let me page through um all the ones that austin has because maybe he's got like 600 and you can't return all 600 with one call so in this case we've decided that we want to have like three extension standards um then this essentially ends this particular contract which is what we would only copy paste into our uh own project
- 10:03
if we want to any questions before we jump into like a little bit of the code from here yeah um so i have a question and it may be a little early but i wanted to know uh what's the optimal strategy for a developer to i guess like the technical term would be override a standard method so for example uh you know you mentioned this um let's just talk about a transfer so i want to send you an nft um but i want uh something kind of special to happen
- 10:42
during that transfer or i want something to be incremented like hey i'm a token and i've been transferred x amount of times how would you go about doing that after the this macro has been applied yeah that that's that's a good question i think that you would actually want to be diving into the contract standards here and it's possible that i uh austin knows more about this but i'll
- 11:12
just mention that real quick i will say that maybe we can just switch gears for a second to the fungible token instead of non-fungible token and where we have ft here there is a pretty good example of this where inside okay so these two functions right here are kind of similar to what you're talking about um but well first of all to answer your qu question directly i don't think that there is some sort of like hook into
- 11:47
this to say you know please don't do the thing that the code says and do this instead this is this is getting pretty close to what i believe you're talking about where we have in the fungible token uh implementation something that says all right someone just uh closed their account basically like you know you use die for a bit and then you had a little bit of storage saying like hey i i paid for mike dot near to have a key value
- 12:16
pair on this fundable token contract i really want that teeny bit of storage back then you can like remove your account and get that teeny bit of storage back for yourself and then when that happens uh we have something that says hey by the way if there is like a function called on account close then just go ahead and call that so then you get kind of best of both worlds where
- 12:38
your entire contract is 103 lines and you like have all the logic you need but this just kind of calls back to here so i guess this is a little bit similar to like a hook like pattern that you may see in other like frameworks this is currently we don't have this for for nft so if you want a bespoke one then you're going to have to look into your contract standards as far as i know and
- 13:00
and modify it there um i have an example also about fungible tokens so one one thing that we had to do for a recent project was we had to lock down a fungible token and basically say that um the only account that was allowed to transfer the fungible token was a particular account and then and then also the fungible tokens were only allowed to be transferred to a certain account and the reason for this is that this was sort of like a
- 13:30
like a casino token that we only wanted to be used in the house so we didn't want it to actually we didn't want this fungible token to be able to be taken out of the door like the chips in a casino you know and and taken to another casino so um probably should stop using casino metaphors but um basically uh we just wanted to keep control of our of our sort of credit system we were using this for like on-chain accounting um basically what
- 14:01
uh the developer this was ryan metta um from developer relations what he did was he simply just didn't call the macro and then um but he still had the object like the underlying uh you know token object uh and all of its associated methods and then he just simply wrapped the methods that he wanted to keep standard and then the ones that that he needed to modify he kind of just uh like he still wrapped it so he still called it ft transfer and then he put a little bit of an
- 14:33
assertion at the front that said predecessor must be so and so and then he just called it uh after the assertion is that is that an okay pattern or is that some pattern that's like is that an anti-pattern so does that does that mean that he if he could still see my screen does that mean that he like removed this uh impul non-fungible token core if you're is that what happened and then kind of put some of the logic in
- 14:58
this story he did this for fungible tokens but this is the exact thing that he did do uh he he basically just didn't include the macro and then he just went through method by method and just wrapped so the ones that were standard he just like ft transfer and then self.token.ft transfer you know so and then for anything else that he wanted to customize like i said he just would sort of put an assertion above it and then call it underneath i'm just curious if that is like is that like a is that a
- 15:29
a bad pattern i can't think of any other yeah yeah i mean like i i don't think it's necessarily a bad pattern especially right now because we don't like as mike said basically previously this stuff will probably uh be iterated on and make it so that it is like kind of extensible and customizable more easily than it is uh currently but i i think it is an anti-pattern as long as
- 15:53
um it just depends if someone is expecting the exact like nft interface to be used like if if that has changed like say if you actually are wrapping the the function itself and like calling it something different then maybe like someone using it might call like the the inner function when you actually want them to call the one that's gonna do you know the extra logic um so i think just be careful that if you are creating this wrapper to like make sure
- 16:17
you're only restricting it to certain amounts that you're either not exposing the one that's automatically being derived if you're keeping that line in um or just you know making sure that those invariants are are upheld yeah i think that was the goal was to keep the interface one to one but but really just it's almost like not at that point if you're scoping a fungible token and like
- 16:40
limiting it it's almost like not extending it it's basically restricting it right but um but there are fields in the nft contract that i think are like make for things to be like a little bit more flexible like the memo fields and things like that so um yeah i'm just wondering how we how we would tackle that how we would like piggyback put like custom logic in you know transfer happens um
- 17:04
with a particular like message or memo field and then something kind of something interesting additional happens and but then it just keeps on going with the core implementation i i i like that um especially because in this what i imagine happened here is that basically you want like if you want to say i want to change i want to add one more assertion to nft transfer then you gotta like comment this out and
- 17:29
then do all of the methods like you can't just say you know okay i want to i want to change this one so that might be something that would be cool to do is hey i have some way of saying like oh i only want to hook into this one and please let me use all the other ones which we should probably make things a little bit more error-prone as well in the future so yeah great great point i just thought of a i just thought of a terrible uh terrible
- 17:53
thing to ask of you guys but uh it would be like uh you know um the instead of implement non-fungible token core macro i mean i mean that macro could call you know maybe half a dozen i don't know how many methods are in there half a dozen other macros and then so you you know you you could just wipe out this line bring in five lines and then change the one that you like wrap the one that you uh that you wanted to change i i don't know what that looks like though from an implementation point of
- 18:25
view like kind of a macro to macro kind of like it's like multiplexing macros or something but i mean it's totally doable i'm sorry i didn't mean to cut you off oh no yeah actually i you're you know way more about this than me so i don't want to cut you off yeah i was just gonna say yeah it definitely is doable but i i'm just definitely being a little bit uh careful and i guess uh cautious not to like add a bunch of overhead that we might
- 18:49
you know move to somewhere else later because i'm not sure if we're gonna keep this like declarative macro style that is that is the way that's right here um so yeah it's definitely something that we should we should either iterate on and like come up with an example of the easiest way to override either some of the methods or all the methods and then like keep that up to date so that people can can easily see how to do that yeah
- 19:13
cool well yeah i mean that was like the the real uh bulk of like my interest in in looking over this contract was sort of um what do i do when i want to do something in you know like a little bit more kind of wild off the beaten path right um cool let's see i guess i think matt you may have to drop off soon but um oh i i think i can keep going on this for a little bit does that sound good or do you have the other i started the recordings i'm gonna have to pass
- 19:49
on something so i just want to make sure i can do that um i'm going to leave meeting and i'm going to make you the host mike and then that should give you the control functionality okay okay i pray this works it's still recording okay bye guys thanks for answering my questions by the way yeah for sure all right yeah so let's take a look at this some of this stuff i don't think we have to keep it too long but this is a great way to dive into this
- 20:23
um i think the next thing i can talk about is something that was mentioned here where we have two kinds of metadata nft contract metadata and then per token right so this is maybe like i'm an artist and i want to put my stuff up here and this is like my anime like collection or something like that um this could be like my nft contract and then an actual piece that's like hey this is pikachu uh which isn't exactly anime but you get what i'm saying that would be like a token metadata
- 20:55
um so these kind of borrow one another but i and we won't go into every single field here but there is that differentiation and then there's some helper uh method here so a person can take a look and see like what is what's the information on this particular contract metadata get some details on that okay so that goes over those two different kinds of metadata macros i don't think that's too useful to get into
- 21:28
a token here this is super basic we just have a token id uh an owner id because owner id the owner a token can be owned obviously and then in this particular case we have added approved account ids this is this thing where i said hey matt is able to take this energy on my behalf so this is stored inside of a mapping here in this particular case we are using hashmap which is a little unusual if you've seen other videos we prefer to use near collections
- 22:02
this one we are quite confident that it's not going to grow to be incredibly large and impossible to page through so we are using hash map and that's totally fine you'll notice that the approved account id there are private near collections so sorry mike's just good question are the newer collections just like size limited versions of hash maps just a little bit of protection on top of them are they fundamentally different data structures yeah great great great question and i'm probably gonna butcher this
- 22:33
um but basically like hashmap when you load this in it'll load up the entire map into memory and that is pretty bad when you talk about like fungible tokens for instance um you know i i'm a huge fan of basic attention token and brave and that probably has like i'm gonna guess like you know tens of millions of rows and so you don't want to be adding you don't want to try to load that into memory
- 22:56
uh and then in particular like the other answer that i think you're getting at here maybe i'll open up the status message again is there are different kinds of okay so this also uses hashmap bad example uh there are different kinds where it's like this uses an avl tree for instance and so avl tree is like um balancing so it'll you know someone can't make a really really long kind of side to the
- 23:28
tree it'll always like rebalance but that also comes at the cost of like that rebalancing and the way the data structure works is much more gas intensive than in certain yeah yeah so yeah distributed i'm wrapping my brain around around thinking about this in a distributed yeah way just just add like one other quick context about the collections is just that the intention of the sdk collections is just to basically lazily load the things from storage that you don't actually have to do all the loading from storage and then
- 24:01
deserializing up front because you want to minimize the gas costs on chains so if you can kind of only load and deserialize the the things that you actually use that that's like obviously ideal okay cool yeah thanks i didn't mean to tangent there but that was um interesting to now it's great it's beautiful um and then yeah these so there's three directories here approval uh core and enumeration and this is basically just where we have the different implementations for what we have in our
- 24:34
standard and you can go to nomicon.io in the left sidebar sidebar there's going to be a standard section and we you'll see these are all the functions we've got tons of more information on what you should put in what you can expect to happen when it should panic all that kind of stuff so here we're just saying please get that please get this particular token um how many tokens are there
- 24:59
and then here we are doing a bit of paging which is which is quite interesting i don't think that we've done a live contract review where we talk about about paging that's probably honestly its own video but essentially we're saying like let's please start from here and then let's have a limit of how many we want and this this makes it possible to say okay there are like 300 items and i actually do want to page
- 25:23
through this uh you can you can do that without hitting the gas limit nfp supply for owner once again this is like jim has uh seven nfts like show me all the nfts he's got oh supply actually sorry this one's this one would return seven and then this one would return uh the seven different tokens that he's got so that's enumeration um and then the core contract has has these methods again this is all come from nomicon resolve transfer
- 26:01
on transfer uh for this one i'm going to recommend we check out the fungible token video because this is a bit to to get into but this is essentially um a replacement and possibly better than using approval management is this the idea of having a on transfer resolve transfer and what's it called transfer call yes but yeah i think that's very different different video and then approval management uh for nfts this is where you can say okay you're cool you're gonna approve who you're gonna
- 26:42
approve this person uh and that's that's quite straightforward this is also almost the exact same for for fungible tokens so yeah i think the overall takeaway is that this is an example of using near contract standards we are kind of imp like iterating on how this is going to work as we mentioned a couple of times but this should make it so that you can just use macros to say hey i don't want to copy paste this whole thing i want to you know use macros for this and then if there are updates to how these things work
- 27:13
like i can't imagine this but like say that there's like a you know security flaw or or more like a if there's a uh enhancement that we make to this then you can update your your crate and everything is going to be all good so we look forward to making as little boilerplate as possible when writing smart contracts and this is an example of of that happening making it 114 lines
- 27:39
and this is down to 113 uh from this recent change that you know austin has done with the memory allocation and yeah we're going to keep doing this as much as best as we can and figure out some way to kind of add a something like a hook system and maybe rethink this but this is where it stands uh it's actually some some pretty good project and we can look forward to experimenting with this on
- 28:04
an upcoming multi-token standard that should be happening fairly soon for my uh community member cool super bowl nate well um thanks for thanks for going through that yeah gives me kind of an idea of what it looks like coming in coming in fresh nice i had no idea i would be doing this presentation but uh hopefully well that made sense well thanks y'all i guess we can keep it to uh to time then and um call it cool sounds good awesome thank you guys
- 28:45
i got thanks y'all talk to you later bye