Loading...
Loading...
returns
и типа данных.pure
.view
.payable
. Полученные средства добавляются к балансу контракта.multiply(5, 3)
, он знает, что получит 15
, но ему не обязательно знать, как именно происходит умножение внутри функции.function setTokenPrice(uint256 newPrice) public returns (bool) { // ↑ ↑ ↑ ↑ // имя параметры модификаторы что возвращает
// тело функции - что она делает. // Здесь – присваивает новое значение переменной состояния tokenPrice = newPrice;
// возвращаемое значение return true;}
function имя_функции(тип_параметра имя_параметра) модификаторы returns (тип_возврата) { // тело функции
// возвращаемое значение return значение;}
calculateArea
лучше, чем просто calc
.»function transferTokens(address to, uint256 amount, string memory reason) public { // ↑ ↑ ↑ // адрес количество причина перевода}
function getBalance(address user) public view returns (uint256) { // ↑ // возвращает число return balances[user];}
contract TokenContract { // Вместо одной огромной функции — много маленьких и понятных function validateTransfer(address from, address to, uint256 amount) internal pure returns (bool) { // Проверка валидности перевода }
function updateBalances(address from, address to, uint256 amount) internal { // Обновление балансов }
function transfer(address to, uint256 amount) public { require(validateTransfer(msg.sender, to, amount), "Invalid transfer"); updateBalances(msg.sender, to, amount); }}
contract GameContract { function calculateDamage(uint256 baseDamage, uint256 multiplier) public pure returns (uint256) { return baseDamage * multiplier / 100; }
function swordAttack(uint256 strength) public pure returns (uint256) { return calculateDamage(strength, 120); // Переиспользуем функцию }
function magicAttack(uint256 intelligence) public pure returns (uint256) { return calculateDamage(intelligence, 150); // И снова переиспользуем }}
view
/pure
) → создают транзакцию, стоят газ, изменения записываются в блокчейн навсегдаcontract Example { uint256 public counter;
// Создает транзакцию! Стоит газ, записывается в блокчейн function increment() public { counter += 1; }
// НЕ создает транзакцию! Бесплатно, выполняется локально function getCounter() public view returns (uint256) { return counter; }}
string
всегда написано string memory
, а у uint256
— нет? Что это за memory
?»storage
— постоянное хранилище (как поле в базе данных) — данные сохраняются в блокчейне навсегдаmemory
— временное хранилище (как оперативная память в компьютере) — данные существуют только во время выполнения функции, в них можно читать и писать временную информациюcalldata
— только для чтения (как компьютерный диск без возможности записи) — данные передаются в функцию, их нельзя изменять и они не сохраняются после выполнения функцииmemory
?memory
нужно указывать только для сложных типов данных:memory
:string
— строкиbytes
— массивы байтовuint256[]
, address[]
и т.д.)struct
)memory
:uint256
, int256
— числаbool
— логические значенияaddress
— адреса// ✅ Правильно - строка требует указания memoryfunction setMessage(string memory newMessage) public { message = newMessage;}
// ✅ Правильно - строка требует указания memory при возвратеfunction getMessage() public view returns (string memory) { return message;}
// ✅ Правильно - простые типы НЕ требуют memoryfunction incrementCounter() public { counter = counter + 1; // uint256 не требует memory}
// ❌ Ошибка - без memory компилятор не поймет, где хранить строкуfunction setMessage(string newMessage) public { // ОШИБКА! message = newMessage;}
public
, private
, internal
, external
) — определяют, откуда можно вызвать функциюview
, pure
, payable
) — определяют, как функция работает с состоянием контрактаpublic
- могут вызвать все// Основные операции с балансом, они могут быть нужны и внутри, и снаружи смарт-контрактаfunction getBalance() public view returns (uint256) { return balance;}
// Перевод средствfunction transfer(address to, uint256 amount) public { // логика перевода}
// Пополнение счётаfunction deposit() public payable { balance += msg.value;}
// Получение информации о контрактеfunction getContractInfo() public view returns (string memory) { return "My Smart Contract";}
private
- может вызвать только функция в том же контракте// Внутренние вычисленияfunction _calculateFee(uint256 amount) private pure returns (uint256) { return amount * 3 / 100; // 3% комиссия}
// Проверка внутренних условийfunction _isValidUser(address user) private view returns (bool) { return userBalances[user] > 0;}
// Сброс внутренних данныхfunction _resetCounters() private { dailyTransactions = 0; weeklyLimit = 1000;}
internal
- может вызвать функция в том же контракте и в наследующих контрактах// Базовая логика переводов, которая может быть расширена наследникамиfunction _transfer(address from, address to, uint256 amount) internal { balances[from] -= amount; balances[to] += amount;}
// Общие проверки, могут быть переиспользованы для дочерних контрактовfunction _validateAmount(uint256 amount) internal pure returns (bool) { return amount > 0 && amount < 1000000;}
// Инициализация для наследуемых контрактовfunction _initialize(address owner) internal { contractOwner = owner; isInitialized = true;}
external
- можно вызвать только из функции в другом контрактеpublic
для больших данных.// Административные функцииfunction emergencyStop() external { require(msg.sender == admin, "Only admin"); paused = true;}
// Функции обратного вызова (callbacks)function onTokenReceived(address from, uint256 amount, bytes calldata data) external { // Вызывается другими контрактами}
// API для внешних вызовов с большими даннымиfunction processLargeData(uint256[] calldata numbers) external { // экономичнее для больших массивов}
public
для функций работает не так, как для переменных!»public
= автоматический геттер, позволяющий прочитать переменную извне контрактаcontract Example { uint256 public counter = 10; // Создается автоматически:
// function counter() public view returns (uint256) { // return counter; // }}
public
= возможность вызова функции извне контракта, пользователями или другими контрактамиcontract Example { function incrementCounter() public { // Можно вызвать извне И изнутри // логика функции }
function internalHelper() internal { // Только изнутри контракта incrementCounter(); // Это работает }}
public
, злоумышленники смогут её вызвать. В то время как неправильная видимость переменной чаще всего приводит лишь к нежелательному раскрытию данных, но не к потере контроля над контрактом.view
- только чтение данных// Получение баланса пользователяfunction getBalance(address user) public view returns (uint256) { return balances[user];}
// Проверка разрешенийfunction isOwner(address user) public view returns (bool) { return user == owner;}
// Получение информации о блокчейнеfunction getCurrentTime() public view returns (uint256) { return block.timestamp;}
// Расчёты на основе текущих данныхfunction calculateInterest(address user) public view returns (uint256) { return balances[user] * interestRate / 100;}
pure
- без обращения к состоянию// Математические вычисленияfunction add(uint256 a, uint256 b) public pure returns (uint256) { return a + b;}
// Расчёт процентовfunction calculateInterest(uint256 amount, uint256 rate) public pure returns (uint256) { return amount * rate / 100;}
// Работа со строкамиfunction concatenate(string memory a, string memory b) public pure returns (string memory) { return string(abi.encodePacked(a, " ", b));}
// Валидация данныхfunction isValidEmail(string memory email) public pure returns (bool) { bytes memory emailBytes = bytes(email); return emailBytes.length > 5; // Упрощённая проверка}
payable
- может получать платежиpayable
отправка ETH приведёт к ошибке.// Пополнение счётаfunction deposit() public payable { balances[msg.sender] += msg.value; // msg.value - отправленная сумма ETH}
// Покупка товараfunction buyItem(uint256 itemId) public payable { require(msg.value >= itemPrices[itemId], "Insufficient payment"); // Логика покупки}
// Донаты с сообщениемfunction donate(string memory message) public payable { require(msg.value > 0, "Donation must be greater than 0"); totalDonations += msg.value;}
// Конструктор может быть payableconstructor() public payable { owner = msg.sender; // Можно отправить ETH при деплое}
Модификатор | Чтение состояния | Изменение состояния | Получение ETH | Стоимость газа | Создание транзакции |
---|---|---|---|---|---|
view | ✅ Да | ❌ Нет | ❌ Нет | 0 (бесплатно) | ❌ Нет |
pure | ❌ Нет | ❌ Нет | ❌ Нет | 0 (бесплатно) | ❌ Нет |
payable | ✅ Да | ✅ Да | ✅ Да | Есть стоимость | ✅ Да |
Обычная | ✅ Да | ✅ Да | ❌ Нет | Есть стоимость | ✅ Да |
pure
для расчётов, view
для проверки балансов, payable
для приёма платежей!»contract TokenSaleVault { uint256 public tokenPrice = 0.001 ether; uint256 public userTokenBalance;
// Pure: мы не читаем переменные состояния function calculateTokens(uint256 ethAmount) public pure returns (uint256) { return ethAmount / 0.001 ether; }
// View: только чтение переменной состояния – balances[user] function getBalance(address user) public view returns (uint256) { return userTokenBalance; }
// Payable: получение платежа и изменение состояния function buyTokens() public payable { require(msg.value > 0, "Send ETH to buy tokens"); uint256 tokens = calculateTokens(msg.value); userTokenBalance += tokens; }
// ...}
contract Example { uint256 private data = 42;
// Комбинация: external + view. Не изменяет состояние и можно вызвать только снаружи function getData() external view returns (uint256) { return data; }
// Комбинация: public + payable. Можно вызывать внутри и снаружи, и функция может принимать ETH function deposit() public payable { // Функция доступна всем И может получать платежи }
// Комбинация: internal + pure. Вызов только изнутри, не читает и не изменяет состояние function helper(uint256 x) internal pure returns (uint256) { return x * 2; }}
function cube(uint256 input) public pure returns (uint256) { // Только вычисляем значение на основе аргументов. Не читаем и не изменяем переменные состояния контракта. uint256 output = input * input * input; return output;}
contract Calculator { uint256 public lastResult;
function getLastResult() public view returns (uint256) { return lastResult; // Только читаем, не изменяем }}
contract Counter { uint256 public count;
function increment() public { count = count + 1; // Изменяем состояние контракта }}
contract Donation { uint256 public totalDonations;
function donate() public payable { totalDonations += msg.value; // Получаем и учитываем платеж }}
// SPDX-License-Identifier: MITpragma solidity ^0.8.0;
contract HelloWorld { string public message = "Привет, мир!";
// Функция для изменения сообщения function setMessage(string memory newMessage) public { message = newMessage; }
// Функция для получения сообщения function getMessage() public view returns (string memory) { return message; }}
setMessage
и изменить сообщение в контракте. Контракт умеет не просто хранить сообщение, но и менять его, а также — возвращать текущее значение.// SPDX-License-Identifier: MITpragma solidity ^0.8.0;
contract Counter { uint256 public counter = 0; // Переменная, которая хранится в блокчейне
function incrementCounter() public { counter = counter + 1; // Пользователи могут увеличить счетчик }}
incrementCounter
и кнопку для ее вызова.incrementCounter
и значение переменной счетчика увеличится на 1.Загрузка...