[Chapter 2] Simple Smart Contract Example and Learning

Simple storage example:

We start with a basic example that sets the value of a variable and exposes it for access by other contracts.


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

contract SimpleStorage {
    uint storedData;

    function set(uint x) public {
        storedData = x;
    }

    function get() public view returns (uint) {
        return storedData;
    }
}
//Q群54548027
//qq201333403

The first line tells you that the source code is licensed under GPL version 3.0. Machine-readable license specifiers are important in the default setting of distributing source code.

The next line specifies that the source code is written for the language of Solidity version 0.4.16 or later, but not including version 0.9.0. This is to ensure that the contract cannot be compiled with new (breaking) compiler versions, as it may behave differently. Pragmas are common instructions to the compiler on how to process source code (eg pragma once).

A contract in the Solidity sense is a collection of code (its function) and data (its state) located at a specific address on the Ethereum blockchain . The lineuint storedData; declares a state variable of uinttype ( 256 -bit unsigned integer ) . You can think of it as a single slot in the database that you can query and change by calling functions in the code that manages the database. In this example, the contract defines functions and ,  .storedDatasetget

To access members of the current contract (such as state variables), you usually don't need to add this.a prefix, you just need to access them directly by name. Unlike some other languages, omitting it is not just a matter of style, it results in an entirely different way of accessing members, more on that later.

The contract doesn't do much other than (thanks to the infrastructure built on ethereum) allowing anyone to store a single number that is accessible to anyone in the world, and there's no (feasible) way to stop you from publishing that number. Anyone can call again setand overwrite your number with a different value, but the number is still stored in the blockchain's history. Later, you'll see how to impose access restrictions so only you can change the number.

Example of sub-currency:

(The simplest form of cryptocurrency is implemented by the following contract. This contract only allows its creators to create new coins (with different issuance schemes possible). Anyone can send coins to each other without registering with a username and password, you All that is required is an Ethereum key pair.

//Q学习群54548027
//q201333403
pragma solidity ^0.8.4;

contract Coin {
    // The keyword "public" makes variables
    // accessible from other contracts
    address public minter;
    mapping (address => uint) public balances;

    // Events allow clients to react to specific
    // contract changes you declare
    event Sent(address from, address to, uint amount);

    // Constructor code is only run when the contract
    // is created
    constructor() {
        minter = msg.sender;
    }

    // Sends an amount of newly created coins to an address
    // Can only be called by the contract creator
    function mint(address receiver, uint amount) public {
        require(msg.sender == minter);
        balances[receiver] += amount;
    }

    // Errors allow you to provide information about
    // why an operation failed. They are returned
    // to the caller of the function.
    error InsufficientBalance(uint requested, uint available);

    // Sends an amount of existing coins
    // from any caller to an address
    function send(address receiver, uint amount) public {
        if (amount > balances[msg.sender])
            revert InsufficientBalance({
                requested: amount,
                available: balances[msg.sender]
            });

        balances[msg.sender] -= amount;
        balances[receiver] += amount;
        emit Sent(msg.sender, receiver, amount);
    }
}

This contract introduces some new concepts, let's go over them one by one.

This line address public minter;declares a state variable of type address . The addresstype is a 160-bit value that does not allow any arithmetic operations. It works for the address of the storage contract, or the hash of the public half of the key pair belonging to an external account .

The keyword publicautomatically generates a function that allows you to access the current value of a state variable from outside the contract. Without this keyword, other contracts cannot access the variable

quantity. The function code generated by the compiler is equivalent to the following (ignoring externaland view)

function minter() external view returns (address) { return minter; }

You could add a function like the above yourself, but then you'd have a function and state variable with the same name. You don't need to do this, the compiler figures it out for you.

The next line mapping (address => uint) public balances;also creates a public state variable, but it's a more complex data type. Mapping types map addresses to unsigned integers .

A map can be thought of as a hash table virtually initialized such that every possible key exists from the start and maps to a value whose byte representation is all zeros. However, it is neither possible to obtain a list of all keys nor all values ​​of a map. Document what you add to the map, or use it in a context where it is not needed. Or better yet, keep a list, or use a more appropriate data type.

In the case of mappings public, the getter functions created by the keyword are more complex. It looks like the following code:

function balances(address account) external view returns (uint) {
    return balances[account];
}

You can use this function to check the balance of a single account.

This line event Sent(address from, address to, uint amount);declares an "event" which fires on the last line sendof . Ethereum clients (such as web applications) can listen to these events emitted on the blockchain without much cost. Once it's emitted, listeners receive the fromto and  amountparameters, which makes it possible to track transactions.

To listen for this event, you can use the following JavaScript code, which uses web3.js to create a Coin contract object, and any UI calls the auto-generated function balancesabove :

Coin.Sent().watch({}, '', function(error, result) {
    if (!error) {
        console.log("Coin transfer: " + result.args.amount +
            " coins were sent from " + result.args.from +
            " to " + result.args.to + ".");
        console.log("Balances now:\n" +
            "Sender: " + Coin.balances.call(result.args.from) +
            "Receiver: " + Coin.balances.call(result.args.to));
    }
})

A constructor is a special function that is executed during contract creation and cannot be called afterwards. In this case, it permanently stores the address of the person who created the contract. The variablemsg (along with txand block) is a  special global variable containing properties that allow access to the blockchain. msg.sender​​​​is always

The functions that make up a contract and that users and contracts can call are mintand send.

The mint function sends a certain amount of newly created coins to another address. The require function call defines the conditions for reverting all changes if not met. In this example, require(msg.sender == minter);ensure that only the creator of the contract can call mint . In general, creators can mint any number of tokens, but at some point, this leads to a phenomenon called "overflow" . Note that due to the default Checked algorithm , if the expression balances[receiver] += amount;overflows , i.e. if the expression balances[receiver] + amountis greater than the maximum value of uint ( 2**256 - 1) in arbitrary precision arithmetic, the transaction will resume. balances[receiver] += amount;The same goes for the statement in the function send .

Errors allow you to provide more information to the caller about a condition or why an operation failed. Errors are used with the revert statement. The statementrevert unconditionally aborts and reverts all changes similar to requirethe function , but it also allows you to supply an error name and additional data that will be provided to the caller (and eventually to the front-end application or block explorer) so that Failures can be more easily debugged or responded to.

Anyone (who already owns some of these coins) can use sendthe function to send coins to anyone else. The if condition evaluates to true if the sender does not have enough coins to send. Therefore, revertthe operation will cause the operation to fail while InsufficientBalanceproviding error details to the sender with an error.

Guess you like

Origin blog.csdn.net/qq_56877291/article/details/126010915