帮助更新此页面

🌏

本页面有新版本,但现在只有英文版。请帮助我们翻译最新版本。

此页不完整。如果您是这方面的专家,请编辑这一页,并将您的智慧撒在上面。

智能合约语言

上次编辑: , Invalid DateTime
Edit page

关于以太坊的一个重要方面是,智能合约可以使用相对友好的开发者语言编程。 关于以太坊的一个重要方面是可以使用相对开发人员友好的语言对智能合约进行编程。

最受欢迎和维护得最好的两种语言是:

  • Solidity
  • Vyper

更有经验的开发者也可能想要使用 Yul:一种用于以太坊虚拟机的中间语言,或者是 Yul+ 语言,这是一种 Yul 扩展。

前置要求

如果已经有编程语言的知识,特别是关于 JavaScript 或 Python 的,可以帮助你体验到智能合约语言的差异。 同时,我们建议你在深入理解语言差异之前,先理解作为概念的智能合约。 智能合约简介

Solidity

  • 受 C++、 Python 和 JavaScript 影响。
  • 静态类型(编译时已知变量类型)。
  • 支持:
    • 继承(你可以拓展其它合约)。
    • 库(您可以创建从不同的合约调用的可重用代码——就像静态函数在其它面向对象编程语言的静态类中一样)。
    • 复杂的用户自定义类型。

合约示例

1/ SPDX-License-Identifier: GPL-3.0
2pragma solidity >= 0.7.0;
3
4contract Coin {
5 // The keyword "public" makes variables
6 // accessible from other contracts
7 address public minter;
8 mapping (address => uint) public balances;
9
10 // Events allow clients to react to specific
11 // contract changes you declare
12 event Sent(address from, address to, uint amount);
13
14 // Constructor code is only run when the contract
15 // is created
16 constructor() {
17 minter = msg.sender;
18 }
19
20 // Sends an amount of newly created coins to an address
21 // Can only be called by the contract creator
22 function mint(address receiver, uint amount) public {
23 require(msg.sender == minter);
24 require(amount < 1e60);
25 balances[receiver] += amount;
26 }
27
28 // Sends an amount of existing coins
29 // from any caller to an address
30 function send(address receiver, uint amount) public {
31 require(amount <= balances[msg.sender], "Insufficient balance.");
32 balances[msg.sender] -= amount;
33 balances[receiver] += amount;
34 emit Sent(msg.sender, receiver, amount);
35 }
36}
37
显示全部
📋 复制

这个示例应该能让你感觉到 Solidity 合约语法是什么样子的。 关于函数和变量的详细描述,请查看文档

Vyper

  • 类 Python 编程语言
  • 强类型
  • 小而且易懂的编译器代码
  • 为了更安全和易于审阅,特意提供比 Solidity 少的功能。 Vyper 不支持:
    • 修饰符
    • 继承
    • 内联装配
    • 函数重载
    • 操作重载
    • 递归调用
    • 无限长度循环
    • 二进制定长浮点

更多信息,Vyper 原理

示例

1# Open Auction
2
3# Auction params
4# Beneficiary receives money from the highest bidder
5beneficiary: public(address)
6auctionStart: public(uint256)
7auctionEnd: public(uint256)
8
9# Current state of auction
10highestBidder: public(address)
11highestBid: public(uint256)
12
13# Set to true at the end, disallows any change
14ended: public(bool)
15
16# Keep track of refunded bids so we can follow the withdraw pattern
17pendingReturns: public(HashMap[address, uint256])
18@external
19def __init__(_beneficiary: address, _bidding_time: uint256):
20 self.beneficiary = _beneficiary
21 self.auctionStart = block.timestamp
22 self.auctionEnd = self.auctionStart + _bidding_time
23
24# Bid on the auction with the value sent
25# together with this transaction.
26# The value will only be refunded if the
27# auction is not won.
28@external
29@payable
30def bid():
31 # Check if bidding period is over.
32 assert block.timestamp < self.auctionEnd
33 # Check if bid is high enough
34 assert msg.value > self.highestBid
35 # Track the refund for the previous high bidder
36 self.pendingReturns[self.highestBidder] += self.highestBid
37 # Track new high bid
38 self.highestBidder = msg.sender
39 self.highestBid = msg.value The withdraw pattern is
40# used here to avoid a security issue. If refunds were directly
41# sent as part of bid(), a malicious bidding contract could block
42# those refunds and thus block new higher bids from coming in.
43@external
44def withdraw():
45 pending_amount: uint256 = self.pendingReturns[msg.sender]
46 self.pendingReturns[msg.sender] = 0
47 send(msg.sender, pending_amount)
48
49# End the auction and send the highest bid
50# to the beneficiary.
51@external
52def endAuction():
53 # It is a good guideline to structure functions that interact
54 # with other contracts (i.e. they call functions or send Ether)
55 # into three phases:
56 # 1. checking conditions
57 # 2. performing actions (potentially changing conditions)
58 # 3. interacting with other contracts
59 # If these phases are mixed up, the other contract could call
60 # back into the current contract and modify the state or cause
61 # effects (ether payout) to be performed multiple times.
62 # If functions called internally include interaction with external
63 # contracts, they also have to be considered interaction with
64 # external contracts.
65
66 # 1. Conditions
67 # Check if auction endtime has been reached
68 assert block.timestamp >= self.auctionEnd
69 # Check if this function has already been called
70 assert not self.ended
71
72 # 2. Effects
73 self.ended = True
74
75 # 3. Interaction
76 send(self.beneficiary, self.highestBid)
77
显示全部
📋 复制

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

Yul 和 Yul+

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

Yul

  • 以太坊的中继语言。
  • 支持 EVMeWASM,一种以太坊风格的 WebAssembly,以及旨在成为两个平台均可用的公分母。
  • 高级优化阶段的良好目标,既使 EVM 和 eWASM 平台均等受益。

Yul+

  • Yul 的低级、高效扩展。
  • 最初设计用于 optimistic rollup 合约。
  • Yul+ 可以被视为对 Yul 的实验性升级建议,为其添加新功能。

合约示例

以下简单示例实现了幂函数。 它可以使用 solc --strict-assembly --bin input.yul 编译。 这个例子应该 存储在 input.yul 文件中。

1{
2 function power(base, exponent) -> result
3 {
4 switch exponent
5 case 0 { result := 1 }
6 case 1 { result := base }
7 default
8 {
9 result := power(mul(base, base), div(exponent, 2))
10 if mod(exponent, 2) { result := mul(base, result) }
11 }
12 }
13 let res := power(calldataload(0), calldataload(32))
14 mstore(0, res)
15 return(0, 32)
16}
17
显示全部

如果您已经熟悉智能合约,可以在 此处找到 Yul 中的完整 ERC20 实例

如何选择

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

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

Solidity 的优点是什么?

  • 如果您是初学者,这里有很多教程和学习工具。 在通过编码学习部分了解更多相关信息。
  • 好的开发者工具可用
  • Solidity 拥有庞大的开发人员社区,这意味着您很可能会很快找到问题的答案。

Vyper 的优点是什么?

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

Yul 和 Yul+ 的优点是什么?

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

语言比较

关于基本语法的比较、合同生命周期、接口、操作员、数据结构、功能、控制流程以及更多,请查看由 Auditless 编写的备忘单

延伸阅读