Перейти до основного контенту
Change page

Докладніше про розумні контракти

Останні оновлення сторінки: 23 лютого 2026 р.

Розумний контракт - це програма, що працює за адресою в Ethereum. Вони складаються з даних та функцій, які можуть виконуватися після отримання транзакції. Ось огляд того, що формує розумний контракт.

Передумови

Переконайтеся, що ви спочатку прочитали про смарт-контракти. Цей документ передбачає, що ви вже знайомі з такими мовами програмування, як JavaScript чи Python.

Дані

Будь-які дані контракту мають бути призначені до розташування: або в сховище (storage), або в пам’ять (memory). Варто змінити зберігання в розумному контракті, тож вам слід подумати, де повинні міститися ваші дані.

Сховище

Постійні дані називають сховищем та представлені змінними стану. Ці значення постійно зберігаються в блокчейні. Вам слід оголосити тип таким чином, щоб контракт міг відстежувати, скільки пам’яті в блокчейні йому потрібно під час компіляції.

1// Приклад на Solidity
2contract SimpleStorage {
3 uint storedData; // Змінна стану
4 // ...
5}
1# Приклад на Vyper
2storedData: int128

Якщо ви вже запрограмували об'єктно-орієнтовані мови, ймовірно, ви знайомі з більшістю типів. Однак тип address буде для вас новим, якщо ви новачок у розробці на Ethereum.

Тип address може містити адресу Ethereum, що дорівнює 20 байтам або 160 бітам. Він повертається у шістнадцятковій системі запису з провідним 0x.

До інших типів належать:

  • логічний
  • цілий
  • числа фіксованих точок
  • байтові масиви фіксованого розміру
  • масиви байтів динамічного розміру
  • раціональні та цілочисельні літерали
  • рядкові літерали
  • шістнадцяткові літерали
  • перелічення

Для додаткового пояснення зверніться до документів:

Пам’ять

Значення, які зберігаються лише протягом усього терміну виконання функції контракту, називаються змінними пам’яті. Оскільки вони не зберігаються у блокчейні назавжди, їх використання набагато дешевше.

Дізнайтеся більше про те, як EVM зберігає дані (сховище, пам’ять і стек) у документації Solidity (opens in a new tab).

Змінні середовища

На додаток до змінних, які ви виділяєте у вашому контракті, є деякі особливі глобальні змінні. Насамперед, вони використовуються для надання інформації про блокчейн чи поточну транзакцію.

Приклади:

ВластивістьЗмінна стануОпис
block.timestampuint256Поточна часова позначка блоку
msg.senderaddressВідправник повідомлення (поточний дзвінок)

Функції

Простіше кажучи, функції можуть отримувати інформацію або задавати інформацію у відповідь на вхідні транзакції.

Існує два типу виклику функції:

  • internal – вони не створюють виклик EVM
    • Внутрішні функції та змінні стану можуть бути доступні лише всередині (тобто з поточного контракту або контрактів, що є його похідними).
  • external – вони створюють виклик EVM
    • Зовнішні функції є частиною інтерфейс договору, що означає, що їх можна викликати з інших договорів і за допомогою транзакцій. Зовнішню функцію f не можна викликати всередині (тобто виклик f() не спрацює, а this.f() спрацює).

Вони також можуть бути public або private

  • Функції public можна викликати зсередини контракту або ззовні через повідомлення.
  • Функції private видимі лише для контракту, у якому вони визначені, і не видимі для похідних контрактів.

Обидві функції і змінні стану можуть бути публічними чи приватними

Ось функція оновлення змінної стану за договором:

1// Приклад на Solidity
2function update_name(string value) public {
3 dapp_name = value;
4}
  • Параметр value типу string передається у функцію update_name.
  • Її оголошено як public, тобто до неї може отримати доступ будь-хто.
  • Її не оголошено як view, тому вона може змінювати стан контракту.

Функції View

Ці функції обіцяють не змінювати стан даних договору. Поширеними прикладами є функції "getter" – наприклад, ви можете використовувати її, щоб отримати баланс користувача.

