Web3 leads everyone to write their first token solidity smart contract according to the ERC-20 document

Above the basic token concept of Web3 tokens, we briefly described the concept of tokens,
and also talked about the concept of the ERC-20 protocol.
The official document address of ERC-20 is as follows https://github.com/ethereum/EIPs/blob/master/EIPS /eip-20.md
does not feel very formal to be honest, even the address is placed on github, but there is no way for the official to do this, so we can only look at it like this

Enter the document first
insert image description here
, flip through the document and you will find that there are actually not many

The following will tell us that we need a name method.
insert image description here
Use the view tag to indicate that he wants to read the state variable returns and return a value of string type.
The name is the name of our own token.

Well, don’t just talk about it, start the ganache environment first
insert image description here
, then open a Truffle project environment
insert image description here
and create a file called grToken.sol in the contracts directory

The reference code is as follows

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;

contract grToken{
    
    
    //因为绑定了public  会自动生成get方法
    string public name = "gerToken";

}

In this way, a token called gerToken is generated
, and it can even be tested like this

We create a file in the migrations directory.
Remember that the file under migrations must start with a number to read this script.
We create a file called 2_contract.js.
The reference code is as follows

const Contacts = artifacts.require("grToken.sol")
module.exports = function(deployer) {
    
    
    deployer.deploy(Contacts)
}

We imported the grToken under contracts
and then we run the project on the terminal
insert image description here
and then we execute

truffle migrate

Deploy the contract
insert image description here
Some people here will worry about whether our previous files will be deployed after truffle migrate. In fact, there is no need to worry
because truffle migrate is still a bit smart, but there are not many
files that you have already deployed. It will not deploy again But
if you change the content and go to truffle migrate, it will not be redeployed,
so if you want to redeploy the changed content, you need

truffle migrate --reser

In this way, the files you have changed will be redeployed to our blockchain

Then we terminal run

truffle console

run to the truffle console

Then we execute

const token = await grToken.deployed()

insert image description here
In this way, the constant token gets our grToken contract object
and then we try to call its name

token.name

insert image description here
After the output, you will find that this is a function

This is the first name function we have implemented in this document. insert image description here
Then there is a symbol after the name in the document.
You can understand that we used to be ETH. You can also identify your own token.
insert image description here
Just add a line
and name all the same

string public symbol = "GRY";

insert image description here
The one I have here is called the GRY proxy symbol

Then there is a decimals below,
insert image description here
as we said before, we have a lot of units for the convenience of processing, the most basic of which is wei,
insert image description here
which is the conversion unit of your tokens.
We can write it like this here

uint public decimals = 18;

insert image description here
There is also totalSupply below. This is over.
insert image description here
The total amount shared
can be written like this

uint public totalSupply;
constructor(){
    
    
   totalSupply = 1000000 *(19 * decimals);
}

insert image description here

Anyway, we have the final say on how much we have here, just start with one million, the total amount, and then because it is the wei unit, we will deal with it and calculate it to really turn it into the same unit as ETH. The total amount is multiplied by one million ten
times ten to the eighteenth power

Then we re-run the terminal and enter

truffle migrate --reser

insert image description here
Because grToken.sol has been deployed before, it has been recorded on the blockchain, so in order to upload the modified content, we need to use –reser
and then we execute

truffle console

Open the truffle console
and then still

const token = await grToken.deployed()

insert image description here
Create a token object again to connect to this grToken object

Then we can pass

token.name()

insert image description here
You can access the token name and
then

token.symbol()

insert image description here
You can see the symbols we defined

Then

token.decimals()

insert image description here
It converted to this uint content for us

and then

token.totalSupply()

But the content will change a bit
insert image description here
but don't worry it's ok

This is actually almost the same, but in fact there is a balanceOf
insert image description here
thing behind it, which is really troublesome.

That is, what is the corresponding balance under each of our accounts?
The method passes in the address of the account,
and the following is the returned balance value.

In fact, we can simulate a clearing

Object public userList = {
    
    
    "admin": 5000,
    "gangdan": 1000,
    "zhanglei": 2000
}

We set up an object here so that when he token.userList( " user address")
will return the
balance

We can write like this and first declare a variable of mapping type

mapping(address => uint256) public balanceOf;

This is more like java's hash map collection
key-value correspondence Here we declare that the value corresponding to the name key is of type uint256
and the name is balanceOf

Then assign a value when the constructor object is initialized

balanceOf[msg.sender] = totalSupply;

insert image description here
Here, the msg.sender
has appeared in our web3 operation smart contract before. At that time, we can get the first one in the user list. This is almost the same as we said that deploying a smart contract needs to consume fuel value. If
we don’t set it, the first one will be deducted by default.
This msg.sender also gets this user.
Then we said before that totalSupply is the total amount. Direct writing in this way is equivalent to the publisher owning all the tokens.

Then there is another transfer method below
insert image description here, because you can’t keep it with the publisher all the time, right?
we write like this

function transfer(address _to, uint256 _value) public returns (bool success) {
    
    
    balanceOf[msg.sender] = balanceOf[msg.sender].sub(_value);
    balanceOf[_to] = balanceOf[_to].add(_value);
}

But in fact, when I just wrote this place, an error will be reported
because there are no such functions in our module for the time being.

We need to import a library
type

npm install @openzeppelin/contracts

This library is very powerful, you can understand it yourself
insert image description here

Then we import at the top of the file

import "@openzeppelin/contracts/utils/math/SafeMath.sol";

