ERC-173 Contract ownership standard

Final · Other · created 2018-06-07

Unifies how to read who owns a smart contract and how to transfer ownership to another address. Wallets and apps can check and manage the owner of any contract in the same way.

Why it is needed

Many smart contracts need to be owned or controlled by someone in order to withdraw funds or perform administrative tasks. But if the way to check and transfer the owner differs from contract to contract, tools for handling ownership cannot be made general-purpose. The original text gives four examples of why such a standard is needed. Exchanges that buy, sell or auction contracts can operate widely only if there is a standard for reading the owner and transferring ownership. The same applies to contract wallets that hold and move ownership of many contracts. A contract registry needs a standard for verifying that a submitter is the real owner, so that only owners can register or remove their own contracts. User interfaces that show and transfer ownership can also only be built if they assume the same interface. This standard defines a single ownership interface for this compatibility.

What to implement

In depth

Interface structure and ERC-165 identifier

A contract that follows ERC-173 must implement the ERC173 interface. This interface consists of one OwnershipTransferred event and two functions, owner() and transferOwnership(address _newOwner). It is also recommended (should) to implement ERC-165 for the ERC-173 interface. The ERC-165 interface identifier is 0x7f5828d0. supportsInterface(bytes4 interfaceID) returns true if it implements the given interfaceID and that value is not 0xffffffff, and false otherwise. With this value, other contracts or interfaces can check for support before calling the ownership functions.

owner(): owner lookup

owner() is a lookup function that returns the owner's address. It is declared as view external in the interface, but the original text explicitly says it may be implemented as pure. This means an implementation that hardcodes the owner in the code instead of reading it from a state variable is also allowed. The return value is a single address, and an exchange or registry can compare it with the caller's address to decide whether the submitter is the owner.

transferOwnership(): transfer and renounce

transferOwnership(address _newOwner) sets the new owner address of the contract. It is declared as external in the interface, but may be implemented as public. To renounce ownership, call transferOwnership(address(0)) with the zero address as _newOwner. This leaves the contract with no owner. The original text defines only the function signature and the meaning of its behavior, and does not specify an access control scheme for who may call this function.

OwnershipTransferred event

OwnershipTransferred(address indexed previousOwner, address indexed newOwner) is emitted when ownership of a contract changes. Both parameters are declared indexed, so you can filter the logs for ownership changes that a given address handed over or received. The original text says a contract should also emit this event when it is created. That way the first owner can be identified from the event record alone.

Rationale: minimal functions, backward compatibility, gas efficiency

The standard weighed four key factors: keeping the number of interface functions to a minimum so contracts do not become bloated, backward compatibility with existing contracts, simplicity, and gas efficiency. After reviewing several ownership schemes, the authors chose the current one because it is simple, has low gas cost, and is compatible with existing contracts. This standard does not rule out other ownership schemes. A single contract can implement this standard together with other schemes, so ownership can be managed and transferred through multiple paths. The original text also notes that other standards can extend this one to add ownership features, and that this has in fact happened.

Approaches considered but not adopted

The first links an ENS (Ethereum Name Service) domain name to the contract. owner() looks up the owner address of a specific ENS name and treats it as the contract owner, so transferring ownership of the ENS name also transfers the contract. Its drawbacks are that it is not compatible with existing contracts and that getting the owner address requires an external call to ENS-related contracts, which costs gas. The second links an ERC-721 based NFT (non-fungible token) to the contract. Its advantage is that existing ERC-721 infrastructure can be used to buy, sell or auction the contract, but it requires added complexity and extra infrastructure. Unless the NFT is separately programmed to track the contract, the NFT side does not know that it owns the contract, and this approach is also not backward compatible.

Backward compatibility and proposal status

The original text states that many existing contracts already implement this standard. This is also why the standard treats backward compatibility with existing contracts as a key factor. This standard belongs to the ERC category of the Standards Track and its status is Final. It was created on June 7, 2018, and the authors are Nick Mudge and Dan Finlay. Because the status is Final, the specification is settled and will not change further.

Things to watch out for

Original ERC · ← ERCs