Перейти к основному содержанию
Change page

Подробнее о смарт-контрактах

Последнее обновление страницы: 23 февраля 2026 г.

Смарт-контракт - это программа, которая запускается на определенном адресе на Ethereum. Они состоят из данных и функций, которые могут выполняться при получении транзакции. Вот обзор того, что представляет из себя смарт-контракт.

Предварительные условия

Сначала убедитесь, что вы прочитали о смарт-контрактах. Эта статья предполагает, что вы уже знакомы с языками программирования, такими как JavaScript или Python.

Данные

Любые данные контракта должны быть присвоены местоположению: либо storage, либо memory. Модифицировать хранилище в смарт контракте - дорогостоящая операция, поэтому вам необходимо подумать заранее, где ваши данные должны храниться.

Хранилища

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

1// Пример Solidity
2contract SimpleStorage {
3 uint storedData; // Переменная состояния
4 // ...
5}
1Пример на Vyper

Если вы уже программировали объектно-ориентированные языки, то вы, скорее всего, будете знакомы с большинством типов. Однако, address может быть для вас в новинку, если вы новичок в разработке на Ethereum.

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

Другие типы включают:

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

Для более подробного объяснения, ознакомьтесь с документацией:

Память

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

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

Переменные среды

В дополнение к переменным, которые вы определяете по вашему контракту, есть некоторые специальные глобальные переменные. Они в основном используются для предоставления информации о блокчейне или текущей транзакции.

Примеры:

СвойствоПеременная состоянияОписание
block.timestampuint256Текущая метка времени начала блоков
msg.senderадресОтправитель сообщения (текущий вызов)

Функции

В наиболее упрощенных терминах функции могут получать информацию или устанавливать информацию в ответ на входящие транзакции.

Существует два типа вызовов функций:

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

Они также могут быть public или private

  • Функции public можно вызывать внутренне из контракта или внешне с помощью сообщений
  • Функции private видны только для контракта, в котором они определены, и не видны в производных контрактах

Функции и переменные состояний могут быть общедоступными или частными

Вот функция обновления переменной состояния по контракту:

1// Пример солидарности
2function update_name(string value) public {
3 dapp_name = value;
4}
  • Параметр value типа string передается в функцию: update_name
  • Она объявлена как public, что означает, что любой может получить к ней доступ
  • Она не объявлена как view, поэтому может изменять состояние контракта

Функции просмотра

Эти функции обещают не изменять состояние данных контракта. Типичными примерами являются функции "получения" - вы можете использовать их, например, для получения баланса пользователя.

1// Пример твердости
2функция balanceOf (address _owner) в публичном представлении возвращает (uint256 _balance) {
3 вернуть 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 example
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 // Функция получения
12 function read_name() public view returns(string) {
13 return dapp_name;
14 }
15
16 // Функция установки
17 function update_name(string value) public {
18 dapp_name = value;
19 }
20}
Показать все

Полный контракт может выглядеть примерно так. Здесь функция constructor задает начальное значение для переменной dapp_name.

События и журналы

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

Примеры с комментариями

Это несколько примеров, написанных на Solidity. Если вы хотите поэкспериментировать с кодом, вы можете взаимодействовать с ним в Remix (opens in a new tab).

Hello world

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 // Добавляет пиццу в массив пицц и получает идентификатор
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 // Возвращает владельца пиццы по идентификатору
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 для более полного обзора смарт-контрактов:

Была ли эта статья полезной?