还在卷Web2?弯道超车第一步 从零到一实现智能合约

161 阅读8分钟

前言

为了写这篇文章,笔者放弃了下班陪女朋友和打如龙7的美好时光,对文章内容和案例代码进行多次修改,争取通过简洁的语言和语法,让大家轻松掌握智能合约编写,入门区块链世界
本文阅读大约10min

最近网上冲浪的时候,时不时就出现区块链的新闻,远的有FaceBook改为Meta,周杰伦玩NFT,近的有Luna暴雷等等,对于区块链的见解,大家可以在评论区讲讲,这里笔者不想讲自媒体宣传夸张的交易金额,毕竟目前区块链还有很多显而易见的弊端,假如只是分析现在形势。当今web2时代,无论技术还是业务蛋糕都瓜分完毕,技术上前端工具要拿Go或Rust编写,业务上各大APP纷纷进入存量时代,我见过同行朋友们,很多都是以下情况,在公司里面被‘卷王’卷的不能呼吸,公司外面各个大厂一波又一波的裁员潮,招聘HC缩紧,让我们视角转到Web3,投资大鳄纷纷撒币,各个大厂都开始布局Web3.0,国外Facebook,谷歌,国内快手腾讯阿里等 岗位更是供不应求 (非故意渲染焦虑 区块链岗位需认真甄别)所以现在花点时间了解Web3或者看下这篇文章,投资自己嘛,怎么都不亏,何况Web3.0利好前端🙈

网上教程比较老,大都是0.7.2版本之前的,Solidity不同版本语法改动较多,笔者踩了很多坑 orz,举一些踩过的坑

  • 0.4.17版本由于中间Layer问题,导致不能返回字符串数组

  • 0.5.0 移除了函数类型constant

  • 0.4.22版本之前没有constructor函数

  • .......

建议大家多追文档~

阅读完这篇文章,你可以收获如下

  • 智能合约编写,部署及测试
  • 如何使用Remix进行debug等
  • 掌握目前Solidity主流版本部分语法

准备

正文

阅读正文前建议大家先简单浏览文档,方便对知识的全面掌握,因为本篇教程面向纯小白,觉得讲的啰嗦兄弟,点击目录Subway.sol完整版

智能合约是基于Solidity语言编写的,深受c++、Python和JavaScript的影响,很多语法和JS一样,很多前端朋友写Solidity的时候都发出了灵魂的拷问,这特喵的和JS有啥区别?

智能合约编写

首先在Remix编辑器中WorkSpaces中新建项目或者选择default_workspace文件中contracts,建立 .sol文件

image.png

这里我以Subway.sol为例子(每天坐地铁被挤成🐶) 在文件的开头声明开源协议及Solidity版本

Pragma 是 pragmatic information 的简称,用于告知编译器如何编译,如果编译版本与语言版本不匹配,编译器会提示错误

// SPDX-License-Identifier: MIT

pragma solidity 0.8.0;

定义Subway.sol及变量 车费(fare),管理者(manager),及乘客(passengers),通过 public 关键字定义是否公开可见还是私有不可见,像管理者这种大佬肯定不能公开,不然哪天他涨地铁票价后,大家都会追着问候他

相对其他语言,address类型比较特殊,它是指能够通过地址校验的十六进制常量,比如0x5B38Da6a701c568545dCfcB03FcB875f56beddC4或者你的MetaMask账户地址

// SPDX-License-Identifier: MIT

pragma solidity 0.8.0 ;

contract Subway {

   uint  public  fare = 2;
   address  manager;
   address[] public passengers;

}

这里通过constructor函数,绑定manager。 msg是Solidity语言全局变量,方便交易及获取信息,类似的还有block和tx等

这里介绍合约用到msg的两个属性,详情见文档

  • msg.sender: 当前调用账户地址

  • msg.value: 随msg发送的wei数量,其中wei为以太币(Ether)单位,1 ether =1e+18 wei Ether换算表一览

constructor函数只会在合约部署时执行一次,代码如下

// SPDX-License-Identifier: MIT

pragma solidity 0.8.0 ;

contract Subway {

   uint  public  fare = 2;
   address  manager;
   address[] public passengers;
   
   constructor (){
       manager = msg.sender;
   }

}

下面我们编写几个函数来完善我们的智能合约,关于Solidity函数类型,文档表述不是特别直观,这里笔者特意整理了表格,方便大家浏览

