Now in the last lesson, we saw how we can use variables and constants in the Motoko programming language.
We also saw how we can import libraries from the Motoko-based library and use it to do things such as
printing into the console.
In this lesson, we're going to dig a little bit deeper and we're going to add a little bit more functionality
to our actor, which is the DBank canister that we control.
Now, one of the things that we're going to have to do if we are creating this money market is we're
going to have to let people be able to deposit their cryptocurrencies or money into our application.
And in order to do that, we're going to have to create a function.
So in the Motoko, functions are created with the func keyword similar to the Swift programming language,
if you ever use that.
And then the next thing is we get to give our function a name, which I'm going to call topUp, and
then we open up a set of curly brackets and we get to define what happens when this function is triggered.
So let's say for now, we're just going to increase the currentValue by $1 each time this topUp() function
is called. To make it less confusing, let's first comment our previous debug print.
So when we've increased the currentValue, at the very end of the function before it finishes, we're
going to try and print the new value of this variable.
Go ahead, pause the video and write a print statement using Motoko to print out the currentValue at
the end of this function.
All right.
So again, we're going to use the Debug.print function and then we're going to need the debug_show to
be able to slot in this variable inside here.
Now, let's go ahead and actually use this function.
Just below where I've created this function, I'm going to call it.
And you'll see that you might get some errors here because we haven't closed off this function with a
semicolon.
So you have to be quite careful with this programming language where every function expects a semicolon
to cap it off.
So now we're going to describe how this function works,
then we're going to call it and if we go ahead and hit dfx deploy right now, you'll see that in the
printout we get
is the currentValue that's being printed right here on line 12 is now 101 because we've incremented
it by 1, and then we printed out the currentValue.
And that is all through calling this function inside our DBank canister.
Now this is what you would call a private function.
It's a function that's only accessible within this particular actor's curly braces.
Now, as you've seen before, when we had the Hello World application, when we first did our setup,
we can actually call functions within canisters from the outside.
So I'm just going to comment this line of code out and I want to be able to call this code from the
command line.
If we take a look at the documentation for that hello example that we've already run,
you can see it tells you that after you've hit Deploy, you can use this structure in the command line
to get the canister to call a particular function within a particular canister.
Now you can also insert an input to that function, but in our case, we have no inputs.
It's empty in here.
So all we need to do is just to call the function. Following that format,
all we have to do is write "dfx canister call...", and then we have to put in the name of our project,
which you can see here is all lowercase, "dbank..."
And then we're going to have to put in the name of our function, which is called, "topUp", and notice
how it's spelt.
Now there's just one problem, and that is the fact that this function is currently private to our actor
DBank, which, as I said, means that it can only be called from within these curly braces, like we
did here.
So that means when I go ahead and hit Run here, I'm going to get an error
and it's going to tell me that this canister, which corresponds to my DBank canister, it "has no update
method called topUp".
It actually cannot see this function because it's private.
So what can we do if we wanted to call this function for this canister from the outside?
Because in the future you can imagine you could have an application that's very complex with multiple
canisters.
How can you call a function within another canister?
Well, we have to add a modifier keyword up here called "public".
And this is going to expose this function to the public, to outside this canister basically, allowing
us to be able to call it from the outside, for example, from the command line here.
So let's go ahead and hit Save on this file to update the changes.
And then we're going to have to use "dfx deploy" to make sure that this new code gets deployed into
the canister.
And then once that's done, we can try that command again where we say, dfx canister call this top
Up function from our DBank.
And you can see now it has executed and we've got that 101 being printed over here again.
So this is how we can create a public function in a canister and how we can call it and get it to run
from the command line.
Now, what if we didn't want to have to type all of this out every single time?
What if there was a way that we could have a simple user interface to be able to just click a button
and get the functions in our canisters to run without having to type a whole bunch of stuff?
Well, the team have already thought of this, and this can be done using the candid UI.
Candid is called an interface description language.
And basically it's kind of like... I don't know if you've seen these API documentations which are interactive.
For example, if we take a look at the one for GitLab, you can see that there is a try it out section
where you can access certain paths or certain API endpoints, and you can interact with these while you're
exploring the documentation.
So Candid basically provides a really easy way for us to interact with our canisters.
And it doesn't matter if the canister is written in Motoko or Rust.
Basically, instead of using our dfx command line, we can actually use Candid to specify input arguments
or get it to generate random input arguments or display return values from our canister methods.
And that means we can actually get a
UI to interact with instead of having to work with the command line all the time.
Let's try it out for our basic a new program.
So the first thing we have to do is we have to get the canister ID for this interface.
You can either go ahead and copy this code here from this link, which I'll provide in the Course Resources,
or alternatively it is just simply dfx canister id
and then this is two underscores Candid with a capital C underscore UI.
And once we put that into our terminal here, you can see we get a canister id back, which we're
going to need because we're going to go to the localhost server that's currently running, and we're
going to add a question mark and then the query, which is canisterId with capital I, and then we're
going to set it equal to whatever it is we got back from this command.
So let's try it out.
So I'm going to copy everything up until the equals sign and then after the equals sign, I'm going
to paste in what I got from here.
And now when I hit run, you can see it's asking me to provide another canister ID, so be careful
here. This ID that it wants is the canister ID for our program,
so in this case it's all DBank program. And we can get a hold of that ID by simply using the command
dfx canister ID and then provide the name of our canister.
So in our case it will be dfx canister id and the name of our canister is dbank, as you can see right
here.
So now let's hit enter and we'll copy this id which you can see is separate from the candid UI ID
and then I'm going to paste it into this field.
Don't worry about this one.
We don't have a did file and then we're going to go and hit the GO button.
So now all Candid UI has been created.
We did absolutely zero front-end work, but this is automatically created by it reading our canister
code in here.
So you can see we have a single function that can be interacted with, which is called topUp, and here
is where you see it.
So now instead of having to type dfx canister call, blah blah blah, I can actually simply just
tap the call button and it will run the same command.
Now once it's run, we can confirm that it worked by seeing the output here. You can see our currentValue
has been incremented yet again by 1 because we called it and we can keep doing that as many times
as we want.
And basically this Candid ID simplifies how we interact with our canisters when we are testing and
writing our code.
So what if we wanted to change our function so that we can add an input?
Because normally when you top up, you don't just top up by $1 each time, right?
In order to add an input to our function, we're going to have to fill some stuff in these brackets.
So we're going to provide a name for the input, which I'm going to call amount.
And then in addition, we have to provide the data type of this input, which in our case can be a natural
number or shortened to Nat data type.
So natural number, as I mentioned before, is any natural number that is positive,
so starting from zero, going up. Now instead of incrementing by 1, we can increment by the amount that
was specified.
If I go ahead and save my file, and then go ahead and run deploy again to update, then when I go back
over here and refresh, you can see we've now got a field that we can type into and it's telling us
is expecting a natural number.
So let's say I decide to top up $12. If I go ahead and hit CALL, you can see that this is going to run,
and then we've now increased our total amount by 12.
So that is how we managed to add an input to our function.
Now some of you, I know, are really keen-eyed and you might have noticed something quite interesting.
Previous to the last deploy we were on $103.
After I deployed the new code, it went back down to 100, added the $12 that I topped up, and we're
back onto 112 instead of 103 + 12, which would have been 115.
So why is that?
Well, that is related to this concept called Orthogonal Persistence, which we're going to talk about
in a lot more detail in a future lesson.
But for now, let's just assume that every time we run dfx deploy, all our variables get wiped and get
reset to their initial values.
So now that we've created the topUp function and we've seen how we can allow the user to provide an
input to say how much they want to top up into dbank,
it's time for a challenge for you,
which is to create another function which will allow users to withdraw an amount from the current
value
and then once they've done that, we're going to decrease the currentValue by whichever amount they
provided.
So try and create this function called withdrawl.
And again, this function requires an input, and then the function is going to decrease the currentValue
by whatever amount is specified.
And finally, make sure that you actually print out the final value of currentValue.
So pause the video here and see if you can create this function.
Once you're done, run the code and test it out on Candid UI, and then afterwards we're going to run through
the solution together.
So,
pause the video now.
All right.
So again, because we need to access this function from the command line and from Candid UI, we're
going to make it a public function, and then we're going to call it withdrawal.
And then we're going to provide an input, which again, I'll call amount and it will again be a
natural number,
so a positive number that we're going to withdraw from our bank. And simply we're just going to do the
opposite,
so the currentValue we're going to -=, so decrement, the currentValue by the amount that
was specified.
And then finally we're going to Debug.print the currentValue after the decrement has happened.
So if this is what you've done, then great. Let's go ahead and hit Save to save our code and then
we're going to run dfx deploy to update our canister with the latest code.
And if we go back to our Candid UI and hit Refresh, then you can see we've got our new function showing
up here,
our withdrawl function. And if I go ahead and specify an amount, say $10 to withdraw from the bank,
hit CALL and then go back over here,
you can see it's now decreased from 100, which is the currentValue by 10, which is what I specified.
And now it's on 90.
So there you have it.
We've got a withdrawl function, we've got a topUp function, and we're able to see these functions
and interact with them using our Candid UI user interface on the frontend.
Now there's just a couple of bugs that we've still got to iron out and the main issue is here in our
withdrawl function. If the user decides to withdraw an extraordinarily large amount, an amount that
we don't have in the bank, then you can see our current code is going to provide an error, something
called a natural subtraction underflow.
So in the next lesson, we're going to learn more about how to work with conditionals in Motoko and
make sure that we fix this issue.
So for all of that and more,
I'll see you in the next lesson.