solidity(智能合约)零基础教学(3)

前言:前面我们将了solidity的一些常用方法,接下来我们来讲一下,我们编写合约经常要用的一些功能;

一,modifier修饰符

在Solidity合约中,修饰符(modifier)是一种用于修改函数行为的特殊函数。通过使用修饰符,我们可以在执行函数之前、之后或中途对函数进行某些操作或检查。我们通常会和异常一起使用;

详细代码如下:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

contract text{
    //案例一:
      address public owner;//初始值为0X000000000...

      constructor(){
          //定义一个构造函数,初始值为合约部署者的地址
          owner = msg.sender;
      }

    //定义一个修饰符,这个修饰符的意思是只能是合约部署者才能执行,其他地址的用户执行会抛出异常
      modifier Onlyowner(){
          require(msg.sender==owner, "you are not owner");
          _;//这行代表我们要引用方法的语句,写在什么位置,就在什么地方去执行
      }

    //定义一个修饰符,这个修饰符的意思是合约不能为空,否者抛出异常
      modifier Vali(address add){
          require(add != address(0) , "Not valid address");
          _;
      }

    //方法中,后面接着就是我们的修饰符
      function modifowner(address newowner)public Onlyowner Vali(newowner){ 
          owner = newowner;
      }



    //案例二:
    uint public x =10;
    bool public locked; //初始值为false
    
    //定义一个修饰符,这个修饰符的作用是,执行期间抛出异常,就不会执行。防止死循环
    //我们可以看到“_;”在中间,我们首先会把locked 赋值为真,再执行被调用的方法,又会把locked重新赋值为假
    modifier noReentrancy{
        require(!locked, "No reentrancy");
        locked = true;
        _;
        locked = false;
    }

    function decrement(uint i)public noReentrancy{
        x -= i;
        if(i > 1){
            decrement(i-1);
        }
    }


}

2,Event事件

当我们写合约的时候,为了更好和前端交互,且减少更多gas的消耗,我们常常会用到事件来处理;他更是存储着我们的日志文件;

  1. 合约状态变化通知:当合约的状态发生重要变化时,可以使用 Event 来通知外部观察者。例如,当合约转移资产所有权,发生交易,或者某个权限被更改时,可以通过 Event 向外部发送通知。外部观察者可以监听合约中定义的 Event,并做出相应的处理或响应。

  2. DApp 触发和反应:在分布式应用程序中,Event 是 DApp 与合约之间的重要接口。DApp 可以监听合约中定义的 Event,以便触发某些操作或更新界面。当合约状态发生变化时,Event 可以通过 DApp 反馈给用户,提供实时的状态更新和交互。

  3. 历史记录和审计:Event 可以用于记录合约执行过程中的重要事件。通过记录 Event,可以在之后进行审计或查看历史记录。例如,在一个众筹合约中,可以使用 Event 记录每次捐款的细节,以便后续审计捐款阶段的数据。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
contract Event{

    //事件参数最多只能有3个,下面我们定义了两个参数的事件和一个参数的事件;
    event Log(address indexed  sender , string message);
    //在Solidity合约中,indexed 是一个用于声明事件参数的关键字。
    //使用 indexed 可以使得事件参数具有索引功能,从而提供更高效的事件过滤和查询。
    event AnotherLog();

    //这里我们定义了一个方法调用我们的事件
    function test() public {
        //emit要对应上面我们定义的事件 
        emit Log(msg.sender, "Hello World");
        emit Log(msg.sender, "Hello Event");

        emit AnotherLog();

    }
}

部署完合约以后,我们点击debug边上的下拉箭头,可以看到我们的日志信息

3,调用其他合约

创建两个contract合约或者是使用import引用其它合约中的数据;类似于java一样,需要实例化,也就是new一个对象出来;

这段代码我们就沿用上面写的程序;主要是下面的contract;

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

contract Event{

    //事件参数最多只能有3个,下面我们定义了两个参数的事件和一个参数的事件;
    event Log(address indexed  sender , string message);
    //在Solidity合约中,indexed 是一个用于声明事件参数的关键字。
    //使用 indexed 可以使得事件参数具有索引功能,从而提供更高效的事件过滤和查询。
    event AnotherLog();

    //这里我们定义了一个方法调用我们的事件
    function test() public {
        //emit要对应上面我们定义的事件 
        emit Log(msg.sender, "Hello World");
        emit Log(msg.sender, "Hello Event");

        emit AnotherLog();

    }
}