1// Приклад на Solidity
2function balanceOf(address _owner) public view returns (uint256 _balance) {
3 return ownerPizzaCount[_owner];
4}
1dappName: public(string)
2
3@view
4@public
5def readName() -> string:
6 return dappName

Що вважається змінами стану:

  1. Запис до змінних стану.
  2. Генерація подій (opens in a new tab).
  3. Створення інших контрактів (opens in a new tab).
  4. Використання selfdestruct.
  5. Надсилання через дзвінки.
  6. Виклик будь-якої функції, не позначеної як view або pure.
  7. Використання дзвінків низького рівня.
  8. Використовуючи вбудовану збірку, що містить деякі коди.

Функції-конструктори

Функції constructor виконуються лише один раз, під час першого розгортання контракту. Подібно до constructor у багатьох об’єктно-орієнтованих мовах програмування, ці функції часто ініціалізують змінні стану, присвоюючи їм зазначені значення.

1// Приклад на Solidity
2// Ініціалізує дані контракту, встановлюючи `owner`
3// як адресу автора контракту.
4constructor() public {
5 // Усі смарт-контракти покладаються на зовнішні транзакції для запуску своїх функцій.
6 // `msg` — це глобальна змінна, яка містить відповідні дані про дану транзакцію,
7 // наприклад адресу відправника та суму ETH, включену до транзакції.
8 // Дізнайтеся більше: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties
9 owner = msg.sender;
10}
Показати все
1# Приклад на Vyper
2
3@external
4def __init__(_beneficiary: address, _bidding_time: uint256):
5 self.beneficiary = _beneficiary
6 self.auctionStart = block.timestamp
7 self.auctionEnd = self.auctionStart + _bidding_time

Вбудовані функції

На додаток до змінних та функцій, які ви визначаєте у вашому договорі, є ще деякі спеціальні вбудовані функції. Найбільш наочний приклад:

  • address.send() – Solidity
  • send(address) – Vyper

Вони дозволяють договорам відправляти ETH на інші облікові записи.

Написання функцій

Потреби функцій:

  • змінна параметра та тип (якщо він приймає параметри)
  • оголошення внутрішнього/зовнішньої
  • оголошення чистий/перегляд/платний
  • тип повернення (якщо повертає значення)
1pragma solidity >=0.4.0 <=0.6.0;
2
3contract ExampleDapp {
4 string dapp_name; // змінна стану
5
6 // Викликається під час розгортання контракту та ініціалізує значення
7 constructor() public {
8 dapp_name = "My Example dapp";
9 }
10
11 // Функція Get
12 function read_name() public view returns(string) {
13 return dapp_name;
14 }
15
16 // Функція Set
17 function update_name(string value) public {
18 dapp_name = value;
19 }
20}
Показати все

Повний контракт може виглядати приблизно так. Тут функція constructor надає початкове значення для змінної dapp_name.

Події та журнали

Події дають змогу вашому смарт-контракту обмінюватися даними з інтерфейсом або іншими підписаними застосунками. Після того, як транзакція буде підтверджена та додана до блоку, смарт-контракти можуть генерувати події та реєструвати інформацію, яку фронтенд може потім обробити та використати.

Приклади з коментарями

Деякі приклади написані в Solidity. Якщо ви хочете поекспериментувати з кодом, ви можете взаємодіяти з ним у Remix (opens in a new tab).

Привіт, світе

1// Вказує версію Solidity, використовуючи семантичне версіонування.
2// Дізнайтеся більше: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma
3pragma solidity ^0.5.10;
4
5// Оголошує контракт під назвою `HelloWorld`.
6// Контракт — це набір функцій і даних (його стан).
7// Після розгортання контракт знаходиться за певною адресою в блокчейні Ethereum.
8// Дізнайтеся більше: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html
9contract HelloWorld {
10
11 // Оголошує змінну стану `message` типу `string`.
12 // Змінні стану — це змінні, значення яких постійно зберігаються у сховищі контракту.
13 // Ключове слово `public` робить змінні доступними ззовні контракту
14 // і створює функцію, яку інші контракти або клієнти можуть викликати для доступу до значення.
15 string public message;
16
17 // Подібно до багатьох об'єктно-орієнтованих мов, конструктор — це
18 // спеціальна функція, яка виконується лише під час створення контракту.
19 // Конструктори використовуються для ініціалізації даних контракту.
20 // Дізнайтеся більше: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors
21 constructor(string memory initMessage) public {
22 // Приймає рядковий аргумент `initMessage` і встановлює значення
23 // у змінну `message` у сховищі контракту).
24 message = initMessage;
25 }
26
27 // Публічна функція, яка приймає рядковий аргумент
28 // і оновлює змінну `message` у сховищі.
29 function update(string memory newMessage) public {
30 message = newMessage;
31 }
32}
Показати все

