It is recommended that you have an understanding of the basic Solidity programming language before reading this article, as there is not much information available on the topic, it is best to go straight to the official documentation (rest assured, it is only available in English, but I am translating it in my spare time, Hope to be able to let some English foundation is not good readers can also quickly on the road to development ๐Ÿ˜†).

Pragma solidity ^ 0.4.16;Copy the code

This line of code is standard at the beginning of all Solidity smart contracts and is intended to inform the compiler of the version of the Solidity language we are writing for smart contracts to prevent incompatibility errors in future releases.

interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) public; }
Copy the code

This line of code declares a tokenRecipientinterface, which can be invoked with other contracts that inherit the interface. This is an important feature of the interface, where interface is the key to declare the interface. The functions in the interface are not implemented, because it is not concerned with how to implement these functions. It can be understood as the agreement between different contracts, and we all abide by this agreement, but the detailed formulation is up to each other to implement. What is in the interface body is the “protocol content,” which from a code perspective is an “empty” function that is not implemented.

contract TokenERC20 {}
Copy the code

We have officially started writing the body of the smart contract, which defines a smart contract called TokenERC20.

string public name;
string public symbol;
uint8 public decimals = 18;
uint256 public totalSupply;
Copy the code

We declared the Token’s full name, symbol, minimum unit, and circulation, all of which are declared public, so we can specify them when deploying the contract.

mapping (address => uint256) public balanceOf;
Copy the code

We declare a mapping type variable, balanceOf, to store the corresponding balance (number of tokens) in each account.

mapping (address => mapping (address => uint256)) public allowance;
Copy the code

This mapping variables are used to store account allows others to transfer the balance of their number, for example is simple I had one million dollars to charity, I gave the right to use the one million authorized to a charitable foundation, allowing them to use the money (i.e., transfer the money to the payee account), as long as they move no more than the number of my authorization to give them the one million, They can spin it any way they want.

event Transfer(address indexed from, address indexed to, uint256 value);
event Burn(address indexed from, uint256 value);
Copy the code

These two lines of code are two events, which are also “empty” functions that simply declare the function name and input parameter. The only purpose of an event is to pass this information to clients when the event is triggered, telling them that something happened, which is indicated by different events, and the details of the event are referenced by the input information.

function TokenERC20(
    uint256 initialSupply,
    string tokenName,
    string tokenSymbol
) public {
    totalSupply = initialSupply * 10 ** uint256(decimals);
    balanceOf[msg.sender] = totalSupply;
    name = tokenName;
    symbol = tokenSymbol;
}
Copy the code

This function is a constructor, one for each contract and fired only once when the contract is deployed. It is typically used to initialize variables such as the number of tokens issued, full name, and symbol.

Where initialSupply * 10 ** Uint256 (Decimals) is used for unit conversion, for example, we issued 100 tokens, but our minimum unit is 18, so we can send 10โˆง-18 tokens when transferring money. Then it would be much better to use the smallest unit for the transfer within the contract (where ** represents the power, that is, x to the power).

Then we pass balanceOf[msg.sender] = totalSupply; Transfer all tokens to the account of the deployment contract, msg.sender is a global variable that represents the account address of the current caller.

function _transfer(address _from, address _to, uint _value) internal {}
Copy the code

This function is used to transfer money. It is a private function (by using the keyword internal) and takes in the sender’s address (_from), the receiver’s address (_to), and the transfer amount (_value). Let’s look at the internal implementation of the transfer function next:

require(_to ! = 0x0);Copy the code

First of all, let’s take a look at this special address 0x0, which can be understood as a black hole. Any Token transferred to this address is equivalent to being permanently locked, and does not belong to anyone. Perhaps only God can get it back ๐Ÿ˜‡.

The require keyword indicates that the code that follows must first pass the conditional expression in this function, that is, the subsequent transfer can only be performed if the payee address is not equal to 0x0, otherwise an exception is thrown.

require(balanceOf[_from] >= _value);
Copy the code

We can also guess the meaning of this line of code, the requirement of the balance is greater than the amount of money he wants to pay, popular point is that you want to pay 100 yuan, that first you have to get the 100 yuan ๐Ÿ’ฐ.

require(balanceOf[_to] + _value > balanceOf[_to]);
Copy the code

This line at first glance look a little meng, this condition is certain to hold water, unless the number is a negative number ๐Ÿ˜‚, we can not ask all people are so honest and comply with the rules, there will always be a few naughty naughty ghosts will play a little narrow-minded. As a procedure, consider all exceptions as possible and handle them.

uint previousBalances = balanceOf[_from] + balanceOf[_to];
balanceOf[_from] -= _value;
balanceOf[_to] += _value;
Transfer(_from, _to, _value);
assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
Copy the code

