Address
Introduction
In the world of Ethereum, an address is a primitive data type that is used to represent the intended recipient for a message. This is similar to a postal address, where the label on a letterbox corresponds to the name of the person and their location.
In Ethereum, an address is linked to a public key and is unique due to the use of public key cryptography. The private key is stored in a wallet and is used to control access to any Ether in the account, as well as to sign transactions to spend any funds in the account.
On Ethereum, an address may look like this:0xd8da6bf26964af9d7eed9e03e53415d37aa96045
There are two types of Ethereum addresses:
- Externally Owned Accounts (EOAs)
- Contract Accounts (Smart Contracts).
EOAs are controlled by their private key, while Smart Contracts are controlled by their code. EOA are typically controlled by end users and currently as of March 5th 2023 are the only accounts that can initiate a transaction on Ethereum.
Address Data Type Overview
In Solidity, an address is a 20-byte data type that is specifically designed to hold account addresses in Ethereum. These addresses are 160 bits or 20 bytes in size and can hold both contract addresses and externally owned account addresses. The address is a value type, and it creates a new copy while being assigned to another variable.
There are two variations for the address type introduced after Solidity 0.5.0:
address
: This is the general address type that can hold Ethereum addresses as part of a contract. It cannot be used to send or receive Ether. They are meant for address management within smart contracts but cannot be used for receiving and sending Ether as part of smart contracts.payable address
: These are similar to the address type with the additional capability of receiving as well as sending Ether to other accounts. It has additional methods,send()
andtransfer()
. Since the payable address is a superset of the address type, it can implicitly be converted into a simple address; however, the reverse needs an explicit conversion.
The idea was to make the distinction between addresses that can receive money, and those who can’t and used for other purposes. Simply address payable
can receive Ether, while a regular address
cannot.
pragma solidity 0.8.16;
contract MyContract {
address public owner;
address payable public recipient;
uint public balance;
constructor() {
owner = msg.sender;
recipient = payable(owner);
}
function sendEther() public payable {
balance += msg.value;
}
function transferEther() public {
recipient.transfer(balance);
balance = 0;
}
}
In this smart contract we have:
- a regular address variable
owner
and a payable address variablerecipient
. - The
sendEther()
function allows the contract to receive Ether, which is stored in thebalance
variable. - The
transferEther()
function transfers the accumulated Ether to therecipient
address using thetransfer()
method, which is only available to payable addresses.
Address Data Type Methods and Functions
Payable address methods
The payable address provides the following two functions to transfer Ether and is often used with call
function:
transfer
: The transfer function is used to transfer Ether from the current contract to another address. It is the preferred method for transferring Ether as it raises an exception and returns the Ether to the caller if the transfer fails.send
: The send function is similar to the transfer function, but it returns a Boolean value depending on the successful execution of the Ether transfer.call
: Thecall
function in Solidity is a low-level function that allows contracts to invoke external contracts or execute arbitrary code.call
takes abytes
parameter and returns a boolean value indicating the success or failure of the operation, as well as any output data. Thecall
method also has avalue
field that allows for transferring Ether along with the function call. However, care must be taken when usingcall
as it can be vulnerable to re-entrancy attacks if not used properly. It is generally recommended to use higher-level functions liketransfer
orsend
for transferring Ether.
pragma solidity 0.8.16;
contract PaymentContract {
address payable public recipient;
uint public balance;
constructor(address payable _recipient) {
recipient = _recipient;
}
function sendEther() public payable {
balance += msg.value;
}
function sendWithSend() public {
require(balance > 0, "Insufficient balance.");
recipient.send(balance);
balance = 0;
}
function sendWithTransfer() public {
require(balance > 0, "Insufficient balance.");
recipient.transfer(balance);
balance = 0;
}
function sendWithCall() public {
require(balance > 0, "Insufficient balance.");
(bool success, ) = recipient.call{value: balance}("");
require(success, "Transaction failed.");
balance = 0;
}
}
The address type has a balance property that returns the amount of Ether available with the account and has a few functions for invoking functions in other contracts. It also provides the following three functions for invoking the contract function:
CALL
: The call function is used to call an external function of another contract.DELEGATECALL
: The delegate call function is used to call an external function of another contract but executes it in the context of the current contract. Simply it takes some of the calling contract's information, inputs into the called contracts logic and gets a result.CALLCODE
: The call code function is used to call an external function of another contract but executes it in the context of the current contract's storage and address space.
We will cover these methods in depth later on.
Notable Global Methods That Uses Address
In Solidity, there are special global variables that are used to often to interact with addresses:
msg.sender
is a special global variable that represents the address of the contract caller.msg.value
is another global variable that represents the amount of Ether sent along with a transaction.
These variables can be used in Solidity functions to perform conditional logic or to modify contract state based on the caller's address or the amount of Ether sent.
Here's an example of how to use msg.sender
and msg.value
in a Simple Storage Smart Contract:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
contract SimpleStorage {
address owner;
uint256 storedData;
constructor() {
owner = msg.sender;
}
function set(uint256 x) public payable {
require(msg.sender == owner, "Only the contract owner can set the value.");
require(msg.value == 1 ether, "Please send 1 Ether along with the transaction to set the value.");
storedData = x;
}
function get() public view returns (uint256) {
return storedData;
}
}
In this example:
- the
owner
variable is set tomsg.sender
in the constructor function, ensuring that only the contract owner can call theset
function to modify the stored data. - The
set
function also includes arequire
statement that checks if the caller is the owner of the contract. - Another
require
statement checks if the transaction includes exactly 1 Ether in value. If these conditions are not met, the function will revert and the transaction will fail. - The
get
function simply returns the value stored in the contract, without requiring any special permissions or Ether value.
Using msg.sender
and msg.value
in Solidity functions allows for conditional logic and access control based on the address
of the contract caller and the amount of Ether sent along with a transaction. These global variables are useful tools for building more complex Smart Contracts that can manage access to data and funds on the Ethereum blockchain.
Best Practices for Using Address and Payable Address Data Types
When using address and payable address in Solidity, it is important to follow these best practices:
- Use
payable address
when sending and receiving Ether. - Use
transfer()
for sending Ether as it is the preferred method due to its safety features. - Always check the return values of
send
andtransfer
functions for errors and handle them appropriately. - Be cautious of using
CALL
orDELEGATECALL
to call unknown external contracts as may could be malicious or prone to errors.
Zero Address
When deploying a smart contract on the Ethereum network, a special transaction is used to specify the contract creation. This transaction requires a sender and a recipient address. In the case of contract creation, the recipient address used is known as the zero-address, which is a special address that contains only empty bytes.
The zero-address is like a "fake account" on the Ethereum network. It is still a 20-byte address like any other Ethereum address but has a unique property of containing only 0x0 values.
This makes it easy for:
- the Ethereum Virtual Machine (EVM) to recognize that a transaction with the zero-address as the recipient is meant for creating a new smart contract.
- developers to
burn
tokens by sending them to the zero address no one controls. This can be done with any address that is assured no one controls but usually the zero address suffices.
address()
The address
primitive in Solidity 0.8.16 provides a built-in method called address()
. This method is used to return the address of the contract currently being executed. It is a read-only property that returns a 20-byte address.
The address()
method is often used in Solidity smart contracts for various purposes, such as implementing logic to restrict certain operations to only the contract owner or to check the balance of the contract.
Another interesting use of the address()
method is to check if a contract has been deployed at a specific Ethereum address. To do this, you can use the address(0)
syntax, which returns the zero-address we mentioned earlier. If the result of address(0)
is equal to the address you are checking, it means that there is no contract deployed at that address.
In Solidity 0.8.0 and later versions, the address
primitive has a built-in method called address()
. This method can be used to retrieve the Ethereum address of a contract instance or an externally owned account (EOA).
For example, in the withdraw
function below, the address(this)
statement returns the Ethereum address of the current contract instance.
Suppose you have a contract that allows users to withdraw funds from it. You can use the address()
method to ensure that only the contract owner can withdraw funds by adding a check in the withdraw()
function as follows:
function withdraw(uint amount, address destination) public {
require(msg.sender == owner, "Only the contract owner can withdraw funds");
require(address(this).balance >= amount, "Insufficient balance in the contract");
require(address(destination) != address(0), "Can't send to burn address in this method");
payable(destination).transfer(amount);
}
- The
withdraw
function takes two parameters:amount
anddestination
. It checks if the caller is the owner of the contract, if the contract balance is sufficient to make the withdrawal, and if thedestination
address is not set to the burn address (0x0000000000000000000000000000000000000000). - Then, it uses the
payable
keyword to make thedestination
address payable and transfer the specifiedamount
to it using thetransfer
method. - Note that the
address(0)
value is used to represent the Ethereum burn address, which is a special address that does not have a private key and is used to permanently remove Ether from circulation.
Address Operators
Conclusion
In conclusion, an Ethereum address
is used to represent the intended recipient for a message on the Ethereum network. There are two types of addresses: Externally Owned Accounts (EOAs) and Contract Accounts (Smart Contracts). In Solidity, an address is a 20-byte data type that can hold both contract addresses and externally owned account addresses. There are two variations of the address type introduced after Solidity 0.5.0: address
and payable address
. Payable address can receive Ether, while address cannot.
Best practices include using payable address when sending and receiving Ether, using transfer() for sending Ether, and checking return values of send and transfer functions for errors. The address() method in Solidity 0.8.16 can be used to retrieve the Ethereum address of a contract instance or an externally owned account, and address(0) is used to represent the Ethereum burn address.
Feedback
Have feedback? Found something that needs to be updated, accurate, or explained?
Join our discord and share what can be improved.
Any and all feedback is welcomed.