Ethereum Hosted Code and Transaction Formatting

Hosted Code

Every time you send a token to another user, the target address of your transaction is not the address receiving the tokens. When an address sends a transaction to move tokens, the target address is (almost) always an automated address that hosts ERC20-compliant code. What is really happening is that the automated address runs a function that subtracts balance from your token count and adds it to the recipient’s.

Below is the structure of a simple ERC20 token code, as written by the Consensys team. Being regarded as common simple code, it is a good starting point to understand Solidity structure.

ERC20 Interface

Compiler

The very first line that is not a comment (which are lines preceded by //) is the directive that says what version of the language is being used. The format is 𝚙𝚛𝚊𝚐𝚖𝚊 𝚜𝚘𝚕𝚒𝚍𝚒𝚝𝚢 ^𝟶.𝚡.𝚡. This is the compiler version used to turn the code into an executable binary. In general, hosted code should use the latest available stable version, since vulnerabilities found in older versions are usually patched on the newer ones.

Contract

The line that starts with the 𝚌𝚘𝚗𝚝𝚛𝚊𝚌𝚝 keyword begins a block that describes all the capabilities that the automated address will have. The block begins with the format 𝚌𝚘𝚗𝚝𝚛𝚊𝚌𝚝 𝙴𝚁𝙲𝟸𝟶 { … }. Inside the code block 4 different types of things can be described.

Interfaces Variables Events Functions

Interfaces. These are single lines of code that work as a template. Interfaces have a format like 𝚏𝚞𝚗𝚌𝚝𝚒𝚘𝚗 𝚏𝚞𝚗𝚌𝚝𝚒𝚘𝚗𝙽𝚊𝚖𝚎();. They start with the keyword 𝚏𝚞𝚗𝚌𝚝𝚒𝚘𝚗 and end with a semicolon. In order to deploy valid code, every specified interface needs to have an implementation counterpart.

Variables. The storage part of the code, variables hold values that persist over time. A variable that users modify every day is the balance storage of token addresses. Every time someone sends tokens, the balance variable adds and subtracts from the corresponding addresses.

Events. While events are useful for DApp developers, they don’t actually affect the final result of the execution. Events are a way to tell nodes that a certain line was reached, so hosted code can tell the node that a transfer was made and under what conditions e.g. from whom to whom and what amount.

Functions. The most important part of the hosted code, functions contain the steps to be followed when executed. Function code is written inside a block, which should contain all the necessary logic to do whatever it is supposed to do. As an example, a possible implementation of the transfer interface could be done like so:

function transfer(address _to, uint256 _value) public returns (bool success) {

require(balances[msg.sender] >= _value); // check

balances[msg.sender] -= _value; // deduct

balances[_to] += _value; // credit emit Transfer(msg.sender, _to, _value); // signal the transfer

return true;

}

Inside function blocks everything comes together, the interface, variables, events, and other functions. In this case, when you send a transaction to the automated address hosting the code above, and ask it to run the transfer function, the following things happen in order:

You create and send the transaction, with the target address being the automated address hosting the code. In the input data you also need to specify which function you want to run and what values it should use. The automated address receives the input data and looks for the matching function. If everything checks out, the code requested is executed. The code execution starts from the top, and moves down, line by line. First it makes sure that you aren’t trying to send more tokens than you actually have. Then the amount you requested is deducted from your balance. Afterwards, the receiver’s balance is credited the amount that you were deducted, and the code execution ends.

We can look at a dissected transaction using Etherscan.

Token Transaction Example

Interpreted Input Data

This transaction was created by the standard address 𝟶𝚡𝚍𝟽…𝚋𝚌𝟺. The target address was the automated address 𝟶𝚡𝟺𝚏…𝚌𝚌𝚌. The transaction included 0 ether. The input data was the long hex string 𝟶𝚡𝚊𝟿…𝟶𝚌𝟺.

The input data was probably filled in behind the curtains by the wallet you used to send the transaction. If we interpret the input data, we can extract the function that you wanted to run, in this case transfer, by identifying its ID: calculated to be 𝟶𝚡𝚊𝟿𝟶𝟻𝟿𝚌𝚋𝚋. (This is how you tell the network which function you want to run when you broadcast the transaction data.) The next values are the encoded address that received the tokens and the token amount you wanted to send. It would be very impractical for users to constantly have to calculate the IDs of the functions and the payload format. It is no wonder that websites like MEW grew so quickly and became a core aspect of Ethereum’s adoption. These websites or wallets calculate the input data silently, so you as a user only have to write the “real” recipient of the tokens and the amount to send.