关键字说明
public表示当前函数可以公开,任意访问
private表示当前函数可以仅合约内访问
internal当前合约及所继承的合约可以访问
external仅外部访问(内部想访问也只能通过外部访问方式实现)
view表示当前函数可以返回变量,不可以修改合约内的状态
pure当前函数不读取合约内状态变量也不修改状态
payable当前函数可以发送eth
revice一个合约只能有一个,不需要function关键字没有参数及返回值,但必须有external和payable关键字
fallback部分条件同上,区分点在于接收ether的话要有payable关键字

常见修改状态如下:

  1. 修改状态变量。
  2. 产生事件
  3. 创建其它合约
  4. 通过调用发送以太币。
  5. 调用任何没有标记为 view 或者 pure 的函数。
    // 设置价格
   function setFare(uint fareValue ) public {
        fare = fareValue;
   }

   modifier restricted(){
     //条件判断,如果是进行下一步
     require(msg.value > fare);
     //这里_ 代指上述条件满足后,被修饰的函数的代码,比如_代表takeSubway里passengers.push(passenger);
     _;
   }
   
   function takeSubway(address passenger) payable public restricted {
       passengers.push(passenger);
   }
   
   function getPassengers()  public view returns( address[] memory ){
        return   passengers;
   }

modifier 表示进入被修饰函数之前要执行的函数,比如 我们坐地铁之前要检查带的钱够不够

Subway.sol完整版

// SPDX-License-Identifier: MIT

pragma solidity 0.8.0 ;

contract Subway {

   uint  public  fare = 2;
   address  manager;
   address[] public passengers;

   constructor (){
       manager = msg.sender;
   }

   function setFare(uint fareValue ) public  {
        fare = fareValue;
   }

   modifier restricted(){
     require(msg.value > fare);
     _;
   }
   
   function takeSubway(address passenger) payable public restricted {
       passengers.push(passenger);
   }
   
   function getPassengers()  public view returns( address[] memory ){
        return   passengers;
    }

}

合约部署及测试

部署

在写好代码后,马上进行代码的本地部署,首先确认编译版本和我们选择语言版本是否一样

WeChat720b9cd7961f7ae1e0ca5455d45232b5.png

当编译器出现 ✅,代表我们可以部署智能合约了,本次部署只是在本地,后面会出部署到链上的教程。

Remix编辑器非常强大,自带了10个免费测试账号,每个账号100ether(测试币),最上方ENVIRONMENT,有很多不同的环境,这里我们选择JavaScript VM(London),可能一些细的兄弟会好奇下方JavaScript VM(Berlin),它们都是Remix内置的 JS Vm,伦敦是较新版本的(相对柏林升级了网络和支持更多的虚拟机并增加了一些EIP)更多知识

WechatIMG345.png

测试

这里只是对合约进行简单的功能测试,实际上智能合约意义重大,关系金额巨大,一旦你写的逻辑不够严谨,很可能导致上千万的💰损失,因此在实际工作中,需要进行更严格的测试,下一节我们将使用mocha对Subway合约进行更严格测试

当合约部署后,我们看到声明的公共变量和函数都显示出来了,点击fare按钮会出现我们初始赋值地铁票价2,同时终端会显示调用信息

image.png

现在,我们设置票价20,并切换上面测试账号,切换测试账号不用重新部署,在value 里写 40 单位wei(想直观感受也可以用单位ether),并且复制切换到账号地址粘贴到我们payable类型takeSubway函数中

image.png

点击takeSubway按钮后,可以看到方法成功调用,当合约真正部署到链上 takeSubway操作往往要等上30s以上,这对用户非常不友好,也许即将到来eth2.0共识层会解决这个问题(eth2.0叫做 共识层,方便大家理解就照错的讲了)eth2.0会对用户更友好点原因是涉及到PoS和PoW共识机制

这个时候点击getPassengers验证,可以看到返回数组里有我们的测试账号地址,第一个智能合约就完成啦,🎉🎉🎉

image.png

Debug

每当调用合约函数或者变量的时候,终端都会显示间短调用信息,这个时候我们可以点击右面的debug,Remix提供了比较强大的debug溯源,拿Remix写智能合约

image.png

最后

感谢阅读,欢迎大家的指正和讨论,您的点赞和批评都是我更新的动力,另外对Web3.0有兴趣的朋友们千万不要当大冤种报班哦,下面是自学资料

image.png

下节预告

  • 薅测试币羊毛(不用发推)
  • 将合约部署到链上
  • 与MetaMask钱包互动
  • 使用mocha对合约进行测试
  • .......

如龙7真的好玩