0基础学习solidity开发智能合约-初识solidity

Posted 听见向日葵的微笑

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了0基础学习solidity开发智能合约-初识solidity相关的知识,希望对你有一定的参考价值。

本篇课程开始,我们来学习一下如何使用solidity开发智能合约,由于博主对于solidity的学习,也是自学的,所以一些不足或有纰漏之处还望指出,大家共同进步,本系列课程会分很多节课讲述,从入门到进阶、实战,在课程最后,我们会通过所学知识来搭建几个不同类型的智能合约如Token合约、NFT合约等等,感兴趣的小伙伴加个关注吧。

一、什么是智能合约

这里引用一段摘自网络的话语来解释一下 

智能合约是区块链中四大核心技术之一,这个概念最开始是在1994年,由知名密码学家尼克·萨博提出的,可由于技术以及其他的一些原因一直都没有落地,哪怕到了今天,智能合约已经在互联网中很多的应用,比如自动还款,无人机售货等等,也多是局限在个人和机构之间的智能合约,个人和个人之间的智能合约几乎没有,原因就在于“信任”问题,我们会发现,只要谈起合约,大多数都是陌生人跟陌生人之间有这种需求,而且还跟钱有关系,如果在没有第三方做担保的情况下我们之间做了个约定,我把钱打给你,结果你毁约了,不承认怎么办?所以智能合约一直没办法在个人与个人之间普及,后来随着区块链的出现,人们发现,区块链与智能合约十分的契合,因为区块链的很多特点,比如去中心化,数据的不可篡改等,可以从技术的角度,去解决陌生人之间的信任问题,这才使智能合约大规模的应用成为可能,这一阶段的开始以以太坊的诞生为标志。在区块链的基础上,以太坊应用了智能合约技术。智能合约使得以太坊可以实现更多功能,智能合约是一个非常重要的应用,于是,慢慢的,智能合约就成了区块链的核心技术之一。 

总结来说,智能合约就是一个写好的程序脚本,它会在一个虚拟机上运行,且不受外界的干扰,所以能保证最大化的公平、公正、公开性。

以太坊作为区块链2.0的代表,它的设计理念和底层系统设计,让它逐渐被大众所认可,从现在开始我们就准备在以太坊上进行智能合约的开发(你可能听过bsc、trc、matic 等等区块链,它们都是基于以太坊虚拟机EVM开发的区块链网络,所以在以太坊上编写的智能合约,在这些网络上均可以使用)

二、什么是solidity

solidity是用于实现智能合约的一种面向合约的高级编程语言,solidity受到C++、Python和javascript的影响,被设计为可运行在以太坊虚拟机(EVM)上,所以用户无需担心代码的可移植性和跨平台等问题。solidity是一种静态类型的语言,支持继承、库引用等特性,并且用户可自定义复杂的结构类型。

 三、合约文件

一个简单的合约文件大概如下图所示:

我们来看一段示例代码,里面有一些简单的注释,可以结合着查看

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;  //solidity编译版本声明

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";  //第三方文件引入

//合约声明
contract DemoToken is ERC20 
    address owner; //地址变量
    uint256 total = 5000000 * 10**18; //数字变量

    //构造器
    constructor() ERC20("demoToken", "DT") 
        owner = msg.sender;
        _mint(msg.sender, total);
    

    //方法
    function getTotal() public view onlyOwner returns (uint256) 
        return total;
    

    //修饰符
    modifier onlyOwner() 
        require(msg.sender == owner);
        _;
    

  • 首先,第一行表示代码许可说明,可选项很多,大家可以自行查询
// SPDX-License-Identifier: MIT
  •  第二行声明了我们编译合约代码的solidity版本,其中^表示最低版本为0.8.17,当前该合约也不会被0.9.0以上版本编译
pragma solidity ^0.8.17;  //solidity编译版本声明
  • 第三行,我们引入了一个其他合约文件,solidity里允许我们引用其他的合约文件,这个暂时先不展开讲解,后面课程里我们会具体说明,大家先有个印象即可
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";  //第三方文件引入
  •  第四行,我们声明了一个合约对象,它是以 contract开头的结构 (is ERC20 表示继承了ERC20合约,后面详细讲解)
contract DemoToken is ERC20 
  • 第五、六行,我们定义了两个变量,关于solidity的变量类型,下一章我们会仔细讲解
    address owner; //地址变量
    uint256 total = 5000000 * 10**18; //数字变量
  • 然后我们声明了一个结构体,它在合约部署的时候会调用,我们可以在里面写一些初始化逻辑,如变量赋值、方法调用等
constructor() ERC20("demoToken", "DT") 
        owner = msg.sender;
        _mint(msg.sender, total);
    
  •  接着,我们声明了一个函数,仔细看它的声明语法有点类似JavaScript,但是后面一些地方却与JavaScript又有一些不同,它多了一些 public、view 等字段(关于这些多出来的字段,后面也会进行详细介绍)
 //方法
    function getTotal() public view onlyOwner returns (uint256) 
        return total;
    
  •  最后,我们定义了一个修饰符,它在合约里可以说是有着举足轻重的地位,在这里大家有个印象即可,在后面的课程里都会一一介绍
  //修饰符
    modifier onlyOwner() 
        require(msg.sender == owner);
        _;
    

通过本节课程的学习,我们先是简单了解了智能合约的概念,接着又对一个智能合约的组成部分进行了简单的分析,让我们对智能合约有了一个基本的概念,下一节课,我们将要学习一下solidity里的变量类型有哪些

 

solidity开发以太坊代币智能合约

