tip-173.md

July 2, 2026 · View on GitHub

tip: 173
title: Contract Ownership Standard
description: A standard interface for ownership of contracts
author: yanghang8612@gmail.com
discussions-to: https://github.com/tronprotocol/tips/issues/878
status: Final
type: Standards Track
category: TRC
created: 2026-05-21

Abstract

This specification defines standard functions for owning or controlling a contract.

An implementation allows reading the current owner (owner() returns (address)) and transferring ownership (transferOwnership(address newOwner)) along with a standardized event for when ownership is changed (OwnershipTransferred(address indexed previousOwner, address indexed newOwner)).

Motivation

Many smart contracts require that they be owned or controlled in some way. For example to withdraw funds or perform administrative actions. It is so common that the contract interface used to handle contract ownership should be standardized to allow compatibility with user interfaces and contracts that manage contracts.

Here are some examples of kinds of contracts and applications that can benefit from this standard:

  1. Exchanges that buy/sell/auction TRON contracts. This is only widely possible if there is a standard for getting the owner of a contract and transferring ownership.
  2. Contract wallets that hold the ownership of contracts and that can transfer the ownership of contracts.
  3. Contract registries. It makes sense for some registries to only allow the owners of contracts to add/remove their contracts. A standard must exist for these contract registries to verify that a contract is being submitted by the owner of it before accepting it.
  4. User interfaces that show and transfer ownership of contracts.

Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

Every TRC-173 compliant contract must implement the TRC173 interface. Contracts should also implement TRC165 for the TRC-173 interface.


/// @title TRC-173 Contract Ownership Standard
///  Note: the TRC-165 identifier for this interface is 0x7f5828d0
interface TRC173 /* is TRC165 */ {
    /// @dev This emits when ownership of a contract changes.    
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /// @notice Get the address of the owner    
    /// @return The address of the owner.
    function owner() view external returns(address);
	
    /// @notice Set the address of the new owner of the contract
    /// @dev Set _newOwner to address(0) to renounce any ownership.
    /// @param _newOwner The address of the new owner of the contract    
    function transferOwnership(address _newOwner) external;	
}

interface TRC165 {
    /// @notice Query if a contract implements an interface
    /// @param interfaceID The interface identifier, as specified in TRC-165
    /// @dev Interface identification is specified in TRC-165. 
    /// @return `true` if the contract implements `interfaceID` and
    ///  `interfaceID` is not 0xffffffff, `false` otherwise
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
}

The owner() function may be implemented as pure or view.

A view implementation is RECOMMENDED for any contract that implements transferable ownership — i.e., any contract that may emit a non-construction OwnershipTransferred. The pure form is permitted to accommodate constant-owner implementations where the owner address is hardcoded into the bytecode (for example, factory-deployed contracts with a baked-in deployer, or contracts where ownership is intentionally non-transferable). A pure owner-getter combined with a functional transferOwnership is a contradiction and SHOULD NOT be implemented. Indexers and explorers SHOULD treat both forms as compliant and SHOULD flag pure implementations as having immutable ownership for user clarity.

The transferOwnership(address _newOwner) function may be implemented as public or external.

To renounce any ownership of a contract set _newOwner to the zero address: transferOwnership(address(0)). If this is done then a contract is no longer owned by anybody.

Compliant contracts MUST emit OwnershipTransferred(address(0), initialOwner) exactly once during construction — or, for clones and proxy patterns such as TRC-1167 where no constructor runs, during the equivalent initialization step — before any state-changing function becomes callable. Subsequent ownership changes (including renouncement via transferOwnership(address(0))) are covered by the standard transfer-event rule above.

Optional Extensions

The following patterns are commonly layered on top of the minimal core defined above. They are non-normative and do not affect TRC-173 compliance; they are listed here so implementers and tools converge on the same names where possible.

Two-step ownership transfer. An optional companion interface that replaces the immediate semantics of transferOwnership with a propose-then-accept flow: transferOwnership(newOwner) records a pending owner (readable via pendingOwner()), and the transfer takes effect only once that address calls acceptOwnership() — analogous to OpenZeppelin's Ownable2Step. This is the RECOMMENDED safe-transfer pattern when the risk of transferring ownership to a wrong or uncontrolled address is a concern. Because it changes the meaning of transferOwnership and adds new functions, it is exposed as a separately-identified TRC-165 interface rather than being folded into TRC-173.

Explicit renounceOwnership(). A separate, no-argument function reserved exclusively for renouncing ownership, as an alternative (or complement) to passing address(0) to transferOwnership. An explicit function makes the irreversible intent unmistakable on the call site. This is an optional implementation choice and is not part of TRC-173 compliance.

Rationale

Key factors influencing the standard:

  • Keeping the number of functions in the interface to a minimum to prevent contract bloat.
  • Backwards compatibility with existing contracts.
  • Simplicity
  • Gas efficient

Several ownership schemes were considered. The scheme chosen in this standard was chosen because of its simplicity, low gas cost and backwards compatibility with existing contracts.

Here are other schemes that were considered:

  1. Associating an Ethereum Name Service (ENS) domain name with a contract. A contract's owner() function could look up the owner address of a particular ENS name and use that as the owning address of the contract. Using this scheme a contract could be transferred by transferring the ownership of the ENS domain name to a different address. Short comings to this approach are that it is not backwards compatible with existing contracts and requires gas to make external calls to ENS related contracts to get the owner address.
  2. Associating a TRC-721-based non-fungible token (NFT) with a contract. Ownership of a contract could be tied to the ownership of an NFT. The benefit of this approach is that the existing TRC-721-based infrastructure could be used to sell/buy/auction contracts. Short comings to this approach are additional complexity and infrastructure required. A contract could be associated with a particular NFT but the NFT would not track that it had ownership of a contract unless it was programmed to track contracts. In addition handling ownership of contracts this way is not backwards compatible.

This standard does not exclude the above ownership schemes or other schemes from also being implemented in the same contract. For example a contract could implement this standard and also implement the other schemes so that ownership could be managed and transferred in multiple ways. This standard does provide a simple ownership scheme that is backwards compatible, is light-weight and simple to implement, and can be widely adopted and depended on.

This standard can be (and has been) extended by other standards to add additional ownership functionality.

Security Considerations

If the address returned by owner() is an externally owned account then its private key must not be lost or compromised.

Calling transferOwnership(address(0)) permanently renounces ownership and is irreversible. Implementations MAY add safeguards such as a separate renounceOwnership() function (see Optional Extensions), a two-step confirmation, or rejecting address(0) in transferOwnership to reduce the risk of accidental loss of contract control.

Ownership of a TRC-173 contract by a multi-signature account — whether via TRON's native multi-signature account system (TIP-16, TIP-105) or via a multi-sig smart-contract wallet — is supported as an implementation choice and requires no specification change. TRC-173 standardizes only the contract-facing msg.sender == owner() check; how the owning account is itself authorized is outside the scope of this interface. Wallets and explorers MAY surface the underlying TRON account-permission structure for UX, but doing so is not a normative requirement.

Backwards Compatibility

Many existing contracts already implement this standard.

Copyright and related rights waived via CC0.