Transcripts
1. Welcome and Project Overview: Hello everyone and
welcome to my course. In this course we're
gonna be building a decentralized bike
rental application on the finance smart
chain test net, we're going to
start off by coding a smart contract and putting
all of that logic together. Then we're going
to deploy it out to the finance smart
chain testing it. Next we'll build out our UI. So we're gonna be using React. We're gonna be building a
homepage in a dashboard page. And then finally, we're
going to connect that front-end with their
deployed smart contract so that we can interact
with the blockchain in make transactions and pull data in all of that good stuff. And sometimes it's just
better to see it in action. So here's a look at
the final application in an explanation
of how it works. Okay, so here's the application. So imagine that you have a lot of bike trails in
the downtown area, and you buy a little office space and put a bunch of bikes in it and set up a
bike rental business. But instead of accepting cash
or debit card or whatever, you're going to accept B&B. So if I wanted to come in
there and rent a bike, I would come to this app. If this was my first time, I would first connect my wallet. So click Connect wallet
and connect your wallet. And then I'd click
choose my bike. And here we have a form. It says, Welcome, Please enter your first and last
name to register. You have to register
yourself as a renter on the smart contract
to check out bikes. So I'm just going to put
Travis test and hit Submit. Then I'll confirm the
transaction in MetaMask. And by the way, I look
at these low gas fees, this is like $0.20. So Confirm. Once this is done, it's going
to display my dashboard because I'll then be a renter
on the smart contract. So it says welcome, Travis or whatever
your firstName is. Here are your stats. So there's B&B credit. So I can add credit
to my account. My amount due, my
amount of ride minutes, if I check a bike out and my bike status currently it's red, which means I don't have
any bike checked out. Now we have two forms. One to credit your account, one to pay your dues, and we have three
bikes to choose from. And I can come down
here and check out a bike and check
back antibiotic. So let's go ahead and
credit our account. I'm going to add in 0.2
B&B to credit my account. So my total is 0.2 with
some minimal gas fees. So hit Confirm. And when this
transaction completes, I'm going to have 0
to B and B credit. So now I'm ready to
check out my bike. I have some credit in here. And I want to check out, let's say I want to check
out this middle bike. So click checkout
and confirm that. And what's going
to happen here is my bike status is
going to turn green, which means I have a bike
checked out currently. In my ride minutes
will start to total up and I'll be able to take
my bike out for a ride. And we're still pending. There we go. My bike status is green. The bike is free to
take out for a stroll. I'm going to come back in
about seven or eight minutes and we'll check the bike back in and I'll show you
the rest of the app. Okay, so it's been
about eight minutes, so let's check the bike back in. So I'm gonna come
down here and click check-in and confirm
the transaction. Now what's going to
happen is my bike status will go back to red, which means it's
not checked out. My B&B do will be totaled up in my ride minutes
will total as well. So my bike status is red. My B&B do I have 0.005 B&B in my ride
minutes or at eight. So now I can pay my B&B, do 0.005 BNB. And click submit. Confirm that. Now once I pay my balance,
this is going to go to 0. My ride minutes will go to 0 and my bike status will be back in. I'll actually be able to
check out a bike again. Because if you have a balance, you're not able to check out a bike because you've got to pay your balance in
that kind of keeps the owner free from having
to chase people down. This is a way that the owner
doesn't have to be super involved with his customers. He just needs to
provide the bike. Because if you don't
pay your balance, you can check out another bike. Now, on our smart contract, we also have a lot of checks in place to make sure
renters don't do things they shouldn't
like trying to pay my do when I don't
have a due amount. So if I click Submit, it should throw an error. I should have an error
slide in up here, giving me some kind
of error message. Yeah, execution reverted. You do not have anything
due at this time? If I try to do
something else like check antibiotic that
I never checked out, I should also get a message. Please check out a bike first. And that's basically the
gist of the application. In addition to this, at the very end of the course, there's a bonus lesson where we build out an owner's dashboard. This dashboard,
it's going to show the total amount
of the contract, the amount that's the owners, the button that gives
the ability for the owner to
withdrawal his amount. Now you may be
wondering, how does an owner make money off of this? So if someone comes in here and credits their
account with $10, it actually credits the
smart contract with $10, but that $10 is
allotted to them. So when they pay their do, it actually comes out
of their credit in that amount that they pay
actually becomes the owners. So every time somebody
pays their Mountain Dew, that transfers
over to the owner. So we'll be creating at the
end as a bonus and owners dashboard where they can actually view that amount
and withdrawal that amount. So I had a lot of fun building this and I know you will too. So who should take this course? We'll see if any of these
scenarios appeal to you. Number one, maybe
you're looking for a solid Web three project
to add to your portfolio. So maybe you're learning
blockchain development and you want to land that job
and get into that industry, but you need some solid projects to add to your portfolio. Then this course is for you. Maybe you've done
blockchain development with a thorium or on the
Ethereum Virtual Machine. And you're wondering
how it works with B&B or how you can
use BNB and remix, or how you deploy to
the BSC test net, then you will find this
course beneficial. Or maybe you just want
the whole package. You want to learn how to
create a smart contract, how to deploy it, and how to interact with it
from a library like React. Or maybe you're interested
in seeing how we can display solidity errors on the front end to let our user know when
they've made a mistake. Or maybe you're
just interested in how an application like this would provide sustainable
income for the owner. If any of these appeal to you, then I think you're
in the right place. Now there are a couple
of prerequisites. Number one, you should have base web development knowledge. So you should probably
have learned HTML and CSS and have built a
couple of easy web pages. Number two, you should
have a base understanding of JavaScript and react. So we're gonna be
using a reactant this course and that's
gonna be expected. It's not gonna be crazy like
we're not going to be using Redux and have all
this elaborate stuff. We're going to try
to keep it simple, but you should still have
that base knowledge. And then finally,
you should have an understanding of the
blockchain and how it works, which I assume you do or
you wouldn't be here. And as far as solidity goes, you don't have to know solidity to take this course
because I have an optional lesson with a solidity primer to get you up to speed
if you don't know it. I think you'll have as
much fun as I did building this app. So let's get started.
2. Creating our Smart Contract: Okay, So if you go to
remix.ethereum.org, we're going to use the
re-mix IDE as we should. Change my workspace to
the default workspace. Click on contracts
and create a new one. Just right-click new file. And let's call it bike chain because I'm not very
good at making up names, but bike chain,
blockchain, kinda catchy. Then as always with solidity, you're going to put it in
your license identifier. So this is commented out
SPD license identifier MIT, which means open-source dinner, pragma statement,
pragma solidity. Then we're just gonna do 0 dot dot 0 because
that's a good number. And we'll say contract and
we call this bike chain. And here we go. Isn't it exciting to have
a fresh screen to codon? Anyway, I had some complaints
and a previous video that it wasn't big enough. I can make this part
of the code bigger, but not really this over here. So bear with me. So as we usually do, Let's start this off with some pseudocode and it's going
to go something like this. Add yourself as a renter because you've got
to add yourself as someone who can rent a
bike, checkout bike. You'll go and you'll
check the bike out. Check in a bike. So you check out the
bike, you ride it around and then you
check it back in. Get total duration of bike use. So how long were
you on the bike? And then we want things like get contract balance just
because it's good to have that info and specifically
get renters balance. And then with this
total duration, we need to be able to
set the amount due, like how much the rent or O's. So set due amount. And I think this
is a good start. Let's start with, this
will go from here. And I'm having this
error down here. It's because I didn't put
a semicolon behind this. I've been in JavaScript
the past few days, so bear with me if I
forget the semicolon. Alright, add yourself
as a renter. And actually before we do that, one thing I like to do
is to set an owner. So if whoever deploys
the smart contract, that's the owner in
case they want to restrict things to
just themselves. So to do that, we'll just put a, a variable up here, a storage variable of owner
of type address. We'll create a constructor. And we'll set the owner
to message dot sender. And what this does is this constructor runs
when it's first deployed. So when this contract
is first deployed, the sender who is
gonna be the person deploying it is gonna
be set as the owner. Now smart contracts
are immutable. They are on the blockchain,
they can't be changed. So this constructor runs once
and the owner will be set. So we're going to put
that before pseudocode. So here's the first one. Add yourself as a renter. So we'll create a struct called renter and we'll set
some properties. So first, address,
payable wallet address. Because each renter
has a wallet address, everything in Web three
is a wallet address. We can identify the person
we can pay the person, the person can pay other people. And that's a type of address
and we set it as payable. By the way, if
you're like, I have no clue what this stuff is, this pragma in this payable. I created a YouTube
video not too long ago. It's about an hour long. It's called Learn
solidity in one hour. If you want to go and
check that out first, I'll explain to you
all the datatypes wouldn't address is
what a payable is. And we'll go over things like functions and loops and
we'll actually create a pretty easy smart
contract so I can teach you how Solidity works. So if you have no
clue what I'm doing, go and watch that, then
come back to this. I think it will be very
beneficial for you. I'll put a link below to that. And again, it's a
free YouTube video. So they have a wallet address. Next, we're gonna do
String firstName. And of course String lastName. Because even though they
are a wallet address, we want some kind of
personality behind it. Then we're going to set
a couple of Booleans so bool can rent, can they rent, are
they allowed to rent? Are not allowed
to rent. You will see how this works in a minute. Bool active, are they active? Are they currently on the
bike when they check it out? There'll be active
when they check it back in, they won't be active. Balance. They can send money to their balance
to cover the fees. And then a couple more UN's. So the amount due this is
the amount they have to pay. So they take the bike
out and it costs this many minutes in a
totaled up to this amount. This is what's due. And then you went to start an
end so we can keep track of the start and end time so that
we can get that time span. You went end. And that's it. That's all I want
with my renter. And we created that in a struct
which is like an object. If you watched my Learn
solidity in one-hour video, what we did there is we
created an array of renters, and then we just did a loop to find the index that we wanted. Whenever we wanted a
particular renter, we would look up the wallet
address, get that index. We'd know the renter is. In this video, we're gonna
do something different. We're going to not use an array. We're going to use a map, which I think makes
it a lot easier. And you don't have
to deal with loops, which sometimes if there's
too many of them or if there are an unknown
amount of loops, it could cause high gas fees. So we're gonna do a
thing called mapping. It's like a dictionary, it's a key-value pair. Do mapping, and the key
will be the address. The value is gonna
be the renter. Will make it public, and we'll call it renters. So we can look a renter up
by their wallet address. We won't have to loop
through anything. We can just say, here's the wallet address,
give me the renter. And finally, we can
make this ad renter function for air parameters. It's going to be the
renter parameters. So we're gonna say address. Actually, it's probably
easier just to copy this, paste it in, because
we're going to put the exact same thing
as the parameters. Take these semi-colons
out and put commas. And by the way, that's
Command D. If you select something and do
Command D on a Mac, you can just select the
next instance of it and then change all of them at once. And I didn't change this one. And then I can take like the whitespace and
hit backspace. And there we go,
put a space between them and they're all in a line. So all of these just correspond to the
properties and the renter. That's all it is. Then take off this
trailing comma and put my curly brackets. And then from here
we want to add this renter to our mapping. And to add to a mapping, you just do renters, right? Because they're mapping
is called renters. And in brackets, you put wallet address
because that's our key. Addresses are key. In this, by the way, is the type, the
type is address. In our wallet, address
is going to be the key. The value is gonna
be the renter. So to add something to a map, you just use like renters wallet address equals
one or something in it adds a key of wallet
address in a value of one. But instead of one,
we want a renter. We're going to add a renter
with the same values above. Wallet address, FirstName. Lastname can rent. Active, balance. And let me turn on. Do they have a word
wrap Word Wrap and editor doesn't seem to
be. Oh, there we go. I had to cut it off
and cut back on. But it's down here
in these options. Balance, do start an end. These are our parameters. So we're going to use this
Add rent or function. We're going to put in
all the parameters we want and it's going to
create us a new renter. In this map. It's just going to,
It's just like a push. In JavaScript. We're just
pushing a renter into this mapping or dictionary or whatever you want to call it. Now I have an error.
What is going on here? No visibility
specified. And Yup, we want to make this public. We have another error and data location must be
memory are called data. So strings have to be
memory are called data, which we're going to use memory. And that should clear the error. Awesome. So that's our ad
rent or function. If I open up the
deploy tab over here, and I just choose
the JavaScript VM. Click Deploy. We can test this out. So add renter. So let me put my values here. So I'm going to choose
just an address up here and account address you've got a bunch
to choose from. You can use one as the owner and the others is the non owner, but right now it doesn't matter. So I'm going to copy the
first one, paste it here. Now FirstName, I'm going
to put Travis. Lastname. Let's put test. And then can rent. So true, everybody can rent
upfront active, false. And then the next four
are gonna be 0, so 0000. So let's try adding a renter. Down here. It looks like it was successful. And if I choose renters and
put in my wallet address, which is our key, we can look
it up by clicking renters. And there I am. Here's all of the values of
the renter I just added, so everything is looking good. Now, close this out
and continue on. Alright, so next on the pseudocode is to
check out a bike. So let's do a function
called checkout. And we're going to
pass in an address. Like I said, you're
gonna be seeing this a lot because I'm
going to check out a bike and when I
pass in my wallet address so that it can identify, that's me checking out the bike. And I want to make it public. And inside of it, I
want to flip a few of my renter properties,
two different values. So when I check out something, I want to set active
to true, right? So. Renters wallet
address, dot active. So this is the renter width, this wallet address
in the mapping, dot active equals true. So this is, hey, I just
checked out a bike. I'm currently active. The next thing I'm
gonna do is I'm going to record that timestamp. So renters dot wallet address dot start equals
block, dot timestamp. Now this used to be
used to just type now. But now in solidity you
use block dot timestamp. So this is gonna
give us a timestamp and that's in part converter. So it's a Unix
timestamp is not like a month, year kind of thing. It's a unique time
Unix timestamp, which is a uint8, which all dates in Solidity RUN. So we're going to
set the start time. And we also want, if
you think about it, if they check out a bike, we need to set the
can rent to false. It starts out, hey, I can rent. There's no restrictions on me, but once I check a bike out, I need to set that can rent to false because I already
have a bike out. Let me select this, paste it and do can rent false, this person cannot rent a bike because they
already have one. And I think that's good. So now we can check out a bike. Now, let's check in a
bike function, check-in, address, wallet,
address, public. And we're gonna do
something similar here. We need to flip active back to false because they're
not on the bike anymore. We need to set the end time. Now, we set the start time, we need to set the end time. So end is blocked timestamp, this will give us the
timestamp for the check-in. Then finally, we want
to set the amount due. So remember, they have
this due property. This is how much they owe based on how long they
had the bike out. We'll do that in a few minutes. So I'll just put up
put it to do here, to do set the amount due. And that's checking in a
bike so we can add a renter, we can check the
bike out and we can check the bike backend. Next, get the total
duration of bike use. And let's create a
function for that. We'll call the function get total duration and
address, wallet address. We're passing in the wallet
address for an identifier. Public in this returns a U, and so it's going to
return to us a total, the total duration
as an integer, a U, and an unsigned integer. So the first thing
we can do is we can subtract the end time
from the start time. Remember it's in
a Unix timestamp, so we can just subtract the two. But I'm going to create
another function to do that. So I don't have to pull in
a lot of parameters here. I'm going to call
this renter timespan. You ant start, you went end. And I'm going to keep this
internal to the contract. And it doesn't do any of that, doesn't alter the contract, are really touch any variables
outside of this function. So I can label it as pure. If it did interact with
some other variables, I could do it as view, but pure means that I'm not
touching any variables. I'm doing all my
work right here in the function because I'm
passing in these two values. And this returns a uint8. And it's as easy as saying
return, end minus start. So back to my function here. I can say u and
timespan equals renter, timespan, renters wallet
address, dot start. And we'll see other parameter. I'll put my start
time in my enzyme. So it's going to
be the same thing. But the end timestamp, the ND, that should get the
difference between the two. And so this is in seconds. So I want to get
this into minutes. So I can do uint8 timespan and minutes equals timespan
divided by 60. 60 seconds in a minute. That should do it. And then return
timespan and minutes. And I have an error here it says function state mutability
can be restricted to view. So I can put here a view. So it's not quite
as low as pure. Pure doesn't even
read other variables. It only deals with this
function view will read other variables but not alter
the blockchain in any way. Then if I needed to change
a value or something, it would tell me I
have to remove view. That's all that is. Again, if you want a
deep dive on this stuff, check out that solidity
and 60 minutes where I go through all of
these things in detail. Let's good. So we've got the total
duration of why queues. So we've got the time, the
total duration in minutes, and we can move to the
next piece of pseudocode. So these are just simple methods
that we can make use of. So like get the
contract balance, we can do function balance of view public returns, a uint8. In all we do is return, address. This dot balance. Now this looks ugly and
you're probably like, what is this for? Well, this refers to
the contract returned, the contracts balance and
this is kinda convention. You'll see it in solidity. Just accept it, memorize it, and if you ever need it, use it. So I can get the balance
anytime you return the address dot balance of
this, It's the contract. And then to get the
renters balance, Let's do that one function,
balance of renter. And we want to
know which Renner. So let's address
wallet, address. Public view returns. You end. And we just want to return the balance of that
particular renter. So renters wallet address
dot balance, semicolon. So we've got renters
balanced, we've got the contract balance, total duration of bike use. The next thing we
wanna do is to set, is to set the due amount. Now for this, there's a bunch
of ways you could do this. What I'm gonna do
is I'm going to say every five-minutes
they have the bike. I'm going to charge 0.005 B&B. So B&B price USD. Alright, so 0.05 is $2. So every five-minutes
you're going to pay $2. So I'm going to use
that 0.005 BNB. And one thing you
might be asking, if you haven't asked already is, hey, this is remix.ethereum.org. What are we doing with B and B? Well, the binary smart chain uses the same amount of
decimals as a theorem. The theorem has this
18 decimal system so that it's able to have small fractional parts of one ether. And it's the same thing on
the ByteDance smart chain. It's 18 decimals. On the bayonets chain, it's, I think eight, but the biomass
smart chain is 18. So we can technically do
anything here in ether. And it will transfer over to the finance chain when
we go to deploy this. We're actually
when we go to test it, you'll see here in a minute. So that means I can
take this 0.005 and move that decimal place 18
and assume that that's way. Which way is like ten to
the 1800s of an ether? It's a smaller number, which means it has more zeros. It's a way to break up your ether into
fractional amounts. We can assume that's the same
on BNB and I'll show it. This will all make sense
to you here in a minute. So let's write a function set. Do so we're going to set the due amount of a
particular address. This is gonna be internal. We're setting this internally. We don't want anybody
else messing with this. Let's put timespan, minutes
equals get total duration. So we're, we're calling
this function to get the total timespan and
minutes. Let's get that. Then we're going to break this into five-minute
increments. So if there's 20
minutes on the bike, it only counts as four minutes because we're only counting
five-minute intervals. So five-minutes You're
gonna be charged 0.005 B&B. The second five-minutes,
0.005 B&B. So I'm just going
to divide that by 555 minute increments equals timespan minutes
divided by five. So that means if you are out
there again for ten minutes, it's gonna be ten divided
by five, which is two. You're gonna be
charged point O one, O, B, and B. Now we want to set
that do property. So renters wallet address dot du equals five-minute
increments times. Now here's what we're
going to move the decimal, 0.05 B&B per
five-minute increments. I'm just going to
say start right here with my decimal and say 12345678910111213141516171818 decimal spaces. So that is five. Let's see. Let me put commas just
to make it clear. Comma there, comma
there, comma there. Comma there, comma there. So we got 3691215
zeros, 515 zeros. Again, if we move
this back over, we got
123456789101112131415161718. And then we put r dot And we have 0.005. That's all that is. We're just
hard-coding this at 0.05. You might want to
pull the latest price and do some kind of math. The thing about
solidity is that they don't do fixed
point out the box. You have to do some kind of
crazy math to get a decimal. So I'm just going to keep the decimals out of it
and not try to be like 0.005 divided by the US dollar or something crazy like that. We're just going to set at
0.05 every five-minutes. Some put a semicolon. And we have a problem. It's because I put
unit instead of you and which I do all the time. And wrong argument count for function called get
total duration. We got to pass in
the wallet address because we need to
know whose duration. And that is set due amount. Now we can visit that
to do we have up here. So when they check
the bike back in, we want to set that amount. So we can just simply call set
due on the wallet address. And that will set that do variable as soon as
they check the bike in. And let's save that. I think we're close to
being able to test it. We do need to put some
required statements in here, but let's give it a test. Actually before we do, there's one more thing I want to add, and that's just to check
something we can use, I think on the front end. And it's just a function
called can rent a bike. This is just a way to say, Hey, Can they rent a bike without
having to go and look at the properties of the struct. We can just call
it right here and get a true or false back. So address, while at address. Public view returns bool, turn renters, wallet
address, dot can rent. So it's just telling us true or false. What does this set S? That's all. Let's test this out. This is gonna be a lot of fun. I think while we're doing this, you'll see all
these conditions of things we want to protect. They shouldn't be
able to do this. They shouldn't be
able to do that. And it'll cause us to
create require statements. So let's test it out. Let's test it just
locally first before we do anything on the
ByteDance chain. So you come over here and we're going to choose
JavaScript VM. Again, like before, I'm just going to choose
the first address and make them the owner because
we're deploying it and click, Deploy and open this up. So first thing,
let's add a renter. And let's make it not the owner. Let's choose the second
person and copy. So I'm going to put the address. Here's all my parameters here. And you can also find them
up here with the renter. But I'm gonna put
my wallet address. What Travis chest can rent. True? Because I can rant. I don't have a bike out. Active false, and
then no balance, nothing is due, no
start and no end times. To add renter. And come down here, choose my wallet address. Come down here and see
that I have a renter here. Great. Can I rent a bike? True? I can rent a bike. Get total duration 0. And to be honest, we shouldn't be
able to check that if the bikes checked out, so we'll put a condition
on that in a minute. But let's go ahead and
check out the bike. I'm going to check it out. And then when I click
renters here, it should say, can rent false because we don't want to be able to rent while we have unchecked out. It should say active, true. And there should
be a start time. So I'm going to run this again. There you have it
can rent false, active is true and
here's my start time. Now we set this up in
five-minute increments and I could go and change that, but I'm just going to wait the five-minutes and come back. I'm going to pause this,
come back after five-minutes and we'll check the bike
back in, see how that works. Alright, it's been
about five minutes. So I'm going to check
the bike back in. And so I'm going to choose
check-in, click check-in. And now if I check, check my renter here it
should have a n time. Active should go to false and
can rent should stay false because they haven't paid and we should have an amount due. So let's click renters,
and there we go. So we have a start time,
we have an n time. We are no longer active
and we can't rent. Great. We also have a Mountain Dew, and it's gonna be five
with all the zeros, which is gonna be
something an ether. But again, it's
going to translate over to B&B when we get there. So let's check some of
these other things. I can rent a bike that's false. Or the balance of the renter, how much balanced I have in there. I haven't
put anything in it. So should say 0. Balance of the contract is 0 and my total duration should now be six minutes.
Yeah, it's a six. So that calculated properly. We had the bike for six minutes. Now the next thing
we'd want to do is to be able to pay our balance
because right now, can I check a bike
out? No, I can't. Because I have a
balanced due and I just realized we didn't set any
way to make a payment. So we need to be able to send money to our balance
to pay that off. So let's close the contract
and put that together. So that's another one I
totally forgot about. So let's put another
pseudocode comment down here and just
say make a payment. And actually before we
make that function, I realized that we also didn't set any way
to deposit money. So the flow is like this. The renter is going to deposit
money into their balance. So one of the properties
here is balanced. They're going to deposit
money into the balance so that there's money
in there already. It's kinda like pre-paying. But the money, when
you deposit it, it's gonna go to the
entire contract and then the amount you put in
is going to go to you. So if ten people put in $10, it's gonna be $100
in the contract, but $10 credited to each person. And then as these
people make payments, money is gonna be deducted
from their balance so that, that money and the total
contract becomes the owners. Hope that makes sense. I think it will once we write this. So let's do this.
Deposit real quick. Composite function,
deposit, address, wallet, address, payable,
public, then renters. And just to show you this, I can actually close this
and just leave it in. This will deposit money to the contract because
it's payable. I can call this deposit
function and send money. And it's going to deposit
it to the contract. It's going to do that anyway. But we also want to add it
to the renters balance. So we want to do renters wallet address balance plus
equals message dot value. Now, message is one of
those global variables, like we had up here, which I didn't mention. I probably should have
message dot sender, who's sending this
message dot sender. We also have a
message dot value. What is the value I'm sending? So when I call this
deposit function, I'm going to send a value to it and it can be picked up
in his global message, variable, message dot value. That's all that is. So we're depositing
money to the contract, but it's also going to credit specifically to this person. So we're depositing
money to the contract, but we're also going to credit this wallet address
or this person. Now to make the payment, let's create a function
called make payment. Address, wallet address. This is payable public. And what we're gonna do here
is we're gonna do renters, wallet address, dot balance, and we're going to take
money out of the balance. So minus equals
message dot value. So say you're the only renter, you put in $10
towards your balance. So there's $10 in the contract, but that $10 is in your balance. So what you're doing when
you're making a payment, you're just pulling that
amount out of your balance. So there's $10 in the contract and it's all allotted to me. And I ride my bike for $10. When it takes that $10
out of my balance, that $10 is no longer mine. I have no balance left. That $10 belongs to the owner. And that's kind of how the
ownership thing plays out, how their owner gets paid. So we're not sending
money to the contract, we're actually removing
money from our balance. And there's also a few other
things we want to check, like Let's see me
just copy this. And there's also a few
other things we want to do. Like we wanna sit, can rent back to true. Because now they can run again. Hey, there balances paid, they're free to rent again. And I'm just gonna I'm just gonna copy this
a few more times. The amount due is going to be 0 because they paid
the amount due. Start time is gonna be 0. In the end time is
gonna be back at 0. So everything is kinda
set fresh again. You have things paid off,
you're able to rent. You have no time on the clock. Go grab a bite, and
I think that's it. I think that's
everything we need. Let's go ahead now
before we deploy it and put it in some
require statements, some checks to be sure we're not allowing things
we shouldn't. And the way you should do this, I've already done it, so I'm going to add them
and explain them. But the way you
normally do this is you take this here and
you deploy it. And then you go clicking buttons and testing things and you go, Hey, wait a minute,
they have a balance. They shouldn't be able
to check out or hey, they shouldn't be able
to make a payment because they don't
have anything. Do you gotta have
checks like this? So as you're testing
and clicking buttons, you'll come up with the
require statements, but I'm gonna go ahead and put
these in and explain them. So let's come up to the
checkout function first, there's two things we
want to check for. One, we want to make sure
they don't have a do balance. If they have a balance due when they shouldn't be able
to check out again, that keeps people
paying their bills. Otherwise, they just keep checking the bike
out and not make any payments because we're
not going to enforce it. We're trying to be
decentralized here. So what it is is they just
won't be able to check out unless they pay their balance. So we
need to check that. And we also need to check
that they can rent that they can rent property
is set to true. So we do that with
require statements. And what's neat about
require statements is that they will revert the transaction before gases span, which
is pretty neat. You don't blow the
gas and then have it fail and then you
lose your money. To do that you put require and then you set your condition
that you're requiring renters dot wallet address dot do and we want to
do to be equal to 0. We don't want any amount, do we want them to
have pay their bill? If that's not true, we can put a comma and
then some kind of message. You have a pending balance semicolon and we're
going to put the other one. Let's make a copy and instead of do, we're
going to check it. Can rent can rent
should equal true? That's what we require. We require that
they're able to rent. If not, we're going
to put a message. You cannot rent at this time. That's all for checkout. Now for check-in, we want
to check that they're active because if
you're not active, you don't have a bike, right? So if you just click check in and you don't have
a bike checked out, it should throw an error. So I'm going to copy
this require statement. I'm going to put this
here and do active. So active should be true, meaning they have the bike
actively checked out. Otherwise the messages, please
check out a bike first. Now let's go down to get total duration and we
want to put a check here. We want to check that
active is false, meaning that they've
checked in their bike. They can't get the duration unless they've
checked the bike in. And if that's not true, then we're going to say bike
is currently checked out. Then finally, on this
make payment function, now there's probably more
that you could put here. Like somebody in the
YouTube comments said, Hey, you forgot this check. Well, there's lots of checks
and things you could put. This one's going to production. We'd want to make sure there's
lots of checks in place. But the last thing I
wanna do is make payment. I want to make sure that I have an a Mountain Dew That
might do is more than 0. If I'm making a payment,
I don't have anything to pay. What's the point? I also want to check that my balance is greater
than the amount I'm paying from trying to pay ten bucks and only have
eight, that's not gonna work. So I need to make
that check as well. To require statements here. The first one is
going to check that du is greater than 0. That's not true. I'm gonna put, you do not have
anything due at this time. The next one we
want to check that the balance is greater
than message dot value. So remember this is a payable, people are sending money. We want our balance
to be greater than the amount of money being sent. In here, we'll put, you do not have enough
funds to cover payment. Please make a deposit. You can't pay directly, you have to deposit
money and then transfer that money is payments
and save that. And I think we're done and we're ready to
do some testing. So first we're going to test
it on this JavaScript VM. Then we're going to deploy it
to the finance smart chain. One last thing we should do for testing this get
total duration here. We haven't set in
five-minute increments. So remember last time we tested, we had to wait five minutes so we could get a
number to populate. Well, let's change that just
to something hard-coded, like returns six minutes, so we don't have to wait again. Returns six and we're
going to have to take out these because it doesn't
like unused variables. So save that. So this time we're just gonna get six minutes.
We don't have to wait. We can check out, check back in immediately, and
be able to test. So let's deploy that. Someone to choose the
first address is my owner. Go and copy the
address and deploy it. In the second address is
gonna be one of my renters. So add the address. First name is Travis, last name is test, which isn't my last
name by the way, I can rant is true. And what are the other? Active is false. 0 balance 0, do 00, start and end times. I'm going to add that renter should be able to
come down here, put in the address,
and see the renter. Great. Now let's check out someone
to check out a bike. Click checkout. And my values down here
should change accordingly. Click renters have a start time. Now active and I cannot rent
because I have a bike out. Great. Let's do some other checks. So can rent a bike is false, get total duration
should give me an error. So if I click that, it reverted and says bike
is currently checked out. So that is this require
statement here. Bike is currently checked
out because active, the requirement
is that active is false but activist true,
so it throws an error. So that works. One other checks do we
have we'll check that one. So check out you have
a pending balance. You can run it this time. I will check all
those in a minute. So let's check back in. Check back in. And if
we get our duration, it should be six minutes
because remember we set that manually. So
here's six minutes. Now that we checked in, we should be able to
come down here to renters and see the changes. So click this. Can
rent as false, I can check out
another bike. Why? Because I have a due amount, this amount and it's
five to all these zeros. But remember, that's to
the one-thousandth power. It's really 0.05. Because we only checked out in one
five-minute increments. Active is now false,
which is good. We're not on the bike
anymore, but we can't rent because we got
to pay this balance. Now what happens if
I tried to check out again, throws an error. It says you have a
pending balance. That check is good. My can rent is false, so it also fails there, but it doesn't hit there. It fails right here. So that check is good. And if we go down
to make payment, we have this balance should
be greater than the value. So if we try to make a payment
and put my address here, and we tried to make a payment of let me type in way converter. So way again is ether to
the one-thousandth power. So I'm going to just do 0.01. Let's just do 0.1 and get
this large way number. So I'm going to take
this number and I'm going to try to make a payment, put that here and make
sure I choose way. And I'm going to try
to make a payment, but my balance is 0. And we have a check-in here
that says the balance must be greater than the value I'm
sending, so that should fail. So I click Make Payment. It says you do not have enough
funds to cover payment, please make a deposit. Because I have no balance. I have no way of paying this. So what I need to do
is I need to deposit money into my balance. So I'm going to put
my address here. I wanted to pause
it that much way, so I have everything covered. I'm going to paste
that here and I'm going to deposit way. Now remember, when
we do a deposit, we have a value that
we're sending and re-mix. You put the value here. In ethers JS, you send
it as a value object. But anyway, we're going
to send this much. We're going to deposit
it to my address. So hit deposit. And then
when I click renters, I should see I have a
big fat deposit here. Great. Have a big balance enough
to cover the amount due. So the only logical thing to do next is to make a payment. Somehow addresses in the
make payment and I'm going to send this much money. This amount is due, 0.05 is due. So I'm going to
paste that up here. And I'm going to send this
amount to my balance. I'm going to click Make
Payment. That went through. Now if I update my renters, I should have an amount of 0 due and that much taken
out of my balance. So it should be instead of 100, it should be like 95 or
something like that. So let's click renters. I have nothing else to do. And it took it out
of my balance. And my start times back to 0, my n times back at 0. I'm not active, but I'm
able, again to rent. It looks like everything
went through great. In that our contract
works wonderfully. Air contract is fully functional and it's
deployed here locally. Now let's deploy it on
the finance chain to see that the finance
conversions work. So let's close
this for a minute. Now, if you go to your MetaMask, you need to add the binary
smart chain tests net. If
3. Finalizing Our Smart Contract: Okay, so before we move
to the next section, we need to add a couple of other functions here
on the smart contract. And I know this because I went ahead and built the
front end and I realized we needed a couple
other things to help us out. So let's add three
functions here. The first one is going to
be called Get do in all it does is get the dual mount for a renter address,
wallet address, a public function, it's a
view and it returns you and and we're just going to return the renters wallet
address, dot do. So the amount that
renter has to do. Next, we're going to
get the actual renter. So we're gonna get the renter
and it's going to return four pieces of information
for us about that renters. So it's basically like
returning the rent or object, but without the Uinta
part, parts of it. So it goes like this. Function, get renter. We're going to pass in
again the wallet address. It's public to view, and it returns for things. So string memory, firstName,
string memory, lastName. Bull can rent. In bull active. That's all we want to
know in this instance. So here we're going
to say firstName equals renters wallet
address dot first name. Whoops. Then I'm going to
copy this three more times on a Mac,
that's Shift Option. And then down to copy
the line you're on. And I'm going to use
Command D to select both instances of the
firstName and lastName. And then I'm going to
change this one too, can rent in this one too active. And all we're doing is just returning these properties
of that renter. And then finally,
we're going to create a function called renter exists. And it's going to return a bool, whether that rent
or exists or not. So we need to know if
that renter needs to add themselves to
the smart contract or whether they're
already added. So we can say function renter exists address while at address, public view, and
it returns a bool. Here we need to check
if that wallet address exists or not. So we can say if renters while at address dot while
at addressed property, if that wallet address is
not equal to address 0. Now you might be like
what is address 0? What does that supposed to be? Well, here's a good explanation. So with mappings in Solidity, there's no way to check
directly if something exists. Everything is set to
its default value until it's changed. That means every
integer starts with 0, every string starts
with a quote. Every array starts as
this and solidity has no concept of null
like other languages. So what they're saying is, if you remember in re-mix, let's, let's pull this up. Just comment this out
since we're not done. So let's come over here
and deploy our contract. I'm going to click
Deploy and open this up. So what if I go to
renters and just put in an address and click the button. Well, you'll see that everything
is in its default state. There's nothing no, like the postal saying there's
nothing null and solidity. It's going to have these, it's gonna be the value of
what it would it is basically, so the balance is 0, do is 0. All of these are gonna be 0. The bulls are gonna be false. I mean, it's just the default
value, it's not a null. And you'll see here the wallet address is
the zeros, zeros, zeros. There's, these are
all the way across. And that is equivalent
to address 0. I think we could also do address 000 or
something like that. But address 0 says, hey, if that person is in the
renters in doesn't have this, then they must exist. That's all that is. I don't
want to get too deep on this. Hopefully that makes sense, but it's a good way to check whether a key is in a mapping. So let me close that out
and get back to this. If renters wallet address dot wallet address is not
equal to a blank address, meaning they do exist. Then we're going to return true. Else return false. Then there's a couple of
tweaks I want to make. So if we go up to
get total duration, I want to remove this
require statement because it's just unnecessary. So we remove that
require statement. Now I want to put one condition. So if the renters start time is 0 or if their
start time is 0, meaning they've checked out the bike but haven't
checked it back in. Or if for some reason
they just have an enzyme which will
probably never happen, I want to return 0
because they're, they're checked out,
time is not complete. So if they want to get
their total duration before they check the bike and
they can't do that. You gotta check the bike and first to do that calculation. So I'm just going to come
up here and do if renters wallet address dot
start equals 0. Or if I'm going to copy and paste this just
because it's quicker for me. If the end time is equal to 0, then I simply want to return 0. You have 0 timespan in minutes. Else. You're gonna
do all this stuff. We already had a copy
that and paste it in. That's it. Your contract
is ready to go. We have our contract and re-mix, and from here we can compile it, we can deploy it, we can get the ABI and
all this important stuff. But nobody really
wants to do that from re-mix because this
is browser-based. I think it saves
it in the browser, but it could be lost. And you want all of your
code normally together and you want to version
control it in GitHub and things like that. So we're going to move this
out into a new project. And I'm going to show
you how we can use something called a
hardhat to bootstrap this whole ecosystem to manage this smart contract.
You're going to love this. So go ahead and open
up your terminal and we're going to create a
folder for our application. So I'm gonna go into my desktop and I'm going to make
a directory MKDIR. I'm going to call it bike
rental application. Hit Enter. And then I'm going
to cd into it. And code dot to open
it up in VS code. Or you can drag the folder in, or you can right-click
or do whatever you want, just open it up in VS Code. Now, what I'm gonna do is I'm
gonna go to hard hat.org. So go to hardhead.org. And what this is again, it's in the theorem development
environment. It allows you to run
solidity locally, to debug, to test. It gives you flexibility and
all this other good stuff. But what you'll see in a minute, all the great things
that it does. So go ahead at the top here
and click Get Started. And we're going to follow these steps because they're
written really well. So installation, we need to
do an NPM install hardhat. So make sure you have
no JS installed. If you don't, just
go to NodeJS and Google and click on NodeJS and just download
the LTS version. Once that's done,
you'll have NPM, you'll have in Bx, you'll have
node, everything you need. So we're going to
use this command. And we're going to
start actually by doing creating a directory
called contract. I'm going to cd into
that contract directory. Then I'm gonna do
npm in it, y dash y. So npm init dash y. What this does is this
creates a package JSON, so that we can install
npm packages in the dash y just makes the
default installation. So click Enter and it should set everything
up for you and you should have in your contract
folder a package.json file. So now we can run our command, which is npm install
save-dev hardhat. So click Enter to
install hardhead. After that's done, we're
going to do this Quickstart. This quickstart is
gonna do is bootstrap a sample project which
we're going to use. To do that. You just
run in px hard hat. So copy that. Alright, so I'm gonna paste that in NP x hardhat, hit Enter. And it's going to
give us some options. So we're going to choose create
a basic sample projects. So the first one here,
hardhat project root is going to be the contract
folder, so we're good there. Yes, I want to get ignore. And it says, do you
want to install this sample projects
dependencies with NPM which you will
need to install. So click, make sure
there's a y and hit Enter. It's going to install
a couple of packages that help us with testing and talking to the
contract and all of those things while it's installing. Let's
see what's next. So it's gonna give
us some examples here of how to run tasks. So you can run in px
hardhat to run tasks. So you can check, you can
print the list of accounts. You can compile your contract. You can run a node, you can do tests, a
lot of good stuff. There is a hardhat config js that allows you to
configure your deployments. We'll get into that in a minute. You can run in px
hardhat accounts to show all of the accounts
that you can work with. It, it pretty much creates
20 accounts for you to use. You can compile your contracts by running npm hardhead compile. You can test by running
NPS Hall at test. And lots of great stuff. We're gonna go through this.
All right, that's done. So if you look in
our folder now we have a Contracts folder, which they give us a demo
called Greeter dot soul. We of course have our
node modules scripts. This is going to be
our deployment script. We'll get into that in a
minute. You can run tests. We're not gonna do much
testing because we just don't want to make
this super long course, so we'll probably
skip the testing. And here's our config. And of course they're
packaged JSON. Let's first copy or
contract in here. So let's right-click on
the contract folder. Create a file called
Bike Rental dot soul. Actually I think we call
this bike chain dot soul. And I'm going to take my
contract from solidity, highlight it all and just paste
it into here and save it. You probably want
to install the, though I don't know
if you need to, but you may want to install
the solidity extension. I think I have that installed. Yeah, I have the
solidity extension. So it's yelling at me because it doesn't like the version. Our current compilers
0 dot phi dot 0. So I can open my
command pilot and choose Change workspace
compiler version. I'm going to change it to 080, which I can select here, and it usually takes
like five seconds or soda to clear.
Yeah, there we go. Cleared up. So my contract is in here. And actually we can take
a look at how this works. So if we go to
greet or not soul, you see we have a
contract called Greeter. We have our constructor
and we have two functions. We have a greet function
which returns a greeting, and then we have a
set greet function that allows you to
change the greeting. So here's the contract. And then if you go to
scripts and sample script, It's setup to deploy
that contracts. So you see here all
the great comments we get the contract to deploy. So get contract factory
called greeter, which is the contract. And then it deploys
that objects. So this is the greeter object
representing the contract. And then it deploys that object with hello hard hat
as the parameter. So if you go back to greeter, you'll see in the constructor that you pass in a greeting, whatever you want your
default greeting to be. The sample script
will deploy this and then await greeter deployed. Then it prints out
greeter deployed to whatever contract address
it deploys it to. So there's the grader contract, here's how the
greeter is deployed. Sample tests. So the, the one
test they give is that the greeter should return the new greeting
once it's changed. In this does the same thing, creates a greeter
object, contract object. It mocked deploys it with the parameter HelloWorld
and then it expects, it doesn't expect statement, making sure that
that contract has HelloWorld as it's greeting in, then it sets the greeting
to something different, and then it expects that
is something different. So that's the test and it should pass the original greeting
and the change greeting. Then in hardhat config, you don't really need
to set anything up for local deployment and we'll
see that in a minute. So that's kinda how it works. And now that we
know how it works, Let's delete this greeter, not soul in reproduce all
of that for our contract. So delete greeter dots soul. Then let's go to sample script and we're going
to change this to bike chain and get contract factory bike
chain and greeter. We're going to make
lowercase bike chain. And then we want to
deploy this object which is now bike
chain not greeter. Change that to bike chain, deploy and we don't send
anything with their deployment. So let's take that out. Change this to
lowercase bike chain. In console, log bike chain deployed to bike
chain dot address. Hopefully that made sense. We're just changing
these variables to deploy our contract
and not the greeter. So that should be good. Go to sample tests. We're just actually going
to comment this out. And that's it. So now we
can do in px hardhat, compile, to compile
our contract. And when we do this, we're
gonna get a new folder with their air compiled artifacts. So you'll see now we have
an artifacts folder. If you open that up,
there's some build info. We don't need to be
concerned with that. And if you open up
the Contracts folder, there's another
folder called bike chain dots soul with two files. In the file we're interested
in is bike chain dot json. And here we have
some key information we're going to have to use
to link up our front end. One of those is the ABI. Now the ABI describes
all of the functions. That are available in our
contract for us to call. Our contract is out there
on the blockchain and the ABI tells our application
what functions it can call. So you'll see here
the constructor, and you'll see
balance of function, add, add renter, balance of rent or all of
the functions we created. That's what the ABI is. We'll have to put this in
our project in a minute. Then down below that we have
this lovely looking code, and this is the bytecode. This is the executable that lives on the Ethereum
Virtual Machine. So when we deploy, This is gonna be some key information there. But we don't have to
keep track of this. In every time you make a
change to your contract, you're going to have to run
this NPM hardhat compile. And all it's gonna
do is it's going to recompile in, refresh
the artifacts. We've talked about
compiling our contracts and testing the contracts. Now let's look at deploying. So what we're gonna do in this course is we're going to deploy it to the
finance smart chain. But let's say you didn't want
to go out to a test net, but you just want it
to do it all locally. Well, here's how
you would do that. So we can use this
sample script to deploy. So right here you'll see in px hardhat run in the R script. It'll say deploying a
greeter with greeting, greeting deployed to this
con, contract address. But you see here a hard
hat will always spin up an in-memory
instance by default. So this is gonna be an
in-memory instance. But it's also possible to run hardhead in a
standalone fashion so that external clients like
MetaMask can connect to it. This can be MetaMask, your dapp front
end, or a script. So you can do this
in px hardhat node. And what this does
is this creates a standalone node that
runs on your computer. So if I type in px hardhat node, hit Enter, it's going to do
a couple of cool things. So one, it's gonna give
me those 20 addresses, but it's going to give
me the private keys to those addresses to, which is really cool and it's
gonna give me 10 thousand. In. What I can do now is
I can open up a MetaMask. And let's take this
first account. So it grabbed the private key of this first account
and go to MetaMask. And actually before you do that, you'll need to add
the local host 8545 endpoint to your MetaMask. So if you go to ad network
and you add a new network, I actually have it already. But I have here localhost 8545. So network name is gonna
be localhost 8545. New RPC URL is gonna be HTTP colon slash slash local
host colon 854 or five. Chain ID is 1337. And by the way, if you don't
have the node running, this is going to
give you an error. But anyway, it's 1337. Currency symbol is
going to be IV. And then you can
leave this one blank. And then hit Save. And this is going
to actually save this local host network for
you to play around with. I can now copy this
private key and then go to Import Account and set
the private key, hit Import. And then now I have 10 thousand to play
with one account two. And I can actually
account details. I can change this to local hardhat test or
something like that. Whatever. Then you want to leave
this node running. Gotta leave this
running. If you stopped, this is not going
to work anymore. So you want to go to
another terminal. And we'll run this next
command, NPS hardhat run. So we're going to
deploy this script, but we're going to use
the network local host. So you can tell IT
network rink OB or whatever testing
it you want to use. You just got to configure
it in your config. But we're going to use
the local host network. And I don't know. I think that just comes
default. I don't see it here. But anyway, let's grab
this and deploy it. In another term that
we'll remember, leave this running in
another terminal, run this. Oh, that's not good. Make sure you're in
your contracts folder. Make sure you're in
your contract folder because when you
change terminals, it kicks you back into the root. So run that again.
And there it is. Bike chain deployed to
this contract address. This smart contract got deployed to your node
that's running here. So as you build your
front-end application, you can just use this account. I mean, you'll have to put in your contract to dress
and stuff like that, but you'll use this account and then you can just
test everything locally. You got lots of Eve.
It's a lot of fun. But we actually want to
go a step further and use the finance smart
chain tests net. So that will be live
on the test net. And then if for some
reason you wanted to take it live and production, or you want to know how
to get to production. It's very simple from there. So let's do that now. So I'm going to
close this browser. I don't need that anymore. I don't need this node running. And I'm just going to
close this terminal out and clear this out. Okay, so that was the scenario of developing in your
local host environment. So it spins up a standalone
node for you to work with. You can deploy it onto that node and then you
can talk to it with external clients like
MetaMask. Great option. But again, we want to
go out to a test net. We want to make this thing legit and to have a real
feel about it, not a local host. Things aren't really happening. Situation. Now there's
a number of ways you could go about connecting to
the ByteDance smart chain. But many developers, they use a third-party service
for this because it allows you quick access and it allows you to scale if you ever wanted to take your
app to production. So there are services like interferer, that's
a popular one. Alchemy is really popular, but both of those focus more
on a theorem, not finance. We're going to use a service
today called Morales. Morales is going to
allow us to talk directly to the Biodefense
smart chain tests net. It has many, many other things that you can
dig into as well, but it gives you quick access. It allows you to scale. It just has a platform built
for this sort of thing. So if you go to Morales.io and you click on sign up for free,
It's completely free. You just put in your e-mail
address, create a password. I think it's going to send
you an e-mail to confirm and you'll be all set. So I'm gonna go to login and
just put in my password. Once you get here,
you want to go to speedy nodes and click on
the BSC network into points. In here you have a
set of endpoints. You have the main net, the main net archive, the test set, and the
test net archive. What we want is the test net. So copy that. And let's go back to our
project and let's add to this. So put a comma here. And so this is where we can define our different networks. So we can do testing
at main net, local host, like
what we just did. We can put some info there, whatever networks
we want to use. So we're going to
call this test net. And there are two properties
we need, URL and accounts. For the URL, we're
going to paste in exactly what we
copied from Morales. Then for accounts,
we're going to grab our account from MetaMask. So if you open MetaMask and
go to the BSC test net. Now if you don't have this, click on again, networks
and ad network. And you'll want to
add a new network for the BSC test net. And that info is right here. So the network name
is BSC test net. The new RPC URL is https
colon slash slash data. Actually just, just
go and type in by Nance Smart chain to MetaMask
or something like that. And it'll say connecting
MetaMask to finance smart chain. Right here, you'll get the
values here, test net. So here's the RPC URL. Here's the chain
ID, which is 97, symbol is B&B in the Block
Explorer URL is this. So make sure you copy
these N. So again, go to Settings
networks at a network, copy these values
in and hit Save. And then you should have an
option called BSC test net. And what do you wanna do is probably create a new account. You don't want to use one
of your normal accounts. I have one called BSC test. To create a new account,
you just click on this circle and create account and then give it a name and hit Create and
it creates one for you. But what you wanna do now
is in make sure this is an account you're not going to use for anything
else, of course. But what you wanna do now
is go to account details. And then you want to
export private key. So click Export private key. And I got, You got to put
in your MetaMask password. So let me grab that. So type in your MetaMask
password and hit Confirm, and it'll show you
your private key. So copy this. Copy that. Then go back to VS code and that's
gonna be your accounts. But see that it's plural. The fact that it's plural means you've got to
put it in an array. So I'm going to put your quotes and then
paste it in like that. Now, of course we don't want
this in our config file. We want to put it
in an ENV file. So let's go to contract
and create a new file. It's going to be called dot ENV. And we're going to have
a value called URL. And we'll grab this URL. And actually it's equals
and paste that in. And then you want to, then
another call to counts equals. And then here's where you want
to paste your private key. So go ahead and paste your
private key here, and save it. Now let's go back
to the config file and we want to use a
package called dot ENV. So npm install dot ENV. And I always forget
how this works. Dot ENV, ES6. Yeah, so we're going
to import dot ENV. And then once we do that, we can use it as NodeJS uses these environment variables which is processed dot
ENV environment name. So up top we will do
import dot ENV config, and then we should
be able to say process dot ENV dot URL. Then here in the array, we're going to say
process dot ENV, dot accounts and save it. And now we should
be able to deploy. We got everything we
need. Let's try it out. In bx dot hard hat. Actually I got Auto Suggest on. So NPS hardhat run scripts slash sample script.js,
dash, dash network. Now we don't want local host, we want what we have up here, which is test net. So we should be able
to erase that in the network we want
to use is test net. If we wanted to, if we wanted
to define something else, we just put all the main
net and same kind of thing. Then we can deploy the
main net if we wanted, but we're going to deploy
to test net and hit Enter. And it says cannot use import statement
outside of a module. That's fine. Let's go back
and grab the other one, which is the require statement. To put require there
and try it again. There we go. Bike chain deployed to this contract address. And if we go to BSC scan tests, net in, confirm this, let's punch in our address
or contract address. There it is, age as Thirty-five
seconds or contract. Here's our bytecode. Go to events. I don't
think we have any events. Transactions, no
transactions. Awesome. We've deployed our
contract out on the finance smart
chain test net. So we're done with the
contract part of it. If we have to make
any changes again, we'll just recompile
and redeploy it. It'll give us a new
contract address and we'll just update
that in the front end. So congratulations, you're
done with your contract. Now it's time to start
on the front end.
4. Project Setup and Building the FrontEnd: Alright, now we're gonna
focus on the front end. And what we would normally do with the React app is we would use Create React app to
bootstrap a project, but we're going to use something
different called vite. Now, vite is exactly
like Create React app, but it's faster and has
some other customizations, but we're not going
to worry about that. So it should be like
one for one the same. We should be able to use
this and do all the things we would do in Create React app. So if you go to vite, it's a byte, js dot dev. And click on Get Started. And then go down to, let's do yarn create vite. Feel free to do npm if you want. I just prefer yarn. And in your root folder, just paste that and hit
Enter yarn, create bite. And it's going to
bootstrap a React project. So project name,
let's call it client. Because this is
gonna be the front end of our application. And then select a framework. Of course we're going
to choose react. Then I don't want
to use TypeScript. So just choose react. And there we go. Done. So if you close your contract, you'll see you now
have a client folder. And if you look at
it, it's almost exactly the same as
Create React app. So we're going to take the
app CSS and delete it. And the favicon and the
logo, delete those. Then in the app JSX, we're just going to delete
all of this input div. Hello just to see that it works. And to run this, if we
look at the package JSON, it is, the script is deaf. So we can do a yarn run dev
or npm run dev. Either one. Of course I gotta be
in the right folder. So make sure you see the end of your client folder.
Run that again. And of course we gotta do Yarn install or NPM install
to install R packages. All right, Let's try that again. You're not Yarn
install Yarn run dev, and go to localhost. 3 thousand failed to input. Okay, So we deleted
a couple of files. We need to delete the
imports also go to app JSX, delete this important
logo statement. We don't have an app CSS, you can delete that, save it. And I think that's it. Main JS. Yeah, that's good. If we open our app
up. There we go. Yeah, It says hello, so
our apps running fine. So the first thing I'm gonna do, we're actually going
to use a thought about what CSS framework we
should use with this. We're actually going to
use chakra UI because I think we can really get this
spun up quick with that. Now I haven't used it a lot. So if you haven't
used it either, we're in the same boat,
but it's really easy. So let's visit the
website first. Chakra UI. And I'm in Brave, I don't want to be in Brave. Let me close this.
Chakra UI.com. Chakra-ui.com, and then
click on Get started. I'd consider using Tailwind, but I did a two tailwind tutorial one time in the
past and it was just so, so many classes to keep up with. I think it'll be much
easier with this. So we go to get started and we get to
this first Steps page. We'll scroll down to the Create React app
page. Click on that. And we see here that if we're
using Create React app, we can actually run
the command that bootstraps this CSS
framework with it. We are not using Create React app even though
it's very similar. So we need to do it manually. So come down here to the
manual installation. Click either yarn or in VM, and let's install it. So stop your server and paste that command and let's
install chakra UI. There's some other packages, emotion and frame or motion. Then we'll want to do
this provider setup. So we need to add this provider wrapping
our app component. So I'm going to use this
import statement first. I'm going to copy it
and go to main JS. Let's just paste that in
here above your index CSS. Then we want to wrap the app. And I'm just going to take this whole thing
and just replace it. We're also going
to be using icons. So if you go to Components and
somewhere there are icons. Let's just search for it. Media and icons look for this
section and click on icon, will want to install
this icons package to copy that and install it. So paste that here and
install your icons package. And while that's
installing what we wanna do for sake of time, since this isn't
really a CSS course, is chakra UI has a lot of components that you can
basically copy and paste. You can copy and then tweak
it to how you want it. We don't want to do
things from scratch here. We don't want to
reinvent the wheel. So if you go to
chakra UI Navbar, that'll take you to a
page that has lots of components that are pre-made. So there's the page sections, navigation forms, components, a lot of stuff that's
already put together. Now this page sometimes for
some reason doesn't load, like this content doesn't load. So I do want this first nav bar because it's the simplest. So just click on this
arrow to open it in a new page to get a preview
of what it looks like. So yeah, this is
what it looks like. Here's your logo,
Here's some nav items. They have sub menus and
then a sign in and sign up. We're going to run with that. So let's go back to this
page and click on code. We're going to use the width
sub navigation and CTA. Click on Code and hit Copy. And then we're going to
create a new component. So let's go to source, create a new folder
called components, and create a new file
called nav bar dot js X. And I'm going to paste
that in this whole thing. And I'm going to find the
main function with this, which is with sub navigation. I'm going to change
it just to navbar. It's already
exported as default, so we don't need to add
that at the bottom. And we do have some
errors. What is going on? Oh, this looks like
it's TypeScript, so we just need to
adjust for that. So let's go down to the bottom and just remove all
of these types. So remove that from
the NAB items array. And we don't need to interface because this isn't TypeScript. Find the next error. Remove that type under
mobile nav item. Keep going up under
desktop subnet. Remove that. And I think we're in the clear. So we should be able
to save that and run air server yarn, run dev. And we should see this
navbar should be that easy. Of course we don't because we didn't add it to
our app component. So that's nav bar. So let's go back to app. So APA, JSX, and then at
the top, Let's import it, import navbar from dot slash
components slash navbar. And then here we can just
change this hello and replace it with navbar and save it. And we should have a
navbar. There we go. It looks great. Now we don't need
all of this stuff, all we're going to keep
as the logo section. We're going to put whatever
the name of our app is. And we need we don't need
sign in and sign up, we just need connect wallet. So let's make some adjustments
so we can get rid of. Let's see, find work. So here are the navbar items. So let's get rid
of hire designers. Let's get rid of
Learn Design and these sub, sub navigations. Let's get rid of the fine work. Let's get rid of the
inspiration label. And we end up with
an empty array. Save it and see if that's okay. Yep, got rid of our nav items. Alright, mobile nav item. Let's get rid of this totally because we don't
have any nav items. It's going to look
fine either way. So I'm going to erase that. I'm going to erase mobile nav. Get rid of that. And I'm sure that's
referenced somewhere. So let's find it.
Mobile nav There it is. So I'm gonna get rid of
that whole section there. And I think that covers it. Let's save it and
make sure it's fine. Still okay. Let's find the sign here it is. Sign in and sign up. Just get rid of the sign M. And just change the sign-up
to connect wallet. We don't really want this pink. We want it till 500. And the hover, we're
going to make also teal, but a little lighter, so yeah, let's do it till 300. And instead of logo, Let's put a bike chain. I think that's what we
call the app bike chain. And let's make the right
before this closing tag. Let's add a font
weight equals 900. Let's make it big.
And font size. Is going to be X large. So save that and see
what it looks like. Bike chain. Then we want to make this
background a little darker. So up here where it's used color mode value,
it's set to white. Let's put gray 200. Save that and take a look. And that looks great. And if we shrink it
down to mobile up, we have this little
hamburger icon, which I don't really want. See if we can find
out where that is. Icon button, probably that. Let's get rid of that
completely. And save. It. Looks like our
buttons disappearing, so there's still something
mobile going on. Um, it's probably
something to do with the desktops sub NAB. Let's get rid of the sub nav. And then let's
actually get rid of desktop nav because we don't
need any of these nav items. So let's get rid of that too. And that would fall
right here desktop. Now, let's get rid of that and save it and
see what we have. Alright, and button is
still disappearing. And it looks like see
this button right here with this display base MD. This is responsive
like media queries. So at base, which I think is
the smallest, it says none. Let's take that out and
just leave the medium. Have it always in-line flex
and that should fix it. Yeah, there we go. And this moves over, but I'm not really
concerned with it. We can fix it later if need be. That looks good. So bike chain and we
have our connect wallet. I see how easy
that was to setup, just paste in the example
and tweak it as you want. Next, we're going to put
a big hero right here that points us to
the dashboard page. So if we go back to
our chakra templates, there is somewhere hero page
sections hero in right here. This is what we want. I'm going to choose
this first one here. There's some other options if
you want to go with those, I'm going to choose
this first one, and sorry, go to code, copy. And we're going to
create a component for this called hero dot JSX. I'm going to paste it
in just like before, and we're going to
change the main function name, the hero. We're going to create one
more component called home. So home dot js X. And this is gonna
be our homepage. We're only going to have
two pages on this app, so we're going to
do it like this. And for home, let's say const home equals return one home. Let's just put home
to return something. Actually. Let's have it. Of course, return our hero. Hero. Make sure you do your
import statement at the top. And down here at the
bottom, I'm going to export default home. And let's go back to our hero and tweak this to make it work. And actually we'll just
put home here for now. I don't want it here, but
let's put it here so we can see what it looks
like as we build it. And again, make sure you
imported at the top. And it doesn't like
that we don't have a parent element wrapping these. So I'm going to wrap it
with these blank elements. Great, and we have
some errors because we need to adjust
some things and hero. So the first thing is it says
import hid from next head, which looks like next to JS. So these templates use
different technologies. We're not using next to js. I'm going to remove that. And I'm actually just going
to remove the head part. We don't need it. And
everything else looks good. Let's save it and kinda
see what it looks like. It's, it's like already
ready to go here, but we do need to
change this text. So let's find our text up here and it says
make money from, and we're going to say,
rent your next bike. And then this text here, we're going to say with crypto. Then for this text, Let's
type connect your wallet, choose your bike, and
you're off to the races. When you return it. You can easily pay
your fare with B&B. And let's turn on word wrap. And we all like
those B&B gas fees because we really do save
that and take a look. Your next blank with crypto,
and here's our statement. And let's actually make this match with our
button up there. Let's make all of
this green match and there's a Get Started
and starting at 15, Let's address that also. So the first thing I'm gonna
do, rent your next blank. Let's put this as teal. We want to be using
teal, not green. Then down here, get started, let's say choose my bike. And again, set that to teal. And these up here, the background until
the color scheme Let's make TOO also see
what that looks like. Then this learn more. We
don't really need it. So just get rid of
that whole button. Then there's starting
at $15 a month. Let's put rent at
no cost upfront. And we should be done with that. Choose my bike rented
knows cost upfront, so we should be
able to click that. And that should take
us to the dashboard. And this ran at no cost. That's a little bit close. Let's go back and see
if we can move that. So let's put the top. We want to put it like
25 instead of 15. I think that's good. Yeah, that's fine. Ran at no cost upfront. You can take the bike
out, you can write it and you just have to
pay when they get back. So now we want to
be able to click this button and go to
the dashboard page. So for that we're going
to need React router. So I'm going to Google
that real quick. React router. Read the docs installation and we just need the yarn or NPM Yarn add React
router dom at six. So let's add that. Stopped my server, run that, start my server backup. And we're gonna
go to the app JSX and add all of this here. So we need to do an import. Actually, I can probably
get it from the page. Import browser router. Let's go ahead and grab that, saves some typing in. Let's do that as a router. I think that's convention. Let's import route, route and routes from React router, dom. In this return statement, we're going to put a router
component, capital R. We're going to wrap it all
in that router component. I'm gonna keep my navbar there. I'm going to remove home. And inside of this router, I want to set my routes. So routes. And then inside of that, we're going to put two routes, one for a homepage, one for our dashboard page. So the first one is route. Then do exact path equals slash, which is their homepage. Thinner element is the home component and its self-closing. And then just copy that. And the second path is
going to be dashboard. Element is going to
be dashboard which we haven't created yet. We will in a minute, It's probably going to error
out, but it's okay. Let me just format this. Yup. I think that's it. That's good and we
don't need this. This is leftover from
the initial Bootstrap. So we have a router
inside of it, we have routes and we
have two routes defined. Now we can go back to our hero into where a
button is right here. And since this is a button, you can't really do a link. So let's just do an onclick. We're going to have
some parentheses and we're gonna be
calling handle click. And as an argument, we're
going to pass in dashboard. Then let's define that. So let's come up here
to our hero function. And actually before that, we need to import navigate, which is a feature
of React router dom, which allows us to navigate
to different paths. So we do import, use navigate from
React router, dom. Now we need to define this hook. So let navigate
equals use navigate. And now let's create
our function Const, handle click equals. We're going to pass any
path as a parameter. And we're going
to call navigate. This is a React router six
convention, by the way, use navigated the
hook and we're just defining it as navigate and we're just going
to use it here. So navigate path in path
being whatever I pass in. And if you look down here,
I pass in dashboards. So this should navigate us, are direct us to the
dashboard route. So save that and we don't
have a dashboard routes. So let's go to new file and
create a new component. Dashboard dot JSX. And I'm just going
to copy home and paste it here and change
home to Dashboard. And I don't need
this hero import. We got to fix the spelling, and I don't need this
component here either. I'm just going to put an H
one that says dashboard. So let's check our
home component. We have our hero. So that's going to
display your hero. In this home component
is going to be called whenever we go to the
homepage based on our routes, remember the routes we created. So we should be
able to now go to our app and go to the homepage. So localhost 3 thousand refresh and it's not working.
What do we forget to do? Dashboard is not defined. Of course it's not defined. We didn't import it at the top. See we're using the component
but we didn't import it. So we just need to add an
import statement under that import dashboard from
components dashboard. Save it and our homepage
should be that. There we go. So we have our navbar, we have a connect Wallet button, which we'll deal with later. We have a nice hero and if
we click choose my bike, it should take us to
the dashboard page. Awesome, our homepage
is finished. So just to recap, we have our main JSX, which is wrapped
with this chakra UI, so we can use it anywhere
by this chakra provider. Their app JSX, we have
route's going on. So our homepage, homepage route is going to
display the home component. Our dashboard route is going to display the dashboard component. And then we have a navbar, which is our navbar that's
called in the app up here. Because we want that
also to be in a router. We have our home component, which is displaying our hero. Because that's what's
on the homepage. We have our hero, which
we just looked at. And then we have a dashboard which we're going
to jump to next. On the dashboard, we're gonna be able to display
all of the stats. We're gonna be able
to choose their bike and interact with their wallet. This is where all the
magic is going to happen. So let's go ahead
and build that.
5. Building the Dashboard: Alright, so the next thing
we wanna do is build out our dashboard page. Now here's what it's
supposed to look like. So we're going to have this welcome statement and we'll have some statistics here. That's gonna be our dashboard, will have a form that
allows you to pay What's du will have a form to
credit your account, will have a selection
of bikes here. So we have three
different types of bikes. Some description
about each bike and the ability to check out
in check and a bike, that's what we're
gonna be building. So first things first, let's create the
statistics panel. So I'm gonna go back to this
chakra templates and I have this Page section
called statistics. And we're just going to pull
it directly from there. So we're using the one
called stats with icon. It's going to look like this. And so click code
and just copy that. Then I'm going to create
a new component for this. I'm going to call it
current totals dot JSX and just paste in that code. And I think this is
also TypeScript, so we'll have to remove types. So we'll remove that, will
remove the interface. And I think that's
all we have to do. So now let's import that into
our dashboard component, which is going to be
the parent component for these child components. So import current total. And my intelligence
is not coming up is telling me we
didn't export it. So let's double-check that. Function stats card. Actually we didn't even name it. So export default function, we're going to call
this current totals. And let's try that again. Go back to dashboard. Import current totals
from current totals. It's in the same folder. And then instead of this H1, let's display the current totals and see what that looks like. And we have an error filter
resolved react icons, BS from current totals, JSX does the file exist? And it looks like they're using the React icons NPM package. Let's make sure
that's a package. React icons. And yeah, so we can click on
this and install it. So right here, npm install,
React, dash icons. I'm going to use yarn
as I've been doing. Yarn install, React icons. Oops, yarn add, react icons. And let us install, and we should be
good after that. Now I'm going to run my server again and refresh.
And there we go. We have our three statistics, but we want four and we want
to tweak them a little bit. So we want the first one
to have a wallet icon. Second one, a money icon.
Let's work on that. So let's scroll down
to the stats card, components of chocolate or UI. And you'll see here it
says like icon BS person, F phi server, go location.
What does all this? Well, we can go back to react
icons and look this up. So I want a wallet. Which one did we use here? It looks like that. It looks like we use
this MD outline account. Now you can tell which
library these come from by the first two letters
or three letters. So if you see like
IO while it's sharp, it's probably this ion icons. If you see MD, It's probably Material Design in our eye is like re-mix icon. So when you actually
click on this, it copies that name
to your clipboard. You want to go up
here and see where it says slash BS slash FI. These are the different
libraries here. So we won't MD because this is Md outline account in
MD is Material Design. I'm just going to
copy this and do import my copied icon name
from React icon slash MD. And we should be good there. So I'm gonna go down and
change that first one. I'm going to change the icon to the MD outline
account balance wallet. And we call this B and
B credit, B&B credit. And let's say 0.05. Awesome, looks good. Next we have this money symbol. So I'm gonna go to
my react icons and type in money. Maybe. Yeah, here it is, RI, money, dollar circle and it's RIs, so it's remixed icon. So click that and
scroll back to the top. And I can probably start replacing these because I'm
not going to be using them. So I'm going to paste
that here and it's RI, and I'll come down here and
paste it in the next one. So paste that. And then I'm gonna
change it to B and B do. So B&B do. And I'm just going to put
0.001 just for filler. Then our next icon
is this clock. And it's gonna be ride minutes. So I'm gonna go back to my
react icon and type in clock. We're gonna go with this one,
ai outline clock circle. It's AI. So we need to make
sure to put that. But that is my third one. And change this to ride minutes. I'm going to leave that seven. That's good with me. Then we need to add one more. So if you look up here, the simple grid is set up for a three-column base and
then one on small screens. But we need to
change this to four. So we'll have four columns because we would want for icons. And then I'm just going to copy this and save it to
make sure that's right. It's not AI outline clock circle is not defined of course. So let's go up here
and paste that. And this is a dy. Then we can get rid of this one and save it and it should work. Now, there we go. So we have our B&B credit
or B&B do a ride minutes. And then the last one says bike status and is
actually a color. So what we can do
is we can first of all make the same bike status. And then we don't
need these two, so I'm going to
comment those out. We need to add a
background color variable so we can come up and take a look at the
actual stat parent. And then we'll see
here that there are actually prompts
being passed in. So title stat and icon correlate to each stats card
has a title stat and icon. And then up here we're actually passing in that information. So all we really
need to do is add another prop here called BG
color for background color. So we're going to pass that in. And these are destructured, so we don't need to go
props dot BG color. We can actually just
use the variable. We can add another
attribute here that says background-color
equals BG color. So whatever we
pass in as a prop, it's going to change it
to that background color. Awesome. Now let's go down. And this last one, we're going to say
bg color equals. And let's go ahead and
just do red for now. Save it and see if that worked. Yeah, right here we have it now. The background colors red. So none none of the others get a background color because
that's not being passed in. It's only being passed
in. And this last one. What we can do is we can
make this conditional, like if the renter has a bike checked out and
we want this to be green. So we'll revisit this when we start putting all
the logic together. So I think we're done there
with their little dashboard. Oh, actually we got
to change this text. So let's change it to
welcome your name. Here are your stats and will make your name
dynamic later. If you come up here, right here. Welcome. Travis. Here are your stats. Awesome. So again, we're just
building out the UI. We don't have anything
dynamic going on. We're just making it look nice. So next on our list, we have these two forms, pay your due and
credit your account. So let's go back to
this chakra templates and see if we can
find something. Here's forms. And I don't really
want to use these. I want something simple. And when I do forums and react, I like to use React hook form, which is a library that
I think is really easy, I think is easier than some
of the others out there. If you do React hook form, and chakra UI, you should get a nice example
that we can work with. So this is actually from
the chakra website. So again, I went to Google, I typed in React hook
form and chakra UI. And you're gonna get
this URL, chakra UI. Plus React hook for them. So click on that. And let's just grab, let's just copy this here
and see what it looks like. So let's create a new component. Let's call it pay form. This is the formula
pe with dot JSX. And paste this in and then find our main function called Hook form and just change
it to pay for them. And then in our dashboard, and actually I think I'm
going to include this in the current totals
in kinda keep those together because we're gonna be adding these values
to that dashboard. So I'm going to put them
down at the bottom here. And what I'm gonna
do is I'm going to create a flex component. And I'm going to justify
content to the center. And I'm going to align
items to also the center. In-between those, I'm going
to put the pay form. A form. If I hit Enter, I think it
auto imports it for me. If not, be sure you come up to the top and import
pay form from a form. In my formatting is all off. Let me format this. There we go. And let's see what
that looks like. So I'm gonna save it
and I have an issue. Fail to resolve, React
hook for him. Okay. Yeah. So we have to do we have
to install this library. So let me kill my
server and do yarn. Add, React, hook form. I think that's what we say. Or you can do npm
install, React hook form. Let's install that first. Alright, run your server again. Let's give it a look. Alright, good. So we do have a little form here that just says firstName. It has a text input for your name and then
a submit button. So that's fine. Let's tweak it a little bit to say pay your due and
then take a payment. So if we scroll down, we'll
see here this is our form. We have a form label
that says FirstName. We have an input that
has some attributes. Id name, placeholder
name, this register, like registers, this
value with the hook form. You'll see how this
works in a minute and then set some
requirements on it. So this is a required field, minimum length must be four. And then there's this
error message that can come up if those
requirements aren't met. So let's tweak this before
we get to form control. Um, I'm just gonna do right
above the form control here. And let me format this because I don't
like the format either, right above this form control
on the return statement. Let's do a text component. This is from chakra
UI Text component. And inside of that, we're going to put a font. Font family equals heading and font size. Because we want
this to be bigger, we're going to make extra
large and font weight. We're going to do 600. And then we're going to put some
margin on the bottom. So nb equals four. And let me bring this back up. And in-between this we're
going to put pay your do. So we're going to
have this above the form or above the input. So all we need to do
here really is changed all these occurrences of name
to something like payment. So we're going to change this is invalid two errors, dot payment. We'll take the label out completely because
we don't need it, because we have the text
above the form control here. For the input, we'll
do ID payment, placeholder, Let's put
payment, capital P payment. We're going to register this
value, whatever we enter, we're going to register
that as payment. And this is really
cool. Like if you did a whole bunch
of inputs here, it will create an array of key value pairs of whatever
you submit in your form. So it's going to
say payment colon, whatever we enter
into the forum, it does all the work for us. Required. Yes, it is required. I'm not going to have
a minimum length. So I'm going to take that out. Then down here arrows dot name, I'm going to put payment
and errors dot name, dot message, change the payment. By the way, you could
leave that as name. It'll just say on the output, it'll have the key of
name instead of payment. That's kinda confusing. So we're making it
payment instead. Awesome. And it has some built-in hook, is submitting, I think it
creates a spinner or something. But here's your Submit button. So let's, let's see
what that looks like. Actually before we do
that, let's go up here and look at the
onsubmit function. So they even include that form onsubmit handle
submit, on submit. This is a React hook form. Convention here, but you'll
see up here on submit, we have a new promise. Now, I don't want
this setTimeout. It's just putting
in like a filler for us that after three seconds it'll show whatever values
we do to make it look real. I don't really want that. I'm going to take that
out. I'm going to keep this JSON stringify. But I'm going to take this out. And I'm gonna make this a
in an ES6 arrow function. So const onsubmit equals values. Then I'm going to
make it a sink. And all I'm gonna do
is log the values to the console, console.log. And let's see if this works. Oops, I need them. So JSON
stringify these values, save that, and let's
give it a whirl. But of course we have an error because we always have an error. Failed to construct text, please use the new operator. So I think it's
because we didn't import this text component. So let's add text to our
import, chakra UI import. And what else did we use? I don't think we used anything
else, so that should work. Save it. And here
we go. Pay your do. Let me clear the console and we should see
our value come up. So I'm going to put
hello and submit. There it is, payment. Hello, key value. So that's good to go, but we don't want for people
to put strings in here. We want them to put numbers
only and not only numbers, but decimal numbers because
we're dealing with B&B. So to do that, we actually come here and
we set the type to number. And then because we wanna
be able to use decimals, we can add the step attribute
and just put any save that. And now we can do like a 0.001, hit Submit, and it
submits properly. And if we try to submit
without anything, it's going to say
this is required. This is required. I
won't let us do it. That's what's neat
about React hook forms. It does like all of
this stuff for you. And once you get
used to using it, it's a great library. And just in case you're
wondering what this step any is, if I remove it and try
to put in that number, I can put in 0.01, but when I hit Submit, it says please enter
a valid value. The nearest values are 01, so you can only
use whole numbers. You can't use this decimal. So we have to allow this
step functionality. So step equals NE. Now that that works, let's go ahead and add the other one, which is the credit
your account, where you can add
credit to your balance. So we're gonna do the
exact same thing. I can actually just
copy this page form. I'm going to create a new
component and call it add two balanced form that JSX paste that in our other form and
just make some tweaks. So instead of pay your do, we'll put credit your account. Then instead of payment, we'll just do credit balance. So I'm going to
select all of these actually and do credit balance. Then for the
placeholder I want to see and I think that's it. Let's make sure that works. We do have the type and the
step there which will need. Let's save that and
refresh this page. And of course we need to
add the form to our page. You go to current totals
and write underpay form, add, add to balance. And we actually need to change this function
names that are paid form. Add to balanced form. Then we need to add it to
our current totals, right? Underpay form. We need to add the component. Be sure to import it at
the top minds gonna do it automatically and
to balance form. So there's my component and
it is imported up here. Now let's check it out. Great. I have the payer due and
credit your account. Now these two look stuck together, see how
close they are. Let's give them some
separation between each other and with the
content above it. I'm going to go to PE form. And then right above this form, I'm going to add flex justify
content equals Center. And this is just Flexbox align items in chakras own way center. Then we'll put some padding, so P equals five. And then I'm going to put
some margin top equals ten. And I need to do the same
thing on the other ones. So I'm just going to
copy the first bit. Make sure you come down to the
bottom and close that out. And also got to put my closing tag there and also make sure you
imported at the top. So make sure you put flex to import that from
the chakra library. And then we want to do the same on the ad to balanced form. So right above form, paste to the flex with the closing tag and come to
the bottom to paste that. And then up here,
added on the import. Let's take a look at
that. There we go. So they have some space between them and they have some
space above and below. Now, right below this we're
gonna be putting three bikes. So we're actually creating what chakra calls a stack here. We're stacking this on top
of this, on top of this. So I want to put a stack in
the dashboard component. And up here above this, I'm gonna write stack as box, boxes and other
convention of chakra. Text align center. Everything is centered. And then we're gonna do
some responsive stuff here. And I think I copied this from some other place in the project. Like I said, I don't want to
spend a whole lot of time on CSS because that's
really not why we're here. We're trying to get this built
real quick so then we can get to the fun blockchain stuff. So spacing base eight. And this is just sayings
on small screens, using eight on medium
is 14. So MD 14. And then PY padding y, which is the top
and bottom padding. We'll put base 20 and MD 36. And we'll do a closing tag. And at the bottom, under current totals,
paste that closing tag. And then up top you need
to import the stack. Imports stack from chakra
dash UI slash react. So just use this import
statement and save it. And now we have an error. Box is not defined, so we need to
import box as well. Save that. There we go. Now you see that our labels and text
boxes and buttons are all centered accordingly because we did this stack
and everything in this stack needs to be centered. So that looks great. So right under this, we're going to put
this row of bikes. So a description and
then these two buttons, and we'll be all done in ready
to get to the fun stuff. So here under current totals, I'm gonna put flex, justify content equals Center, and align items equals
center as well. And my closing tag
I'm going to put below in my closing tag, I'm going to put
directly below that. In in-between those. I'm going to add this
bike components. So I'm just gonna
put bike for now. And we're going to
have three bikes. So go up here to components, right-click create a new file, and let's call it bike dot JSX. Const bike equals return bike a H1 of bike. Let's export that
export default bike. And then in our dashboard, let's add three of these bike and be sure to import
it at the top. Import bike from bike. Let's add three of these
and make sure it works. Check that out. And box is not defined
in the dashboard. It is defined. Let's save that again. Maybe I just need to refresh. Okay, flex is not defined, so be sure to add
flex up here as well. Here we go, bike, bike, bike. So we need to replace
these with images. I have three images
for you to use. It'll be below this
video or somewhere, wherever the course content is. And what I can do
is I can open up, well, I'll create a
folder called assets. Let me open that up in
Finder and open up another. And let me find mine. So I'm going to paste
in these three items. Bike one, bike to
and bike three. Alright, so for our bike, what we're gonna do
is create a box. Remember these, these
are all flexed. So each one is going to be
have this box component. And then the box size
equals large margin x, which is left or right.
We're gonna put two. So there's some
space between it. Close that out. And in-between the box, we'll do an image which is gonna be our image source equals bike, margin, bottom equals ten. In this bike is actually
going to be a prop. So instead of props, we're just going to
destructure it and put bike. We're going to pass
that in as a prop. Let's close this image.
It's self-closing. Then we'll do a text component. And here you can just
put some Lorem Ipsum. You can find some bike
details if you want. I'm just going to do Lorem
Ipsum generator for now. And I'll just copy this bit. Again. You can put whatever
you want there, paste it in. And I'm going to
put on word wrap. So if you go to VS code up to View and click on word wrap. So there's some texts that's
going to be under the image. Then I'm going to
stack some buttons. So I'm gonna do a stack. Spacing equals 0,
direction equals rho, align, center, justify center. And then margin top equals five. Inside of the stack we
want to put a button in. Remember we've used a
button in the hero. So I'm just going to copy that. Go over here and
copy this button. It will make life easier
than us typing all this out. Go back to bike
and paste that in. So there's my button will change this text
to say checkout. And we'll put another
one below it. So copy that again and
change that to check in and remove the onclick. We don't want to
deal with that yet. I'm going to format my
my document and save it. And let's actually,
let's do this before we check Import button
from tracker UI, import box, image, text stack. And I think that's it. Also we want to, well, we're not gonna be able to
see our images yet because we're passing it the bikes. Let's deal with that
before we check our site. So our bike is a
child to dashboard. So here's where we need
to define our bike image. So up here I can do import bike. One from I think it's dot, dot slash assets slash bike one dot JPEG because I think the name of the
image, copy that twice. And change bike one to bike
to change bike 12 by three. So now we can take these
and pass them as props. So we can say bike
equals bike one. Bike equals bike to
bike equals bike three. And so we're passing in each individual bike
and we're receiving it as a prop in the
bike component. Awesome, Let's take a look
at this and see if it works. Great. So our images are here. They should be responsive. We're using Flex. Yeah,
they're responsive. And we have some
text that we can go back and tweak
however you want. And we have a checkout
and check-in buttons. Now these are circular and they don't have a
space between them, so let's fix that. So under button, we don't
need this color scheme, teal, Let's put m equals two
to put some margin there. Font size equals small. Font weight equals 600. And then this background
should be a total of 500. Remove the rounded and
remove this padding x. And then for hover,
Let's make it a 300. So it's a little lighter
when you hover over it. So I'm going to take all of
this and paste it down here. I'm going to paste
that here and save it. And now it should
look a lot better, except that the text is black. Let's make the text white. Color equals white. To match everything else. Make sure you do it on
the other button to save it and boom,
it's looking good. Now we should make
this bike chain, this logo up here, go to the homepage when
you click on it. So let's go to header
nav bar, sorry. Let's find out where that is, bike chain, and let's
make that a link. So let's put link. Because remember we
have React router setup a link to slash, which is our homepage. And then we'll put bike
chain in between that. And that will link to the
homepage. So save it. And now refresh. And now when we hover over
it, we'll see it's a link. We can click on it. And it does not take us to the homepage.
Something went wrong. Oh, I see what's going on. It's importing link
from chakra UI. And we actually need to import
it from React router dom, import link from
React router dom. That's what's going on. So we don't need this link here. Let's take that out
and how it should work. Yeah, here we go. Bike chain and you see below localhost 3 thousand
comes up down here. If we click on it, we
go to the homepage. So awesome. I think we're done with the UI and can actually get
started now and the logic. So if I'm on my homepage, I can connect wallet, the button there, I can choose my bike to go to the dashboard, which we have set up here. The dashboard gives
my B&B credit. B&b do ride minutes
in my bike status. I'm allowed to pay my du
payment, credit, my account. I can choose a bike down
here, check-out, Check-in. And I think I'm good. The only thing really
left is when the, when a new user comes
onto this page, they don't want to
see their dashboard because they haven't entered themselves as a renter in
the smart contract yet. So if I come to this app
and I've never used it, I need to register
myself as a renter. Remember we have that
add rent or function. So when they first come here, there needs to be a form where they can add
themselves as a renter, but we haven't really put any logic down yet
to determine that. So we're going to hold off. And as we get the logic going, when we're actually able to determine whether
they are or not. We'll add in that form. So great job pushing
through this UI. I know you're more excited with interacting with
the smart contract and building out that logic
and connecting to the wallet and
making transactions, all that fun stuff. But we had to get
this out the way and it's now out of the way. And we're going
to have even more fun in the next section.
6. Connecting MetaMask and Talking To Our Contract: Okay, so now to the fun part, let's hook our application up to the smart contract and start
talking to the blockchain. So before we get
into the front end, we need to go back to the
contract folder here. And remember when we
compile this contract, it created this artifacts
folder and a Contracts folder, a bike chain dots soul folder in this JSON file
with a bunch of data. And remember we talked about
the bytecode and the ABI. The ABI again, is a way to tell your application what functions
or methods it can call, what functions that
can call and you're smart contract and some other information
to do with that. We need to include this
in our project, this ABI. So grab the entire array and
just scroll down to the end of it and include the
brackets and copy it. And now we're going to
create in our client folder a file in the source folder
called config dot json. And we're going to create
just some regular JSON. So curly brackets in here, we're going to put ABI as
a key and has a value. We're going to paste
in that array. And I'm going to format it. And that'll be our ABI. Now in addition to
that, we need to be able to now in addition to that, we need air contract address like where we
deployed our contract too. So I'm going to add another
key down here after that. So put a comma and type
in contract address. And the value is gonna be the address to
which we deployed. And I don't remember what
that was when I did that. So I'm going to deploy it again. I'm going to cd back
to the root folder, cd into my contract folder
and run NP x hardhat, run scripts slash
sample script.js. We're going to set this
network flag for tests net. Remember we set in
our hardhat config, actually hardhat
config this networks, this object of networks and recreated one called test net. So that's what we're doing.
We're deploying were running this sample script or this deploy script
onto the test net. So I'm going to hit Enter and let that deploy
and then I'll grab the contract address
that was deployed to there it is bike chain
deployed to this address. I'm going to copy it, go back
to my config JSON and paste that as a value to contract address and save it
in our contract, we can put it away for now. So open backup the
client folder. And we're going, and we're
going to get back to this. So what we're gonna do next is we need a way to store state. And I don't really
want to deal with redox because this is a small project and Redux
is somewhat complicated. So we're going to use
something that's a lot easier called the Context API. And this is part of
reactant comes with React and it allows us
to manage state. So if you've worked
with reacted before, you know that we
pass props down to children and sometimes
that can get like way out of control and we're passing events backup to parents and it's just crazy. So what this context API does is like Redux in that
it manages state. But what this does,
what this benefits us with is that we can
wrap our entire project in this provider and then any component within that
provider can access the state. So the state is
going to be global and you can access it anywhere. You just bring that
context in, in access it. So we're going to
set that up and that's actually going to control like all of our
functions that we talked to this smart
contract with. So if you go to source
and right-click and create a new folder, and we'll call it context. Whoops, create a. We're going to right-click
on the source folder, create a new folder
called context. For some reason
it just will not. Let me do that. Here it is, context. So let's right-click
on the source folder and create a new folder
called contexts. And within that folder
will create a file called blockchain context dot js X. And from here we're going
to import a few things. So import, React and use state because we're going
to use that from React. Next we're going to import that. Config JSON. So we're
going to import that ABI and the
contract address, and we're going to
structure it so we can access both of
these individually. So import ABI,
contract address from. And then I think it's dot, dot slash config JSON. Good. Then next
we're going to be, then next we're gonna be using a package called ethers js. Now a lot of people
use Web three js. This package allows us to
talk to the blockchain, but I'm next we're gonna be using a package
called ethers JS. Now a lot of people I
know use Web three JS. I like ethers, JS more and
more acquainted with it. So I'm going to use that in
this package allows us to talk to our smart contract
into the blockchain. So it's very easy to install. Come down here. Let me get back into
my client folder. In run Yarn, add
ethers, ETA GRS. And while that's installing, I'm going to import ethers. Ethers. Pretty easy. Great. Next, we're going to create a context and we're going to export it as
blockchain contexts. So we're going to
put Export. Next. We're going to actually
create this context. We're talking about
the context API. We're going to create
this now and we'll set it as a variable
and export it. So we can put export, const, blockchain context equals
React dot create context. And that's it. Next we'll
create our component. Export. Next we'll create our
provider component. And if you don't know
how to use this, just Google it. And
it's pretty easy. You can read up on it and be caught up within a
couple of minutes. And just remember
there were gonna be using the hooks variation, which is a lot easier
in my opinion. Let's do export, const
blockchain provider equals. And we're going to destructure our children
instead of props. And that looks good. So what we're going
to return here, the key to this whole
thing is to return this blockchain
context dot provider. So let's do blockchain contexts dot and you'll see they
have consumer provider. We don't need consumer.
We're using hooks, but there's a lot of
things you could use here. We're going to use provider. And it's mandatory that
you put a value in there, which we don't have
at the moment. So I'm going to
leave that blank. Actually, let me put
this on the next line. We're going to return here the key component
in this provider. So we're gonna do return, blockchain context dot, and you see there's a
consumer and a provider. If you read up on
the context API, you'll read about both
were using hooks. So we're gonna be
using the provider. And we're going to provide, actually let me just
close this out. We're gonna be providing in here a value which we
have to provide. But we don't have anything yet. I'm going to
leave that blank. And then in-between
these will put children because that's
what we're passing in. So save that. And then we have
this provider here. But we need to go
to our main JSX and wrap the entire app
in this provider. So I'm going to first import it. Import blockchain provider from dot slash contexts slash
blockchain context. And then we're going to
wrap this whole thing. So down here I can say blockchain provider and just put it outside of the chakra or UI provider and the entire app. And save that. Now this, these values that we pass in, any values that we pass
in here are going to be available to all components
that bring in this context. I hope that makes
sense. Alright, so let's next go to the
ethers, JS documentation. Ethers. Let's just type in ethers
JS in the Google search, and then just click
on getting started. We're going to follow
these instructions. So how do you install it? We already did that. We
already imported it. We're not using a script
tags, so keep going. So here's the key to
this whole package. In my opinion,
it's three things. You gotta provider a
signer and a contract. So the provider
thank, read only. So a provider is a class
which I provider in ethers. Let's not mistake that with their Blockchain
provider or Context API. This is separate. A provider in ethers
is a class which provides an abstraction for a connection to the
Ethereum network. It provides read only access to the blockchain
and its status. Remember that when you think provider think read-only
access to the blockchain. Now a signer is a class
which in some way directly or indirectly has
access to a private key. Remember, we put her private key to a private key which
can sign messages and transactions to
authorize the network to charge your account or
perform operations. So when you think provider,
you think read-only, when you think signer think private key and sign messages, create transactions, make changes directly
on the blockchain. So you'll need the
signer for that. You've got the provider
read-only signer can act and do things. So you've got the
provider that's read-only and the signer that is able to transact
and make transactions. And then you have this contract. And we're gonna talk
about that next. Contracts and abstraction,
which represents a connection to a
specific contract on the Ethereum network. Smart contract that we
deployed so that applications can use it like a normal
JavaScript object. So we're gonna be creating
this contract object and we're going to be calling all of our functions from it. So the first task here is to connect our wallet to our application and we do
that through MetaMask. So be sure you download
MetaMask if you don't have it, just go to MetaMask. I don't know why
it's dot Zendesk. If you don't have it
downloaded and get it set up, there's a million articles
out there on how to do that. But I assume since you're taking this course that you
already have MetaMask, but just Google MetaMask and go to Download
and it's a browser. So be sure you have MetaMask
downloaded and setup. Here's ethers sample
of how to talk. So here's ethers take on
interacting with MetaMask. So remember there's a
provider, there's a signer. The provider is the connection
to the Ethereum network. So the provider is actually
gonna be MetaMask. And then the signer hold your private key and consign things. Remember we entered our private
key when we deployed it. And remember our private
key is in that ENV file. And we use that when we deploy the contract and then our wallets going to
match that private key. You're going to use
that same account that you use for your contract. Alright, so let's look at this. Let's go ahead and copy it
because we're going to use it. Right? So looking down here, the
comments are really helpful. This documentation is
really good, in my opinion. But first you have this provider and they went through
provide a wraps, a standard web three provider, which is what MetaMask injects As window dot a theorem
in the each page. So on this browser page, MetaMask injects
something called window dot a theorem
into each page. So when we set up this
provider, we use, we instantiate a new
web three provider, which is provided by ethers. So we do a new ethers adopt providers dot width
three provider and we pass in basically MetaMask
window data theorem is the MetaMask object. So that's going
to be a provider. We say that under the
provider variable. Then we can actually use
provider to send this. And then we can use
the send method to request permission to
connect user accounts. Then finally, we can take
this provider and call, get signer on it and
save that as our Signer. We're actually
going to copy this and paste it into
our applications. So copy that. And up here at the
top, just paste it in. And I'm going to remove
all these comments. One thing I'm gonna do is take
out this await providers. And we're going to add that in an actual function
because we only want it to happen when we click the Connect wallet
buttons. So take that out. We have a provider,
we have our signer. Now we need the contract. Now this is where
it's going to make all the sense to you. So if you keep going
down to contracts, it says the contract object
makes it easier to use an onchange contract as a normal JavaScript
objects with the mat, with the methods map to encoding and decoding
data for you. This is great. This contract object
makes it just, this contract object makes it
so that we can treat all of these smart contract functions is just JavaScript objects. So if you keep
scrolling, they give you the best example here. So copy this whole thing and paste it in
your application. So I'm going to come
down here, copy that in, and we're gonna work
through this one by one and it will
make sense to you. So instead of dy address, we're not dealing with di we
just we're dealing with B&B. So just change that
to address and we just put in,
what do you think? Well, if you go
up, remember we're importing the ABI and
the contract address. So our address can actually
be contracted dress. Now die ABI, where again
we're not using die, so just change this to ABI. And what do you
think that could be? Well, ABI. But the problem is we've
kinda confused JavaScript. Abi is grayed out, which means it's
not going to work. So let's change this to contract ABI. Contract ABI. So we're gonna put
here contract ABI. So we have our address defined. We have the ABI. Again, this is a good comment. The ERC-20 contract ABI, which is a common contract
interface for don't put that. So let's get rid
of that comment. And then finally we
have the actual object. Again, change this to contract. Then it instantiates
a new contract. So instead of dy address
will put address, instead of dy ABI,
put contract ABI. And then we pass
in our provider. But I'm actually
going to pass in my Signer because I'm gonna be doing a lot
of transactions. Awesome. So save that. We have all of our
info here to talk to her. Smart contract. Now let's run air application. So yarn, run dev. And let's do
localhost 3 thousand. And here's our application. So let's do yarn run dev to run our server and open up
localhost 3 thousand. And we have some errors, good. Alright, so let's do yarn, run dev to startup or a server. That's gonna be on local host, 3 thousand. So
let's open that up. Oops, the Saudi open refresh. And we have an error or
the requested module does not provide an export
named contract ABI. So something's wrong with that. You guys probably call it that, but it is importing ABI
because in our config JSON, it's under the key of ABI,
So we got to keep it that. So let's do this. Let's change the VAT, the variable to contract ABI and leave what we're
importing as ABI. And then we change down here. Now the problem is that we're
importing contract ABI, which is wrong because
in their Config JSON, it is a key of ABI. So we have to import ABI. And then we'll call this constant contract
ABI equals ABI, which is what we're importing. And then down here
we got it right, so we had all kinds of mistakes there. You
probably caught it. But make sure you
make those changes. Import ABI, save it as a
variable called contract ABI, and then pass that
into your contract. Let's save it and
see if that fixes it. Yeah, there we go. So now what we wanna do is when we click this
connect wallet, we want it to open
up MetaMask and requests their permission to connect the wallet
to our account. Requests permission to connect
to one of the accounts. So let's create a
function for that, right, under this, I'm
going to say const, connect wallet equals
is going to be async. We're gonna do a
try-catch statement. Try-catch. Here, we're going to say if window data theorem, so if this, this MetaMask
object doesn't exist, then we're just going to
return a alert and alert. Please install MetaMask. Then next we'll do
const accounts. We want to get the
accounts from MetaMask, so await provider dot send. Remember in ethers JS,
if I still have it up. That was our example, a
weight provider dot sinned. And what we want is
yf request accounts. That's what we're calling
them just for kicks. Let's console dot log accounts. And the first one, because that's gonna be the one that we're currently using,
the current account. And let's just
leave it there and see that we're consoling that or we're logging
that properly. And then down here in the catch, we'll do console.log error. And I'm actually going to
do a throw here new error. And let's just say
no, a theorem object. And I can't spell the
word throw. There we go. So we want to call this when that connect
Wallet button is pressed. So how we work
with this provider is we take this function name, we come down here
and we pass that in as a value, connect wallet. And then where's
the button that? Well, the button if
we go and components, the button is a navbar. So at the top of navbar we're going to
import the provider. So import blockchain
contexts from context slash blockchain contexts. So make sure you import it. Then because we're using hooks. We can come down
here and type const. And what function are we providing and the
provider will connect wallet equals use context,
blockchain context. Now you can create multiple
contexts in your application. You can have like
a user context in a transaction context
and things like that. So all we're doing
here for this. Component is we're just making available this
blockchain context. And we're bringing
in Connect wallet. And then down here where we have our button that
says Connect wallet, we're going to add an onclick. Onclick equals connect wallet
to call that function. And that's how easy it is. So let's save it and check
and see if it works. Open the application
and there's an error. So the error is used, context is not defined. So we've got to come up here. And where we are not even. And just do an import. Use context from React in, remember when you have a
JSX file in now in React, remember when you have, so
be sure to import that. Let's save it and try it again. And so when we click this
connect to Wallet button, it should open up
MetaMask just like that. And I want to connect my BSC test account. So
I'm going to click Next. Now if I selected multiple, it's going to put
all four into this. So that's why we're
choosing the first one. But I'm just going to click
on one because that's all I really do. Hit Next. So if I click Connect wallet, it's going to bring up
MetaMask as it should. And I'm going to
select the account I want to connect. Now. I could collect connect. Now it could connect multiple. And that's why we
have the accounts 0, because it's an
array of accounts in the first one is going
to be your current account. But I'm just going to select one and click Next and connect. And it's going to connect my MetaMask wallet with
my application. Great, so we're connected. If we open up MetaMask, we see this little
connected light is green. But the problem is we
don't know it in our app. It just says while it's still. So I'm going to disconnect
and we're going to fix that. So disconnect this account, and then let's go back and
do something better with it. So back to the
blockchain context. We're going to create some state to store that
current account in. So I'm going to come
to the very top and do const current account. Set. Current account
equals use state. And this is just React Hooks. They use statehood. And all it's saying is the current account is
going to be the variable that holds
my state in set. Current account is
what I use to set this state down here where
I consoled the account. I'm also going to save that into the current
account state. And you do that by saying set current account, accounts 0. So that's going to save it at, so that's going to
save it in there. So that's going to save
it as current account. But that doesn't really help
us because we need to pass that current account
through air provider. So come down here and
put a comma and put current account so that we can pass it to our provider and
then back to the navbar. And we want to also bring
that in current account, make that available
to our component. Then down here we
can do some logic. So we'll say if there
is no current account, note the exclamation mark, then we'll just say
connect wallet. This means nothing's connected because there's no
current account that hadn't been set yet. Then else we're going to
display our wallet address, but we're going to slice
it up so that it's like the first five characters, dot, dot, dot, and then
the last four characters. Most apps do that. So
we're gonna do that too. And we can say we're going
to use a template literal. So do the two backticks, dollar sign curly braces. And we'll put current
account dot slice. Then 0 to five, so the first five characters. And then we'll put
dot, dot, dot. And that's why we use
these template literals because we can mix in variables with string values
like dot, dot, dot. And then right after that,
we'll do the dollar sign. Curly braces in type
current account, in type current
account, dot slice. And this time we're gonna
go to the end and count up all the characters and then
just grab the last four. So we can do that by saying
current account dot length. This will get the
length of that while at address minus four. And that's what we're
going to slice. So let's save that
and try it out. Refresh. And now let's go
to connect wallet. Make sure you disconnect so
that you can connect again. Choose your account, click Next. And once I hit Connect, it should say store that
in the state and then update my component to
show my wallet address. So hit Connect. Look
at that already. There's my wallet
address, 0 x six to 73 dot dot, dot B F6. But we still have one problem. If I refresh, it's
gonna be gone. Now it says Connect wallet, even though I'm still connected. Let's disconnect and fix that. To fix that, we'll need
another function back in the blockchain context to check to see if the
wireless is connected. So here's how we connect. But when the app first loads, we need to check if
it's connected or not. If it is, we need
to store the state. Let's create another function. And actually I'll
just copy this. And we're going
to call this one. Check if wallet is connected. And we'll still do this. We'll check if the
MetaMask object is there. We'll do accounts. But in this time instead of e underscore request accounts, we're actually just going
to do underscore accounts. So this is going to
request the accounts, not permission to
use the accounts, but just the
accounts in general. So if there's
anything connected, it's going to show up here. And then we'll do
something here like if accounts dot length is true. So if there is linked
on the accounts, then we'll set current
account accounts 0. Else console.log. No, no accounts found. And get rid of these
two. This time I'm not going to throw an error. But again, all we're doing is getting the
connected accounts. And then if there are
any, will set the state. If not, we'll just console
it out. So we'll know. So this one we don't
want to pass to the provider because we
don't need it anywhere else. We actually need it when
the page first loads. So I'm gonna come down here
and add a user effect Hooke. And use effect hooks
allow you to run. And use effect
hooks allow you to run functions once
something loads or once something changes. So at the very end of this,
you can do comma, whatever. Like if you're
watching a variable whenever that variable changes, this thing will run again. But we're going to put empty
brackets here are empty. Empty brackets here, which
means it's going to run when the component first
loads, finishes loading. We're going to actually
put that checkup while that is connected there. That'll run when the
page first loads up. Again, when the
page first loads, it's going to check if
a wallet is connected. If so, it's going
to set the state. So let's save that
and try it out again. And by the way, every
time you load in, by the way, every time you save. By the way, every time I save, it just throws
these crazy errors. I'm going to show you how
to fix that in a minute. But let's just refresh
and test this out. So click Connect wallet. I'm going to connect it again, connect and it sets my address. And now if I do refresh, it stays. It's good to go. If I go to the next
page, it's still there. I go to the first
page is still there. So that took care of that. Now, just as I was saying, if I save this again, And come back, my page
is completely wrecked. And to be honest, I don't
know what's going on. For some reason, vite JS
is doing a page load, is doing a page reload
instead of the hot reload. I don't know if it's a bug or maybe something I overlooked. But other people are
complaining online. I think this is a new thing. And if I knew this, I would
have used Create React app, but it's actually
a pretty easy fix. This guy just listed it here. And what we need to do is go to our vite config and just add in this
server configuration. So if you go, if yours isn't doing this,
don't worry about it. But if it is go to vite, config js and just add this in, put a comma after this, and do server h EMR true, which is hot module reload, which is what's
supposed to be happen in any way I thought. And then do watch. Use polling. True? And that's it. Now save it. And I probably want to
restart my server just because it's a config. A lot of times we need to I'm going to restart it and that should take
care of the problem. So let me refresh now let me go save and see if it
throws that error. I'm going to come
over here and click save a couple of times. And there's still an error. What is going on?
Server ASMR true, Watch, use polling, true. Alright, server restarted. So let me save it. It's fine. Save it again. Save it here. Save it here again. It actually looks like
it's just happening in my provider file. So if I come here to
main JSX and hit Save, then everything is fine. But if I go to my
provider and do that, save it, it messes it up. Well, I'll try to figure out the answer to
this in the future. Me. We'll come back and
tell you how to fix it. But it really doesn't matter. Only in development,
like if you come here and click around,
it never happens. It only happens with this
white hot module reload. So I'll figure
that out and I'll, I'll post it here
in a little bit. Alright, so the last
thing we wanna do in this video is we want to try to talk to our contract to make sure
we've established that. And once we have
in the next video, we'll just go full speed ahead
and get everything set up. So let's go back to our
blockchain contexts. And let's create a
function that gets the balance of their
smart contract. So if you remember, we have in our contract folder
and our contract, remember we have
a function called balance of that returns
the contracts balance. Let's try to call that
and see if it works. So I'm gonna go to my
blockchain context and just do const, get balance equals,
equals a sink. And we're gonna do a try-catch. Console dot log error. In up here under try, we're going to say
const balance. And remember we have this
contract object that allows us to talk to
our smart contract. We're going to say contract. We're gonna do a wait because
we have an async function. And then contract dot balance of because that's their smart
contract function name. Then right after that, we're going to save
that in our state. So. Actually, let's just
console it out to Ashley. Let's just log into the console. So console.log balance and
just see if that shows up. Go back to the project
and reload the page, and it should be popping
up in our console. It takes a minute to
call it an actually no, that's not going to work. Then right after that we're
going to set the state, we're gonna put it in the state. Then we can put that in the
console to see if it works. Let's go up here and create
a new state variable, constant, balance, SET balance. And you see the pattern here. There's the word and then
set word equals use state. And so down here, we're going to set
balance to balance. Then I'll console.log balance. And this is not
being used anywhere, so it's not going to be called. There's none of this
is going to work. But just to test it, Let's come down here
and call get balanced. When the page loads. Let's save it and
refresh our page. And look at that. We get returned what's
called a big number. A big number is error amount in way or air
amount with 18 zeros on it. That's why it's
called a big number. C right here at 0 x 00
is big number true. So the big number is great. It's great to do the
work on the contract, but it's not readable. Like we don't want to
look and be like I got 1 trillion something of ether. We want to say I have 0.001
or 0.01, B&B or whatever. So there's a helper function. If you go to ethers, JS, and type in utils, and type in utils. And that wasn't helpful. Type in ethers, dot js utils, and click on utilities. And then you should see, and then type in a big number. There it is. And you should see down here, I think it's called parse ether. Yeah, here we go. So there are these,
there's these conversions. Ether dot utils,
dot format units, ethers utils format
ether parse units. And all this does is it just
converts this value for us, like the one we're gonna
be using is format ether. And this just isn't a good page. Let me, let me copy
and paste this. Ethers dot js. Here we go. Ether strings and weigh. The one we're gonna be using
is called format ether. And this is when you have way
and you want to show it as regular ether or regular B&B or whatever you're used to seeing like the human-readable amount. So formatted amount of way into a decimal string representing
the amount of ether. That's what we're going to use. To do that, we'll type in. So to do that, we
need to set balance. So to do that we need to
put instead of balance, we need to put ethers, dot util, utils
dot format ether. And then we pass in the balance. And this is going to set it to this nicely readable
format in ether or B&B, not the way 180 formatting. So let's save it and now
it should be showing 0. Let's refresh the page. It still says big number. Let's save it again. I don't know, maybe my state It's still showing big
number and that's probably because I'm calling
balance, which is this. Oh, yeah, that's it's
still showing big number. I think my issue is that I named this balance and then
I also have set, my state is balanced,
which I'm using here. So it's probably using
this original number. Let's change this to a balance
of just put balance of. And then now we're sure that
this is our state variable up here and not this.
So that's my bad. So let's call the
variable balance of format that and then
grab the state variables. So save it and now
it should be good. So refresh the page. In the try part of this, we're gonna say const,
balance of equals. And we're going to use
our contract object. Remember that's how we're
going to call all of these smart contract functions will do contract dot balance of, because you remember if you
go back to our contract, we have a function called
balance of we could call get total duration or set do and we're gonna
be doing all of that. But for now we're just
going to test this one. So we'll call it. So we'll
say contract dot balance of. Then right below that,
we're going to set another state variable
to hold that value. Let's come back up
here and type in, right under this put const, balance, SET balance
equals use state. Now you see the pattern here. First one is the variable and the second one starts with set, because that's the
variable you use. That's what you use to
set this first variable. So we can save this
now in our state. So right below this, we'll say SET balance. Balance of in this try block, we're going to get the balance. So let's do a const, contract balance equals
and we're going to use our contract object because
that's how we talk to these functions in
our smart contract. Now we're going to
use this contract object that we created here because that's how we're gonna interact with
their smart contract. So we'll say contract dot. And if you remember, if you
go back to the contracts, you remember we have
a function called balance of that returns
the contract balance. We also have set do and
get total duration. We're gonna be
using all of these. But for now we're going
to use this balance of. So we'll do contract
dot balance of. And then here we're
going to save that value in our state. So let's come back up and
set a new state variable. So const, we'll call it
balance and then SET balance. You see the pattern here. There's the state variable
and then you set it with the second one,
equals use state. So back down here we'll say SET balance to contract balance. And let's save that. Shoot. In this try block, what we're gonna do
is get the balance. So we'll say const. Let's call it contract balance equals await because this
is an async function. And then remember up here we
have this contract object. This is what we're
gonna be using to interact with their contract. So we'll do contract dot in what function do
we want to call? Well, if we go back
to our contracts, we want to call this balance of function because it returns
AIR contract balance. Now, later we'll be calling
balance of renter and get total duration and get
du and all that fun stuff. But for now we just want
to get the balance to make sure that
everything's working. So contract dot balance of
That's gonna get our balance. And then we want to save
that value in our state. Actually, before we do that, let's just console
dot log this out, contract balance and see what, see what it returns. And remember this get balanced
didn't mean italicized. Remember this get balanced
isn't being used. So if you see this, this get balanced isn't being called anywhere, so
it's not going to work. So we need to come down
here and just add it to our user effect
for the time being. Save that and let's see what
shows up in the console. So let's go to console and
wait for it to return. It takes a minute. There it is. Big number. It
returns a big number. Well, that's not helpful. We were thinking it
was going to return 0. So what is this big number? Well, if you remember
in our contract, remember the value way
that had 18 zeros on it? Well, that's what
this big number is. It's the way equivalent of ether or the way
equivalent of B&B. So if you have 0.01 B&B, well this big numbers
like 100000018 zeros. So what we wanna
do is convert this into what we're normally
used to seeing, which is the decimal amount. And to do that, ethers has these ethers has this
utilities package. So if you go to the ethers documentation or
if you just Google like either ab.js parse ether or something
or format ether. We're gonna be using
this format Ether method because you pass in way, it's going to format
the amount of way into a decimal string representing
the amount of ether. That's exactly what we want. So we're gonna do this
utils format ether. And so we need to do, in this time we're
going to store it in state because that's
what we wanna do anyway. So I'm gonna come up here and create a new state variable, const balance, SET
balance equals U state. Then down here we can
just put SET balance. And instead of putting
contract balance in here, we're going to put ethers
dot utils, dot format ether. And then we're going to
pass in the way equivalent, which is the contract balance. Pass that in. And
that should be it. So if we go back to our
project and we reload, and if you haven't used react a lot and don't know
about the reactive to
7. Building the Add Renter Form: Now we're gonna get started
on our dashboard here, where we can start populating
these dynamically. Currently we just
have static values, but we need to be able
to populate these. We need to be able to make a payment and
credit our account. And by the way, up
here we have credit and then the payment in
here, it's backwards. Let's swap these real quick. If we go to the current
totals at the bottom, just swap these two components, add the balanced form
before pay for them. That'll fix that. But before we do all that, we need to create
a form like this, the way this dashboard
is currently, it assumes that the renter has already added
themselves as a renter, but we haven't yet. This again is just static text. So we need to put a form here to display if the rent or hasn't added themselves
as a renter. And then if they have already, then we'll show the dashboard
and their current values. If we try to go in
credit the renter and check their ride
minutes and all of that, it won't work because
remember we have this function in our contract up here that says Add renter. We need to add renter to our
mapping of renters here. So that's what they need to do. Essentially, they
need to fill out the form to add
themselves as a renter, which then allows them
to check out a bike. Right before we do that, we have one thing to address. So in the previous video, you, one thing you might have noticed is whenever I was working in his blockchain context file and I made a change or
whatever I was doing. And I went to hit
Command S to save it, it would actually
crashed my page. So let me hit Command S, go back and you'll see
my pages crashed. If I open the console, you'll see a whole
bunch of errors that relate back to the
used contexts hook. Now the reason for
that is because in air blockchain context at the top where we
create the contexts, we left the argument
null or parameter. No, we should put something in here and we're just going
to put an empty string. And I'm going to save that. And now let's test it again. So let me refresh this. And I'm gonna come over here
and save it a few times. And you should see
that my page is fine. So that's an error on my part. Go to the React dot
create context and make sure you put in a value, in which case we're going
to put an empty string. Alright? So let's create a new form. We're going to call it
rent or form dot JSX. And again, we're
just going to take the one of these other forms. Let's try the ad
to balanced form. And we're just going to
copy and paste this in. And then we'll come up to the function name and
call it rent or form. Alright, and then
we scroll down, you see this credit
your account. We want to change
this to something different and I'm actually going to come up here above the flex. And I'm just going
to put a text field. And in the TextField
I'm gonna put as attributes, font-family
equals heading. Font size equals 600, or actually x large. And then font weight equals 600. Alright, and make sure
you put the closing tag. And then inside of that, we're
going to put some texts. We're going to say welcome. And then I'm going
to put a line break. And please enter your first
and last name to register. You might be like, isn't
this a decentralized app? Why do we want somebody's
last name or even firstName? But it's just a concept I came up with when
I made the app. If you want to change it,
feel free to change it. And you'll see we have
this error because we, because we can't have
multiple tags and a return, we resolve that by doing this
open and close empty tags. So put that at the top and a closing one at the
bottom in all as well. So we have our texts here. We have a flex and
then we have our form. In the form we
actually just want the firstName and
lastName because can rent remember
is gonna be set to true because they're just
creating their account. Of course, they can rent. Active will be set to false because they don't
have a bike Yet. Then the start time, end time, balance and amount
due are all going to be 0. So that's going to be
set on the backend, or outside of the
forum or outside of the users ability
to change that. So we just need a
first and last name. So we have already one input. So I have formed control. Let's do it. Let's actually do a label here. So form label in HTML
four equals firstName. And we're gonna put
FirstName here. This is just a label. And then we have our
input, our error message. And then we're going to copy and paste another one of these. So another form label
input and error message. So right under the error
message, paste another one. And we're going to
set these two up. So HTML for firstName. So we're going to
again put firstName, take out this type
number in step any because we do
want characters. Placeholder, firstName. And then everywhere
there's a credit balance, just do firstName. And then in the second one, we want last name right here, change this to LastName, lastName, take out
number in step. Placeholder is going
to be LastName. Register is LastName. And remember I told you
that this register, and I'm going to make
these not that camel case. I want to make it all lowercase to match with the other ones. But remember I told you
about this register. It actually registers the input that you're putting in
the fields and puts it in this object that's then sent to wherever you're sending the form, it's pretty cool. That's all I have to do. So lastName, change
these two to LastName. And then up here where
it says form control, there's a check for is invalid. I want to check if
there are errors. Firstname and whoops,
and errors last name. So right here we have
an error message. So if there's an error
in this one or this one, and actually we set it
for, and so both of these have to be error-free to pass. So you can't put a field. So you can't put values
in one and not the other. And for this one we do
want a minimum length. So let's do men
length value four. And the message is going to be minimum length should be four. We're going to put
that in the next one. Let's save it. And up here where it says
credit your account, take out that whole text because their texts is
going to be above it. In then in air onsubmit. We're going to console
log the values. So let's, I think we're good. Actually, let's see
what this looks like. So we haven't put any
conditions here if I refresh and actually we haven't even added
it to the page. So that's actually going to go in current totals, I think. Nope, it's gonna
go in dashboard. So right here where it
says current totals. Let's just comment
that out for now. Just to see what
this looks like. We're going to pull in
a renter renter form and be sure you import it, save that and let's take a
look at what that looks like. Yeah, so here's
FirstName, LastName. So I'm going to add
a little space below the first one to make it
look a little better. So if I go to the dashboard, actually it's going
to be rent or form. So this second form label, I'm just going to do
margin top equals four. Let's do three. See
what that looks like. Three is not quite enough. Let's try five. Alright, so welcome,
please eat ether. I put ether. Please enter your first
and last name to register. So let's try Travis
and then test. And if I hit Submit, it
should log into the console. There it is, firstName
Travis, last name, test. It's that easy with React
hook form. Awesome. So now we need a way to know
if a renter exists or not. And if you remember,
in our contract, if we go to the bike
chain dot soul, we created this renter exists
in all it does is return true if there is
a wallet address for that renter
and false if not, we're going to use this to
determine and that'll help us flip between air form
in our dashboard. So good a blockchain contexts. And right where we left
off at this Get balanced. And actually you don't need to call the get balanced because nobody really needs
to get the balance of the contract but the owner. So we don't want that
color, but you can leave it right here under
Get balanced, we're going to create
a new function called get renter exists. So we're gonna check and
see if the renter exists. A sink. And we're gonna do a try catch. And the catch, we're just
going to console it. Then up here we're
going to do two things. We're going to check
if they exist. And if they do exist, we're gonna get
their information. So remember in our
contract here, we have a function
called renter exists. And what that does
is it returns true if they have a wallet
address and our mapping. So it returns true if they do exist in false, if they don't. If this returns true, then we're gonna
go ahead and call this get renter function
so that we can get the renters information in stored in our state and do
everything we need to with it. So we're actually going to
have two functions here. We'll start out with
getting renter exists. And actually I don't
know why I named it that it's check renter exists
makes more sense. So here we're going
to say const renter equals await contract dot, and we call that
function renter exists. See here on the smart contract. Contract dot renter exists. And we need to pass in
air wallet address. And if you recall up here, we're saving that in state under a variable called
current account. So copy that, come down
here and pass that in. And then we want
to set that state. So we want to set the state
whether they exist or not. I like to keep things in the
state in case I need it. I think in other pages
we're going to need to be able to know if
that's true or false. So let's create a
state variable. So canst renter exists, set renter exists
equals US state. And let's put here
set renter exists. Renter will pass that in. Awesome. And like I said, if they do exist, we want to go ahead and
get their information. So right under this, I'm
gonna say if renter, so if renter exists,
if that is true, then we're going to call a
function called get renter. And let's put in a weight on it. So right below that, I'm going to put
const, get renter. Let's create that
function equals a sink, whoops, equals a sink arrow. Then we'll do this try-catch, but I'm just going to
copy this to save time. And contracted dot. Now, what is their
function called for that? It's called get renter and
we pass in a wallet address. So here, get renter, we pass in a wallet address and then we're going
to set the state. We're gonna save that renter
values in their state. So let's come up here
and create a new one. Const, renter, set
renter equals U state. And down here, we'll
just put set renter, renter to save it in our state. Then we can remove that. So now when this component
loads, this context loads, we wanted to call check renter exists because we want
to know that upfront. So we need to take this and include it in our user effect. So that it's called
when this loads. And then that check
render exists, saves, saves that true or false in the renter exists
state variable. So we can come
down here and pass to our provider, renter exists. So that'll tell
us true or false. And then let's save
that and we'll come back to getting the
renter information. But we just want to know now true or false
whether they exist. We're going to send
this to our provider. And then in our
dashboard will be able to test whether we should be showing the
form or the dashboard. So up here, we're
going to say const, renter exists equals
use contexts, blockchain context, and
be sure you bring that. You import use contexts
from React and also import the blockchain
contexts as well. Now we can come
down here and say, so we need to check
a few things here. We want to check
if renter exists. We want to display a spinner. Else, if renter exists is true. We want to display
the dashboard. Else display their form. So if we set the
default value of the renter exist if we set
this to false or something, that wouldn't be any good
because that would tell us always to show the form because their rent or doesn't
exist. So show the form. But we actually want it to
spin before it sets anything. So we want to spinner
before it determines, Hey, it's false or
hey, it's true. So we can actually do this
with the ternary operator. And a lot of people
don't like this. I don't mind it
because I see it a lot and I'm used to it. But we can do like an if else, else with ternary
or if else-if else. And we can do it like this. So a renter exists equals null. Then showSpinner. I'm just going to put
this in quotes for now. Else, if renter exists is true, then show current totals. Else show the rent or form. So I know that may look
kinda weird to you. If renter exists equals
null, then show spinner. And it's usually
like else something. But you can say else if
renter exists is true, then when you put this
question mark here, then show current totals, else show rent or form. So this checks three conditions, null, false, and true. So instead of the showSpinner, this isn't gonna do anything. Let's install some kind
of spinner package. I'm gonna go here and just do
react to spinner. Spinners. Let's go with that. So yarn add, react to spinners. Start my server. Install that. Awesome. So here we're
going to display a spinner. And how do we do that? So we're just going to
use this clip loader. So copy this. This is a short clip Loder
from this React spinners. Going to paste it up at the top. What else? It looks like. We need to set a state variable
loading and set loading. And that's by default
going to be true. So that's going to be loading
when we start the page. Then that's probably going to correlate to our
spinner somehow. So here's our clip loader. There's a color property which we don't
want to mess with, or CSS or size, maybe we do want
to mess with size, but here's loading
equals loading. So let's copy that and put
it in error clip spinner. And actually I'm just going
to copy this whole thing. And we'll just take out
what we don't need to copy that and paste it here. And let's take out color. And let's take out
CSS equals override. And I'm thinking 150
is gonna be big. So let's do 75. And then take out
this pseudocode and save it and see
what that looks like. So let's start our application. Yarn run dev. And let's refresh. We have a big error. Use state is not defined, yeah, so we need to
bring in US state. There's used contexts. Just add use state, save it. Awesome. So it looks like
we have a spinner and it's not resolving
to anything. And then it looks like we're
still showing the form. We want to get rid of this form because it's not
supposed to be showing. And then we want to
center this spinner. So to center the
spinner is very easy. We just take this clip
loader and just wrap it in this chakra UI
Center component. So just put Center and put that at
the beginning and then the closing tag at the
end of the clip loader. And then we forgot to remove
rent or form down here and then go ahead
and remove this commented out current totals. Now let's save it and
see what happens. So it's refreshed the page
and it's just stuck spinning. So that tells us
that something is wrong because it should resolve like rent or exists should
change in this condition. She should not show this
clip loader anymore. It should actually
show current totals or rent or form once it resolves. So there's some other
issue going on. And you can see that right
here, we have an error. That error says resolver or address is not
configured for DNS name. This is like one of the most
vague errors of ethers JS. It can mean a million things, but I do know in our context, it probably means that in
our blockchain context, when we're using this
current account, this probably means that
this current account isn't set yet when
we're calling this. And we can determine
that by putting a console log here,
current account. And actually I'm going to put backticks and
say current account. And then current account just
so we know what that is. Let's save it and see what it gives us the
current account. So look at that. Current account is blank. So that's exactly
what's going on. And to be honest, I don't
know the fix at the moment. I have to dig into
this to see why, but I'll figure it out
and I'll let you know here in the next video. But a quick fix for us now
is to come down here to the US effect and add in
current account here. Now would use effect does use effect is called when
the component loads. It can also be called again when these values change
anything in this array. So I can have current account, I can have renter and
all this other stuff. When these values change. Or updated in some way it'll cause the call they
use effect again. If we put current
account in here, if this function is called, there is no current account
and it throws an error. Well, when the current
account is resolved, It's going to come back
and call this again, which is going to call
both of these functions. Again. Though it will error,
it'll go back and call it again once it is resolved. So we're gonna do that for now just so we can keep moving. I'll give you the fix
here in a little bit, but if you save this now
it should work fine. So refresh. And there we go. And then you see current
account is blank here, but then it shows it
again with the address. So that is the issue going on. We'll address that in a bit. But right here it says, Welcome, Please enter your
first and last name so it shows that
things are working. If we refresh again, it's spins and then it shows, Hey, the renter doesn't exist. So it's making a call, it's returning false
and showing our form. So now let's set it
so we can actually register as a renter. So right under get renter, we need to make a call to
register ourselves as a renter. So let's go back to
our contract in find that I think we called it add renter here
does add renter. That's what we need to call. And so let's go back here and let's create a new function. I'm going to copy
and paste this in. I'm going to call it add renter. And renter. And then we're gonna
do contract dot add renter because that's
a smart contract function. Then in this ad
rent or function, if you come back to
the smart contract, we're passing in everything
while at address, first name, last name can rent active, start in time balance and do. So. We're just going
to pass that directly into our function up here. So put wallet
address, FirstName, LastName can rent, active, balance, do start and end. So we're going to pass in all
of that when it's called. And so right here
in the ad renter, we're going to pass
in that information. So I can actually take this, copy it and paste it here. Then when we're making
calls to the contract, we can use this nice
method called weight. So you can see a weight,
add renter weight. And what that does is it stops there until the
transaction is finished. So it stays here and waits. And then when the
transaction finishes, then it continues
to execute code. So we're just going
to test that by console log, rent or added. We're actually we can
do some fun stuff. We can do firstName added. And then right under that, we're going to want to get
that renter information. So we have this
function called get renter that sets
the renters state variable with the
renters information in that get renter is called by
this check rent or exists. So all we have to do
down here is just call check rent or exists. And that will check
that they exist in populate our state with
that renters information. So let's save that. We don't want this called
when the page loads. So we're going to take
the whole function and pass it to our provider. Save that, and then we'll
go to a renter form. And we want to bring that
provider information that state information into
a renter form component. And you've done this a bunch,
you know how to do it. It's as simple as const. Add renter equals, use
context, blockchain contexts. And be sure to import
use contexts from React and import the
blockchain context. And then when we go to onsubmit, we're going to call
that add renter. Now remember, we're only getting the firstName and
lastName from the form. And that's because can
rent when a renter has created can rent is true because obviously
they're able to rent. Active is going to be false because they don't
have a bike Yet. They're just signing up.
Balance is going to be 0. The amount due is 0, and the start and end time we're
going to be zeros. So they can always be
set from here so that the person filling out the form don't need to put in
useless information. So in our onsubmit,
we're gonna do this. We're passing in the values. We're going to say values. Can rent equals true. And what we're doing
here is setting more values in an object. So let me just copy and
paste this a couple times. Values, active equals 0, values, balance equals 0. Values do start and end. All equals 0. Oh sorry, active is false. Then zeros, zeros, zeros. So we're populating
these because they're always gonna be default. Then we also need to pass
in the wallet address. And we don't want
the user to have to pass in a while that address and we didn't
put it in the forum, so we need to include
that as well. So we can bring in
the current account here from the
blockchain contexts. And we can do this
spread operator to create a new values object. So const new values object. What we'll do is we'll
have wallet address. Whoops. What we'll do is we'll
create an object. The first key value in the
object will be wallet address, that will equal current account. Then we can just
spread the values out. In this object. This is
the spread operator. And what this does is it just
adds all of these values, the ones they submitted, including these
two, this object. It's really cool.
If we console log out new values object. Let's
see what this looks like. A fresh, Let's put Travis test, submit and look at this. We have an object that has
wallet address, FirstName, LastName can rent, active
in all this other stuff. So we have our key values
and we're ready to use them. But we don't want
to have to be like new values object
dot wallet address new values object dot can rent. So let's now use D structuring
to pull these out. So const wallet address, FirstName, LastName, can rent. Active balance. Do start in, then equals new values object. This is just the structuring. It pulls all these
values out so we don't have to use this dot notation. And finally, the last step
is we'll call air wait, add renter will
pass all this in. Again, if we didn't do
this restructuring, we'd just have to do like this. New values object dot wallet address new values or objects. So this is just a
shortcut. You can do that. But I think this
looks a lot cleaner. So again, we're
passing in our values. We're adding these
defaults to it. We're adding our wallet
address in creating a new object where D structuring
the values out of it. And then we're passing them
into our add renter function. Awesome, Let's try this out
and see if it adds a renter. So I'm going to say Travis
test and click Submit. And it should bring up
MetaMask. We have an error. Cannot read property is of
undefined reading length. So add renter. Yeah, there's some issue here. So let's let's go back
to here instead of. But wait, add rent or
let's do a console.log. Save that and see what it says. Travis test. We got some undefined
true-false zeros. Alright, so last
name is undefined. It looks like that's
the issue ever wallet address, FirstName. Lastname is undefined. Let's see what's going on. So if we go to our
render form down here. Yeah, I knew I did
this out of feeling. Lastname. It's like
last capital N. Here is FirstName
without the capital N. I'm gonna put these
capital ends back just to be consistent. So let's highlight all of this. And do firstName. And then highlight all
of the last names. And do it the same way,
capital N. And then up here, we need to make sure we
have the right things. And those change both
of these first name, last name, and save that. And now we should be good. Let's try to console
it out again. Travis test, submit and we have wallet address Travis
tests true-false 0000. Alright, We're good. Let's change this back to await, add renter, and try it again. Refresh just to make sure
I have everything clear. Travis tests and click Submit. This should bring up MetaMask. And here we go. Look at that low gas
fee. That's great. I like it. Now. I'll hit Confirm. And let's see. It's
probably pending. It's pending now and see
how this is still spinning. That's React hook form. The is submitting hook
that they added to the form that keeps that
spinning until it's complete. Now, look at that. Once we were added, it detected the change and
now it shows our dashboard. Isn't that awesome? That's great. Now if I refresh, I should
see my dashboard instead. So I got the spinning wheel
and there's my dashboard. Awesome. So again, so again, just to recap that, that issue was that we should have been
using this camel case, lowercase, first word
and then capital, all the other words. That messed up our last name. So we just went back and
changed all these camelCase. Change first names to CamelCase. Then up here, just
making sure that we're passing in the
camelCase version. So great job. It looks like
a dashboard is working. It can tell whether we are
renter or not a render. So in the next video,
we're going to start populating these
fields dynamically. We're gonna be able to
credit our account, pay our balances,
and check out bikes. So we're going to do a big
push in the next video. And that'll get us close to
the end of our application.
8. Populate dashboard final optimized: Alright, so I redeploy
my contract just so I can test that everything
is working again. So I'm gonna put Travis test and I'm going to add
myself as a renter. So I'll click Submit. Metamask will come up
and I'll confirm it. And once that is done, it should show my dashboard. So it's currently
pending. There we go. Dashboards up. So before we press through all
of these values, which actually won't take
as long as you'd think because they're smart
contracts done all the work. Before we actually do that, there are two things
I want to address. First, we have a
little bit of a bug. So if I open my dev tools, so if I come up here to MetaMask
in disconnect my wallet. So disconnect and then refresh. You'll see that the spinner will just continue to spin and spin and spin and spin. And
nothing will load. We need to fix that. And the way we fix
that is we come to the dashboard and
remember we put this if else-if
else ternary here. Well, we need to add
one more condition. So if the problem is, if the renter exists is null, then the spinner spins. But if we don't have
an account connected, then the renter exists,
is going to be no. So the spinner is
always going to spin until we connect a wallet. So to fix that, we just put another
condition here. We put end current account. What that does is it
makes it so that if the render exists is null and
there is a current account, then show the spinner. So if there's not
a current account, it's not going to
show the spinner because both of
these won't match. And then it will move on to check whether
the renter exists, which it won't, and it'll
show the renter form. So just add that current account and save it. Let's try it again. So let me refresh. And actually I need
to bring that in. So up here in my context, need to say current account
so that I can access it. So I'll save it. And we should be good
now. Yeah, there we go. My wallet is not connected
and it's showing my form. Now that's not
gonna do anything. If I fill it out, it's
going to throw an error. If I put something like that, it's going to throw
an error because obviously we don't have
a wallet connected. We can't talk to the blockchain
or the smart contract. So let's go ahead and
connect her wallet. Connect. And now my dashboard will show. Now the second thing
we want to address is that issue we were having
in the last video. Now remember, whenever we call the current account
in these functions, the value hadn't been
populated yet in the state, so it would throw an error. And we combated that by adding current account
in our user effect. So when that changed, It would call Hughes
effect again. Then we would get our value. So remember that we have current account is blank
and then we get an error because we're calling a
value that doesn't exist yet in them and that
populates, then it works. So we talked about
that in our last video and we're going to fix that now. We don't want to throw an error every time before
it actually runs. So the way that I'm
going to address it in this application is to just
wrap it in an if statement. So anywhere that we're looking to get the
current account, like here, I'm gonna get rid of this console log anywhere we're looking to get
this current account. I'm going to wrap in
an if current account. So if that exists,
only run this. I'm gonna go to my next function that uses current account. And I'm also going to wrap that. If current account then only
do this, do these things. I think those are the
only two at the moment. What that does is
when this loads and it comes here and it
tries to get the renter or actually check if the
renter exists and it calls render exists
in current account isn't set yet in the
throws that error. This time, it will check if that current
account is set first. It won't be, so it'll skip this. And then down here in the US
effect when it gets called, remember we passed it in here. So whenever this changes, it's going to call
Hughes effect again. Whenever that happens, it's going to call this
function again. And this time it's
going to work. Now if we save it and
go back and refresh, we don't get that error,
we just get this. Something is not
supported any longer. And react 18, which is not a big deal, I have
to look into that. But we also have
this favicon error, which we can fix by going to index.html and just
taking out the favicon. I think I need to
stop or restart my server for that
to take effect. So let me refresh and
that error is gone. So I think we're good
to get started here. The first thing we're gonna do is populate this BNB credit. So this is air balance,
the renters balance. So if we go back to our
contract and scroll down, we have this function
called balance of renter. That's what we're going
to call that's going to check air balance or Air BnB credit that we've put on ERA account balance of Renner. Let's go back to
blockchain contexts. And let's do const, get. A renter balance equals a sink. We're gonna do a try-catch in the error console dot log error. Then here we're
just going to say const balance equals await. Use our contract object and call the balance of
rent or function. We're going to pass
in current account. And let's wrap this again
in an if statement. If current account, then
only do these things. And then we're going
to set the state. So we're going to
come up here and create a state for this. So we're gonna say const
rent, rent or balance. Set. Renter balance equals use state. Here we're going to set
the renter balance. Set renter balance to balance. Actually, we need to format this because it's going
to return back way. So we need to format
this as we did with their other balance that
we did at the beginning. So to do that you put ethers
dot utils, dot format ether. And we'll pass in balance. We need this to be called
when the context is loaded. So we're going to add
it to our user effect. We're going to call that and it's going to be
setting the states. So we need to pass that state
variable onto our provider. So we'll put renter balance. And now that should be available
for us to use elsewhere. So then we need to
go to our dashboard. Actually, current totals
is where we need to go. Current totals. We need to bring
in air contexts. So let's do const. Renter balance equals. Use context,
blockchain, context. Awesome. Now make sure you
import that at the top. So we should have
Blockchain context and we should have used
contexts important. That's available down here. Now in our stats card, we can change this static
number to rent or balance. So let's save that. And let's refresh the page. And we have 0, which has to be right because we don't
have a default value set. But to check that,
let's go ahead and get this credit your
account form working so that we can go
ahead and credit our account and
make sure that it changes this value
up here according to how much we have on
the smart contract. So let's jump over to the
Add to balanced form. Actually, we need to start out in the blockchain contexts. Let's come here to the bottom. And we're going to call, if we look in our
smart contract, we're going to call
the deposit function. See if we can find that deposit. Here it is. We're going to call
this deposit function. We pass in our wallet
address in its payable. The fact that it's
payable means that we can also send it an amount of ether or B&B or whatever we're sending in that'll be sent in an object, which I'll show you in a minute. So we have deposit, it's also payable and it's going to add this to the
smart contract, but credit the renters account that is at
this wallet address. So let's call this
deposit function. Let's come back to
blockchain context. And I'm just going to
copy this function. And I'm going to
call it deposit. And I can remove this if let's
just remove this Totally. So think about this. Now we're entering a
decimal and we want to convert it to weigh
or ten to the 1800s. Because in our smart contract, we want to be
dealing with way not decimals because solidity
doesn't yet support decimals. So we need to convert
this the other way. So we've been using Format ether to convert it from
way to decimals. Now we need to use
a utility function to convert from
decimals to weigh. That function is
called parse ether. So here we're going to get
when I say const B&B value. So the amount that we're
going to be passing in. And actually let's put
this as a parameter. Value. So B&B value equals
ethers dot utils. We're going to format
this value two way. So we need to call parse ether. And we'll pass in the value. Once we have that, then we
can call our deposit function Const, deposit equals await. Contract dot inner function
is called deposit. And we're going to pass
in our wallet address, which is current account. And we don't need to
wrap this in an if because this doesn't
load on page load, it only looks for it when
we click the button. So at that point
it'll be well loaded. And then after current account, this is where we can pass in the value of how much we're
sending to the contract. And I told you this
was an object. So let's create a curly braces. And for the key
will put value in. For the value, we'll put b and b value because we're
passing in this amount here. And then there's this lovely
method called weight, where when we're doing
this transaction, we start the transaction
and we want to wait till that transaction
is finished before we move on
to the next thing. So to do that, we just
put await deposit, which is what we defined
above dot weight. And that'll wait until the
transaction is finished. Then we want to refresh the
balance, the renters balance. So once we credit the account, we want to refresh that
number on the page. And to do that,
it's pretty easy. We just call get renter balance. Again. This deposit, this is not called
when the page loads. It's only called when
we submit that form. So let's go down here and send that function to air
provider deposit. And then let's jump over to
our Add to balanced form. In here, we're gonna go to the onsubmit and values
is what we're getting. Let's check out and see
again what this submits. So hit Save. Let's see what this log to
the console looks like, the test and it's
being a little slow. There we go. So if I put 0.1 and submit it, It's going to submit
an object with a key of credit balance
and a value of 0.1, we don't need this
credit balance, we just want the number only. So we're going to
D structure that out by going const credit, credit balance equals values. Then we can call
await deposit warps. What was that? Await deposit, credit balance. And that should be
all we need to do. So let's save that
and give it a shot. I always like to refresh my page just to make sure
I'm starting fresh. So before you do this, make sure you have some
tests B&B in your account. So if I open mine, I have 1.96. If you don't have
any, just go to B and B test faucet in Google. Click on the test
net.finance.org, then send yourself a B&B. You can send yourself
one B&B per day. In here you just put in
your wallet address. Click give me BNB and click on the one BNB and it'll send it to you in
like five-minutes. It's really cool. But I've already gotten
my end for today so I can't send anymore. So I'm going to credit
my account with 0.1 B&B. So if I click Submit,
we have an error. Deposit is not defined. That's in our ad to balance form is probably because we
didn't bring it in. Yeah, we can't call deposit because we haven't
brought in our context. So come back up to the top. Deposit equals use contexts. And I'm going to pass in blockchain context and make
sure you import these two. Mine does it automatically? I've told you that
a million times, but I'm just trying
to remind you. So now let's try it again. Refresh the page. And I'm going to credit
my balanced with 0.1 B&B. Click submit, and I'll
wait for MetaMask. Alright, so my total, so it's a very small gas v, That's why I like BNB. It's 0.0043 B&B. And tack that onto my 0.01. It's very little gas. So let's confirm it. When we do that,
it's going to wait. Remember we call that weight
method, it's going to wait. And then when that's
done, it should refresh Airbnb credit. So click Confirm
will watch it here. It's currently cubed.
Now it's pending. In our spinner spinning
because of that React hook form, built-in hook, I think it's called
is submitting, but you'll see now
that our B&B credit is 0.01 or 0.1 B&B price. Let's see how much that is. 0.1. B&b is 38 bucks. Great. I liked that balance.
That's working. Now let's go to B and
B do populate that. So let's go back to
blockchain context. And I'm going to copy and paste this down to the next one. If we look in our contract, we have a function
called get du. So that's what we're
going to call get do. We're not passing anything. And then I'm going to remove this rapid in an if
current account. Then we'll do this
kannst du equals await contract dot get,
do current account. And then we're going
to set the state. This is gonna be kind
of a recurring pattern for the next few functions. So I'll come up here and create a state variable called do, and then set du equals U state. So I can come down
here and do set, do, and I'll set it to the due amount we
defined right above that. So don't mistake this do
with the state variable do. And we want to call this get
do when the contexts loads. So get du. And then that's going to set
the due state variables. So we want to pass that to our providers so we can
use it in our dashboard. So just pass and do save that, go to your dashboard, not dashboard current totals. And then pass in, do here. So we're going to pass
in due to our context. And then on the second
one where it's 0.01, we're just going to pass in
due and save it and see if that gives us an amount una
through us a big error. And it says objects are not
valid as a React child, what that means
is it's returning a big number, which
is an object. So we actually need to parse
it, forgot about that. So instead of, instead of do, we need to put ethers, dot utils, dot format ether. Do, and that should fix it. That's gonna give us
our decimal amount. And it's already there. Looked at 0, refresh
again, 0, cool. And we'll test that in a minute. Let's go ahead and get
a ride minutes setup. So what about ride minutes? Where's that at in our contract? So if we go back
to our contract, we have this function
called get total duration. So we're going to call
this, it returns 0 if they haven't checked in their bike yet or they haven't
checked it out. L said returns the amount of
time they were on the bike. So if they have a
start and an end time, it's going to calculate it here. So we need to call this
get total duration. So again, I'm going to
copy this and paste it in. I'm actually going to call
this get total duration. And we're gonna leave
this if statement. And we're gonna do the
exact same thing here. We're going to say const total duration equals await contract dot get total duration, which is a function in our
contract like we just saw. And then pass in the
current account. And then we're going
to set the state. So let's come up here. And right under this just
put const, duration, set the duration
equals use state. And come back down
here and let's set it. Set duration to total duration. And this is actually
gonna be a string. We want to cast it to a number. So let's save that. And we also want to
get that when the page loads because it's
on a dashboard. So we come down to use Effect, get total duration in that
setting the duration. So let's pass the duration
state value to their provider. And then just like
we did before, let's jump over to current
totals and add it here, duration to bring it in. And then down here under ride
minutes instead of seven, we're going to put
duration. Save it. Refresh my page, and we
have Ryan minutes of 0. Now let's set this bike status. So the way I had it set
up was this is going to stay red until you
check the bike out. If the if the bike is
actively checked out, it's going to change to green. Like Hey, you're good
to go, enjoy your bike. Once your bike is checked
in, your back to red. Red means when your bike
is checked back in, you can't check another one out until you pay your balance. Now you may want to distinguish between when they do
pay the balance in, when they check the
bike out again. You can do that if you
want. I'm going to leave it red just for simplicity. So to do that, we need to
come down here and see, yeah, we're setting this
background color to red. What we wanna do is we want to find out if they're
active or not. If they're active
than we want to set it to green otherwise read. So let's go back. I think we have that
already in air. We have error. Add renter. No, not we
have somewhere here. Get renter here it is. We check if renter
exists, if they do, we call get renter in populate that renters state variable
C where it says Set renter. So we should be able to
come down here and just pass the renter amount. So renter and that should give us remember when
we add a renter, it gives us the wallet
address, FirstName, LastName can rent
active balance, all of that good stuff. So we should have
that available. So it should just be as easy as passing the renter information, coming to our current totals and adding renter
to our contexts. And then instead of red here, we'll say renter dot active. If that's true, then we want
to change this to green. Otherwise, red. Save it. Let's test it out. So we've
got a big error here. It says cannot read
properties of undefined. And what that usually means is that it hadn't populated yet. So it's checking it this state variable before
it's populated. So what we can do is also put a check in for renter
to make sure that renter is available also. So renter and renter is active in then only
green else read. So if we save that,
We should be good. Refresh bike status is red. Now when we check it out, this should turn to green. Next, we need to get this form working so that we can
pay the amount due. Once we do that and add our bikes will test
that all this works. So let's do that one next. So back to blockchain contexts. And I'm going to again copy
this, paste it below it. And I'm going to call
this make payment. And we're going to
pass in a value. Because remember
this is payable. We're gonna be sending
an amount with this. And let's take a look at the
function in our contract. So somewhere it should be where
we're making our payment. Here, make payment. So
here's our payment function. Remember it subtracts
it from our balance, so it makes a payment to the contract and subtract
that amount from our balanced it sets can rent back to true because now you
can rent a bike again. It sets due to 0 and start
and end back to zeros. So it kind of makes
your payment and it refreshes you as you
were at the beginning. So we're gonna come
over here and we'll just call the function
make payment. And inside this current account. And we don't need the current
account because again, it only runs when we
press the button. So I'm going to do kind
of like I did up here. I'm going to copy this much. Actually, I'll just
copy all of it. Paste it. And so B&B value, this is the value
that I'm sending. And then I'm going to call deposit because we're depositing money, we're making a payment. But instead of calling
the deposit function, we'll call the make
payment function. We'll pass in our wallet address and the amount that
we're sending, we'll wait until that's done. Then we need to do
several things here. So remember in our
contract function, we're doing a bunch of things. We're subtracting
from our balance. We're switching can rent back to true in all of these two zeros. So we need to refresh
a couple of things. Right, under this,
we're going to call a weight get renter. Because we need to
refresh our renter. They have new values now, the can rent the balance. All of that is refreshed. So we need to
refresh the renter. We need to refresh the
get rent or balance. Need to refresh that because our balance
is going to change. We need to refresh the duration because we had a
riot of ten minutes. We need that to go back to 0,
so we need to refresh that. So await, get total duration. And then finally we need
to refresh the amount due. So await, get do, because that's also
going to be 0. And this only runs when
we press a button. So we're going to pass the
function to the provider. And then we're going
to go to the pay form. And bring in our context. Canst, make payment
equals use context. In our context is the
blockchain contexts. So again, be sure
to import both of these then in air on our summit. So let's try our Submit
first, see if it works. So pay your dues 0.1 submit, and there it is. So again, we want to structure
this to just get the 0.1. To do that, we'll
say const payment. I think that's what
we use down here. Yeah, Payment D equals values and then we can
call await, make payment. Payment, payment. Let me save it and
we could try it out, but we don't have
any Mountain Dew. So let's also jumped down to our bikes and make
those buttons work. So back in the
blockchain context, let's add two functions. One is going to be
called checkout, const, check out equals a sink. And the other one's going
to be called check-in. So we're going to
check out the bike. We're going to check
back in the bike. And we'll do a try catch. Console.log the error. In here. We'll say if current
account make that check, then only run this
will make that check. If that's true, only run this. So we'll start out with const checkout equals
await contract dot. And let's see what we got. So we have a checkout
and we have a check-in. And you'll note on the checkout, we probably want to refresh the renter because they're
going to have new values. And then on the check-in, there's a lot going on. We're changing some
renter values, but we're also setting
the amount due. So we're calculating how much is due and we're going to set that. We need to refresh these values. So contracts, dot, check
out, current account. We're going to wait
for the transaction to finish, checkout dot weight. And then we're going to call
get renter to refresh that. In down here. I'm
going to actually copy this, paste it in. Here. We'll say check in, contract dot check in. Then we're going to
await the check-in. Then we're going to
call get renter. We're going to call
get due to refresh that value and get total duration because we
need to set that back to 0. In these, like the other
ones are buttons you press. So we're going to pass the actual functions
to our provider. And I actually don't
need this if current account because it's
a button press, it's not going to
happen on page load. So let's move these
back and save it. And I'm going to
pass the checkout and and check in to my provider. And then we're gonna
go to dashboard bike. Now it's going to be bike. There we go. So let's
bring in the context to our bike component. So const, check out, check n equals, use contexts, blockchain contexts,
bringing your imports. And I'm gonna save it. Now there's one thing
we should talk about. One thing you can do with your contract is when
you check out this bike, you can have it
saved the name to your contract or in your
state or something like that. So you could display up here the type of bike also
that you checked out. I didn't want to make this too complicated and I
wanted to leave some things for you to be creative and make your
own app out of it. But all of these checkout and check-ins are gonna
do the same thing. So if I check out this bike, it's the same as
checking out this bike. We don t have to differentiate which bike we're checking out. So it's gonna be
the same and each one of these bike components. For the checkout, I'm
going to add an on-click. Equals checkout. And for this button,
the check-in button, I'll add an on-click
saying check-in, calling my check-in function. And then we save that. And I think we're
good for those. We can actually try it out. So refresh my page. And I'm going to try
to check a bike out. Now there's a lot of
stuff that's going to happen here that we can test. So first off, I'm going
to check out this bike. Alright. And it's charges me a
very miniscule gas fee. B&b price. Let's see how much
that actually is. It's like 27, gas v is $0.20. Glad we use to BnB, even
though it's testimony. So let me go back to MetaMask. Let me confirm it.
So what's going to happen here is
when I confirm it, this status should turn green. And it should set a bunch of things that we said
in our contract like, can rent should be false, Air start time should
be documented, there should be a timestamp for that and all of that, you know, the contract just as well as me, you know, what's
going to happen. So I can click Confirm. Now it's pending. Once that pending is done, this should turn green,
so watch out for that. That is done. And we are green. Look at that. Or bike is checked out. And what we wanna do now
is wait about six minutes, something over five minutes, and then we'll check it back in and see that
everything happens properly. So it's 1157 here. So I'm going to come
back at like 1203 and we'll check back
in at that time. We should have Ride minutes
of like six minutes. We should have an amount of B&B. Do remember 0.05
every five-minutes. And from there we should be able to pay or do pay that down to 0 and have our B&B credit
reflect the difference. So I'll see you back
in about five minutes. Alright, so it's almost time
to check my bike back end. Before I do that,
I'm going to check my state variables just to see that things
changed properly. So go to components. You'll see that can
rent is actually false now because it's checked
out, so that worked fine. And then true, active is true. Those worked out great. And everything's
working properly. Alright, so it's been
about 78 minutes. So what we're gonna do is
check the bike back in. When we do this and this
transaction finishes, I should have my
bike status should go to read my ride
minutes should be populated with how long
I was on the bike in my B&B do should be
populated as well. So let's try that. So I'm gonna click check-in
and confirm it in MetaMask. And let's check that status. So that's pending.
When this is done, we should have values populated. Alright, great. So bike status went back to red. I was out seven
minutes in my B&B do is 0.005, which is right. If I was 12 minutes, I would have 0.01. Do remember it's 0.005
every five-minutes. So great. So the final test here is
can I pay the amount due and have it reset this and deduct
it from my B&B credit. Our state right now is can rent is still false because
I haven't paid my dues. And active is false because I'm no longer
active on the bike. So let's put in mount do 0.005
and let's try to pay it. So submit and we are making a payment of
0.005 and then gas fees. So hit Confirm and this
is going to be pending, but once this is done, my ride men, it should be at 0. My B&B do should be a 0 and my credit should be
deducted the amount I paid. It just went through
Reimann, it's 0. B&b do is nothing. And B&B credit is this much. So 0.01 minus 0.05 is 0.095. So I still have some credit. I can still check
out another bike in our app is working wonderfully. So in the next video,
we're gonna do a little clean up and we're going to add a couple of security features that we didn't add
from the outset. Once that's done or
Apple be finished. You'll be able to
show off all of your work. I'll see
you in the next video.
9. Optimizing UI and Security Checks: In this video, we're
gonna be putting the finishing touches
on our application. In wrapping things up, we're going to start out by displaying these require
messages on our front end. So if you remember, in our smart contract
we have these require statements that
if they're not true, then we spit out this message. We need to display
them on the front end. So we're going to work on that. Then after that, we're
going to implement some security features
so that renters can't interfere with other
renters information and also some owners stuff
that's really important. So push through this lesson because there's gonna
be a lot of fun. And as always before we
get started on those, we need to fix a couple of bugs. We're going to fix a
simple one upfront and another one later
on in the video. In the first one goes like this. So if you open up your
blockchain context, and you might have
noticed this already. If you open up your blockchain
context and save it, then this dashboard changes
to the ad renters form, which means we're losing
our state somehow. So if you go to blockchain
context and save it, you'll see that, hey, now we
have the add renters form. If you go to your dashboard
and just do a console.log, renter exists, you'll
see the problem. So save that. And I'm going to
refresh the page. And I'm going to save
my blockchain context. As soon as you do that, you see over here in the
console it says Hot updated, which means Vijay
S is Hot Reload happened and then that
value is undefined. You see right above it is true. But as soon as this reload
happen, it's undefined. Now I've tried to find a
good solution for this, and I'm convinced
it just has to be some byte JS bug or some issue with Vijay S
I just don't know about, but I have an easy fix for us, one that won't impact
us much at all. It has to do with a
plugin that Vijay S uses. So if you go in the root folder and go to
vite dot config dot js. There's this plugin
react plugin. So we're importing
it up here and we're using it here with React. Now inside of this,
we just need to disable the faster refresh. And you do it by writing
this an object of key, fast refresh, value false. So we're disabling
the fast refresh. If we save that and now go and refresh this page,
actually refreshed anyway. You shouldn't have
that problem anymore. So I'm gonna go to
blockchain context, context, and I'm going
to save it here. And I'm going to
save it in my page, just refreshes without
losing the state. So that's a simple fix. Add that in your config file
and we can move forward. Now, just a word of
caution if you're making UI changes and want to
see them instantly, I think you'll need
to re-enable that, but we're currently
done with UI changes. So you don't need to
worry about this, but just wanted to note it. Again. If you find a
solution, please let me know. Or if I find one
in the meantime, I'll paste it below this video. Alright, so first, like I said, we want to add these error
messages when we have errors. So if we go back
to our contract, you remember we have
these require statements that say things like You do not have anything
to it this time, you do not have enough funds to cover payment, things like that. So if the user tries to do something that they're
not allowed to do, than it should pop
up an error message. So for instance,
if I tried to pay, might do when I don't
have anything due. So 0.1 and submit it, I get this error over
here in the console. Here it is this object. So it says code
message, data stack. All this good stuff.
So if we open that up, you'll see we have
this data object. And if we open that up, there's a message in there
that says execution reverted. You do not have anything
due at this time. That's what we want to pull
out in display on the page. So to do that, we just need to grab those specific values. So if I go to make payment, which is what we're
calling right now, in my blockchain contexts. In instead of console.log error, we're going to say
Error dot data. Remember that was the
object dot message. So save that and
let's try it again. Let me refresh 0.1 and submit, and I should just see
the message here it is. Execution reverted. You do not have anything
due at this time. So now we just need to
display it on the page. Well, one of my
favorite packages and react is toast defy. Testify is used to alert the
user on certain actions. And there's a million
ways that it can display. It can slide in on the page. It can do all of this stuff, but we're just going
to keep it simple. So if you go to testify, react there should be an NPM package yet
react to testify. It's very easy to set up. You can see right here all the different messages you can use. You can do spinners. You can put icons on it. You have different
colors, lots of options. So to install it
just got a yarn and react to justify or NPM install. So stop your server, install it, and then
start your server backup. In what we're gonna
do is we're going to display it through
the same context here, the blockchain contexts. Normally you would want to
create a new context for this. Like a toaster phi context. Set that up and use that just to alert on messages and errors. But if I start doing that, then we're going to
get another hour video of just setting up
error messages. So we're gonna do it easy here. But if you were in
a bigger project and you wanted to put
more time into it, you of course one would want
to use a separate context. So if we look at our
documentation for React testify, I'm going to click on the
demo and the documentation. And you'll see here, we'll just check out
positioning toast. Actually, let's go
to the next one because that's not very helpful. But what you need to
do here is you need to put this toast container on the, on the page you
want to display it. And then you can call
the toast function. So you can see that better here. So Toast dot success, and then you have
your notification, whatever you want to say, and then you pick your position on the page to display it. You can do a toast
to access an error, a warrant and info, or some kind of custom toast. So we're going to start out by putting this toast container. Well actually that's imported. We're going to put this on
the current totals page because we have the
two forms there. The one where we
credit our account in, the one where we make a payment. So go to current totals. Then at the top, you
want to just put this import statement,
import toast container. Then I'm going to
grab this example. And I'm going to scroll down
and then at the bottom. So here's my current totals function down at the
bottom under the box, so that I don't have any
kind of styling with it. I'm going to just put that toes container auto close is
set to eight seconds. I'm gonna change it to, let's do 3 thousand for three seconds. And then we have
multiple parents here. So we need to put an empty tag. One at the top,
one at the bottom. My toast container
is on that page. So when it's called, it
should display on that page. Now I'm gonna go back to
the blockchain contexts, and I'm going to
call it here with that toast dot error call. So I'm going back to positioning
and toast dot error. So I'm going to take out this
console dot log message and just replace it with
this toast dot error, which again you'll find on the positioning toast
part of this page. Then for my error notification, I'm going to put error
dot data, dot message. And I wanted to come
in in the top right. So let's save that. Now there's one more thing you have to do. You have to import
the CSS or it won't look proper or even
work properly. So just go up to getting
started installation. And they don't mention it
here with the installation, but you'll see it imported here. So copy that. And we want to import that
on air current totals page because that's where we're displaying that toast container. So up at the top, bring
that in, in, save it. And let's try this out. So I'm going to refresh the page just because I like to do that. Now I'll put just the
number one and submit. And let's see if we
get a toast message. We don't, because
toast is not defined. So let's go back to our
example and make sure we grab import toast from
reactors to fire. Back in air blockchain
context, put that at the top. Import toast. We can remove toast container because
we're not using that here. We're just using toes because
we're calling toast error. So save that and let's
try it again. So refresh. Alright, and I'm going to put
the number one and submit, and you should see something
pop in at the top right. There it is. Execution reverted. You do not have anything
due at this time. It looks like at hung
up there for a second, but it's supposed to go
away in three seconds. But that's great. So somebody comes in and submits it will let them know you do not have
anything to do with this time. Let's add one to
our credit form. So get du will put
the same thing there. You can customize these
however you want. There's a million ways to do it. You go to this. Where's
it at reactors defy Demo. There's like all kind of things you can look at info
success warning error. But yeah, you can select
which one you want to see. And then click Show Toast, and it'll show you what it
looks like. Different themes. Here's the dark theme
and the color theme. Pretty cool if you're using, if you're using promises, you can say promises pending
and then promise resolved. Lots of great stuff. So I'm going to grab
this and add it to the crediting form. So the deposit. And I'm gonna save that and
actually that won't error. I don't know if we have
any thing for the pie. We don't have
anything for deposit. But let's find something else. Make payment, get renter, check in, Let's do check-in and check-out because those both
have require statements. Let's go back. So I'm going
to remove that from deposit. It will go to the check-in and check-out and add it there. Awesome. So if I tried to check in
a bike that I don't have, I think I'll get an error. Let me confirm that. Check in. Please check out a bike first. Yeah, let's see if we
get something there. So I'm going to choose
actually let me refresh just to habit of mine
and go to check in. And there it is. Please check out a bike first. Awesome. So we have messages
and feel free to tweak that however you want to
put it on a different side, add some different colors, do a dark theme, whatever. So I think that covers
air require statements. We got checkout, we've got
to check in acquire require, we got to make payment. And that's it. So that's react to
justify have added. Now the next thing
we wanna do is add some security features
to air Smart Contract. So theoretically if I have someone else's public
wallet address and can insert that in some
of these functionalities. Then I can check out a bike
for someone else in charge, money to someone else's account. I can do things to
other people's account. There's no check to say, hey, you can only interact
with your address. And I don't think in general anything on the front end
you can do that like I don't think I can come here
and click checkout and add someone else's
wallet address. But still you want to
put those checks there. And I think it's good to go
through it just so you see that if you go to the
bike chain contract, let me give you an example. If I go to checkout and I know someone
else's wallet address, I can put their address in and check out
a bike and then I can leave it running for a week and then check it back in. And then they had this
huge balanced did they had no part in running up? So we would just want to
put a check that says, hey, you can only perform
these actions on your particular account. And it's really easy to do. We just insert a modifier. So right under Add renter, I'm going to say
modifier. Whoops. I'm gonna say
modifier is renter. And then I'm going to pass in an address while at address. And then you put these
brackets and you say require message dot sender equals
wallet address in it. That's not true. You will say you can only
manage your account. Then right under that, you have this underscore semicolon. And what that means is continue on with the
rest of the function. So how this works is down here. For this checkout function, you would add right
here is renter. This is a modifier and you would pass in the while at address. In this is a way
of a clean way of adding a repeatable require
statement two functions. So when this function is ran, it's going to check first, if this is renter, it's going to pass
in this wallet address and it's going to say, does the message sender, the person making this call, match the wallet address, meaning they can only
modify their own account. So when you create a modifier, you just tack it on
to the function. And I'll show you
how that works in a minute when we
throw it in remix. But we need to add
that to everything that we're adding a
wallet address too. So I'm going to put it
down here on check in. You can only check in a
bike with your address. No one else's rent or
timespan is internal. We don't have to
worry about that. Get total duration. You only want to get
your own duration. And since this one
returns something, we're going to put this
right after the public. And then this one also returns
something and it's public. But this is the get
the contract balance. We only want the owner to do this and we're going to
deal with this next. But get renters balance, you can only get
your own balance. Put that after public
set due amount. This is internal, No problem. Call it outside of the contract, can rent a bike, put it there, deposit. You can only deposit
via your own address, even though people would like
you to deposit to theirs. Make payment. Tack
that on the end. Get do put it there. Get renter. You can only
get your own information. And renter exists,
put it there too. So all this is doing again, instead of putting
a require statement repeatedly in every
single one of these, we're just putting
this modifier in this function statement right here before the curly braces, we're just adding this modifier. You're modifying the function
to meet these requirements. Alright, so that's
the renter modifier. Now we have two more things
and we'll be all done. First, we have to fix a bug. In second, we need to
talk about the owner. The owner should be able to see how much money is
actually his or hers. And they should be able to withdraw gains that they've
made from these transactions. So let's fix the bug first. Now you recall we talked about the logistics behind
the smart contract. If someone deposits money, it goes to the smart contract, but it credits their account. So if somebody puts
in $10 in there, the only person that's put
money in, they put in $10. There's $10 in the
Smart Contract, but all ten of that is
credited to their account. Now, they spend $5 on a
bike and make a payment, then there's still
$10 on the contract, but only five of that
is credited with them. Well, we made a mistake
with make payment. When we make a payment, we're actually just subtracting that amount from the balance. We're not actually sending
money to the contract. We're just subtracting it from the balance in the money that's left over is
the owners money. So we can't do payable here and we can't use
message dot value. In fact, we actually in
the blockchain contexts, when we make a payment, we are sending money,
this BNB value. So that's a mistake.
We shouldn't do that. We should just be
subtracting from the credit. In the smart contract, there's a couple of tweaks
we need to make. First, take out payable because there's no longer
a payable function. Second, Let's put a second, Let's put a U and amount. So we're going to
send an amount. When we make a payment,
we need to send an amount that's actually going to be deducted
from our balance. So we've got an amount here. And then we're going to
change this message dot value to amount because we're not
actually sending money, we're just deducting
from our balance. And that should be all. So when we run make payment, we're going to test
this in a minute. We're going to
send an amount and that amount is going to be
deducted from our balance. Then because we removed
the payable factor in added a uint8 amount parameter, we need to update our blockchain context function here
and make payment. We're passing in
this value object, which is how you deal
with a payable function. That's how we pass an amount
to a payable function. The only difference
because we're bringing in the amount now as a uint8
and not that payable amount, we just need to replace
this object with B&B value as the second parameter
or the second argument. So be sure you update that in the blockchain context and then jump back over to your contract. Now that segue is
perfectly into the owner. The owner, if somebody has $10 and they pay $5
in their account, they have $5 leftover in the other five actually
belongs to the owner. So we need to allow the
owner of the contract who's going to basically be running the bike store to
check their balance. Like how much is their profits? How much of the, all of the money in
the smart contract, how much of that is dares, based on people
running up bills and making payments and recreating their account and all of that. So there's a couple of
ways we can do this. I thought about. So
we use mappings. You can't loop
through a mapping. I thought about maybe
when we add a renter to create an array and just have an array of addresses
that we can loop through. But we really don't want
to loop through stuff because we might end
up having hundreds, maybe thousands of
renters and that's gonna be monstrous gas fees. If we got to loop
through 11000 renters, I think the best
way to address this is to create a new variable called uint8, owner balance. So we have owner balance. And if you think about it, the only time money will go into the owner's balance is
when people make payments. Again, if I have $10
on the smart contract and all ten of that is mine
and I make a $5 payment, then my balance goes down to five and the other five
belongs to the owner. So that's really the
only time that we need to be adding to
the owner balance. So down here where
we make payment, we're just going to
add one more thing under this. It's gonna be. Owner balance plus
equals amount. So that's gonna be credited
to this owner balance. And then backup here where
we have the balance of, we want this only to be
called by the owner. So let's create another
modifier, modifier, only owner. And we don't have any
parameters there. And we can require that message
dot sender equals owner. Because that's a wallet address. And you are not allowed
access to access this. And then we'll do our
underscore semicolon to run the rest of the function. And we'll use only
owner on air balance of right here on the owner. If we want to add two more
owner related functions, one to get his balanced or her balance function,
get owner balance. And we'll do view public
and let's make it only owner and returns a uint8. And here we're just going
to return owner balance. And then we want to do
one more function for the owner to withdraw the money. Now you might be
like, Man, that's, that's risky because
the owner can just rip everybody's money
out and run with it. But that's not true because
the owner balance is only the money in the account that's not
credited to people. So let's do function. Withdrawal, owner balance. This is gonna be
payable and public. And we're going to say owner
dot transfer, owner balance. Now you see that we
have this error here. And it says Send and transfer
are only available for objects of type address
payable not address. Now we can fix this by just
casting this owner S payable. Then finally, we need to set
the owner balance back to 0 because we're transferring
out that owner balance, which is set up at the top. You went owner balance. We're transferring that
amount out to our wallet. Now we need to set
that back to 0. So owner balance equals 0. And with that, I
think we're done. So select this whole
thing and copy it and we're going to paste it into remix so that we
can test it out. I'm going to paste it
here and compile it. And then make this bigger. Alright, so let's
deploy the contract. And I'm gonna, I'm gonna deploy using the first account
that's gonna be the owner. So click Deploy. Then let's add a renter. So I'm going to choose
the second person. Copy and put it in
that wallet address. Want to put the Travis test? Can rent is true. Activists false. Zeros, zeros, zeros 0. So we'll click Add renter. And I'm gonna go
ahead and check out a bike for that renter. Bike is checked out. And now I'm gonna go
to the third account. So it's gonna be the second
renter going to copy that. Paste it here. And I'll
put something like Tracy. And I'm going to go ahead
and check out a bike. Well, I need to add them first. So make sure you've
got the right address for that third person
and add the renter. And then I'm going to check
out a bike for that renter. Awesome. So we have timestamps, will be able to check
it here in a minute. But let's go ahead while we're here and deposit some money. So I'm going to choose one ether and I'll choose
the second renter. And they're going to
deposit one ether to the smart contract. So right here where
it says deposit, make sure this is one ether
and then click deposit. Awesome. So they
deposited one ether. If I check that renter here, you'll see that they
have a start time, so the bikes checked out
and they have a balance. Now what happens if
I try to switch to the third the
second renter here. And deposit using the
first renters address, I should get an error. So click deposit. Here we go. You can only
manage your account. So that is renter
modifier is working. That's awesome. And that's the use case. So if I'm if I'm
depositing money, but I'm doing it from a
different wallet than my own into somebody
else's account. That shouldn't be allowed. That works. So let's actually
switch to the right person. So let's actually grab that person's address and
deposit an ether as well. So I'm going to click deposit. And I didn't change the address, so make sure you
change the address. So click deposit.
Okay. So we have to renters with two bikes
checked out in each. Renter has deposited money. So in a couple of more minutes,
I'll come back and we'll check the bike back in and
we'll finish things up. Alright, so before we
check these backend, let's actually
switch to the owner. And actually now actually
before we check back in, check the bytes back in, Let's try to get the balance of the contract with
one of the renters. So click balance of
and you get an error. You are not allowed
to access this. Get owner's balance. You are not allowed
to access this. So now let's switch to the
owner and see what that is. If we get the balance
of we have we have one ether I thought I'd
deposited another one. Let's check our renters and see. The first renter has won. The second renter
doesn't have any, so I must not have clicked
deposit for the other Enter. So let me do that real quick. Or maybe I deposited nothing and maybe I didn't
select the 1 eighth. So let's put it in the
other renter ending in dB. Make sure I choose that renter. And then put this ether
to one and click deposit. An Alpha switch
back to the owner. I can check the balance
of that's to Eve. So let me actually put this
over here to keep track. Contract has to leave. The owner's balance is 0. The owner has 0. Rent or one has, has, has one ether
in orange are two, has one ether also. Okay, so that's where we're at and we're going
to test this out. Let's check these bikes back in. So I'm going to choose
this first render. I'm going to check them back in. Check in. And that renter
now has an a Mountain Dew. Then I'm going to check
the other render in. Check them in. And then they
should have the same amount. Do awesome. In a GAN or balance. Again, let me go
back to the owner. The balance should be the same and the owner's
balance still should be 0. So let's see what happens
when we make a payment. We make a payment the smart contract balance
shouldn't change. It should just swap hands
to the owner's balance. So this renter here, rent or two O's, this much five to
however many zeros. So let's copy that and
make that payment. So I'm going to
grab this amount. They have five whatever, do however many zeros that is, we don't need to
come up here and add that amount in way up here. Because now in the
make payment function we accepted as a
second argument. So I'm gonna put that and then the first argument was
their wallet address. So let's go ahead and
make the payment. So make payment and I can
only manage my account. So let me switch to
the right account. Here we go. I'm gonna go ahead
and make the payment. And you see now than when I click renters,
they have nothing to do. But they had that five to however many zeros deducted
from their balance. Now that amount, that five, however many should now be
part of the owner's balance. So let me switch
back to the owner. Actually, let me make
these changes here. So the balance now for rent
or one is this much 995. They've had five whatever
deducted from it. And if I switch over
to the owner now, I should have that
amount in my possession. So switched over to the owner. I'm gonna click balance of and it's the same,
nothing changed. That's what we fixed
because before we were adding to the balance and deducting from Eric
count, which is wrong. So the balance of
is still the same. Get owner's balance, Let's click that and there is that amount. So now the owner has this much. And if you add this
much with rent or one, we get back to this one
to however many zeros, so we know that it's working, everything is working great. And I think that's it. We test it is renter. We tested only owner and
EHR contracts working fine. So now all we have to do is since they're smart
contract changed, we have to actually redeploy it. So let's do that to
get a fresh contract. That's very simple. Just go back to your
application, stop your server, go out of your client folder
into your contract folder. In before we redeploy, we actually have to
compile that new contract. And in fact, let me copy it from here just to make sure I
have the latest changes. So copy that into my contract, save it and we need
to recompile in, refresh this
artifacts folder with new bytecode ABIs, all
of that good stuff. So just do NP x,
hardhat, compile. Awesome compiled one
Solidity file successfully. Now go to your artifacts folder, contracts by chain dots soul and choose bike chain dot json. First thing we wanna do
is grab this entire ABI again From bracket two bracket, copy that and paste it in our config dot json
in our client folder. Grab all of that, and paste that in. Then we need to update
the contract address. So first we need to deploy it. So that's NP x hardhat run and then scripts slash
sample script.js. And then for your network, choose test net to redeploy. So click Enter. When we do this, we have
a brand new contract. In a brand new
application. Basically. There it is bike chain
deployed to this address. So copy that and paste it
in your contract address. Save it and you're good. So cd dot dot cd client and then yarn run dev and we
should have a new application. I'm gonna go to localhost 3 thousand and I'm
actually going to disconnect my wallet from
it to get a fresh start, to disconnect this account
and refresh the page. Choose my bike and it says, Welcome, Please enter
your first and last name. So let me connect
my wallet first. Connect. Alright. Enter in my name to
register as a renter. Travis test. Submit. Deploy that. Awesome. Let's credit the
account with the 0.1 B&B. There it is. 0.1 just for kicks. Let's try to check in a
bike that we never checked out and we get this
warning up here. Please check out a bike
first. That's still working. Now let's check out
a bike and confirm. And once that's done, we should turn green here because their bikes checked out. Still pending. There it is. We're green. So it looks like our
app is working great. We have our dashboard in order. We now have checks
so that people can only modify their own accounts. And we have messages
popping up to display errors that we get from
require statements. And that's all I have for you. I hope you enjoyed
this course a lot. If you're looking for some
more things to do here, one thing that
would be fun is to put a navigation item up here, like a menu item
that says admin, that pops up if
the owner logs in. Like I thought about doing this, but I don't want
to keep the course going and going and going. You've already come a long way. But if let's say
since I am the owner, I deploy this contract
address, I'm the owner. And we already
have the functions in place on a smart contract. So you can put a or you may want to add a function
called is owner. And then you can check like
if that person is the owner. If so, put an admin menu item up here and when
you click on it, there'll be two forms. One where you can click and
check your balance into, one where you can withdraw the balance and you should know a 100 per cent how
to do that because we did it here and
we did it here. And in the smart contract
that's already in place, we've already built
the function. We just refresh the contract and redeployed it, so it's there. So that's my challenge to you. That'll be a lot of
fun to follow up on. But at this point we have
a fully functional app. We've done a lot of work. You should
congratulate yourself. Feel free to tweak this
to make it cleaner. Add some more features
to it, some better CSS, whatever you feel like doing, push it to GitHub and
show it to the world. Again. Thanks for picking
this course up and following along with me as I
pieced this thing together. If you enjoyed it, consider leaving a review or
shooting me a message, telling me if if you liked
it or if you have anything, you would like to see done
better in the future. I'd love to hear it. So again, thank you for going through
this course with me. Now talk to you later.
10. Owner Bonus Features: So here's a bonus
project for you. What we're gonna do is create
a dashboard for the owner. The owner would be able to
view the contract balance, their balance, the
owner balance, and would be able to
withdraw the owner balance. So it looks like this. I'm logged in as not the owner. And if I go to dash admin, I'm gonna get a page
that says access denied. So what you wanna do
is you want to create a route called slash admin. And if you're not the owner, you just see access denied. Now, if you are the owner, let me disconnect this. And I'm going to connect
the owner account. Now, you should see a dashboard. So this page is just like
the dashboard we have here. There's a title, there's
some stat cards, and then there's a form. So it's the same thing here. So if I go back to admin, I have a title, it has some stat
cards and then I have a form with no text
fields is just a button. And what we'll do here is
we'll have the owner balance, will have the full
contract balance. And then when we withdraw, withdrawal this owner
balance to our wallet. And since the owner balance is part of the entire
contract balance, we should see this change to
0.18. So let's try that out. So it's processing. Alright, so I withdrew my 0.01 B&B in my contract
balance is now 0.18. So that's your challenge. If you're kinda burnout
from the project, you've been working
hard at it and you're done and don't want to even deal with this, don't
worry about it. It's bonus. But I think
it's important if you can, to do it because one, an owner needs to
get paid, right? He's building revenue
from these bike rentals. He needs to be able
to get paid for it. Second, this is a
great opportunity for you to take all that you've learned in this course and do something without
any assistance. So take all of
these skills you've learned and try to
do it yourself. Now, below this video, I've put a couple of
steps to help you out. Like a couple of steps you
should take to get this done. And then finally,
I've posted a link to the branch on GitHub with these code changes
that you can check out, but don't look at that
until you're done. Try to attempt this. Anyway. I think you'll find
it a lot of fun. So have at it.