Solidity by Example - Digital Marketplace

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video we're going to be implementing another solidity by example the project that we're going to be building out is for a digital marketplace the digital marketplace will consist of two smart contracts one is for allowing users to create unique digital assets in the form of an nft implementing the erc 721 standard from open zeppelin the other contract is the marketplace the marketplace will allow users to put items for sale and facilitate the sale of items between users and also transferring the value from one party to the other we'll also implement a payment mechanism that allows the owner of the marketplace to charge a listing fee and for that listing fee to be transferred to the owner of the contract upon completion of a sale with that being said let's go ahead and get started writing some code for reference all of the code from this tutorial will be located in a link in the comments so to get started let's go ahead and go to the remix ide at remix.etherium.org now from here i'm going to go ahead and just go ahead and create a new workspace called live marketplace and here we're given a few example contracts so the contract that we want is for a marketplace so to do that i'll go ahead and create a new file called marketplace.sol all right so if we look at these other contracts we see that we kind of go ahead and need to define a couple of things we need to define the version of solidity as well as the contract license that we're going to be using so to get started i'm going to be setting the license here and then setting the solidity version here now i mentioned that we're going to be implementing the erc 721 standard so instead of having to kind of go in and copy and paste all that code we can just import a implementation of that standard so the most common one that everyone uses and that works really well is the open zeppelin erc 721 contract and if we'd like to import that we can just go ahead and import it here we don't have to install it or anything and then we can go ahead and just save that and when we save that we'll see that these dependencies were installed and we see we have our npm packages and open zeppelin is there and we're ready to keep going another thing that i might go ahead and import is hard hat and hard hat has a really great utility that allows us to do console.logging similarly to how we might in a javascript project or in you know many other traditional languages next we'll go ahead and define our contract so the contract that we are going to be writing here is for the digital asset and we'll give the contract name of nft and it's going to be inheriting from erc 721 storage now i didn't really go through exactly what these imports are so let's take a quick look the counters import allows us to have access to a counter utility that makes it easy to create a number and then increment from the number every time a function is called now you could write this functionality yourself but this is a pretty nice way to kind of just have access for a way to increment numbers and then have the value of those numbers which in our case will be the unique identifier for the digital assets we're also inheriting from erc 721 uri storage now this contract itself inherits from erc 721 so we get all the functionality from erc 721 with one additional or maybe a couple additional pieces of functionality the one that we're going to be using is set to token uri set token uri allows us to set the uri of the actual asset itself so often this is something like an ipfs url that holds the name the description and the image property for the digital asset now this could be anything you know it just needs to be a string essentially that points to the location all right so now let's go ahead and create a couple of variables the first thing that we're going to be saying is we want to be using the counters for counters dot counter this is basically going to allow us to have access to this counters.counter property that we will be using to define a variable called token ids and we're setting it to private meaning we only want to access this variable from within the contract token ids is going to be set to zero by default and then anytime we want to get a value the value of that number we can say dot current so we can say tokenids.current and whenever we want to increment the value we can say tokenids.increment and we'll be using that in just a moment the other thing that we have is the contract address because basically for us to interact from one contract to the other we're going to be needing to call this function called set approval for all from within the erc 721 digital item set approval approval for all allows us to pass in the contract address that we want to give permission to make transfers on behalf of so we need to have that value somehow now you could pass it in as an argument if you would like but i think it's really handy to just have it stored here within the contract and that way we only have to pass in the single variable of the token uri or the asset uri that we're going to be dealing with and we already have the contract address available in memory all right the next thing that we're going to do is define our constructor and the constructor is going to take in a single argument of marketplace address and this is where we're setting the contract address to be the marketplace address so we basically need to deploy our marketplace contract first which gives us the address and then we deploy this contract passing in the marketplace address as an argument the erc 721 constructor takes in a couple of arguments as well it takes in the name as well as the symbol so here we're just going to give this whatever name you would like i'm calling this matters digital marketplace and ndm is the symbol all right so with that being said we're kind of ready to write the one and only function that we need for this contract and the function that we are creating is called create token and create token takes in the token uri of the token that's the only argument that we need and we're going to be able to kind of create everything else based on what we already have uh you know and and memory i would say so the first thing that we're going to do is we need a token id so we want to create a unique id for this token so to do that we call tokenids.increment so this increments the value by one and then we define a new variable here that is just setting the new item id which is kind of the new token id to token ids dot current and this is going to be our unique identifier for our token and now all we need to do is mint this token and we do that by calling underscore mint passing in the address of the person that's invoking this function which is message.sender and then we pass in the token id which is new item id we then also call set token uri using that that new token id that we just created and passing in the uri for the token which was passed into the function argument and then we call set approval for all and this is going to allow us to have access to this token and our other contract so we can transfer the ownership between parties and then finally we just return the new item id and this is important because if you're interacting with this contract from a front-end application you need that token id to call and you know retrieve information back from the contract itself or maybe you need that you would often need that on the client for other reasons as well all right so that's it for the digital asset or the nft and now we're going to go ahead and create the contract for the marketplace itself so i'm going to go ahead and save that and i'm going to make this small by clicking here and giving us more room and then the next thing we want to do is we want to import something called re-entry guard now this is basically a modifier that is for security purposes that allows us to add this non-re-entrance modifier and the modifier is something that you will use when you are calling one contract from another to prevent re-entry attacks now this is something that you would probably need in production but reality for this demo maybe not that necessary but i think it's important just to kind of uh maybe get exposure to these types of security details sometimes and basically what this is doing is when you're calling one contract from another you often open the contract up for recursive calls meaning that before that other function has resolved then maybe someone wants to call this function again and they can maybe drain funds or they can when you're dealing with uh with money when you're dealing with it with eth you know you have to be very careful so you want to kind of make sure that you're implementing you know as much security as possible so this is one of those security measures so this just gives us access to a modifier that we're going to basically be using and that's going to be the only thing that we inherit from so we're basically going to go ahead and create our new contract called nft market and we're inheriting from the re-entry guard and this is just going to give us access to that modifier now we'll go ahead and create a couple of variables and the two variables that we're going to be using are going to be item ids and items sold and they're both going to be counters the same counter type that we used in the last contract and item ids will be very similar to how we were keeping up with the token id so we want to have a unique identifier for every marketplace item and items sold is actually going to keep track with how many items have been sold and we can use this value to calculate not only how many items have been sold but we can subtract the items sold from the current item id to understand how many items have not been sold and this is important because if we want to return different views of our data we need to be able to populate an array with structs and you cannot do this with a dynamic array and solidity you need to know the length so by having the items sold we can now have the number of items sold the number of items not sold as well as the total number of items and we can then know the length of these different arrays that we're going to be populating so the next thing that we'll do is we'll go ahead and create the struct for the market item itself the market item struct is going to have these values that will make up each individual item so we'll have the item id which is the unique identifier we'll have the address which is the contract address for the digital asset we're going to have the token id for the asset we're going to have the address of the owner or the seller i would actually say this is the person putting this item for sale and then the owner is going to be set to an empty address when the marketplace item is put for sale because the seller is going to have their own address but the owner is not known yet because the new owner has not taken you know ownership by purchasing the item so we're going to set this to an empty address and then the price is going to be defined by the user selling the item next we're going to go ahead and create a mapping and the mapping is going to be called id to market item and this is going to allow us to have a key value pair where we can pass in the id of a market item and then return that market item and this is going to be really valuable for us to be able to retrieve the metadata for items based on their item id the next thing that we're going to do is we're going to define an event and the event is going to be for when a new item is created and we'll call this event market item created and this will be taking in the same values that the market item has and we can use this to emit a new event when someone has purchased something and this is useful for not only event listeners in your in your application itself but also if you want to use something like the graph protocol to index the data from a smart contract you can use these events and makes it really easily really easy to do the next thing that we want to do is now that we have our base set up for our contract we want to create a function that allows someone to purchase a market item so we're going to create a function called create market item and this is going to allow someone to put an item for sale and the things that the user needs to pass in as arguments are going to be the contract address the token id that they would like to sell um and also the price that they would like to define um so we in our nft market i'm sorry in our nft contract we return the token id for when someone creates an item and that's important because once they've created their item we want to use that id to put it for sale so they need to know the id for the item that they've sold the next thing that we want to do or i would say the first thing that we want to do in this function is require that the price that they're passing in is not zero because if they're putting this thing for sale then it needs to have some value and um and also actually we're using this non this non-re-entrant modifier here and again this is going to be something that's important for when you're calling one contract from another contract to help security around if someone tries to do a re-entry attack and this is kind of going to be some built-in functionality that we can just implement by using this modifier next we can go ahead and define a local variable for the item id or the id for the market item and we do that by incrementing the item ids and then creating a variable called item id setting it to the current value of the item ids next we'll create a mapping and we're basically using that id to market item mapping passing in the item id and then we're setting this to be the value of one of the market items and here we just pass in all the values that we have available to us so we know the item id because we just defined it here the contract address came in as an argument the token id and the price came in as arguments as well we know the value of the the seller because that's going to be the message.sender and we just can wrap that in a payable and then finally we also know that since this is an item that's now being put for sale there is no owner yet so the owner is going to be set here as a empty as an empty address so to do that we can just pass in zero to the address and then this will set the value as an empty address and then now that we've gone ahead and set up all of the the variables and we've kind of stored that locally we can now go ahead and transfer the ownership of this digital asset from the person that is sending this transaction to the owner of this contract or to the address of this contract actually and the way that we do that is we call ierc721 passing in the contract address and then we say transfer from and we pass in the argument from the person creating this to the address that it needs to be sent to as well as the id of the item and this is now transferred ownership of the digital asset from the person sending this transaction to the the address of this smart contract and then that's that's it this will go ahead and complete everything we need in this function we can now emit an event just saying that this item has been created and we're passing all the values that we need to make that happen so that is one of the two main functions that we're going to write for for transactional things that are going to happen the other is we actually also need to have a function for actually executing the sale so we've put the item for sale with create market item and let's see if i can minimize that so we've created the function for create market item here now we want to create a function for creating the market sale and let me make sure i have not i think i need to put this below here yeah there we go okay cool so i can go back here and try to minimize this again i think that was a mistake on my part there we go okay so we have create market item and now we have create market sale create market sale takes in two arguments it takes in the contract as well as the item id and the value of this transaction is actually going to be sent along not as an argument but it will be part of the transaction so we'll be able to to see the value that's been sent to make sure that that value is the amount that the item is for sale for and that's going to be available in the message.value so we're going to create a couple variables we're going to create a variable for the price the price is going to be accessible to us by using the item id and and using the mapping of id to market item passing in the item id and getting the price so we we're going to get the price using the mapping we're also going to get the token id for the asset using the the mapping as well so using this mapping we can get any value that we need off of this this this item so here we're going to go ahead and set a couple of variables one for the price one for the token id the next thing that we want to do is we want to make sure that the user that is sending this transaction has actually sent the amount of money that the seller asked for so to do that we can say we want to require that the message value is equal to the price and here we're going to say if it's not we want to have an error message saying please submit the asking price in order to complete the purchase and if it is if they have sent the right value we can now continue on and we're going to now execute the transaction and and set up everything in these next four lines of code so we're going to transfer the the value that is sent into this transaction to the seller so i am the seller like this is going to be my address so we're taking the id we're going to get the seller's address and then we're going to say dot transfer and then we're going to transfer to them like the value of this transaction so let's say i sent i sold this item for one eth this person is sending one either along with this transaction this is going to now go to my address we then do the actual transfer of the asset itself from the nfc contract and we are using the similar function where we call ierc721.transfer from and in this case we're taking the value from this this address that this contract is and we're sending it to the message sender and then we're also referencing the token id and then finally we update the local mapping to set the owner to the message.sender because now they own the assets and then we increment the items sold by one because now we can start keeping track of how many items have been sold that those two functions kind of take care of all the functionality as far as transactional purposes are concerned so this creates an item and then uh i'm sorry the previous function creates an item and this creates the cell for that item so we have create market item create market sale so the next function that we want to create is a function to fetch the market items that are currently available for sale so this will fetch all of the items that are for sale but we don't want to actually return every single item because in in reality for a regular application you probably want to have a view for only seeing the items that are currently for sale right because you don't want to offer for sale the items that that's um that have already been sold now you could you could basically return all this and show it if you would like and it would be actually a lot simpler than what we're about to do but for this function we want to do something that is more real world we only want to return the items that are currently for sale not the items that have already been sold so to do so let's get started we'll go ahead and create a couple of variables the variables that we're going to be working with are item count unsold item count and current index the item count is the total number of items that have been created so far the unsold item count is the number of items that are still not yet sold and that way that we get this value is that we subtract the current items that have been sold minus the total items and we're going to need that because we're going to basically be returning an array of the length of the unsold items so we need to know that count and then we also have a current index value that we're setting to 0 and we're going to be using this when we are looping over the total number of items in order to get the current index that we're going to be needing to work with in order to populate an array so the next thing that we're going to do is we're going to create a variable called items and this variable is going to be holding an array of market items and we're going to be setting it to a new array with the length of the unsold item length so we know that we want to only return the items that are unsold so that should be the value of this so let's say again we have 70 items that means the link of this array will be 70. and then we're going to now do a for loop and what we want to loop over is every item in the entire array of um of items that we have we want to kind of like go through every single item that has ever been created and then we are going to be using um another statement here where we're basically going to whoops check to see if the address is an empty address because if the address is an empty address that means that this item has yet to be sold and we do want to return it if the address was not empty then we do not want to return that so all we want to do is return the items that are unsold so if the item is is unsold if it has an empty address we create a variable called current id and we set that to the value of this id to market item mapping and the index is starting at zero but our counter started at one so we're just kind of going to say index plus one and then we create an another variable called current item and we set the value of this items array here to be that that uh that mapping or i'm sorry the the value of that item the next thing that we do is we then increment the value of our current index by one um because you know we started that index at zero and we're going to be adding a new item maybe on the next loop so we kind of want to increment that so the index of this array of course is going to you know start as an empty it's an empty array we're going to populate it with the zero with item the first time this this code is called and then we increment that to one and the next time this is called the current index is one and so on and so forth and then all we want to do at this point is is like we've populated we've populated the array at that point we're just going to go ahead and return the items so this will return the market items that have not yet been sold and the next thing we want to do is we want to have another similar function that only returns the items that we have purchased ourselves so we're returning all of the unsold items here now we're going to create a function that only returns the items that we've purchased and this way we can kind of you know view and log in with our address our wallet address and we can see the items that we own and we're going to do some very similar functionality as we did before we're going to have our total item count we're going to have our local item count and then we're going to have our current index and before we actually knew the actual length of the array because we were able to just subtract the um the value between the total items created and the items sold but we don't really we haven't been keeping up with the number of items that have been purchased for each individual address because that would be you know maybe a little bit too too many variables to kind of be keeping up with so what we can basically do is we can loop over or we can do like a for loop where we can say we want to loop over every single um item in this total item count which is the total items that have been created and we want to see if the owner of that one of the item itself is equal to the person sending this transaction or sending this request and if they do own that if they were the one that purchased that then we're going to increment the item count by one and then over the course of looping through all of the items we're going to know how many items that i've create i have purchased so this might be five or might be one or it might be zero or whatever but at least at that point we'll know the the length of this array so we we are no longer doing a dynamic array as far as the dynam the length we now know the length so we're doing a similar thing here where we're going to create an array of items and we're going to actually do that same exact for loop as we did in the last function as well the only main difference now is that um we are going to be checking to see if the owner is the message.sender as opposed to the owner being an empty address and if that is true if i am the one sending this message and i own that that asset it will go ahead and add the item to the array and then we can now just return the items array all right so that's it this is the functionality for the main part of the contract that we that we want to go over um so the last thing we might want to implement is something that we haven't yet added and that is what if we wanted to allow the marketplace owner the person that created this marketplace to start making a profit off of every single um item that's been been sold on the marketplace so we can actually add that functionality fairly easily so let's go ahead and scroll back up and after we add this last piece of functionality we're going to test this out but let's go ahead and create a couple of new variables the two variables that we want to start keeping up with are we want to know the address of the owner of this contract so when i deploy this contract i'm going to be deploying it from an address so we can actually get that address and we're going to be storing that in the contract as a variable called owner and then we can also define our listing price so how much does it cost for someone to list an item on our on our platform so just for the sake of testing purposes let's say that we charge 10 ether to to allow someone to list now this is probably of course way higher than you actually would but it will allow us to be able to um test this out pretty easily because we can you know send this transaction through and see the balances changing very apparently with this much with this much value the next thing is that we're going to do is we don't have yet a constructor in this in this contract so we're going to go ahead and create a constructor and we're going to go ahead and set the owner to be the message.sender meaning that whoever deploys this contract is the owner the next thing that we're going to do is we are going to add a new check and create market item here so in in addition to requiring that the price is more than zero we also want to require that the listing price is equal to the value that's being sent along with this transaction so when they create an item they are you know setting the price that they want to sell their item for but they also need to send some eath along with this transaction and that each needs to match the listing price and if it does then we can allow them to continue on and then finally and create market sale we actually want to transfer the amount of the listing price to the um to the owner of this contract so once the transaction is complete where we kind of have create market sale and all these things you know happen we're going to now transfer that 10 eth to the owner of this contract so that way every time someone buys something my account starts filling up with money um and that's kind of you know i think how a lot of these marketplaces are working all right so with that being said i think we're ready to go ahead and test this thing out so to do so i'm going to click right here and this is kind of where we can start executing stuff i'm going to go ahead and save and make sure you know that my contract is saved and i'm going to open this up and here we can kind of see that we have some logging whoops and i'm going to clear that out and we're going to go ahead and start testing it out so we have all of our contracts down here and the two that we want to deploy are the nft market and the nft the first one we want to deploy though is the nft market because we need that address to deploy the other one so if i click deploy we should see a green check mark everything works properly and now we have our contract deployed here and we can kind of see that we can play around with it in just a moment but what i want to do now is just copy the address by clicking this button here and we're going to now go to nft and we're going to deploy this one as well and if we go to backup to nft we see that in our constructor the only thing that we have to pass in is a marketplace address so we can just pass that in here and if i click deploy we should see that that deployed successfully so we've deployed our contracts now we can start interacting with them so the owner you know of the the contracts now has you know a little less ether because they've they've deployed some stuff so let's go ahead and switch to a new account so this account has 10 either let's go ahead and put an item for sale so the way that we'll do that is we're going to go to nft contract and let's go ahead and create a token with a uri of something like myuri.com or whatever now if we just try to create this without sending an e that should fail because we're supposed to send some type of value along with this um so oh i'm sorry no no this should be fun because we can actually create the token but when we create the market item that's when we notice in the eth so we create the token and it succeeds and all that so we have our first token created and we should be able to actually retrieve the token url by going to token uri here and just entering in the token id and remember the first item that we're going to create is going to start off at one so if i run that we should see that my uri.com is there so that's that's actually working as expected now when we actually put this item for sale that's when we need to send across some eth with the transaction so to do that i'm going to go to nft market and we're going to go to create market item right here and if we go look at create market item we should see that we want to pass in the contract address the token id and the price so the contract address i can just copy by clicking here it's my clipboard so i'm going to pass in the contract address the token id is one and the price let's say this is going to be in way by the way which is kind of you know 1 18 of an ether so the way that we might want to do that is say let's say 1 100 that's thousand and then three more zeros is million so i'm doing one with six zeros now now this is where if i try to actually to run this it should fail unless i pass in um you know enough either so let's go ahead and test that out so if i create market item we see that it fails and that's that's right because it says the price must be equal to the listing price so our our you know contract is working as expected so let's go ahead and send across 10 ether with this transaction because that's our listing fee and if i go ahead and click create market item then we see that this is successful and if i look at the account here we see that this person now only has 89.9 eth and this person still only has 99 and then this third person has a hundred so let's go ahead and purchase that that item and the way that we're gonna do that is we're gonna go ahead and select another account we're gonna go down here and i think we go ahead and copy that address again and i'm gonna create market sale and create market sale takes in the contract address and the item id along with the of course the price that this needs to be purchased for so the contract address is that the item id is one and the price for this one was one one million way so if i s if i choose way i'd say one with six zeros then this should uh this should work so let's go ahead and give this a shot all right so the transaction is successful so let's go ahead and look at the amount of money that each of these accounts now holds so the buyer now has um i'm sorry yeah 99.999 because like we sent only a little bit of of of way to go along with this transaction so the seller actually lost a lot of money because they paid 10 just a list and they only got you know one fraction of an eth as a sale price so maybe next time i'll send you know the value along as uh we'll we'll make that ether as opposed to way to kind of make this a little bit more real world but what's interesting is that if we go to this account the marketplace owner now has 109 eth that means that in a single transaction we were able to take money from one person send it to another person and then take money that was locked in the contract and transfer it to the to the owner of the contract itself so i think that's about it that's everything that we're going to be covering today in this video in future videos i'm going to be doing a similar example but it's going to be a full stack example showing how to build out not only the contract the smart contract part of this but also the front end and if you're interested in learning more about building a front end check out my other video the complete guide to full stack ethereum development it kind of shows you how to do everything there and yeah that's it for today so thank you for checking out the video and i'll see you again in the future
Info
Channel: Nader Dabit
Views: 4,111
Rating: 4.9560437 out of 5
Keywords: solidity, ethereum, programming, blockchain, defi
Id: 4Pm1Furz5HM
Channel Id: undefined
Length: 36min 39sec (2199 seconds)
Published: Wed Jun 23 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.