智能合约开发是以太坊编程的核心之一,而代币是区块链应用的关键环节,下面我们来用solidity语言开发一个代币合约的实例,希望对大家有帮助。

以太坊的应用被称为去中心化应用(DApp),DApp的开发主要包括两大部分:

  • 智能合约的开发
  • 用户界面的开发

在本文中,我们将介绍智能合约的开发语言solidity。

让我们先从一个非常基础的例子开始,不用担心你现在还一点都不了解,我们将逐步了解到更多的细节。

contract SimpleStorage {
    uint storedData;

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

    function get() constant returns (uint retVal) {
        return storedData;
    }
}

在Solidity中,一个合约由一组代码(合约的函数)和数据(合约的状态)组成。合约位于以太坊区块链上的一个特殊地址。

uint storedData; 这行代码声明了一个状态变量,变量名为storedData,类型为 uint (256bits无符号整数)。你可以认为它就像数据库里面的一个存储单元,跟管理数据库一样,可以通过调用函数查询和修改它。在以太坊中,通常只有合约的拥有者才能这样做。在这个例子中,函数 set 和 get 分别用于修改和查询变量的值。

跟很多其他语言一样,访问状态变量时,不需要在前面增加 this. 这样的前缀。

这个合约还无法做很多事情(受限于以太坊的基础设施),仅仅是允许任何人储存一个数字。而且世界上任何一个人都可以来存取这个数字,缺少一个(可靠的)方式来保护你发布的数字。任何人都可以调用set方法设置一个不同的数字覆盖你发布的数字。但是你的数字将会留存在区块链的历史上。稍后我们会学习如何增加一个存取限制,使得只有你才能修改这个数字。

编写代币合约

接下来的合约将实现一个形式最简单的加密货币。任何人都可以发送货币给其他人,不需要注册用户名和密码,只要有一对以太坊的公私钥即可。

contract Coin {
//关键字“public”使变量能从合约外部访问。
    address public minter;
    mapping (address => uint) public balances;

//事件让轻客户端能高效的对变化做出反应。
    event Sent(address from, address to, uint amount);

//这个构造函数的代码仅仅只在合约创建的时候被运行。
    function Coin() {
        minter = msg.sender;
    }
    function mint(address receiver, uint amount) {
        if (msg.sender != minter) return;
        balances[receiver] += amount;
    }
    function send(address receiver, uint amount) {
        if (balances[msg.sender] < amount) return;
        balances[msg.sender] -= amount;
        balances[receiver] += amount;
        Sent(msg.sender, receiver, amount);
    }
}

这个合约引入了一些新的概念,让我们来逐个介绍。

address public minter;

这行代码声明了一个可公开访问的状态变量,类型为address。address类型的值大小为160 bits,不支持任何算术操作。适用于存储合约的地址或其他人的公私钥。public关键字会自动为其修饰的状态变量生成访问函数。没有public关键字的变量将无法被其他合约访问。另外只有本合约内的代码才能写入。自动生成的函数如下:

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

当然我们自己增加一个这样的访问函数是行不通的。编译器会报错,指出这个函数与一个状态变量重名。

下一行代码创建了一个public的状态变量,但是其类型更加复杂:

mapping (address => uint) public balances;
该类型将一些address映射到无符号整数。mapping可以被认为是一个哈希表,每一个可能的key对应的value被虚拟的初始化为全0.这个类比不是很严谨,对于一个mapping,无法获取一个包含其所有key或者value的链表。所以我们得自己记着添加了哪些东西到mapping中。更好的方式是维护一个这样的链表,或者使用其他更高级的数据类型。或者只在不受这个缺陷影响的场景中使用mapping,就像这个例子。在这个例子中由public关键字生成的访问函数将会更加复杂,其代码大致如下:

function balances(address _account) returns (uint balance) {
    return balances[_account];
}

我们可以很方便的通过这个函数查询某个特定账号的余额。

event Sent(address from, address to, uint value); 

这行代码声明了一个“事件”。由send函数的最后一行代码触发。客户端(服务端应用也适用)可以以很低的开销来监听这些由区块链触发的事件。事件触发时,监听者会同时接收到from,to,value这些参数值,可以方便的用于跟踪交易。为了监听这个事件,你可以使用如下代码:

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));
    }
}

注意在客户端中是如何调用自动生成的 balances 函数的。

这里有个比较特殊的函数 Coin。它是一个构造函数,会在合约创建的时候运行,之后就无法被调用。它会永久得存储合约创建者的地址。msg(以及tx和block)是一个神奇的全局变量,它包含了一些可以被合约代码访问的属于区块链的属性。msg.sender 总是存放着当前函数的外部调用者的地址。

最后,真正被用户或者其他合约调用,用来完成本合约功能的函数是mint和send。如果合约创建者之外的其他人调用mint,什么都不会发生。而send可以被任何人(拥有一定数量的代币)调用,发送一些币给其他人。注意,当你通过该合约发送一些代币到某个地址,在区块链浏览器中查询该地址将什么也看不到。因为发送代币导致的余额变化只存储在该代币合约的数据存储中。通过事件我们可以很容易创建一个可以追踪你的新币交易和余额的“区块链浏览器”。

以上是关于0基础学习solidity开发智能合约-初识solidity的主要内容,如果未能解决你的问题,请参考以下文章

初识SolidityRemix与Geth节点结合部署智能合约

区块链开发之Solidity编程基础

蚂蚁链学习1初识蚂蚁链的智能合约(solidity)

solidity 0.5.7简明教程

ENS 域名注册表智能合约(ENSRegistry.sol)解析

智能合约从入门到精通:Solidity语言的开发规范和开发流程