Токен

1pragma solidity ^0.5.10;
2
3contract Token {
4 // `address` можна порівняти з адресою електронної пошти — він використовується для ідентифікації облікового запису в Ethereum.
5 // Адреси можуть представляти смарт-контракт або зовнішні (користувацькі) облікові записи.
6 // Дізнайтеся більше: https://solidity.readthedocs.io/en/v0.5.10/types.html#address
7 address public owner;
8
9 // `mapping` по суті є структурою даних хеш-таблиці.
10 // Це `mapping` присвоює беззнакове ціле число (баланс токенів) адресі (власнику токенів).
11 // Дізнайтеся більше: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types
12 mapping (address => uint) public balances;
13
14 // Події дозволяють реєструвати активність у блокчейні.
15 // Клієнти Ethereum можуть прослуховувати події, щоб реагувати на зміни стану контракту.
16 // Дізнайтеся більше: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events
17 event Transfer(address from, address to, uint amount);
18
19 // Ініціалізує дані контракту, встановлюючи `owner`
20 // як адресу автора контракту.
21 constructor() public {
22 // Усі смарт-контракти покладаються на зовнішні транзакції для запуску своїх функцій.
23 // `msg` — це глобальна змінна, яка містить відповідні дані про дану транзакцію,
24 // наприклад адресу відправника та суму ETH, включену до транзакції.
25 // Дізнайтеся більше: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties
26 owner = msg.sender;
27 }
28
29 // Створює певну кількість нових токенів і надсилає їх на адресу.
30 function mint(address receiver, uint amount) public {
31 // `require` — це керуюча конструкція, яка використовується для забезпечення виконання певних умов.
32 // Якщо вираз `require` має значення `false`, виникає виняток,
33 // який скасовує всі зміни, внесені до стану під час поточного виклику.
34 // Дізнайтеся більше: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions
35
36 // Лише власник контракту може викликати цю функцію
37 require(msg.sender == owner, "You are not the owner.");
38
39 // Встановлює максимальну кількість токенів
40 require(amount < 1e60, "Maximum issuance exceeded");
41
42 // Збільшує баланс `receiver` на `amount`
43 balances[receiver] += amount;
44 }
45
46 // Надсилає певну кількість існуючих токенів від будь-якого викликаючого на адресу.
47 function transfer(address receiver, uint amount) public {
48 // Відправник повинен мати достатньо токенів для надсилання
49 require(amount <= balances[msg.sender], "Insufficient balance.");
50
51 // Коригує баланси токенів двох адрес
52 balances[msg.sender] -= amount;
53 balances[receiver] += amount;
54
55 // Генерує подію, визначену раніше
56 emit Transfer(msg.sender, receiver, amount);
57 }
58}
Показати все

Унікальний цифровий актив

