Cover photo

智能合约开发-1

lesson-1-hello

几个知识点

  • msg是内部变量,不能使用

  • 函数的参数变量,不需要存储,因此可以指定类型之后,添加```memory```关键词

  • 如果函数返回内部变量,只读,可以使用关键词```view```

  • 返回变量的关键词是```returns```,而不是```return```

// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.4;

contract Hello {
    string public name;
    
    function setName(string memory name_) public{
        name = name_;
    }
        
    function getName() public view returns (string memory){
        return name;
    }
}

使用msg的时候,出现如下的编译警告

Warning: This declaration shadows a builtin symbol.
--> contracts/lesson/lesson-1-hello.sol:7:5:
|
7 | string public msg;
| ^^^^^^^^^^^^^^^^^

lesson-2-unitEth

以太坊中单位的对应关系

// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.4;

contract EthUint {
    uint public oneWei = 1 wei;
    uint public oneGwei = 1 gwei;
    uint public oneEth = 1 ether;
    
    function testOneWei() public view returns (bool) {
        return oneWei == 1;
    }    
    
    function testOneGgei() public view returns (bool) {
        return oneGwei == 1 * 10**9;
    }    
    
    function testOneEth() public view returns (bool) {
        return oneEth == 1 * 10**18;
    }
}

也可以参考网站:https://eth-converter.com/

post image

lesson-3-fun-visibility

函数的可见性严格排序

// private internal external public 
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.4;

// private internal external public 

contract funVisibility {
    uint age;
    
    function funPublic() public view returns (uint){
        return age;
    }
    
    function funExternal() external view returns (uint){
        return age;
    }
    
    function funInternal() internal view returns (uint){
        return age;
    }
    
    function funPrivate() private view returns (uint){
        return age;
    }
    
     function testFun() public view returns(uint) {
        // return funPublic(); // ok 
        // return funExternal(); // not ok
        //  return funInternal(); // ok
        return funPrivate(); // ok
    }
}


contract subFunVisibility is funVisibility{
    function testParentFun() public view returns(uint) {
        // return funPublic(); // ok 
        // return funExternal(); // not ok
        // return funInternal(); // ok
        // return funPrivate(); // not ok
    }
}

扩展阅读:https://tsaiyee.com/blog/2018/01/07/solidity-external-public-best-practices/ 【Solidity中的external与public使用最佳实践】

lesson-4-inherit

Play Video

继承知识点

  • 继承的语法是子类 is 父类

  • 如果需要重写父类函数,父类定义需要使用virtual,子类需要使用pure override

  • 如果父类构造函数有参数,子类定义的时候,也需要为父类指定构造函数的参数

// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.4;

// private internal external public 

contract Parent {
    uint age;
    
    constructor(uint age_){
        age = age_;
    }
    
    function getAge() public view returns (uint){
        return age;
    }    
    
    function getDesc() public view virtual returns (string memory){
        return "Parent";
    }
}


contract Son is Parent(55){
    // can call getAage fun
    
    function getDesc() public pure override(Parent) returns (string memory){
        return "Son";
    }
}

扩展阅读:https://medium.com/taipei-ethereum-meetup/solidity-weekly-11-70c5208a3bf1 【pure 跟 view 的区别】

更正確的講,如果一個 function 不會改變到合約的 state,就可以加 modifier constant 在 returns 前面,因此在 web3.js 就可以用 call() 來呼叫該 function, 而不需要用 sendTransaction() 來呼叫。

到了 solc 0.4.17, 更把 constant 細分為 view 或 pure 兩種,只是程度上的不同。

view 一般來說,就用來取代 constant, 跟 compiler 説,該 function 不會對 storage state 有任何變動。(但會進行讀取, 所以 constant 改名為 view,更為恰當)

string greeting;
function SayHello() public view returns(string says) {
        return greeting;
}

pure 定義該 function 連讀 storage state 都沒有。有人舉了一個誇張的例子如下:(它跟合約的所有 states 都無關, 可以加 modifier pure)