using SafeMath for uint256;

insert image description here
In this way, we will not report an error when we use those two functions. The business
insert image description here
of transfer here is not complicated . _to token We need to operate the user address to him plus the corresponding number of tokens of _value

There may be a misunderstanding here.
When we use msg.sender in the constructor, we get the user who issued the contract,
but the msg.sender we get in the transfer is the user who called this function
, but we must use our first user here. Because we have no operation to switch the login user

But what we need to pay attention to here is that if none of our current users has a value equal to _value, how can we deal with this business, right?
So we want to add an if outside
insert image description here
, which is to simply add a greater than or equal judgment on the outer layer
insert image description here
, but compared with if in solidity, there is a more suitable syntax called require

The business function of require is that if the condition you give him is true (true), it will continue to go down, if not, it will directly throw an exception and this exception will be recorded by our blockchain

Then let's be more rigorous

require(_to != address(0));

insert image description here
Because this address is passed from the front end, we still need to make a simple judgment. Although it is not certain whether it is a valid address, it is still useful. You can understand it as !=
null

Then here we will also notice that this transfer has returns of
bool success. It is required to return a Boolean value.
insert image description here
If it can go through all the business logic, we return a true to indicate success.

But the document says here that we must trigger a Transfer event.
insert image description here
We pull down the document to find an Events.
insert image description here
We first copy the event interface on this document into our own code.

event Transfer(address indexed _from, address indexed _to, uint256 _value)

insert image description here
You can understand this as calling the log to record the operations we sent,
and all operation records will be visible in the blockchain log

In our previous centralization, some people may be able to record their own operations to him, and even say that some Internet companies have ghosts in their platform operations, but
our blockchain is really recorded, so it is difficult to remove this record, and it can be recalled at any time.

Then we call it in the transfer
or it can be said that as long as the blockchain is still in this record

emit Transfer(msg.sender,_to,_value);

insert image description here
In this way, our business will be fine. Here we will do a small test.
We will not operate the terminal. It is too troublesome.

We found the scripts in the root directory. If there is no scripts, create a test.js below.
insert image description here
Our terminal will execute it first.

truffle migrate --reser

Redeploy the smart contract
insert image description hereand then our test.js representative writes as follows

const GrToken = artifacts.require("grToken.sol")

module.exports = async function(callback) {
    
    
    const grTokenDai = await GrToken.deployed();
    let res1 = await grTokenDai.balanceOf("0x323E82B10DCd0E5fB100BcC3F0ABAB561AA04974");
    console.log(res1);
    callback()
}

Here everyone needs to pay attention to 0x323E82B10DCd0E5fB100BcC3F0ABAB561AA04974 is the public key address of the first account in my ganache environment.
You also have to fill it in according to the situation. Just check the getoken number under this account.
We run the terminal

truffle exec .\scripts\test.js  

insert image description here
Here is the total amount of token.totalSupply() that we output earlier

It means that the logic in our constructor is completed,
insert image description here
but this unit obviously looks a bit of a headache

We can change it to this

const GrToken = artifacts.require("grToken.sol")

const towei = (bn)=> {
    
    
    return web3.utils.fromwei(bn,"ether");
}

module.exports = async function(callback) {
    
    
    const grTokenDai = await GrToken.deployed();
    let res1 = await grTokenDai.balanceOf("0x323E82B10DCd0E5fB100BcC3F0ABAB561AA04974");
    console.log(towei(res1));
    callback()
}

Many people will say that web3 has not been introduced?
You can rest assured that the method of web3 in the test environment can be used by the way

we run again

truffle exec .\scripts\test.js  

This time the unit is fine
insert image description here
, so now we can be sure that balanceOf is really easy to use

Next test the transfer

But there is a terrible point here.
We have not logged in to authorize transfer. It cannot get the currently logged in user.
We can write like this

Here we change the test.js code as follows

const GrToken = artifacts.require("grToken.sol")

const toWei = (bn) => {
    
    
  return web3.utils.fromWei(bn, "ether");
}
const inWei = (bn) => {
    
    
    return web3.utils.toWei(bn.toString(), "ether");
}

module.exports = async function(callback) {
    
    
    const grTokenDai = await GrToken.deployed();
    let res1 = await grTokenDai.balanceOf("0x323E82B10DCd0E5fB100BcC3F0ABAB561AA04974");
    console.log(toWei(res1));

    await grTokenDai.transfer("0x096A90463E48723d3631b3291Dd76b6BA425eD4e",inWei(10000),{
    
    
        from: "0x323E82B10DCd0E5fB100BcC3F0ABAB561AA04974"
    });
    let res2 = await grTokenDai.balanceOf("0x096A90463E48723d3631b3291Dd76b6BA425eD4e");
    console.log(toWei(res2),"第二个用户");
    let res3 = await grTokenDai.balanceOf("0x323E82B10DCd0E5fB100BcC3F0ABAB561AA04974");
    console.log(toWei(res3),"第一个用户");
    callback()
}

inWei is a reverse conversion transfer. In the test environment, we use the first parameter to whom to send to, the second to send how much, and the third is an object. Note that 0x096A90463E48723d3631b3291Dd76b6BA425eD4e is also a user address simulated by my ganache. After all, this must require
two Only the user can operate
{ from: current login user address } and then we run the terminal again


truffle exec .\scripts\test.js  

insert image description here
take off, take off

Guess you like

Origin blog.csdn.net/weixin_45966674/article/details/131806726#comments_27681866