• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

How ETH Is Received in Smart Contracts

Sascha Оффлайн

Sascha

Заместитель Администратора
Команда форума
Администратор
Регистрация
9 Май 2015
Сообщения
1,483
Баллы
155


Smart contracts on Ethereum can receive ETH directly. But what actually happens when someone sends ETH to a contract? And why do some transactions fail silently while others go through?

Let’s dive deep into how Ether is handled in Solidity, the differences between receive() and fallback(), and some key developer mistakes you should avoid.

ETH Transfers 101


When you send ETH to a contract, one of two functions will be triggered based on the context:

  • receive() external payable
  • fallback() external payable

These are special functions in Solidity that aren’t called directly in code. They get triggered under very specific circumstances.

When Does receive() Run?


The receive() function runs when:

  1. A contract receives ETH with empty calldata
  2. The receive() function is marked payable

Example:


receive() external payable {
emit Received(msg.sender, msg.value);
}




If someone calls the contract with just ETH (e.g., using .transfer() or sending ETH directly via MetaMask), this function will run.

Use case: Simple ETH deposits with no logic or function calls.

When Does fallback() Run?


The fallback() function is more general. It runs when:

A function is called that doesn’t exist

OR when calldata is not empty

AND receive() is either not present or doesn’t match


fallback() external payable {
emit FallbackCalled(msg.sender, msg.value, msg.data);
}




You can also define a non-payable fallback if you want to reject ETH:


fallback() external {
revert("ETH not accepted");
}



Common Developer Mistakes

1. Not defining receive() or fallback()


If your contract is meant to accept ETH but has neither, any direct ETH transfer will revert.

Fix: Add at least one payable function (receive() or fallback()).

2. Heavy Logic in Fallbacks


Since fallback functions can get triggered unintentionally, avoid writing logic-heavy operations that might increase gas use or create vulnerabilities.

3. Not Handling msg.data


Sometimes, users (or attackers) send ETH with extra calldata. If you're only using receive(), those transactions will revert. Always consider a fallback for maximum safety.

Real-World Example: Accepting ETH in a Treasury Contract


// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

contract Treasury {
address public owner;

event Received(address sender, uint256 amount);
event FallbackCalled(address sender, uint256 amount, bytes data);

constructor() {
owner = msg.sender;
}

receive() external payable {
emit Received(msg.sender, msg.value);
}

fallback() external payable {
emit FallbackCalled(msg.sender, msg.value, msg.data);
}

function withdraw() external {
require(msg.sender == owner, "Only owner");
payable(owner).transfer(address(this).balance);
}
}




Try sending ETH from your wallet or via Remix — both receive and fallback will log different events based on how the ETH was sent.

What About Vyper?


Vyper handles this similarly but doesn’t use receive() or fallback() keywords directly. It uses:


@external
@payable
def __default__():
# Code here runs on unknown function call or direct ETH




Everything is handled in default, so you must manually manage what to accept and reject.

Best Practices


Always define receive() if your contract is meant to receive ETH directly.

Use a fallback() to catch unexpected calls or ETH sent with data.

Don’t rely on these functions for business logic.

Always emit logs for transparency (emit Received(...)) for off-chain monitoring.

Final Words


Many developers forget to test how their contracts behave with unexpected inputs or ETH sent manually. A missing receive() function can easily break dApps like fundraising contracts, treasuries, or NFT mints.

When building production-grade contracts, always include proper ETH handling, and test them via .call, .transfer, or even raw transactions.

Want me to cover gas optimizations, reentrancy, or cross-chain bridging next? Stay tuned.


Источник:

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу