How to Send Ethereum to Message Sender in Solidity?

To send Ether back to the address that called your contract, convert msg.sender to a payable address and use call with a value. The withdrawal function must update its accounting before the external payment, then reject a failed transfer.

Send Ether to msg.sender with call

A payable function can receive Ether, and msg.value tells you how much arrived with that call. In a withdrawal, payable(msg.sender).call{value: amount}(“”) sends an amount from the contract balance to the caller.

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

contract SenderPayout {
    mapping(address => uint256) public credit;

    function deposit() external payable {
        credit[msg.sender] += msg.value;
    }

    function withdraw(uint256 amount) external {
        require(amount <= credit[msg.sender], "insufficient credit");
        credit[msg.sender] -= amount;

        (bool sent, ) = payable(msg.sender).call{value: amount}("");
        require(sent, "Ether transfer failed");
    }
}

Why payable(msg.sender) is required

Because msg.sender identifies the immediate caller as an address, payable(msg.sender) gives it the payable type used by the value transfer expression while the call result reports whether the recipient accepted the payment attempt.

What the success flag means

The low-level call returns a boolean and returned data, so require the boolean because a receiving contract can revert, reject the transfer, or fail while running its receive or fallback function.

Compile the contract

I compiled this contract with solc 0.8.36 and ran a local withdrawal check. The check deposited 1 ETH, withdrew 0.4 ETH, then confirmed that both the caller credit and contract balance were 0.6 ETH.

node compile.js

The compiler should report the SenderPayout contract and its credit, deposit, and withdraw functions.

Terminal output compiling the SenderPayout Solidity contract with solc
The compiled contract exposes credit, deposit, and withdraw.

Protect a withdrawal function before sending Ether

By updating credit before the external call, the function follows the checks-effects-interactions approach and prevents a recipient that calls back into withdraw from spending the same recorded credit again.

Reentrancy changes the order of operations

An Ether payment can execute code in the receiving contract, and a function that decreases credit after calling the recipient lets a callback observe the old balance and attempt another withdrawal.

The receiving address can reject the payment

Keep the failed-transfer check and design a recovery path when your application must handle a recipient that reverts, because a successful compile does not guarantee that every recipient accepts Ether.

When msg.sender is not the address you mean

msg.sender is the immediate caller, not always the end user. A router, multisignature wallet, or another contract becomes msg.sender when it calls your function, so choose an explicit recipient parameter when your payout should target a different address.

Frequently asked questions

The payment line is small, but the surrounding accounting and caller model decide whether it fits your contract.

Conclusion

Use payable(msg.sender).call{value: amount}(“”) when the caller should receive Ether, check its success flag, and reduce the caller credit before the payment. Compile the sample, then replace its simple credit mapping with the access rule and accounting model your contract needs.

Aneesha S
Aneesha S

Aneesha S writes practical guides to MongoDB, Mongoose, and Node.js. Her articles cover document queries and updates, file operations, and HTTP requests.

Articles: 169