1pragma solidity ^0.5.10;
2
3// Імпортує символи з інших файлів у поточний контракт.
4// У цьому випадку це серія допоміжних контрактів від OpenZeppelin.
5// Дізнайтеся більше: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#importing-other-source-files
6
7import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol";
8import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
9import "../node_modules/@openzeppelin/contracts/introspection/ERC165.sol";
10import "../node_modules/@openzeppelin/contracts/math/SafeMath.sol";
11
12// Ключове слово `is` використовується для успадкування функцій і ключових слів від зовнішніх контрактів.
13// У цьому випадку `CryptoPizza` успадковує контракти `IERC721` та `ERC165`.
14// Дізнайтеся більше: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#inheritance
15contract CryptoPizza is IERC721, ERC165 {
16 // Використовує бібліотеку SafeMath від OpenZeppelin для безпечного виконання арифметичних операцій.
17 // Дізнайтеся більше: https://docs.openzeppelin.com/contracts/2.x/api/math#SafeMath
18 using SafeMath for uint256;
19
20 // Константи-змінні стану в Solidity схожі на інші мови,
21 // але ви повинні присвоювати їм значення з виразу, який є константою на етапі компіляції.
22 // Дізнайтеся більше: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constant-state-variables
23 uint256 constant dnaDigits = 10;
24 uint256 constant dnaModulus = 10 ** dnaDigits;
25 bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
26
27 // Типи Struct дозволяють вам визначати власний тип
28 // Дізнайтеся більше: https://solidity.readthedocs.io/en/v0.5.10/types.html#structs
29 struct Pizza {
30 string name;
31 uint256 dna;
32 }
33
34 // Створює порожній масив структур Pizza
35 Pizza[] public pizzas;
36
37 // Відображення ідентифікатора піци на адресу її власника
38 mapping(uint256 => address) public pizzaToOwner;
39
40 // Відображення адреси власника на кількість токенів у власності
41 mapping(address => uint256) public ownerPizzaCount;
42
43 // Відображення ідентифікатора токена на затверджену адресу
44 mapping(uint256 => address) pizzaApprovals;
45
46 // Ви можете вкладати відображення, цей приклад відображає власника на затвердження оператора
47 mapping(address => mapping(address => bool)) private operatorApprovals;
48
49 // Внутрішня функція для створення випадкової піци з рядка (назва) та ДНК
50 function _createPizza(string memory _name, uint256 _dna)
51 // Ключове слово `internal` означає, що ця функція видима лише
52 // в межах цього контракту та контрактів, що походять від нього
53 // Дізнайтеся більше: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#visibility-and-getters
54 internal
55 // `isUnique` — це модифікатор функції, який перевіряє, чи піца вже існує
56 // Дізнайтеся більше: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html#function-modifiers
57 isUnique(_name, _dna)
58 {
59 // Додає піцу до масиву піц і отримує id
60 uint256 id = SafeMath.sub(pizzas.push(Pizza(_name, _dna)), 1);
61
62 // Перевіряє, чи власник піци такий самий, як і поточний користувач
63 // Дізнайтеся більше: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions
64
65 // зауважте, що address(0) — це нульова адреса,
66 // що вказує на те, що pizza[id] ще не призначена конкретному користувачеві.
67
68 assert(pizzaToOwner[id] == address(0));
69
70 // Відображає піцу на власника
71 pizzaToOwner[id] = msg.sender;
72 ownerPizzaCount[msg.sender] = SafeMath.add(
73 ownerPizzaCount[msg.sender],
74 1
75 );
76 }
77
78 // Створює випадкову піцу з рядка (назва)
79 function createRandomPizza(string memory _name) public {
80 uint256 randDna = generateRandomDna(_name, msg.sender);
81 _createPizza(_name, randDna);
82 }
83
84 // Генерує випадкову ДНК з рядка (назва) та адреси власника (автора)
85 function generateRandomDna(string memory _str, address _owner)
86 public
87 // Функції, позначені як `pure`, обіцяють не читати та не змінювати стан
88 // Дізнайтеся більше: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions
89 pure
90 returns (uint256)
91 {
92 // Генерує випадковий uint з рядка (назва) + адреси (власник)
93 uint256 rand = uint256(keccak256(abi.encodePacked(_str))) +
94 uint256(_owner);
95 rand = rand % dnaModulus;
96 return rand;
97 }
98
99 // Повертає масив піц, знайдених за власником
100 function getPizzasByOwner(address _owner)
101 public
102 // Функції, позначені як `view`, обіцяють не змінювати стан
103 // Дізнайтеся більше: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions
104 view
105 returns (uint256[] memory)
106 {
107 // Використовує місце зберігання `memory` для збереження значень лише на
108 // час життєвого циклу цього виклику функції.
109 // Дізнайтеся більше: https://solidity.readthedocs.io/en/v0.5.10/introduction-to-smart-contracts.html#storage-memory-and-the-stack
110 uint256[] memory result = new uint256[](ownerPizzaCount[_owner]);
111 uint256 counter = 0;
112 for (uint256 i = 0; i < pizzas.length; i++) {
113 if (pizzaToOwner[i] == _owner) {
114 result[counter] = i;
115 counter++;
116 }
117 }
118 return result;
119 }
120
121 // Передає піцу та право власності на іншу адресу
122 function transferFrom(address _from, address _to, uint256 _pizzaId) public {
123 require(_from != address(0) && _to != address(0), "Invalid address.");
124 require(_exists(_pizzaId), "Pizza does not exist.");
125 require(_from != _to, "Cannot transfer to the same address.");
126 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");
127
128 ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);
129 ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);
130 pizzaToOwner[_pizzaId] = _to;
131
132 // Генерує подію, визначену в імпортованому контракті IERC721
133 emit Transfer(_from, _to, _pizzaId);
134 _clearApproval(_to, _pizzaId);
135 }
136
137 /**
138 * Безпечно передає право власності на даний ідентифікатор токена на іншу адресу
139 * Якщо цільова адреса є контрактом, вона повинна реалізовувати `onERC721Received`,
140 * яка викликається під час безпечної передачі, і повертати магічне значення
141 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;
142 * інакше передача скасовується.
143 */
144 function safeTransferFrom(address from, address to, uint256 pizzaId)
145 public
146 {
147 // solium-disable-next-line arg-overflow
148 this.safeTransferFrom(from, to, pizzaId, "");
149 }
150
151 /**
152 * Безпечно передає право власності на даний ідентифікатор токена на іншу адресу
153 * Якщо цільова адреса є контрактом, вона повинна реалізовувати `onERC721Received`,
154 * яка викликається під час безпечної передачі, і повертати магічне значення
155 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;
156 * інакше передача скасовується.
157 */
158 function safeTransferFrom(
159 address from,
160 address to,
161 uint256 pizzaId,
162 bytes memory _data
163 ) public {
164 this.transferFrom(from, to, pizzaId);
165 require(_checkOnERC721Received(from, to, pizzaId, _data), "Must implement onERC721Received.");
166 }
167
168 /**
169 * Внутрішня функція для виклику `onERC721Received` на цільовій адресі
170 * Виклик не виконується, якщо цільова адреса не є контрактом
171 */
172 function _checkOnERC721Received(
173 address from,
174 address to,
175 uint256 pizzaId,
176 bytes memory _data
177 ) internal returns (bool) {
178 if (!isContract(to)) {
179 return true;
180 }
181
182 bytes4 retval = IERC721Receiver(to).onERC721Received(
183 msg.sender,
184 from,
185 pizzaId,
186 _data
187 );
188 return (retval == _ERC721_RECEIVED);
189 }
190
191 // Спалює піцу — повністю знищує токен
192 // Модифікатор функції `external` означає, що ця функція є
193 // частиною інтерфейсу контракту, і інші контракти можуть її викликати
194 function burn(uint256 _pizzaId) external {
195 require(msg.sender != address(0), "Invalid address.");
196 require(_exists(_pizzaId), "Pizza does not exist.");
197 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");
198
199 ownerPizzaCount[msg.sender] = SafeMath.sub(
200 ownerPizzaCount[msg.sender],
201 1
202 );
203 pizzaToOwner[_pizzaId] = address(0);
204 }
205
206 // Повертає кількість піц за адресою
207 function balanceOf(address _owner) public view returns (uint256 _balance) {
208 return ownerPizzaCount[_owner];
209 }
210
211 // Повертає власника піци, знайденого за id
212 function ownerOf(uint256 _pizzaId) public view returns (address _owner) {
213 address owner = pizzaToOwner[_pizzaId];
214 require(owner != address(0), "Invalid Pizza ID.");
215 return owner;
216 }
217
218 // Дозволяє іншій адресі передавати право власності на піцу
219 function approve(address _to, uint256 _pizzaId) public {
220 require(msg.sender == pizzaToOwner[_pizzaId], "Must be the Pizza owner.");
221 pizzaApprovals[_pizzaId] = _to;
222 emit Approval(msg.sender, _to, _pizzaId);
223 }
224
225 // Повертає затверджену адресу для конкретної піци
226 function getApproved(uint256 _pizzaId)
227 public
228 view
229 returns (address operator)
230 {
231 require(_exists(_pizzaId), "Pizza does not exist.");
232 return pizzaApprovals[_pizzaId];
233 }
234
235 /**
236 * Приватна функція для скасування поточного затвердження для даного ідентифікатора токена
237 * Скасовується, якщо вказана адреса насправді не є власником токена
238 */
239 function _clearApproval(address owner, uint256 _pizzaId) private {
240 require(pizzaToOwner[_pizzaId] == owner, "Must be pizza owner.");
241 require(_exists(_pizzaId), "Pizza does not exist.");
242 if (pizzaApprovals[_pizzaId] != address(0)) {
243 pizzaApprovals[_pizzaId] = address(0);
244 }
245 }
246
247 /*
248 * Встановлює або скасовує затвердження для даного оператора
249 * Оператору дозволено передавати всі токени відправника від його імені
250 */
251 function setApprovalForAll(address to, bool approved) public {
252 require(to != msg.sender, "Cannot approve own address");
253 operatorApprovals[msg.sender][to] = approved;
254 emit ApprovalForAll(msg.sender, to, approved);
255 }
256
257 // Повідомляє, чи затверджений оператор даним власником
258 function isApprovedForAll(address owner, address operator)
259 public
260 view
261 returns (bool)
262 {
263 return operatorApprovals[owner][operator];
264 }
265
266 // Приймає право власності на піцу — тільки для затверджених користувачів
267 function takeOwnership(uint256 _pizzaId) public {
268 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");
269 address owner = this.ownerOf(_pizzaId);
270 this.transferFrom(owner, msg.sender, _pizzaId);
271 }
272
273 // Перевіряє, чи існує піца
274 function _exists(uint256 pizzaId) internal view returns (bool) {
275 address owner = pizzaToOwner[pizzaId];
276 return owner != address(0);
277 }
278
279 // Перевіряє, чи є адреса власником, чи затверджена для передачі піци
280 function _isApprovedOrOwner(address spender, uint256 pizzaId)
281 internal
282 view
283 returns (bool)
284 {
285 address owner = pizzaToOwner[pizzaId];
286 // Вимкнути перевірку solium через
287 // https://github.com/duaraghav8/Solium/issues/175
288 // solium-disable-next-line operator-whitespace
289 return (spender == owner ||
290 this.getApproved(pizzaId) == spender ||
291 this.isApprovedForAll(owner, spender));
292 }
293
294 // Перевіряє, чи піца є унікальною та ще не існує
295 modifier isUnique(string memory _name, uint256 _dna) {
296 bool result = true;
297 for (uint256 i = 0; i < pizzas.length; i++) {
298 if (
299 keccak256(abi.encodePacked(pizzas[i].name)) ==
300 keccak256(abi.encodePacked(_name)) &&
301 pizzas[i].dna == _dna
302 ) {
303 result = false;
304 }
305 }
306 require(result, "Pizza with such name already exists.");
307 _;
308 }
309
310 // Повертає, чи є цільова адреса контрактом
311 function isContract(address account) internal view returns (bool) {
312 uint256 size;
313 // Наразі немає кращого способу перевірити, чи є контракт за адресою,
314 // ніж перевірити розмір коду за цією адресою.
315 // Дивіться https://ethereum.stackexchange.com/a/14016/36603
316 // для отримання більш детальної інформації про те, як це працює.
317 // TODO Перевірити це ще раз перед випуском Serenity, оскільки тоді всі адреси будуть
318 // контрактами.
319 // solium-disable-next-line security/no-inline-assembly
320 assembly {
321 size := extcodesize(account)
322 }
323 return size > 0;
324 }
325}
Показати все

Для подальшого читання

Перевірте документацію Solidity і Vyper's для більш повного огляду смарт-контрактів:

Чи була ця стаття корисною?