All right. 1
So now that we've seen that our frontend is up and working, we can move on to the next step which is 2
getting this check balance section to actually work. 3
Now for someone to actually have a balance, we actually have to assign it to them. 4
So we basically have to write some code in our main.mo that assigns a amount of token to a particular 5
user. 6
So who are we going to assign it to? 7
Well, we're going to have a owner that owns the tokens. 8
So in the case of the DAngela coin, it will be me. 9
And in the case of the coins that you're going to be creating, it's going to be yourself. 10
So how can we identify ourselves to know who to give it to? 11
Well, in the Internet computer, there's this type which is called a principal. 12
And this is a way of identifying users and canisters. 13
So it basically gives us an ID to be able to uniquely identify either a particular canister that's 14
running some sort of smart contract, or a particular user that's interacting with the canister. 15
Now, the principle type has a number of functions that can be associated with it. 16
And it's something that we're going to be using to assign ourselves the starting allocation of all of 17
our tokens. 18
Now, as I mentioned, the user has a uniquely identifying principle ID, and we can get hold of that 19
by typing into the command line dfx identity get -principal. 20
And once you hit enter on that, it will give you the principal ID of the default user, which is yourself. 21
And this is the ID that we're going to be assigning our tokens to when we create our canister. 22
So as soon as we mint our freshly made tokens, let's say we're going to make a billion tokens, then 23
we're going to assign all of those tokens to the owner, which is yourself through this ID. 24
Let's go ahead and create a new actor in our main.mo. 25
So we're going to call our actor Token with a capital T, and inside this actor we're going to create 26
some variables. 27
The first variable we're going to create is going to be the owner. 28
In this case, it's going to be yourself. 29
So this is going to be assigned the principal ID that you just got hold of. So we can define its data 30
type as principal. 31
Now, in order to use this data type, as always, we're going to have to import it. 32
And then once we've got hold of that data type, we can use one of the methods in the data type, which 33
is called fromText, in order to convert a piece of text into a principal data type. 34
So as you notice here when we got hold of our actual principal ID, this is just a piece of text. 35
It's a string, right? 36
So we're going to use Principal.fromText and we're going to parse in this string. So you can select 37
all of it, make sure that you got the entire long string with all the dashes and everything from the 38
beginning to the end. 39
Hit command+c to copy and then we can paste it into here so that we actually get hold of this principal 40
and we can use it when we assign ourselves some tokens. 41
Now, in addition to the owner, we're also going to create some other variables. 42
So for example, we're going to create something called the totalSupply. 43
So this is going to be the totalSupply of our particular token, and it's going to be a data type of 44
natural number, 45
so it can't go below zero. 46
And I'm going to set it to 1 billion, so I'm going to mint 1 billion of my own tokens. 47
So that's nine zeros. 48
And finally, I'm going to give my token a symbol as well. 49
So I'll just create something called symbol, which will be text 50
and this is going to be the decentralized Angela coin, also for short known as DANG. 51
You'll notice that many crypto tokens have an abbreviation. 52
For example, ether goes by eth or ETH, and this is modeled after real currencies. 53
So USD for U.S. dollars or GBP for great British pounds. 54
And you've got coins such as Ethereum, so ETH, or something like DOGE for the dogecoin. 55
So we're just going to create our own currency name and you can name it whatever you like. 56
In my case, mine is going to be called DANG, and it's up to you what you want to call your own tokens. 57
But once we've created that, we now have to figure out a way to create our ledger. 58
Our ledger is just going to be a data store that stores the id of a particular user or canister, 59
and then it's going to be the amount of token, 60
so in this case DANG tokens that they possess. 61
So the thought might have come to you as well. 62
A good data structure for this would be a dictionary. 63
And there's something that's very similar to a dictionary in Motoko, which is called a HashMap. 64
A HashMap in Motoko is commonly known as a hash table in other languages, and it's basically a way 65
of mapping a key to a value. 66
And the nice thing about HashMaps is they don't really have an explicit required data type. 67
So you could put your own objects in there, your own data types. 68
And it's a really efficient way of indexing items so that you can hash the key and be able to store 69
it into a location in the memory of the computer to store your value. 70
And when you're looking for the value, you can simply find it by looking at the position of the hash. 71
But for all intents and purposes, you can consider a HashMap just like you would work with a dictionary. 72
It's got a key and it's got a value. 73
And in order to get hold of a value, you have to provide the key. 74
And we're going to be using it to create a variable called balances. 75
And this is basically a way for us to keep track of who owns how much of our custom token. 76
In order to use the HashMap again, we have to import it. 77
So make sure that you've got the capital H, capital M and also here as well. 78
And we're going to set our balances to equal a HashMap. 79
We're going to use the equal sign and then HashMap.HashMap. 80
And we get to assign what the data type will be for the key and the value. 81
And the key, in our case, is going to be the principal data type, because remember, we're trying to 82
associate a bunch of IDs with an amount that that ID owns. 83
So it'll be a user or a canister, and then that will be linked to the amount of our custom token that 84
they own. 85
So in that case, the value is going to be of type Nat, it's just going to be a natural number. 86
And once we've done that, we're going to initialize our new HashMap with a set of parentheses, and 87
we have to provide three inputs. 88
What is the initial size of our HashMap? Which we're going to set as one. 89
Next, how are we going to check for the equality of our keys? 90
So when we give our HashMap a key, how is it going to check against the actual HashMap? 91
Well, thankfully, because we're using the principal type, they've helpfully provided a method in 92
here called equal which we can use to check that a principal that we give our balance equals the principal 93
thats stored. 94
And finally, we have to tell this HashMap how it should hash those keys now. Because those keys are, 95
again, principals, 96
we're going to use a method from the principal type called Principal.hash which knows how to hash 97
out principle IDs. 98
So now you should have this variable which is set to equal this HashMap. 99
And we can now go ahead and add our owner to this ledger as the first entry. 100
So to do that, we tap into our balances and we say .put. And .put is going to insert the value, 101
whatever we supply, at a particular key, which we also supply, and it will overwrite any existing entries 102
with the same key. 103
So because we're doing this as the first order of business, there won't be anything in here. 104
It's completely empty. 105
So we're going to put our owner as the principal key and the value is going to be the total supply. 106
So basically in this line of code, we've added our owner's principal into our ledger of balances and 107
we've given all of the tokens that we're going to mint to the owner, which should be yourself. 108
So now that we've created our ledger, we have to figure out a way to be able to query in order to find 109
out who owns how much, 110
so a check balance method. 111
I'm going to create a new public query function which is going to be called balanceOf. And in the balance 112
Of method, 113
we're going to supply the who, which in this case is going to be of type principal. 114
So we're going to query how much balance does this particular ID own in our ledger from our balance 115
HashMap? 116
And then we're going to asynchronously return the output, which is going to be a natural number because 117
it's going to be the value that's inside this HashMap that's associated with the queried ID. 118
So we want to check if the balances.get-- 119
This .get allows us to pass in a key and get hold of the stored value. 120
But notice here that if it doesn't have that particular key and there's no associated value, then it's 121
going to return null. 122
What if we check that this particular principlal ID that was passed in, so balances.get pass in the 123
who, and if that is equal to null, 124
well, in that case, we want to return zero because that particular ID doesn't have any associated 125
balance in our ledger. 126
However, if it doesn't return null, then it means that it succeeded and we should be able to return 127
the actual balance. 128
So balances.get(who). 129
Now, there's just one problem with this code, and the problem is that this expression, when we use 130
a get on a HashMap, it outputs a data type of ? 131
Nat. And instead of an actual natural number. 132
So what's this question mark business? 133
Well, it's a data type called an Option. 134
And if you've done Swift, you would have heard the Optional. 135
So basically it's very, very similar to that concept. 136
Essentially, it's a typesave. 137
null. 138
What it means is that it retains the data type of a particular value, but it can be null or it can 139
have a value. 140
The way that we're supposed to deal with these optionals is we're supposed to use a switch statement to 141
check if it's null or if it, in fact, is an optional of a particular data type. 142
Let's transplant this into our situation and we can sub the required parts for what we need. 143
So let's create a constant with the let which we'll call the balance. 144
And this is going to be a natural number and we're going to switch using this method balances. 145
get and then we're going to pass in the who. 146
And in order for it to switch on the entire statement, we're going to have to wrap it inside a pair 147
of parentheses, like that. 148
Now, in the case that the result of this function call is null, then we want to set the balance to 149
equal zero. 150
But in the case that it is an optional that gets returned, 151
so our optional result, 152
well then we want to simply return that result. 153
This syntax, it's actually not that difficult if you know how switch statements work, which you should, 154
because we've covered it in JavaScript. But the syntax is formatted differently. 155
Essentially, we're checking the result or the outcome of this method call, 156
so passing in the ID of the person we're checking into our balances ledger and we'll get the value 157
of how much of this currency that they own. 158
And then once we get that result, because it's an optional, we have the check in case the result is 159
null, in which case we set this balance constant to zero. 160
But if the result is an optional, then we'll set the balance to the result and we get rid of that optional 161
question mark. 162
Now, instead of having this if statement, we can simply return our balance. 163
And because this balance is a natural number which is what we want to output, we get rid of all of 164
these problems. 165
Now that we've done all of that, we're finally ready to actually to do our dfx deploy again. 166
So save your main. 167
mo 168
file with all the updated code. 169
Go ahead and run dfx deploy which should now put yourself, your own principal, as the owner of a billion 170
tokens of your own currency. 171
Now, in order to call the balanceOf method from the command line, we have to get hold of our principal 172
ID to pass in as an input. 173
Now there's a little bit of formatting that's involved as well, 174
but don't worry, I'm going to walk you through step by step. If you head over to the README.md 175
file that's included in the starter project, 176
you can view this markdown file in its proper formatting by clicking on this button here with the magnifying 177
glass. In order to check our balance, 178
the first thing we're going to do is we're going to find out our principal ID. 179
So you've already seen that we can use this command 180
dfx identity get -principal in order to get hold of the owner, so ourselves, 181
principal ID. I'm just going to open up a new terminal window here which is inside my token project. 182
So it's really easy from VSCode because it always knows where you are. And I'm going to paste that 183
in here. 184
And once we hit enter, you should see that principal that you got earlier on. 185
And the reason why I've got this read me is because there's a lot of code that we're going to write 186
into the command line in order to issue commands. 187
And if you get any of these wrong or if you make a typo, it's really difficult to tell where you went 188
wrong. 189
So instead you can just copy and paste the commands, which is a lot easier. Once you've got hold of 190
your principal, 191
I want you to go ahead and save it somewhere. 192
So inside the README.md you can see I've got this section 2 where it says save it somewhere and I want 193
you to just go ahead and replace the xxx-yyy. 194
This is really useful because you always have to know in the future who you as a user is. 195
Now, we're not going to use that right now, but instead we're going to format our principal ID into 196
a format that the method, balanceOf, will accept. 197
So because it wants a principal data type, we can't just simply pass this in as text. 198
In order to format this, we're going to use this command. 199
I'm just going to walk you through what it does. 200
We're going to create a new variable in the command line called the OWNER_PUBLIC_KEY. 201
And it's going to be set to a string or a piece of text that starts out with the word principal, lowercase, 202
a space, and then in between a set of double quotes, it's going to paste in whatever it is result 203
of this command, which is dfx identity get -principle, which, as you know, generates this string. 204
So let's give it a go. Let's copy that entirely and then paste it in here and hit enter. 205
Now, you won't see much after that, but we can confirm that it worked by using the echo command, 206
which will print out the value of any of our variables. 207
And this is the variable that we just created, the OWNER_PUBLIC_KEY. 208
So let's paste that line in here and you should see that we've got this formatting exactly as our method 209
requires it, which is principal "the actual principal ID" 210
at the end. 211
So now we can use this to actually check the owner's balance. 212
So we're going to call this token, which is our canister over here, our main. 213
mo, we're going to call the method balanceOf, which is this one. 214
And then inside the parentheses, we're going to pass in the who as the OWNER_PUBLIC_KEY, so our own 215
public key. 216
Again, copy this command in its entirety and then paste it into the terminal. 217
And once you hit enter, it should give you the result. 218
And it tells me that I've got 1 billion of these tokens that belong to my principal ID and it's also 219
a natural number. 220
So that's perfect. 221
That means that everything we've done so far where we created our balances HashMap, and we gave the 222
owner, ourselves, our own public key, the entire supply of tokens, and we're also able to use our balance 223
Of method to query it. 224
All that's left to do now is to hook up our backend with the frontend, which is our balance.jsx 225
and to be able to do the same thing in our website using our front-end. 226
So for all of that and more, I'll see you on the next lesson.