# ZTP-173

**ZTP-173** is the Zetrix Contract Ownership Standard, inspired by Ethereum's [ERC-173](https://eips.ethereum.org/EIPS/eip-173). It provides a standard interface for querying and transferring ownership of a smart contract on the Zetrix blockchain.

### Overview

| Property     | Detail             |
| ------------ | ------------------ |
| **Standard** | ZTP-173            |
| **Category** | Contract Ownership |
| **Network**  | Zetrix Blockchain  |

### Abstract

ZTP-173 defines a standard interface for **contract ownership** on the Zetrix blockchain. It specifies how a smart contract declares, queries, transfers, and renounces a single owner address enabling block explorers, tooling, and other contracts to interact with ownership in a predictable and interoperable way.

The ownership model follows a **two-step transfer** pattern: the current owner initiates a transfer, and the new owner must explicitly accept it. This prevents accidental or malicious transfers to inaccessible addresses.

### Motivation

Many smart contracts deployed on Zetrix require an administrative owner — an account that can adjust parameters, mint tokens, pause functionality, or manage funds. Without a common interface:

* Block explorers cannot uniformly display or verify contract ownership.
* Tooling cannot generically transfer or renounce ownership across contracts.
* Other contracts cannot safely query the owner of an on-chain resource.
* Security audits cannot follow a predictable, auditable ownership lifecycle.

ZTP-173 solves this by standardising five entry points so every conforming contract exposes the same ownership API, consistent with existing Zetrix contract conventions (`Chain.load`, `Chain.store`, `Chain.tlog`, `contractInfo.issuer`).

### Specification

#### Interface

A ZTP-173-compliant contract **MUST** implement the following functions:

| Function                      | Access     | Description                             |
| ----------------------------- | ---------- | --------------------------------------- |
| `owner()`                     | Public     | Returns the current owner address       |
| `transferOwnership(newOwner)` | Owner only | Initiates a two-step ownership transfer |

#### Functions

**owner**

```javascript
function owner()
```

Returns the address of the current contract owner. Reads from `contractInfo.issuer` stored under the `CONTRACT_PRE` key.

| Items       | Description                                                   |
| ----------- | ------------------------------------------------------------- |
| **Access**  | Public (query)                                                |
| **Returns** | `String` — current owner Zetrix address, or `''` if renounced |
| **Throws**  | Never                                                         |

**transferOwnership**

```javascript
function transferOwnership(newOwner)
```

Initiates a two-step ownership transfer. The proposed new owner must call `acceptOwnership()` to finalise the transfer. This function does **not** immediately change `contractInfo.issuer`.

| Items          | Description                                                                                                |
| -------------- | ---------------------------------------------------------------------------------------------------------- |
| **Access**     | Owner only                                                                                                 |
| **Parameters** | `newOwner` — target Zetrix address                                                                         |
| **Emits**      | `OwnershipTransferStarted(newOwner)`                                                                       |
| **Throws if**  | Caller is not owner; address is invalid or empty; address is same as current owner; address is blacklisted |

#### Invoking the Contract

#### Query — owner

```json
{ "method": "owner" }
```

**Response**

```json
{ "result": "ZTXabc123..." }
```

#### transferOwnership

json

```json
{
  "method": "transferOwnership",
  "params": { "newOwner": "ZTXxyz789..." }
}
```

### Sample Code

```javascript
'use strict';

// ============================================================================
// CONSTANTS
// ============================================================================

const CONTRACT_PRE = 'contract_info';

// ============================================================================
// INTERNAL HELPERS
// ============================================================================

function getOwner() {
  let contractInfo = JSON.parse(Chain.load(CONTRACT_PRE));
  return contractInfo.issuer;
}

function validateOwner() {
  Utils.assert(Chain.msg.sender === getOwner(), 'Only the contract owner can perform this action.');
}

function validateNotBlacklisted(address) {
  // Plug in your blacklist logic here if needed.
  // Example: Utils.assert(!isBlacklisted(address), 'Address is blacklisted.');
}

// ============================================================================
// OWNERSHIP MANAGEMENT (ZTP-173)
// ============================================================================

function owner() {                           
  return getOwner();
}

function transferOwnership(newOwner) {
  validateOwner();
  Utils.assert(                              
    newOwner !== undefined && newOwner.length > 0,
    'New owner address is required.'
  );
  Utils.assert(                              
    Utils.addressCheck(newOwner),
    'New owner address is invalid.'
  );
  validateNotBlacklisted(newOwner);

  let contractInfo  = JSON.parse(Chain.load(CONTRACT_PRE));
  let previousOwner = contractInfo.issuer;
  Utils.assert(previousOwner !== newOwner, 'New owner must be different from current owner.');

  contractInfo.issuer = newOwner;
  Chain.store(CONTRACT_PRE, JSON.stringify(contractInfo));
  Chain.tlog('OwnershipTransferred', previousOwner, newOwner);
  return true;
}

// ============================================================================
// CONTRACT LIFECYCLE
// ============================================================================

function init(input_str) {
  let params = JSON.parse(input_str).params || {};

  Utils.assert(params.name   !== undefined, 'Contract name is required.');
  Utils.assert(params.symbol !== undefined, 'Contract symbol is required.');

  let initialOwner = params.owner || Chain.msg.sender;
  Utils.assert(Utils.addressCheck(initialOwner), 'Invalid initial owner address.');

  let contractInfo = {
    name       : params.name,
    symbol     : params.symbol,
    issuer     : initialOwner,
    createTime : Chain.block.timestamp
  };

  Chain.store(CONTRACT_PRE, JSON.stringify(contractInfo));
  Chain.tlog('OwnershipTransferred', '', initialOwner);
  return true;
}

function main(input_str) {
  let input  = JSON.parse(input_str);
  let method = input.method;
  let params = input.params || {};

  Utils.assert(method !== undefined && method.length > 0, 'Method is required.');

  if (method === 'transferOwnership') {
    return transferOwnership(params.newOwner);
  }

  Utils.assert(false, 'Unknown method: ' + method);
}

function query(input_str) {
  let input  = JSON.parse(input_str);
  let method = input.method;

  Utils.assert(method !== undefined && method.length > 0, 'Query method is required.');

  if (method === 'owner') {
    return JSON.stringify({ result: owner() });   // ✅ owner() now defined
  }

  Utils.assert(false, 'Unknown query method: ' + method);
}

```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.zetrix.com/en/developer-resources/smart-contract/ztp-standard/ztp-173.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
