以太坊开发者文档03 智能合约语言

智能合约语言

以太坊的一个重要方面是智能合约可以使用相对开发人员友好的语言进行编程。如果您熟悉 Python 或 任何大括号语言,您可以发现一种有熟悉语法的语言。

两种最活跃且维护最频繁的语言是:

  • Solidity
  • Vyper

更有经验的开发人员可能还想使用 Yul,一种用于以太坊虚拟机的中间语言,或 Yul+,一种对 Yul 的扩展。

如果您好奇并想帮助测试仍在大力开发的新语言,您可以尝试使用 Fe,这是一种新兴的智能合约语言,目前仍处于起步阶段。

先决条件

以前的编程语言知识,尤其是 JavaScript 或 Python 知识,可以帮助您理解智能合约语言的差异。我们还建议您在深入到研究语言对比之前将智能合约作为概念理解。智能合约简介

Solidity

  • 用于实现智能合约的面向对象的高级语言

  • 受 C++ 影响最深的花括号语言

  • 静态类型语言(变量的类型在编译时已知)

  • 支持:

    • 继承(你可以扩展其他合约)
    • 库(你可以创建可从不同合约调用的可重用代码 - 例如其他面向对象编程语言中静态类中的静态函数)
    • 复杂的用户定义类型

重要链接

合约示例

// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.7.0;

contract Coin {
    // The keyword "public" makes variables
    // accessible from other contracts
    address public minter;
    mapping (address => uint) public balances;

    // Events allow clients to react to specific
    // contract changes you declare
    event Sent(address from, address to, uint amount);

    // Constructor code is only run when the contract
    // is created
    constructor() {
        minter = msg.sender;
    }

    // Sends an amount of newly created coins to an address
    // Can only be called by the contract creator
    function mint(address receiver, uint amount) public {
        require(msg.sender == minter);
        require(amount < 1e60);
        balances[receiver] += amount;
    }

    // Sends an amount of existing coins
    // from any caller to an address
    function send(address receiver, uint amount) public {
        require(amount <= balances[msg.sender], "Insufficient balance.");
        balances[msg.sender] -= amount;
        balances[receiver] += amount;
        emit Sent(msg.sender, receiver, amount);
    }
}

这个例子应该让你了解 Solidity 合约的语法是什么样的。有关函数和变量的更详细描述,请参阅文档

Vyper

  • Pythonic 编程语言

  • 强类型

  • 小而易懂的编译器代码

  • 高效的字节码生成

  • 功能故意设计地比 Solidity 少,目的是让合约更安全、更容易审计。 Vyper 不支持:

    • 修饰符
    • 继承
    • 内联汇编
    • 函数重载
    • 运算符重载
    • 递归调用
    • 无限长循环
    • 二进制不动点

重要链接

示例

# Open Auction

# Auction params
# Beneficiary receives money from the highest bidder
beneficiary: public(address)
auctionStart: public(uint256)
auctionEnd: public(uint256)

# Current state of auction
highestBidder: public(address)
highestBid: public(uint256)

# Set to true at the end, disallows any change
ended: public(bool)

# Keep track of refunded bids so we can follow the withdraw pattern
pendingReturns: public(HashMap[address, uint256])

# Create a simple auction with `_bidding_time`
# seconds bidding time on behalf of the
# beneficiary address `_beneficiary`.
@external
def __init__(_beneficiary: address, _bidding_time: uint256):
    self.beneficiary = _beneficiary
    self.auctionStart = block.timestamp
    self.auctionEnd = self.auctionStart + _bidding_time

# Bid on the auction with the value sent
# together with this transaction.
# The value will only be refunded if the
# auction is not won.
@external
@payable
def bid():
    # Check if bidding period is over.
    assert block.timestamp < self.auctionEnd
    # Check if bid is high enough
    assert msg.value > self.highestBid
    # Track the refund for the previous high bidder
    self.pendingReturns[self.highestBidder] += self.highestBid
    # Track new high bid
    self.highestBidder = msg.sender
    self.highestBid = msg.value

# Withdraw a previously refunded bid. The withdraw pattern is
# used here to avoid a security issue. If refunds were directly
# sent as part of bid(), a malicious bidding contract could block
# those refunds and thus block new higher bids from coming in.
@external
def withdraw():
    pending_amount: uint256 = self.pendingReturns[msg.sender]
    self.pendingReturns[msg.sender] = 0
    send(msg.sender, pending_amount)

# End the auction and send the highest bid
# to the beneficiary.
@external
def endAuction():
    # It is a good guideline to structure functions that interact
    # with other contracts (i.e. they call functions or send ether)
    # into three phases:
    # 1. checking conditions
    # 2. performing actions (potentially changing conditions)
    # 3. interacting with other contracts
    # If these phases are mixed up, the other contract could call
    # back into the current contract and modify the state or cause
    # effects (ether payout) to be performed multiple times.
    # If functions called internally include interaction with external
    # contracts, they also have to be considered interaction with
    # external contracts.

    # 1. Conditions
    # Check if auction endtime has been reached
    assert block.timestamp >= self.auctionEnd
    # Check if this function has already been called
    assert not self.ended

    # 2. Effects
    self.ended = True

    # 3. Interaction
    send(self.beneficiary, self.highestBid)

这个例子应该让你了解 Vyper 合约语法是什么样的。有关函数和变量的更详细描述,请参阅文档

Yul 和 Yul+

如果您是以太坊的新手,并且尚未使用智能合约语言进行任何编码,我们建议您开始使用 Solidity 或 Vyper。只有在您熟悉了智能合约安全最佳实践和使用 EVM 的具体细节后,才能研究 Yul 或 Yul+。

FE

  • 以太坊虚拟机 (EVM) 的静态类型语言。
  • 受 Python 和 Rust 的启发。
  • 旨在易于学习——即使对于刚接触以太坊生态系统的开发人员也是如此。
  • Fe 开发仍处于早期阶段,该语言于 2021 年 1 月发布了 alpha 版本。

如何选择

与任何其他编程语言一样,这主要是关于为正确的工作以及个人喜好选择正确的工具。

如果您还没有尝试过任何语言,请考虑以下几点:

Solidity 有什么优点?

  • 如果你是初学者,有很多教程和学习工具。在“通过编码学习”部分中查看更多相关信息。
  • 提供良好的开发人员工具。
  • Solidity 拥有庞大的开发者社区,这意味着您很可能很快就能找到问题的答案。

Vyper 有什么优点?

  • 对于想要编写智能合约的 Python 开发人员来说,这是入门的好方法。
  • Vyper 的功能数量较少,因此非常适合快速制作创意原型。
  • Vyper 旨在易于审核并最大限度地提高人类可读性。

Yul 和 Yul+ 有什么优点?

  • 简单而实用的低级语言
  • 允许更接近原始 EVM,这有助于优化合约的 gas 使用

语言比较

有关基本语法、合约生命周期、接口、运算符、数据结构、函数、控制流等的比较,请查看 Auditless 的 cheatsheet

延伸阅读


以太坊开发者文档03 智能合约语言
https://alphafitz.com/2022/08/31/officialweb-03-smart-contract-languages/
作者
alphafitz
发布于
2022年8月31日
许可协议