One of the most important thing to note is that every state change in Ethereum is triggered by a transaction, and such transaction has a payload which is contained in two fields: value and data.
Transactions can have both value and data, only value, only data, or neither value nor data. All four combinations are valid in the Ethereum Protocol. In this article, we will look at transaction payload(value and data) and how they are useful for contract/function invocation.
An Ethereum transaction with payload can be contained in two field as stated above and it is majorly meant for invocation of contract function and payment respectively. A transaction with only value is a payment. A transaction with only data is an invocation. A transaction with both value and data is both a payment and an invocation. A transaction with neither value nor data — well that’s probably just a waste of gas! But it is still possible.
An example of that below in ethers js
- Transaction with value
- Transaction with both data payload and value
- Transaction with neither of both
Other Technical details about Payload
There are quite a number of things that happens when you construct an Ethereum transaction that contains value or data. We would would be looking at both instances below:
In a case where transaction payload with value is sent to an EOA address, Ethereum will record a state change, adding the value you sent to the balance of the address.
In a case where transaction payload with value is sent to a contract, then the EVM will execute the contract and will attempt to call the function named in the data payload of your transaction. If there is no data in your transaction, the EVM will call a fallback function and, if that function is payable, will execute it to determine what to do next. If there is no fallback function, then the effect of the transaction will be to increase the balance of the contract, exactly like a payment to a wallet.
- When your transaction payload contains data and it is sent to an EOA address, interpretation of the data is up to the wallet you use to access the EOA. Most wallets ignore any data received in a transaction to an EOA they control. That doesn’t mean you cannot send a data payload to an EOA — that is completely valid in the Ethereum protocol.
- When your transaction payload contains data and it's been sent to a contract address, in this case, data will be interpreted by the EVM as a contract invocation. Most contracts use this data more specifically as a function invocation, calling the named function and passing any encoded arguments to the function. This takes us to understanding data payload and how it works in details.
The data payload sent to a contract is a hex-serialized encoding of:
- The function selector: The first 4 bytes of the Keccak-256 hash of the function’s prototype. This allows the contract to clearly identify which function you wish to invoke.
- The function arguments: The function’s arguments, encoded according to the rules for the various elementary types defined in the ABI specification.
Let take a practical look or approach to what these things implies by an example below:
In the Ethereum space, token contract conforms to a standard called ERC20 standard and for example sake, we would generate a data payload to transfer 10 Pikatic on Polygon Mainnet to a recipient address.
First of all, we will need to get the function selector. For ERC20 token interface, transfer function has following signature :
Let’s calculate Keccak-256 hash of this function signature :
const hash = await ethers.utils.keccak256(utils.toUtf8Bytes("transfer(address,uint256)"));
hash returns 0xa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b in which the function selector is the first four bytes a9059cbb
Now, let’s calculate argument values. First we will calculate recipient address value 0x2792f4C16F124942886DF20f3C5B4c2cB195aEe2. Since address is already hex-serialized, we don’t have to encode it. We will have to pad it to 32 bytes though.
0x0000000000000000000000002792f4C16F124942886DF20f3C5B4c2cB195aEe2 (after padding to 32 bytes)
Now, next let’s encode second parameter to a hex value. Here we want to transfer 10 PIKATIC tokens. And since PIKATIC has 18 decimal units (just like 1 Ether = 10¹⁸ Wei), our value in uint format is 1000000000000000000 (10¹⁸).
const bigNum = ethers.BigNumber.from("10000000000000000000") console.log(bigNum.toHexString()); "0x8ac7230489e80000" "0x0000000000000000000000000000000000000000000000008ac7230489e80000" (after padded to 32 bytes)
So, now we have all the data needed to construct our data payload. Next step is to concatenate data generated from all 3 steps above together :
Function Selector + Function Argument(s)
This gives us our data payload -
Function Selector = a9059cbb,
First Argument = 000000000000000000000000337c67618968370907da31dAEf3020238D01c9de,
Second Argument = 0000000000000000000000000000000000000000000000008ac7230489e80000.
Data payload = Function Selector + First Argument + Second Argument
which gives us
Lets try to send this raw transaction with data payload with MyEtherWallet
In the above image, I have added our generated data as data payload and then sending this transaction to PIKATIC token contract. The next thing is to verify the contract below
Once, transaction is sent and confirmed, 10 PIKATIC tokens are transferred to receiver address.
Lets look at the transaction receipts on our block explorer.
Voila!! our data payload is displayed in Input Data field and transaction have been successfully mined on Polygon.
In conclusion, I hope this article helped you understand transaction payload and it's importance to contract invocation on the Ethereum Protocol. If you have any comments or suggestion, do well to comment below. Thanks!!