Solidity进阶编程注意一下合约中的细节1.

这是我参与8月更文挑战的第20天,活动详情查看:8月更文挑战

补充知识:

  1. 转账的话是与部署者无关,与交易者有关!
  2. gas是以太坊网络中的一个计量单位,是为了对算力消耗进行量化而设计的指标,也就是说有了gas这个计算单位,我们可以方便的计算出用户完成一笔交易需要支出多少gas费用,矿工完成一个区块的打包确认能收到多少gas报酬。

请添加图片描述

1. 内置的全局变量

  • msg.sender:

获取调用者地址,下面的例子是部署者调用了,所以是部署者的地址,
比如a账户部署,但是是使用b账户调用下getOwner的话,那么这个时候的owner就是b账户的地址了。

pragma solidity 0.4.22;
contract Owner {
    address public owner;
    function getOwner() public {
        owner = msg.sender;   // 获取调用者的地址
    }
}
复制代码
  • msg.value:

可以接收payable修饰的转账金额,单位:wei,必须要有payable

可以用接收的value进行判断限制,比如转账金额必须在某个范围,balance做不到

pragma solidity 0.4.22;
contract Value {
    uint256 public money;
    function getValue() public payable {
        money = msg.value;
    }
}
复制代码

如果加if判断:

pragma solidity 0.4.22;

contract Value {
    uint256 public money;
    function getValue() public payable {
        if( msg.value == 666) {  // 转钱金额为666wei才赋值 
            money = msg.value;
        }
    }
}
复制代码

注意:需要转钱,注意单位默认是wei

内置的全局变量 简称 类型
blockhash 哈希值 byte32
block.coinbase 当前块矿工的地址 address
block.difficulty 当前块的难度 uint
block.gaslimi 当前块的gaslimit uint
block.number 当前块的块号 uint
block.timestamp 当前块的时间戳 uint
gasleft() 剩余的gas uint
msg.sender 调用者的地址 address
msg.value 转账的金额(单位:wei) uint
msg.data 完整的调用数据 calldata bytes
now 当前块的时间戳 uint(和block.timestamp相同)
tx.gasprice 交易的gas价格 uint
tx.origin 交易的发送者 address

请添加图片描述

2. 错误处理

  • require:

require 式的异常不会消耗任何 gas,官方推荐使用require,相当于if {throw},没有else的
最终底层触发的也是assert式的错误

require(msg.value == 666);    // 如果不满足则报错,否则继续往下执行
复制代码

类似于下面的:注意条件正好是相反的

if (msg.value <= 6 * 10 ** 18)  {
    // todo 涉及到错误处理
    throw;
}
复制代码
  • assert:

即使有错误,也会执行并扣除gas

assert(msg.value == 666 );    // 如果不满足则报错,否则继续往下执行
复制代码
  • revert():处理更复杂逻辑的场景,比如if/else
if (msg.value <= 6 * 10 ** 18){
    revert();
} else {
    b = 666;
}
复制代码
  • require(条件); 如果满足条件则继续往下执行,如果不满足则报错,不扣除gas,推荐使用
  • assert(条件); assert扣除gas,不推荐使用
  • revert(): 负责逻辑中使用,if(条件){revert();}else{...}

3. 访问函数

原来要返回一个变量,得写个函数返回

pragma solidity 0.4.22;
contract Hello {
    string name = "hallen";
    function get_name() public view returns(string){
        return name;
    }
}
复制代码

如果用public修饰了变量,会生成一个同名的访问函数,可以直接访问

pragma solidity 0.4.22;
contract Fan {
    string public name = "fanone";
    function getName() public view returns(string){
        return name;
        // return this.data(); 合约内部使用this也是要调用访问函数的
    }
}
contract One {
    function getHelloName() public view returns (string){
        Fan h = new Fan();   // 地址直接强转合约类型
        return h.name();    // 这里必须加括号,是个访问函数
    }
}
复制代码

4. 创建合约

  • new : 返回的是地址,需要转合约类型

初始化合约的时候用到这种方式

Fan h = new Fan();  // 把地址直接强转为合约类型
复制代码

和java有点像
合约变量(Fan public h),此时是空的,需要赋值地址才能使用,否则报错
合约类型作为参数的场景用到这种方式

Fan public h;
// 函数中赋值
address addr = new Fan();
h = Fan(addr); // 赋值地址
复制代码

转账语法:
h.get_money.value(20).gas(800)();

h必须是赋值地址后的合约对象

pragma solidity 0.4.24;
contract Test1{
    // 获取转账钱
    function contractGetMoney() public payable{
    }
    // 查看余额
    function getBalance() public view returns(uint256){
        return address(this).balance;
    }
}
contract Test2 {
    // 查看余额
    function getBalance() public view returns(uint256){
        return address(this).balance;
    }
    // 获取转账钱
    function contractGetMoney()public payable{
    }
    // transfer:谁调用就给谁转钱
    Test1 public t1;
    function getAddr(address addr) public{
        t1 = Test1(addr);
    }
    // 转钱给Test1合约
    function payToT1() public{
        t1.contract_get_money.value(5 * 10 **18).gas(200)();
    }
    // 付钱得用payable修饰,使用匿名函数
    function () public payable {}
}
复制代码

5. 合约继承

  • 使用is关键字,多个父合约用逗号隔开

contract 合约名 is 父合约1,父合约2,... {}
constract Cat is Animail,Lactation{} // Lactation:哺乳动物
如果两个父合约中有相同的函数,则遵循最远继承原则(继承顺序,Animail最近,Lactation最远,所以是Lactation中的)

6. 修饰器modifier

在函数执行前检查是否满足前置条件,满足条件才执行函数

pragma solidity 0.4.22;
contract Value {
    uint256 public money;
    modifier check_money(){
        require(msg.value == 10);
        _;  // 修饰的代码,指进入函数后的所有代码
    }
    function get_value() public payable check_money{  // check_money就是前面定义的修饰器
        money = msg.value;
    }
}
复制代码

可以结合构造函数,判断是不是管理员(部署者),只有是管理员才可以访问的函数可以加修饰器

pragma solidity 0.4.22;
contract Value {
    address public owner;
    uint256 public money;
    constructor() public{
        owner = msg.sender;
    }
    modifier check_owner(){
        require(msg.sender == owner);
        _;   // 修饰的代码,指进入函数后的所有代码
    }
    function get_value() public payable check_money{
        money = msg.value;
    }
}
复制代码

最后

小生凡一,期待你的关注。

在这里插入图片描述