All right.
So now that we've seen that our frontend is up and working, we can move on to the next step which is
getting this Check Balance section to actually work.
Now for someone to actually have a balance, we actually have to assign it to them.
So we basically have to write some code in our main.mo that assigns an amount of token to a particular
user.
So who are we going to assign it to?
Well, we're going to have an owner that owns the tokens.
So in the case of the DAngela coin, it will be me.
And in the case of the coins that you're going to be creating, it's going to be yourself.
So how can we identify ourselves to know who to give it to?
Well, in the Internet Computer, there's this type which is called a Principal.
And this is a way of identifying users and canisters.
So it basically gives us an ID to be able to uniquely identify either a particular canister that's
running some sort of smart contract, or a particular user that's interacting with the canister.
Now, the Principal type has a number of functions that can be associated with it.
And it's something that we're going to be using to assign ourselves the starting allocation of all of
our tokens.
Now, as I mentioned, the user has a uniquely identifying Principal ID, and we can get hold of that
by typing into the command line, "dfx identity get -principal".
And once you hit Enter on that, it will give you the principal ID of the default user, which is yourself.
And this is the ID that we're going to be assigning our tokens to when we create our canister.
So as soon as we mint our freshly made tokens, let's say we're going to make a billion tokens, then
we're going to assign all of those tokens to the owner, which is yourself through this ID.
Let's go ahead and create a new actor in our main.mo.
So we're going to call our actor, Token with a capital T, and inside this actor we're going to create
some variables.
The first variable we're going to create is going to be the owner.
In this case, it's going to be yourself.
So this is going to be assigned the principal ID that you just got hold of. So we can define its data
type as Principal.
Now, in order to use this data type, as always, we're going to have to import it.
And then once we've got hold of that data type, we can then use one of the methods in the data type, which
is called fromText, in order to convert a piece of text into a Principal data type.
So as you notice here when we got hold of our actual principal ID, this is just a piece of text.
It's a string, right?
So we're going to use Principal.fromText and we're going to pass in this string. So you can select
all of it, make sure that you got the entire long string with all the dashes and everything from the
beginning to the end.
Hit command + c to copy, and then we can paste it into here so that we actually get hold of this Principal,
and we can use it when we assign ourselves some tokens.
Now, in addition to the owner, we're also going to create some other variables.
So for example, we're going to create something called the totalSupply.
So this is going to be the totalSupply of our particular token, and it's going to be a data type of
natural number,
so it can't go below zero.
And I'm going to set it to 1 billion, so I'm going to mint 1 billion of my own tokens.
So that's nine zeros.
And finally, I'm going to give my token a symbol as well.
So I'll just create something called symbol, which will be text
and this is going to be the decentralized Angela coin, also for short known as DANG.
You'll notice that many crypto tokens have an abbreviation.
For example, Ether goes by ETH or E-T-H, and this is modeled after real currencies.
So USD for U.S. dollars or GBP for Great British pounds.
And you've got coins such as Ethereum, so E-T-H, or something like DOGE for the Dogecoin,
so we're just going to create our own currency name and you can name it whatever you like.
In my case, mine is going to be called DANG, and it's up to you what you want to call your own tokens.
But once we've created that, we now have to figure out a way to create our ledger.
Our ledger is just going to be a data store that stores the id of a particular user or canister,
and then it's going to be the amount of token,
so in this case DANG tokens that they possess.
So the thought might have come to you as well,
a good data structure for this would be a dictionary.
And there's something that's very similar to a dictionary in Motoko, which is called a HashMap.
A HashMap in Motoko is commonly known as a hash table in other languages, and it's basically a way
of mapping a key to a value.
And the nice thing about HashMaps is they don't really have an explicit required data type,
so you could put your own objects in there, your own data types,
and it's a really efficient way of indexing items so that you can hash the key and be able to store
it into a location in the memory of the computer to store your value.
And when you're looking for the value, you can simply find it by looking at the position of the hash.
But for all intents and purposes, you can consider a HashMap just like you would work with a dictionary,
it's got a key and it's got a value,
and in order to get hold of a value, you have to provide the key.
And we're going to be using it to create a variable called balances.
And this is basically a way for us to keep track of who owns how much of our custom token.
In order to use the HashMap again, we have to import it.
So make sure that you've got the capital H, capital M and also here as well.
And we're going to set our balances to equal a HashMap.
We're going to use the equal sign and then HashMap.HashMap,
and we get to assign what the data type will be for the key and the value.
And the key, in our case, is going to be the Principal data type, because remember, we're trying to
associate a bunch of IDs with an amount that that ID owns.
So it'll be a user or a canister, and then that will be linked to the amount of our custom token that
they own.
So in that case, the value is going to be of type Nat, it's just going to be a natural number.
And once we've done that, we're going to initialize our new HashMap with a set of parentheses, and
we have to provide three inputs.
What is the initial size of our HashMap? Which we're going to set as 1.
Next, how are we going to check for the equality of our keys?
So when we give our HashMap a key, how is it going to check against the actual HashMap?
Well, thankfully, because we're using the Principal type, they've helpfully provided a method in
here called equal which we can use to check that a Principal that we give our balance equals the Principal
thats stored.
And finally, we have to tell this HashMap how it should hash those keys. Now, because those keys are,
again, Principals,
we're going to use a method from the principal type called Principal.hash which knows how to hash
out principle IDs.
So now you should have this variable which is set to equal this HashMap.
And we can now go ahead and add our owner to this ledger as the first entry.
So to do that, we tap into our balances and we say .put. And .put is going to insert the value,
whatever we supply, at a particular key, which we also supply, and it will overwrite any existing entries
with the same key.
So because we're doing this as the first order of business, there won't be anything in here.
It's completely empty.
So we're going to put our owner as the Principal key and the value is going to be the total supply.
So basically in this line of code, we've added our owner's Principal into our ledger of balances and
we've given all of the tokens that we're going to mint to the owner, which should be yourself.
So now that we've created our ledger, we have to figure out a way to be able to query in order to find
out who owns how much,
so a Check Balance method.
I'm going to create a new public query function which is going to be called balanceOf(). And in the balanceOf()
method,
we're going to supply the who, which in this case is going to be of type Principal.
So we're going to query how much balance does this Particular ID own in our ledger from our balance
HashMap.
And then we're going to asynchronously return the output, which is going to be a natural number because
it's going to be the value that's inside this HashMap that's associated with the queried ID.
So we want to check if the balances.get...
This .get, allows us to pass in a key and get hold of the stored value,
but notice here that if it doesn't have that particular key and there's no associated value, then it's
going to return, null.
What if we check that this particular Principlal ID that was passed in, so balances.get pass in the
who, and if that is equal to null,
well, in that case, we want to return 0 because that particular ID doesn't have any associated
balance in our ledger.
However, if it doesn't return null, then it means that it succeeded and we should be able to return
the actual balance.
So balances.get(who).
Now, there's just one problem with this code, and the problem is that this expression, when we use
a "get" on a HashMap, it outputs a data type of,
?Nat. And instead of an actual natural number.
So what's this question mark business?
Well, it's a data type called an Option.
And if you've done Swift, you would have heard the Optional.
So basically it's very, very similar to that concept.
Essentially, it's a typesafe
null.
What it means is that it retains the data type of a particular value, but it can be null or it can
have a value.
The way that we're supposed to deal with these optionals is we're supposed to use a switch statement to
check if it's null or if it, in fact, is an Optional of a particular data type.
Let's transplant this into our situation and we can sub the required parts for what we need.
So let's create a constant with the let, which we'll call the balance.
And this is going to be a natural number and we're going to switch using this method,
balances.get(), and then we're going to pass in the "who".
And in order for it to switch on the entire statement, we're going to have to wrap it inside a pair
of parentheses, like that.
Now, in the case that the result of this function call is null, then we want to set the balance to
equal zero.
But in the case that it is an Optional that gets returned,
so our optional result,
well then we want to simply return that result.
This syntax, it's actually not that difficult if you know how switch statements work, which you should,
because we've covered it in JavaScript. But the syntax is formatted differently,
essentially, we're checking the result or the outcome of this method call,
so passing in the ID of the person we're checking into our balances ledger and we'll get the value
of how much of this currency that they own.
And then once we get that result, because it's an Optional, we have the check in case the result is
null, in which case we set this balance constant to 0.
But if the result is an Optional, then we'll set the balance to the result and we get rid of that Optional
question mark.
Now, instead of having this if-statement, we can simply return our balance.
And because this balance is a natural number which is what we want to output, we get rid of all of
these problems.
Now that we've done all of that, we're finally ready to actually to do our "dfx deploy" again.
So save your
main.mo
file with all the updated code.
Go ahead and run "dfx deploy" which should now put yourself, your own Principal, as the owner of a billion
tokens of your own currency.
Now, in order to call the balanceOf() method from the command line, we have to get hold of our Principal
ID to pass in as an input.
Now there's a little bit of formatting that's involved as well,
but don't worry, I'm going to walk you through step by step. If you head over to the README.md
file that's included in the starter project,
you can view this markdown file in its proper formatting by clicking on this button here with the magnifying
glass. In order to check our balance,
the first thing we're going to do is we're going to find out our Principal ID.
So you've already seen that we can use this command,
"dfx identity get -principal" in order to get hold of the owner, so ourselves,
Principal ID. I'm just going to open up a new terminal window here which is inside my token project.
So it's really easy from VS Code because it always knows where you are. And I'm going to paste that
in here.
And once we hit Enter, you should see that principal that you got earlier on.
And the reason why I've got this README is because there's a lot of code that we're going to write
into the command line in order to issue commands.
And if you get any of these wrong or if you make a typo, it's really difficult to tell where you went
wrong.
So instead you can just copy and paste the commands, which is a lot easier. Once you've got hold of
your Principal,
I want you to go ahead and save it somewhere.
So inside the README.md you can see I've got this section 2, where it says, "Save it somewhere." and I want
you to just go ahead and replace the xxx-yyy.
This is really useful because you always have to know in the future who you as a user is.
Now, we're not going to use that right now, but instead, we're going to format our Principal ID into
a format that the method, balanceOf, will accept.
So because it wants a principal data type, we can't just simply pass this in as text.
In order to format this, we're going to use this command.
I'm just going to walk you through what it does.
We're going to create a new variable in the command line called the OWNER_PUBLIC_KEY,
and it's going to be set to a string or a piece of text that starts out with the word principal, lowercase,
a space, and then in between a set of double quotes, it's going to paste in whatever it is the result
of this command, which is "dfx identity get -principle", which, as you know, generates this string.
So let's give it a go. Let's copy that entirely and then paste it in here and hit Enter.
Now, you won't see much after that, but we can confirm that it worked by using the echo command,
which will print out the value of any of our variables.
And this is the variable that we just created, the OWNER_PUBLIC_KEY.
So let's paste that line in here and you should see that we've got this formatting exactly as our method
requires it, which is 'principal, space, double quote "the actual principal ID", and then double quote
at the end'.
So now we can use this to actually check the owner's balance.
So we're going to call this token, which is our canister over here, our main.mo,
we're going to call the method balanceOf, which is this one,
and then inside the parentheses, we're going to pass in the who as the OWNER_PUBLIC_KEY, so our own
public key.
Again, copy this command in its entirety and then paste it into the terminal.
And once you hit Enter, it should give you the result,
and it tells me that I've got 1 billion of these tokens that belong to my Principal ID and it's also
a natural number.
So that's perfect.
That means that everything we've done so far where we created our balances HashMap, and we gave the
owner, ourselves, our own public key, the entire supply of tokens, and we're also able to use our balanceOf
method to query it.
All that's left to do now is to hook up our backend with the frontend, which is our Balance.jsx
and to be able to do the same thing in our website using our front-end.
So for all of that and more, I'll see you on the next lesson.