function returnTrue() public pure returns(bool response) {
    return true;
}

lesson-5-multiInherit

Play Video
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.4;

// private internal external public 

contract A {
    uint age;
    
    constructor(uint age_){
        age = age_;
    }
    
    function getAge() public view returns (uint){
        return age;
    }    
}

contract B {
    string name;
    
    constructor(string memory name_){
        name = name_;
    }
    
    function getNmae() public view returns (string memory){
        return name;
    }    
}


contract C is A, B{
    constructor()A(10) B ("hello"){
        
    }

}



contract D is A, B{
    constructor(uint age_, string memory name)A(age_) B (name){
        
    }

}

lesson-6-event

// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.4;

contract Event {
    event Log(address sender, string msg );
    
    function trancfer() public{
        emit Log(msg.sender, "This is 1 mag");
        emit Log(msg.sender, "This is 2 mag");
        emit Log(msg.sender, "This is 3 mag");
    }
}

lesson-7-globalVal

Play Video
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.4;

contract Hello {
    event Log(address, uint);
    
    function getGasInfo() public view returns(uint, uint){
        return (tx.gasprice, block.gaslimit);
    }
    
    function getMagInfo () public payable {
       emit Log(msg.sender, msg.value);
    }
}

lesson-8-errorHandle

Play Video

参数尽量提前检查,多执行代码,会增加gas费

// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.4;

contract ErrorHandle {
    int public balance = 0;
    
    function add(int trans_num) public{
        require(trans_num >= 0, "The trans num should big than 0");
        
        // int old_balance = balance;
        balance += trans_num;
        
        //assert(balance >= old_balance);
        
        // if(balance < old_balance){
        //     revert("error");
        // }
    }
}

lesson-9-array

需要注意的是,array的del函数并没有删除数据,只是把数据进行了清空

// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.4;

// array 
// push pop del length

contract Array {
    uint[] public array1;
    uint[3] public array2;
    uint [] public arrar3 = [1,2,3];
    
    function push(uint val) public{
        array1.push(val);
    }
        
     
    function pop() public{
        array1.pop();
    }
    
    function length() public view returns(uint){
        return array1.length;
    }
        
    function del(uint index) public{
        // param check
        delete array1[index];
    }
    
    function test() public{
        array1.push(1);
        array1.push(2);
        array1.push(3);
        array1.push(4);
        
        assert(length() == 4);
        
        pop();
        assert(length() == 3);
        assert(array1[2] == 3);
        
        del(2);
        assert(length() == 3);
        assert(array1[2] == 0);
    }
}

lesson-10-map

需要注意的是

  • map的del函数,也只是把数据清空而不会把数据真正的删除

  • map没有遍历函数,如果希望遍历,可以添加一个辅助的数组

// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.4;

contract Map {
    mapping(address => uint)  public MyMap;
    
    function setMap(address add_, uint num) public{
        MyMap[add_] = num;
    }
        
    function delMap(address addr_) public{
        delete MyMap[addr_];
    }
        
    function getlMap(address addr_) public view returns (uint){
        return MyMap[addr_];
    }
}

lesson-11-struct

注意事项

  • 外部string参数使用memory修饰,int、bool等类型无需

  • 内部结构体需要使用storage修饰

// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.4;

contract Struct {
    struct Todo{
        string task;
        bool complete;
    }
    
    Todo [] public todo_list;
    
    function add(string memory _task) public {
        // Todo memory todo = Todo(_task, false);
        
        // Todo memory todo = Todo({
        //     task: _task,
        //     complete : false
        // });
        
        Todo memory todo;
        todo.task = _task;
        todo.complete = false;
        
        todo_list.push(todo);
    }
    
    function get(uint index) public  view  returns (Todo memory){
        return todo_list[index];
    }
    
    function getEle(uint index) public  view  returns (string memory, bool){
        Todo storage todo =  todo_list[index];
        return (todo.task, todo.complete);
    }
}