Polybase 🛠Build an NFT Gated Chat app using Polybase
ETHGlobal·Mon, Oct 9, 2023, 12:00 AM
Join Calum from Polybase for a talk titled "Build an NFT Gated Chat app using Polybase". As new users flock to web3, critical infrastructure advancements are needed to scale. Scaling Ethereum is your chance to shape the future of Ethereum. Join us March 10th-29th for three weeks of hacking and summits featuring teams like Gnosis Chain, Scroll, Hyperlane, UMA, IPFS/Filecoin, and more. ----------------- Follow us: https://twitter.com/ETHGlobal​ Check us out: https://ethglobal.co​m Email us at: hello@ethglobal.com
Transcript
foreign [Applause] [Music] today we're going to be creating a chat app using polybase so this is going to be a fairly long video so we might split it into two parts but today I want to cover creating a schema logging with a adding the libraries and kind of getting an initial rewrite requests going employee base and we're going to build an nft gated chat app just to kind of see the full options available in playbase so the first thing I'm going to do is just jump into the dots and the getting started guide and as you can see here we have some instructions on how to install the client but I'm actually going to skip down to the creating a collection so employee base everything all data lives inside collections a collection is similar to a database table and you can have Fields um and you can Define kind of a schema for that database table you can do it in code as it's shown here but I would highly recommend using our Explorer they will just give you a much easier experience in terms of creating that first collection for yourself so I'm going to log in and you want to log in for the Explorer using this you need to have a metamask extension to log in and then I'm going to select this test account here to log in it's going to ask me to log in with the Explorer and I can sign that request and then you can ask me to sign another one because I'm a new user you enter your email address if you want updates I'm going to skip that for now and then we'll go in create our chat app so create the chat app again it's going to ask me to sign messages if you're interested to know this is an eth personal sign message so no nothing to do with your eth balance can be done with this type of signature virtually metamask doesn't really do a good job of explaining that this is kind of a weaker level signature or weaker in terms of risk level that you're putting up so this we obviously need to sign requests in playbase to make sure that we know who is sending requests to the database so that's what this is doing and this is creating some demo codes for us which you can see here so as I mentioned before we've got a collection we've got a bunch of fields highly recommend reading the comments on this first question because it kind of gives you a bit of an overview of the different set of functionality but you're watching this video so maybe you'll pick it up from that I'm going to just remove this for now and just jump into creating some schema with you so the first thing I'm going to want is obviously a user or collection and I'm going to give it an ID field string now all collections have to have an ID field a string and that that field has to be mandatory so I'm gonna put that one in and then I'm also going to add public key here or type public key and you'll see why we need this in a minute but this is to do with and then I'm going to create a Constructor so you can see the syntax looks very similar to a typescript class and that's intentional it is the syntax is very similar to JavaScript typescript the main difference being instead of class here you see collection so when you want to create a new user it makes sense to call the Constructor function which you would do if you were instantiating on your class now in this case what I want to do is actually I want to use context Dot publicly so when we run this code context will be automatically populated with us for us with a property called public key now public key if the public key used to sign this request so when creating the record the user as you saw that metamask pop up previously that's the same thing it's it's basically getting us this public key this will only be populated if the public key of the user is sent or the messages signed otherwise you won't get it so we might actually want to check here to say okay we definitely want to have public keys so if public key is not there we're going to like throw an error one thing to note is we double quotes are also not accepted at the moment that's a bug we're gonna fix that for you so just make sure it's single quotes and then you can say you must be you must sign the transaction just to let the user know that and then I'm also going to start so as I mentioned before this ID field needs to be a string context of public keys of type public key so we actually need to convert it to a string and the conversion to a string we can turn it into a hexadecimal which is kind of a string that starts with 0x and we can assign that then to the ID and then we're going to also store the public key in its root form so in as a public key type as well because that enables us to use it with our permissioning logic okay so we have our user collection but we're creating a an nft dated chat app so we're going to need some more collections here so I'm going to create an nft and I'm just going to give that an ID and then I'm also going to give it an owner and I'm going to give the owner as a user so this is one of the really cool things you can do with polybase is you can pass in another collection or record from another collection into another record so it's kind of like a foreign key or kind of a relationship between these two things and again I'm going to write the Constructor for so in this case we're saying we've got an ID string and we're actually going to pass in the ID this time for nft very simple nft which just has an ID that's defined by the user that's once you claim your your nft no one else can take that off you or mint it I can review this dot ID equals ID this dot owner equals owner great so you can see just there's going to be a lot of this kind of assigning values from the parameters in the Constructor this boilerplate we'll look to make this easier in the future but for now that's what you got to do so then the next one I want to probably next question I want is probably something to do with like a particular chat very more chat group that you've been invited to or that you're able to access as an owner of this nft so we're gonna obviously again we have to have an ID stream that's mandatory if you want to have an optional property you can you can just use the the optional property same as in typescript but I'm going to leave that out for now we're going to actually make this mandatory again so again I have my Constructor here one of the things to bear in mind is that the semicolons here are mandatory which is unlike a JavaScript where they're not mandatory then 100 tree employee base or at least for the time being so in terms of the chat we actually probably want a members as well because we want to have we know know who or the member of the chat but we're actually going to date it by nft so actually we're not looking at here with the user of the chat we don't care who the user is we just care whether you have an nft or not so in this case I'm going to do again I'm gonna map over the idea which is a string the name just a string again and then members I'm just going to set to an empty array for the time being and we'll add some logic around in a minute about how sorry m0 I like to just do all of the fields in the constructors first because I think it just it gets me understanding the scripture that I want to create and then finally we probably want some sort of message so that would be again we definitely need a string we want obviously the message as a string we want the time set the messages sent so that's going to be a number it'll be Unix timestamp so a number of seconds since 1970 or Epoch if you want to call it that and then in the Constructor we're going to pass in oh the other thing we need here is obviously what chat does this message belong to otherwise it's going to get very confusing a few messages from every single chat and so we have ID string here message string plant stamp a number and the chats we're going to pass in as well okay cool again I just need to assign these apologize for this boilerplate we'll make this better uh and let's still timestamp of course timestamp chaps the course chat Okay so we've got some great boilerplate going on here in terms of our collections but one of the things we're missing first that I can recognize is that there's no way to actually add a member so there's no way to add someone to the chat or even the original member card we added to this chat so we're going to add a function called add number now all rights in polybase have to happen via these functions either the Constructor to create or you can add your own custom functions if you want to update the record this is similar to solidity where you have to write a function and you can write any code in here so you could write you know if this dot numbers dot length is bigger than five then again we can error choosing and besides too many people in the room all right so you can imagine there's like some really exclusive rooms right because you can only have five people in a room whatever logic you want to implement here and then you've got some kind of thing to say okay I'm going to remembers.push and I'm gonna add in this nft right so still here don't forget the semicolon at the end it's the most common mistake I make when I'm coding okay so now we've got a way to add a number but with all of these things at the moment it's very open in that like I happen to find who is allowed to read these messages and who is allowed to do rights and create records so that's what we're going to do next so I'm actually going to start off with message because message is kind of the lowest level primitive because to read a message you probably want to be part of the chat group and to be part of the chat group we we kind of specify that you need to be a member which you need to have this nft and this nft has an owner so and that owner belongs to some kind of you so thinking through that we obviously want to start with a message and say okay you can read a message if you are part of a chat and there's no semicolon after these These are called annotations or directives and and there's no there's no semicolon after these because you can actually you can actually write this so but I think it's a bit nice one separate line so we're saying okay anyone who is part of this chat can read from this chart and then what we want to say is okay so we're now given say you know responsibility to this chat but we want to specify kind of more specifically who like what does it mean to give responsibility of this read to this chat Group Well it actually what we want to say is if you're a member of this chat so what we can do is we can delegate our Authority from from here into from the from the list into the chat and then from the chat into being having a particular nft and so this is quite powerful because we can basically say we don't care how chat does its permissioning from a message perspective we just care that like this is the chat and the chat is responsible for determining how the permissions should be delegated and again in the members we delegate to the nft and then if we go back we look at the nft and we see oh actually the nft needs to be delegated as well to the user because the responsibility of the NFC or the control and ownership and of the permissioning of the nft is actually ultimately going to go to the user who actually owns that in it and so we delegate to that user and then finally we need to delegate to this public key and this enables us to basically ends the the chain of events everything that will need to end at public key eventually because that's what people use to sign requests so you should always have kind of a delegate on a private key now the other thing we need to do is we haven't actually specified who can read chat we've delegated the responsibility to any control and permission that's been given to chat obviously goes to the NIT members but we haven't said who can actually read chat so again we're going to add a rule here to say you can read chat and you'll see this a lot with your collections is that you probably need to where you have a delegate you probably want to have a read as well to allow people to there are some exceptions to that and and again if you are the user then you get to read your own public record the nfts you might actually want to be public it could be more interesting in that case so maybe we'll add an app read at the top here if you have an app read at the top and that means that the collection if anyone's able to read that function which is which is super beautiful in some cases the other thing we want to do so we've now added read permissions and and how we want them when we we probably want to be able to control through can actually adds a I remember here and what we can use is that at call directive and then in the parameters we want to specify what field is responsible for being for controlling this permission of being able to call this member now we can obviously as we've done here we can write in specific rules in addition to this but this is quite good for the daisy chaining of missioning from message to chat to nft which would be quite complex and verbose to do as code um so this just kind of makes it a lot easier to do and we can say okay at call if you're a member and so that's delegated to the nft so you can both read the chat a group or you can add a member if you are already a member of that chat one thing to know about Constructors is that anyone can call a Constructor generally speaking so you'll need to add your own rules if you want to specify something a bit more specific around that and the other thing to note is if we're passing in user you have to have at least read permissions of this user in order to pass that in so you wouldn't be able to have someone creating an nft for some other user you can only create an nft in this particular setup if you have read access which we do if we own the public key so that's something else to keep in mind so I think we're roughly done in terms of this code we might want to have some way to set name for example look good at that here and again we want to add this call that to specify who can do that but I think that's probably it so I'm gonna say this and hopefully there's no and there is if there is it's probably two with semicolons okay no errors great so I'm going to silence requests we're going to ask you to say it four times because internally each collection is being saved separately to the database and now that's saved I can actually go into my Collections and I can see I have all the four collections there so if I wanted to create a new collection there's no button here to create a collection because the collections are derived from your schemat so you just add a new collection at the bottom of your schema and you'll be good to go the other thing to note here is that this is what we're going to use for later it's definitely worth copying your initiating your client code from here because we populate your main space and this is required to access your collections but we'll jump back into that in a minute okay so let's actually look at wiring this up now we've built our Arc actions so I've got a create react app here as you can see it's a very simple app I just go to the root here we use chakra which is a UI Library for doing some of the basic UI elements but essentially we've just got some Roots here we use react router Dom for that and we've only got two pages we've got a home and we've got chat and you can see these two pages here so I've tried to keep the app very simple because what we're really interested in here is how we use based on how we kind of wire up polybase to an existing UI so I'm going to start this code so we can see exactly what we're looking at here so we've just got a very simple thing and asking us to log in now if I click login with wallet it's not going to do anything because we haven't wired it up yet so let's go ahead and do that so you've got the sign in button which is what we're going to use and you can see that this is the page that we were just on we've got some logic to determine if we're logged in but we're not actually setting that at the moment so first thing we want to do is actually install the you are at the different libraries we need so we want client we want react and we want all so client is basically anytime you want to interact whether you're using the actual view or any kind of vanilla JavaScript this will interact with your database react has some helpers to help working with react and auth is used for kind of wallets and sign in and makes that process easier so install those so once those are installed you should be able to uh grab the dependency here and we want to grab our off and then we can just instantiate it here so all should be instantiated outside of your function and you should only instantiate it once for your app I'm just going to do it here for now but we probably want to move it up at the scope a little bit if we're doing this for all a bigger application and then it's really simple all I have to do is call so this now this sign-in is being called by this button here sign in log in with wallet so we're going to call this sign-in function and let's see what happens okay great so this is actually what the user would see they get an option so sign in with metamask or sign in with email if they sign in with email they'll be a custodial wallet so we would have the private key for that so less decentralized but obviously if you don't have if you're not already on boarded into web 3 you might not have a metanask wallet and then you've got metamask which obviously just delegates to the metamask extension now the great thing as a developer is regardless of which one the user chooses the experience for you should be the same or very similar and that makes it really easy and we'll be adding more authentication methods in the future different wallets but from your perspective you can use exactly the same API regardless of what the user decides to use as off so let's go through and actually let's log out what this responds with always interesting to see what's happening so I'm going to refresh this log in with wallet it's login with metaphase I've already connected on a different what website so it's going to just ask me to continue and then we're in now if we look in here we can see there's an object and we've got type metamask and a user ID that's all metamask gives us so that's what we've got to work with if we log in with these logs into metamask so obviously nothing happened because we didn't actually update any of the UI components so probably what we'd want to do is say okay if if there's some response object from here then we'll set the log logged in state and so again if I refresh and do it again maybe install it down with the process because he now got the logged in state which is just a quick UI update based on the logged in state now probably what I want to do is I want to I mentioned before metamask only gives us those two properties but we all we really want the public key so we're going to write a function to get public key if it's not provided to a song Sometimes if they use email public key will be provided in this result but if not we're going to find a way to get the public key so equal okay but if it's not available then we're going to say we're going to find a way to get it and I'm going to define a function up here put that public here and there's basically a way to recover a public key for an assigned message and that's the way we have to do it this we're not given a public key straight away so the message is just going to be log in with chat because it's a simple message because we just need to sign any message we're going to grab the signature and we can actually use the old fiber to grab the signature which would be youth personal sign and sign up message that will respond with a signature foreign we need a separate library for this so I'm going to just go and grab that out from here there's a library called polybase slash eat so this has some Utilities in that just making work working with ethereum based signing a bit easier because it's a bit of a Minefield out there and these all work without any browser polyfills as well which is nice so we want to be able to recover the past public key from a signature so we will get the public key back actually we'll just return that public key once we get that back and so it will pass in a signature and we have to pass in the message again so you don't really have to understand how this works but essentially if you have a signature you can get a public key from it that was used to sign up signature and that's exactly what we want in this case so we'll say in this case click the public key of the user and then we've now got that pocket queue which is great the reason we want that public key is we're going to actually create a user based on that public key so the next thing we want to do is actually create that user from our collection this commission is it here in our database and we're also going to want to load in the polybeth library to do that so as I said before you want to grab this to instantiate the client and we've got our DB now and we're going to say okay we want to create user if not exists already get user we're actually going to try in here so we're going to say PB The Collection so everything start for the collection so we would say user here and then we would say create and then we have an NT array object here because if you look back at our code we don't actually have any parameters so if you have parameters this for example would have an array of two items but because there's no parameters here we just put in an empty array actually what I want to do first is check if the user already exists so that's the first thing I want to do now hmd DB dot collection user and I'm going to look up a record by ID so look at the record pass in the ID and that ID would be our public key and then what we want to do is say get okay so if this fails because there isn't a use we will create the user but otherwise we'll we'll check that the user exists first so I'm sure that we have the user one thing to note about this public key actually if I log this out let's create the user first just so you can see what's happening there now the other thing we need to do here is we need to obviously tell when we're creating records on getting records from the database we need to give playbase away to actually call records so we need to actually do db.signer and pass in a function which will sign requests because the client doesn't know how to to you know there's many different ways to sign a request it just knows that he needs to sign a request so that it can create a record or get a record so if you just click into here we can actually see the signature type which is this final response which is here so we can just grab that um we get the data in which would be a string that's the data we want to sign this is a way of static value and we don't need the public key but the signature well we actually already got the signature using this each personal sign up here and so let me just copy that in so that's going to request a signature and we want to sign the data that the the client library is asking us to sign because that's what the client Library needs to sign okay so now when we log in we should create a new user so let's go and give that a go okay log out again log back in continue it's not going to ask me to sign now this is to get the public key like we wanted to to get and then it's going to ask me to sign another message and that's because we implemented the DB signer to read records and then finally the final record to create that new user okay so now we're logged in and the user should be created so let's go back to the Explorer and have a look now we can see here that there is an EU there we might think oh that's a mistake but actually it's because of the read rules on this collection as an admin you don't necessarily get the right to read anyone else's records it's one of the Privacy preserving things of web 3. but when in development it can be really useful to be able to see these things so we can actually add the public parameter during testing so that we can kind of see everything that's happening and make sure everything's happening correctly and then we could remove that parameter once we're ready so now you can see that this now appears because I've made this collection public the downside of this obviously is that everyone can see these these records now which is not what we wanted but yeah for testing it it can be useful now one thing to note about this public key that is created from your a two hacks function is that there are 64 byte public key now there are two types of kind of public key and some of them basically have a prefix on so there'll be 65 bytes some of them are 64 bytes like this one is 64 bytes so the only difference is you'll see 0x 0-4 if the prefix is there and you will see no zero four if the prefix is not there this is something to keep an eye out for because different libraries use different keys and actually the the this is returning going to be returning a 65 byte key so I'm just going to log this out here maybe you will be able to see that this key matches almost matches what we need so if I go back to the app I will refresh and we'll log in log out login again and so we have to send messages again so you can see this one here has 0x04 and then it and then the rest of the key is the same if I copy this bit you can see that this bit is is the same key so we do have the zero four prefix here but we don't have the zero four prefix here so we're going to need to just edit our code slightly to handle this zero four prefix so all I'm going to do is I'm going to say okay return public key dot slice and we're going to take up the four first four values and then add on the Zero X at the beginning again and that's just to make sure that everything is now the same in terms of the public key so when I log in again it shouldn't try and create a new user because it should now be able to look up let's just log this out okay so let's try again and let's sign okay and we've got the user data back so we know that user exists and we're logged in correctly which is great so that's now working but what we want to do is we want to now allow the user to Mint their own nft using the rules that we have in our next collection which is the nft collection and so we need to pass in this time an ID and an owner of that public key so I'll type user so I'll show you how you do that right now but before we do that actually just one quick thing one of the useful things to be able to do is to be able to every time now when we refresh the page we have to log in again but actually the alt is saved for you so you can actually use DB sorry auth dot on auth update and then this we can actually set the we can actually grab the auth from here we'll stay and we can kind of log them in straight away if they are so this will basically now when I refresh the page it will automatically log the user in because we've already logged in from a previous session which is obviously a nice feature one thing you need to remember to do is add the signer because we're not calling this function anymore necessarily every time but we need still need to tell the date that the employee-based client how to sign requests so we can still do that using that method and then we want to down here we want to create an nft so our collection was called nft so we want to do something like that's actually giving me some code here it's a DB collection nft create oh it was almost correct in here in this create you need an array like I mentioned before so the array would have two properties the ID and the owner so the ID is going to be the ID pass by the text box here so whatever this value is will be passed in so we're going to grab that nft ID from here that's already been wired up you can see here the input settings if I take the nft ID so we can create a mft connect to this and then we also want to pass in the user and the way you do that because it's another collection is you say user dot record and then you can pass in the public key now we probably store this public key somewhere once we've done it once but because we haven't done that I'm just going to grab the code from up here and make sure we grab that public key again and Okay so we've now got both nfts should be being created with whatever I put in there and the other thing we need to do is obviously we need to get a list of Records so I'm going to write this query and we can do that by calling collection again so everything starts with kind of collection we want to get the nft and then one of the things we want to do is we want to import our react library before using react because it has to help us in us to help us with read theories and we've got something in here called use collection that will allow us to do automatic updates whenever so it's kind of like the Firebase listener where you get automatic updates of of things that are changing so we're gonna have three properties here data error and loading the one we're really interested in is data here and that's going to be our list of nfts and then we can pass in our query so it's simple as that and then we need to pass in the data because it's under the the array of Records under the data property so that should give us our list of nfts and if this is all wired up correctly and then it should work when I now try to create an nft so I'm going to create one chord I mean my analytical palette world it's going to ask me to sign and then it's going to ask me to sign this message to say that that's correct and you can see the nft has appeared and it automatically re-rendered itself because that's what the news collection does it it automatically updates whenever there's a change in the database there's a change in the database so this is my nft and so I think that's everything for this video will cover some more of the chat up and kind of going in and building out the rest of the chat app in the next video but I think this gives a good overview creating the all creating your initial record and also reading a record from your collection and creating the UI hope that helps if you've got any questions I make sure to join our Discord Channel where we'd be happy to help [Music]
Automatic transcript — names and jargon may be misspelled.