Let’s put these lines together, starting with line 1 and line 5. Before the transfer operation, we first recorded their total balance, and then after the transfer operation to check whether their total balance is still the same as before the transfer. This is a bit superfluous ah, like a nonsense ๐Ÿ˜‹. This is mainly to ensure that the actual results of the program must be consistent with the expected results. The program is written by a human, so there is no way to avoid bugs. Assert is often used to identify bugs when used in conjunction with static analysis tools, because throwing an exception means the code must have been written incorrectly.

Both assert and require functions judge conditional expressions and throw exceptions if the condition is not met. Assert is only used for internal error debugging to verify results that are immutable (for example, the sum of the balance should not change before and after the transfer). Require is used for values that can be invoked by external contracts (such as checking whether the payer’s balance is sufficient, etc.). These information can be checked by everyone and is public.

Transfer() will broadcast an event to all clients on the blockchain. ~ make money XXX to the payee XXX transfer XXX money), as for the client to receive or not that is the client’s own matter ๐Ÿ˜.

By the way, we notice that this method is internal, meaning that it is not externally callable. We usually name these internal methods beginning with an underscore (it’s a best practice after many, many lines of code to look back and see that the method is internal).

function transfer(address _to, uint256 _value) public {
    _transfer(msg.sender, _to, _value);
}
Copy the code

This is the transfer method open to the outside world. From the input, we can see that the remitter must be the account that invokes this method. The transfer operation is performed inside the method by calling the internal method _transfer().

function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
    require(_value <= allowance[_from][msg.sender]);
    allowance[_from][msg.sender] -= _value;
    _transfer(_from, _to, _value);
    return true;
}
Copy the code

This method is terrible from the entry and function, anyone can call this method, and make money can be designated at will (you have more money, I designate you to make money, oneself for the payee, crazy to their account transfer money). Of course we can’t let that happen, so let’s look at it from the perspective of what this method is supposed to do.

Remember, our example is the official example, all the logic in it is modifiable, can be supplemented or deleted!

We hope that we can put your part of the money agent to others, let them to do (like bank financial products, but no interest ๐Ÿคฃ, if you think that is very small, so you can modify this method, such as to acting out of the money is on a regular basis, and to have the interest, then add the code to implement this part needs good!) .

To implement this proxy function, we only need to add a variable that stores how much money the remitter gives the proxy ownership of the transfer. This is the allowance variable explained at the beginning of the article.

Allowance [_from][msg.sender] : _from [_from][msG. sender] : _from [_from][msG. sender] The following code is easy to understand. First, we need the total balance managed by the agent to be sufficient (to pay the transfer amount), and then deduct it from the total balance to conduct the transfer operation and return success.

function approve(address _spender, uint256 _value) public
    returns (bool success) {
    allowance[msg.sender][_spender] = _value;
    return true;
}
Copy the code

Want agent to be able to manage, must authorize agent above all, this method is to do this matter. You want someone to represent your money, so call this method, enter the agent’s account number and the amount you want to represent.

function approveAndCall(address _spender, uint256 _value, bytes _extraData)
    public
    returns (bool success) {
    tokenRecipient spender = tokenRecipient(_spender);
    if (approve(_spender, _value)) {
        spender.receiveApproval(msg.sender, _value, this, _extraData);
        return true; }}Copy the code

The basic function is the same as the approve() method, but it calls the receiveApproval() method of the proxy (which is the same method as invoking other contracts), if the approve() method is implemented in the proxy contract.

To call the public methods of other contracts in a contract (internal methods you don’t have permission to call), we need to instantiate the interface, pass in the address of the other contract, and then call all methods declared in the interface (again, if the other contract implements the method).

function burn(uint256 _value) public returns (bool success) {
    require(balanceOf[msg.sender] >= _value);
    balanceOf[msg.sender] -= _value;
    totalSupply -= _value;
    Burn(msg.sender, _value);
    return true;
}
Copy the code

My site I master, the same, we give you “burn money” right ๐Ÿ˜Œ. Once you call this method, the money is gone, which is worse than going to the black hole 0x0 address. First line, you have to burn money you can afford; The second line is deducted from your balance; The third line, the total issuance of our tokens decreases accordingly; The fourth line, the release of burning money notice (the whole network know I burned money, think is also installed force of not ๐Ÿ˜‚); Line five, return success, burn success!

function burnFrom(address _from, uint256 _value) public returns (bool success) {
    require(balanceOf[_from] >= _value);
    require(_value <= allowance[_from][msg.sender]);
    balanceOf[_from] -= _value;
    allowance[_from][msg.sender] -= _value;
    totalSupply -= _value;
    Burn(_from, _value);
    return true;
}
Copy the code

Since there is an agent, then the agent has the power to “burn other people’s money”!


This is the end of the official Token code explanation, we can according to the official examples to transform the function of the Token we want, are programmable, so there is a lot of imagination

Finally, the official full code is attached: TokenERC20 ยท GitHub

Welcome to pay attention to the public account: “Bitbuckle”, and explore the world of blockchain with me.