Přeskočit na hlavní obsah
Change page

Jazyk chytrých smluv

Jednou z výhod Etherea je, že smart kontrakty lze programovat v relativně uživatelsky přívětivých programovacích jazycích. Pokud máte zkušenosti s Pythonem nebo jiným jazykem používajícím složené závorky(opens in a new tab), můžete si najít jazyk s podobnou syntaxí.

Dva nejaktivnější a nejvíce udržované jazyky jsou:

  • Solidity
  • Vyper

Remix IDE poskytuje komplexní vývojové prostředí pro vytváření a testování kontraktů jak v Solidity, tak ve Vyperu. Vyzkoušejte webový Remix IDE(opens in a new tab), abyste mohli začít kódovat.

Zkušenější vývojáři mohou také chtít používat Yul, což je intermediární jazyk pro Virtuální stroj Etherea, nebo Yul+, rozšíření jazyka Yul.

Pokud jste zvědaví a rádi pomáháte testovat nové jazyky, které jsou stále ve fázi intenzivního vývoje, můžete experimentovat s Fe, nově vznikajícím jazykem pro smart kontrakty, který je v současnosti ještě v rané fázi.

Předpoklady

Předchozí znalosti programovacích jazyků, zejména JavaScriptu nebo Pythonu, vám mohou pomoci lépe porozumět rozdílům mezi jazyky pro smart kontrakty. Doporučujeme také, abyste nejprve pochopili koncept smart kontraktů, než se ponoříte do srovnání jazyků. Úvod do smart kontraktů.

Solidity

  • Objektově orientovaný, vysoce úrovňový jazyk pro implementaci chytrých kontraktů.
  • Jazyk se složenými závorkami, který je nejvíce ovlivněn jazykem C++.
  • Staticky typovaný (typ proměnné je znám v době kompilace).
  • Podporuje:
    • Dědičnost (můžete rozšiřovat jiné kontrakty).
    • Knihovny (můžete vytvářet opakovaně použitelný kód, který můžete volat z různých kontraktů – podobně jako statické funkce ve statické třídě v jiných objektově orientovaných programovacích jazycích).
    • Komplexní uživatelem definované typy.

Ukázkový kontrakt

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}
Zobrazit vše
Kopírovat

Tento příklad by vám měl poskytnout představu o tom, jaká je syntaxe kontraktů v Solidity. Pro podrobnější popis funkcí a proměnných si přečtěte dokumentaci(opens in a new tab).

Vyper

  • Pythonický programovací jazyk
  • Silné typování
  • Malý a srozumitelný kompilátor
  • Efektivní generování bytekódu
  • Úmyslně má méně funkcí než Solidity s cílem učinit kontrakty bezpečnějšími a snáze auditovatelnými. Vyper nepodporuje:
    • Modifikátory
    • #Dědičnost
    • Inline sestavení (assembly)
    • Přetěžování funkcí
    • Přetěžování operátorů
    • Rekurzivní volání
    • Nekonečné smyčky
    • Binární pevné body

Pro více informací si přečtěte Vyper rationale(opens in a new tab).

Příklad

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
19# Create a simple auction with `_bidding_time`
20# seconds bidding time on behalf of the
21# beneficiary address `_beneficiary`.
22@external
23def __init__(_beneficiary: address, _bidding_time: uint256):
24 self.beneficiary = _beneficiary
25 self.auctionStart = block.timestamp
26 self.auctionEnd = self.auctionStart + _bidding_time
27
28# Bid on the auction with the value sent
29# together with this transaction.
30# The value will only be refunded if the
31# auction is not won.
32@external
33@payable
34def bid():
35 # Check if bidding period is over.
36 assert block.timestamp < self.auctionEnd
37 # Check if bid is high enough
38 assert msg.value > self.highestBid
39 # Track the refund for the previous high bidder
40 self.pendingReturns[self.highestBidder] += self.highestBid
41 # Track new high bid
42 self.highestBidder = msg.sender
43 self.highestBid = msg.value
44
45# Withdraw a previously refunded bid. The withdraw pattern is
46# used here to avoid a security issue. If refunds were directly
47# sent as part of bid(), a malicious bidding contract could block
48# those refunds and thus block new higher bids from coming in.
49@external
50def withdraw():
51 pending_amount: uint256 = self.pendingReturns[msg.sender]
52 self.pendingReturns[msg.sender] = 0
53 send(msg.sender, pending_amount)
54
55# End the auction and send the highest bid
56# to the beneficiary.
57@external
58def endAuction():
59 # It is a good guideline to structure functions that interact
60 # with other contracts (i.e. they call functions or send ether)
61 # into three phases:
62 # 1. checking conditions
63 # 2. performing actions (potentially changing conditions)
64 # 3. interacting with other contracts
65 # If these phases are mixed up, the other contract could call
66 # back into the current contract and modify the state or cause
67 # effects (ether payout) to be performed multiple times.
68 # If functions called internally include interaction with external
69 # contracts, they also have to be considered interaction with
70 # external contracts.
71
72 # 1. Conditions
73 # Check if auction endtime has been reached
74 assert block.timestamp >= self.auctionEnd
75 # Check if this function has already been called
76 assert not self.ended
77
78 # 2. Effects
79 self.ended = True
80
81 # 3. Interaction
82 send(self.beneficiary, self.highestBid)
Zobrazit vše
Kopírovat