contract constructorsolidity{
    //这里我们调用上面的合约,
    Event public eve;

    function Creat() public {
        eve = new Event();
    } 
}

 运行的时候,我们选择下面的合约部署;至此我们简单的调用其他合约就成功了;

接下里介绍第二种方法使用import调用。当使用import关键字导入合约时,需要提供合约文件的路径。路径可以是绝对路径,也可以是相对路径。绝对路径是相对于项目根目录或源文件的根目录,而相对路径是相对于当前合约文件的路径。

我们可以清晰的看到,代码量减少了很多,提高了代码的可复用性;

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

//用import引用外部sol文件
import "./three.sol";

contract constructorsolidity{
    //这里我们调用上面的合约,创建一个Event对象;
    Event public eve;

    //给eve对象实例化;这样就拥有里面的数据了;
    function Creat() public {
        eve = new Event();
    }
    
    
}

当我们想引用别的合约的数据的时候,用 . 来引用就行了。

4,继承is标签

在Solidity中,合约之间可以通过继承来建立关系。一个合约可以继承另一个合约,并继承合约的属性(状态变量)和方法(函数)。被继承的合约称为父合约或基合约,继承它的合约称为子合约或派生合约。

通过继承,子合约可以继承父合约的属性和方法,从而拥有父合约的行为和功能。这样做可以实现代码的重用和模块化,提高代码的可读性、可维护性和可扩展性。

在Solidity中,使用is关键字来声明继承关系。例如,定义一个名为ChildContract的子合约继承自ParentContract的父合约,可以使用如下语法:

contract ParentContract {
    // 父合约的属性和方法
}

contract ChildContract is ParentContract {
    // 子合约的属性和方法
}

子合约继承父合约后,可以访问父合约的属性和方法。子合约也可以重写父合约的方法,并且可以使用super关键字来调用父合约的方法。

需要注意的是,Solidity中只支持单继承,即一个合约只能继承一个父合约。但是一个合约可以被多个合约继承,从而形成更复杂的继承关系。

继承是Solidity中实现代码重用和模块化的重要机制。通过继承,可以在合约中扩展已有的功能和属性,避免重复编写代码,提高代码的复用性和可维护性。

5,编写第一个Dapp(捐款系统)

代码的解释我在文档有注释,先说一些,界面使用问题吧!

选择多个账户,这里每个账户都有100以太坊;

 

更换货币符号

直接转账到我们的目标账户

 

 

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
contract FundMe{

    //部署一个用户地址,用immutable,减少gas的消耗
    address immutable public ower ;
    address[] public funder;
    mapping (address => uint) public map;
    constructor(){
        ower = msg.sender;
    }

    //有payable意思是,可以往里面存以太坊
    function Fund()public payable {
        //设置一个异常,捐款不能小于一个以太坊
        require(msg.value >= 1e17, "The amount is too small, please enter a suitable amount");
        //把我捐款的地址放到地址数组中,方便后续查找,有那些人捐款过
        funder.push(msg.sender);
        //把金额放到mapping中,方便查询用户存款的金额
        map[msg.sender] = msg.value;
    }

    function count() public view returns(uint){
        return funder.length;
    }

    //设置,只允许部署合约者,提款
    modifier onlyOwer{
        require(msg.sender == ower, "not adderss contract!");
        _;
    }

    //直接转钱过来的两个功能,及时只转账,也会记录转账人的地址和金额
    receive() external payable {
        Fund();
    }

    fallback() external  payable {
        Fund();
    }

    function withdraw() public onlyOwer {
        
        //方法一,已经淘汰了的,偏向与底层代码,定义一个bool类型的值,获得账户的地址,将账户提现到自己账户上;
        // bool sendSuccess = payable(msg.sender).send(address(this).balance);
        // require(sendSuccess, "transation failed");

        //方法二,差不多也被淘汰了,只有少部分人在用
        // payable(msg.sender).transfer(address(this).balance);


        //方法三,现在用的比较多的方法,他的限制比较少,第二种方法,他会有很多限制
        (bool callSuccess,) = payable(msg.sender).call{value:address(this).balance}("");
        require(callSuccess, "fail transaction");

        //当把账户提款到自己账号上时,把捐款地址,金额全部清空;
        for(uint i = 0 ;  i < funder.length ; i++){
            map[funder[i]] = 0;
        }
        //赋值一个新的空mapping数组
        funder = new address[](0); 
    }
}

  • 17
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值