Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I send ether and data from a smart contract to an EOA?

I'm trying to create a "real" transaction from inside a smart contract to an EOA. This is so that I can attach data/input_data to send to it.

I've read several resources on this but I've come to contradictory information: some say it's impossible, some say that call() can achieve this. I've been testing multiple methods and have not come to see that it is possible.

Here's a simple example of what I'm trying to achieve:

pragma solidity 0.8.6;

contract Simple {
    uint32 value;
    constructor() payable {
        // Contract is initialized with 0.5 ether
        value = 22;
    }

    function foo() public {
        require(address(this).balance >= 0.1 ether);
        // Along with transfering ether, I want to send some data to the EOA,
        // for example, whichever value is in the variable "value"
        payable(msg.sender).transfer(0.1 ether);
    }
}

On a "normal" transaction, it is possible to set the field "input data" (normally used to make function calls when sending a transaction to a smart contract), which allows us to send data on a transaction from an EOA to another EOA. I was able to achieve this already.

But, from my understanding, contracts "can't" create transactions; they only create "internal transactions" (informal name) that are associated with the "parent transaction" (transaction that called the contract in the first place) and therefore don't have the data field. But they're able to call another contract on the network, so I assume they're able to send some data along the network, right?

Furthermore, this question seems to imply that the low level call() method is able to achieve this. I've tried multiple approaches but have not been able to reproduce the wanted behaviour.

msg.sender.call{value: 0.1 ether}("data", value); // Doesn't work
msg.sender.call{value: 0.1 ether}(value); // Doesn't work
msg.sender.call{value: 0.1 ether}(abi.encodeWithSignature(value)) // Doesn't work

At some point, I did find my message on a block's "extra data", but from my understanding, this was written there by the miner for some reason.

So, to sum it up, is it possible to, from a contract, send ether + message to an EOA account? How would I achieve this?

Edit: Fixed the function name, which was a reserved keyword.

like image 922
Pedro Perpétua Avatar asked Oct 16 '25 05:10

Pedro Perpétua


1 Answers

function msg() public {

This function name is a bit problematic, because you're overriding the global msg variable, and can't use the msg.sender.

So I changed the function name to generic foo().

function foo() public {

msg.sender.call{value: 0.1 ether}

Since Solidity 0.8, an address is not payable by default (source: docs). So if you want to send them the native currency (in case of Ethereum, that's ETH), you need to cast the address to payable first.

payable(msg.sender).call{value: 0.1 ether}

Finally to the data sending part.

At some point, I did find my message on a block's "extra data", but from my understanding, this was written there by the miner for some reason.

I'm not exactly sure, but it seems like you stumbled upon the correct field, which is simply the data field of the raw transaction, and the blockchain explorer probably named it "extra data". The data field is not filled by the miner, but by the transaction creator.

Since you're sending an integer, and the data field is bytes (array of bytes), you need to encode it to bytes. In your case:

abi.encode(value)

To you put it all together:

pragma solidity 0.8.6;

contract Simple {
    uint value;
    constructor() payable {
        value = 22;
    }

    function foo() public {
        require(address(this).balance >= 0.1 ether);
        payable(msg.sender).call{value: 0.1 ether}(abi.encode(value));
    }
}

When you execute the foo() function (and the contract has enough funds), it will create an internal transaction (some blockchain explorers might use a different name) to the msg.sender with value 0.1 ether and the decimal 22 encoded as hex 16 in the data field.

like image 172
Petr Hejda Avatar answered Oct 18 '25 23:10

Petr Hejda