Tento příklad by vám měl poskytnout představu o tom, jaká je syntaxe kontraktů ve Vyperu. Pro podrobnější popis funkcí a proměnných si přečtěte dokumentaci(opens in a new tab).

Yul a Yul+

Pokud jste v Ethereum nováčkem a ještě jste neprogramovali v jazycích pro smart kontrakty, doporučujeme začít se Solidity nebo Vyperem. Na Yul nebo Yul+ se zaměřte až poté, co si osvojíte osvědčené postupy v oblasti bezpečnosti smart kontraktů a specifika práce s EVM.

Yul

Yul+

  • Nízkoúrovňové, vysoce efektivní rozšíření Yulu.
  • Původně navržen pro kontrakt optimistického rollupu.
  • Yul+ lze považovat za experimentální návrh upgradu Yul, který do něj přidává nové funkce.

Ukázkový kontrakt

Následující jednoduchý příklad implementuje funkci mocniny. Lze jej zkompilovat pomocí příkazu solc --strict-assembly --bin input.yul. Příklad by měl být uložen v souboru 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}
Zobrazit vše

Pokud již máte se smart kontrakty bohaté zkušenosti, plnou implementaci ERC20 v Yul můžete najít zde(opens in a new tab).

Fe

  • Staticky typovaný jazyk pro Virtuální stroj Etherea (EVM).
  • Inspirován jazyky Python a Rust.
  • Cílem je, aby byl snadno naučitelný – i pro vývojáře, kteří jsou v ekosystému Ethereum noví.
  • Vývoj Fe je stále v raných fázích, první alfa verze jazyka byla vydána v lednu 2021.

Ukázkový kontrakt

Následuje jednoduchý kontrakt implementovaný v jazyce Fe.

1type BookMsg = bytes[100]
2
3contract GuestBook:
4 pub guest_book: map<address, BookMsg>
5
6 event Signed:
7 book_msg: BookMsg
8
9 pub def sign(book_msg: BookMsg):
10 self.guest_book[msg.sender] = book_msg
11
12 emit Signed(book_msg=book_msg)
13
14 pub def get_msg(addr: address) -> BookMsg:
15 return self.guest_book[addr].to_mem()
16
Zobrazit vše

Jak si vybrat

Stejně jako u jakéhokoli jiného programovacího jazyka jde především o výběr správného nástroje pro daný úkol a o osobní preference.

Uvádíme několik věcí, které byste měli zvážit, pokud jste ještě žádný z jazyků nezkusili:

Co je skvělé na Solidity?

  • Pokud jste začátečník, najdete mnoho tutoriálů a vzdělávacích nástrojů. Více se dozvíte v sekci Learn by Coding.
  • K dispozici je dobrá sada nástrojů pro vývojáře.
  • Solidity má velkou vývojářskou komunitu, což znamená, že na případné otázky pravděpodobně najdete odpovědi poměrně rychle.

Co je skvělé na Vyperu?

  • Skvělý na začátek pro Python vývojáře, kteří chtějí psát chytré kontrakty.
  • Vyper má menší počet funkcí, což ho činí skvělým pro rychlé prototypování nápadů.
  • Vyper usiluje o snadnou auditovatelnost a maximální čitelnost pro lidské bytosti.

Co je skvělé na Yul a Yul+?

  • Jednoduchý a funkční nízkoúrovňový jazyk.
  • Umožňuje dostat se mnohem blíže k surovému EVM, což vám může pomoci s optimalizací spotřeby paliva vašich kontraktů.

Porovnání jazyků

Pro srovnání základní syntaxe, životního cyklu kontraktů, rozhraní, operátorů, datových struktur, funkcí, řídicích struktur a dalších rozdílů se podívejte na tento cheatsheet od Auditless(opens in a new tab)

Další čtení

Byl tento článek užitečný?