GitHub Logo HIP-857: NFT Allowances REST API

Author Mugdha Goel
Working Group Steven Sheehy, Ashe Oro
Requested By Hashpack and Zuse Marketplace
Discussions-To https://github.com/hashgraph/hedera-improvement-proposal/discussions/858
Status Accepted
Needs Council Approval Yes
Review period ends Thu, 01 Feb 2024 07:00:00 +0000
Type Standards Track
Category Mirror
Created 2023-12-07
Updated 2024-02-15

Abstract

Hedera customers have requested the ability to view their current NFT allowances. Hence, we propose adding a new mirror node REST API /api/v1/accounts/{id}/allowances/nfts to return this information.

Motivation

NFT marketplaces have requested the ability to view a NFT allowance’s details via an API.

Rationale

There have been requests to enable querying spending approvals for NFTs based on the owner ID. Additionally, there is a request to be able to query by the spender ID as well. It was also asked for the ability to know whether the approval was given via approveForAll or not. This information was requested by HashPack and Zuse marketplace.

The API described below has been chosen to make the implementation easier for NFT explorers and marketplaces that wish to search NFT allowances based on the owner and spender. The decision to design one API for both use cases is aimed at reducing the number of APIs that essentially perform similar tasks. This API would also return the approveForAll information.

User stories

  • As a mirror node operator, I want to provide my API clients with the ability to list NFT allowances for an account that has granted allowance for a specific NFT serial number, as well as for those who have used approveForAll.
  • As a mirror node operator, I want to provide my API clients with the ability to list NFT allowances for a spender who has received an allowance for a single NFT serial number, as well as via approveForAll.

Specification

This is a HIP for adding the ability to query the allowances on NFTs from the mirror node.

Constraints

When designing the NFT allowances APIs, it is important to consider certain constraints on the number of allowances and tokens. These constraints may limit the ability to query unbounded information.

  • An approval transaction can include a maximum of 20 allowance change operations.
  • An account can have a maximum of 100 hbar, token, and approved for all NFT allowances.
  • An account can have an unbounded number of individual NFT allowances.
  • A non-fungible token can have an unbounded number of approved for all NFT allowances.
  • A specific NFT can only have one explicit approval. The last one to be approved will take precedence.
  • When an NFT is transferred by either the owner or a spender, it results in the individual spender’s allowance being cleared.
  • A specific NFT can have an unbounded number of implicit approved for all NFT allowances.

Approved for all NFT Allowances API

This API accepts a path parameter that represents either the owner or spender, depending on a boolean flag provided as a query parameter called owner. When the owner value is true or omitted, the accountId path parameter should specify the ID of the owner, and the API will retrieve the allowances that the owner has granted to different spenders. Conversely, when the owner value is false, the accountId path parameter should indicate the ID of the spender who has an allowance, and the API will instead provide the allowances granted to the spender by different owners of those tokens.

Following are example responses of the NFT allowance API:

GET /api/v1/accounts/0.0.1000/allowances/nfts?limit=3&owner=true

{
  "allowances": [
    {
      "approved_for_all": true,
      "owner": "0.0.1000",
      "spender": "0.0.8488",
      "token_id": "0.0.1033",
      "timestamp": {
        "from": "1633466229.96874612",
        "to": null
      }
    },
    {
      "approved_for_all": false,
      "owner": "0.0.1000",
      "spender": "0.0.8489",
      "token_id": "0.0.1034",
      "timestamp": {
        "from": "1633466229.96874618",
        "to": null
      }
    },
    {
      "approved_for_all": true,
      "owner": "0.0.1000",
      "spender": "0.0.9857",
      "token_id": "0.0.1032",
      "timestamp": {
        "from": "1633466229.96884615",
        "to": null
      }
    }
  ],
  "links": {
		"next": "/api/v1/accounts/0.0.1000/allowances/nfts?limit=3&order=asc&account.id=gte:9857&token.id=gt:0.0.1032"
	}
}

GET /api/v1/accounts/0.0.8488/allowances/nfts?limit=3&owner=false

{
  "allowances": [
    {
      "approved_for_all": true,
      "owner": "0.0.1000",
      "spender": "0.0.8488",
      "token_id": "0.0.1033",
      "timestamp": {
        "from": "1633466229.96874612",
        "to": null
      }
    },
    {
      "approved_for_all": true,
      "owner": "0.0.1000",
      "spender": "0.0.8488",
      "token_id": "0.0.1034",
      "timestamp": {
        "from": "1633466229.96874618",
        "to": null
      }
    },
    {
      "approved_for_all": false,
      "owner": "0.0.1001",
      "spender": "0.0.8488",
      "token_id": "0.0.1099",
      "timestamp": {
        "from": "1633466229.96875612",
        "to": null
      }
    }
  ],
  "links": {
		"next": "/api/v1/accounts/0.0.8488/allowances/nfts?limit=3&order=asc&account.id=gte:1001&token.id=gt:0.0.1099"
	}
}

Query Parameters:

  • account.id: Filter by the spender account ID or owner account ID, depending on the owner flag. ne operator is not supported. Only one occurrence is allowed.
  • limit: The maximum number of items to return. Defaults to 25 with a maximum of 100 allowed.
  • order: Order by account.id then token.id. Accepts asc or desc with a default of asc.
  • owner: Indicates whether the path parameter accountId is the owner or the spender ID. Accepts a boolean value of true or false with a default value set to true.
  • token.id: Filter by the token ID. ne operator is not supported. Only one occurrence is allowed.

Pagination is important to implement because there are accounts that could have a large number of NFT allowances, making a non-paginated response impractical. This requires multi-column pagination, including owner, spender, and token IDs.

Ordering

The order is governed by a combination of the account ID and the token ID values, with the account ID being the parent column. The token ID value governs its order within the given account ID. The default order for this API is ascending.

Filtering

When filtering there are some restrictions enforced to ensure correctness and scalability.

The table below defines the restrictions and support for the endpoint.

Query Param Comparison Operator Support Description Example
account.id eq Y Single occurrence only. ?account.id=X
  ne N    
  lt(e) Y Single occurrence only. ?account.id=lte:X
  gt(e) Y Single occurrence only. ?account.id=gte:X
token.id eq Y Single occurrence only. Requires the presence of an account.id query parameter ?account.id=X&token.id=eq:Y
  ne N    
  lt(e) Y Single occurrence only. Requires the presence of a lte or eq account.id query parameter ?account.id=lte:X&token.id=lt:Y
  gt(e) Y Single occurrence only. Requires the presence of a gte or eq account.id query parameter ?account.id=gte:X&token.id=gt:Y

Both filters must be a single occurrence of gt(e) or lt(e) which provide a lower and or upper boundary for search.

Serial level allowance information

To retrieve NFT serial number level allowance information for a specific token ID you can use the existing API:

GET /api/v1/tokens/{tokenId}/nfts

{
  "nfts": [
    {
      "account_id": "0.0.123",
      "created_timestamp": "1704827664.003435784",
      "delegating_spender": null,
      "deleted": false,
      "metadata": "AA==",
      "modified_timestamp": "1704827664.003435784",
      "serial_number": 1,
      "spender": null,
      "token_id": "0.0.1000"
    }
  ],
  "links": {
    "next": null
  }
}

Backwards Compatibility

This HIP primarily adds new information that mirror node operators and other record stream consumers can simply ignore if they do not need it. However, NFT marketplaces using the Hedera mirror node could start using the new API.

Security Implications

There are no security implications for this HIP.

How to Teach This

The Hedera documentation and the OpenAPI specification will be updated to add this new API.

Reference Implementation

Please follow this issue for progress on the reference implementation.

Rejected Ideas

  • We briefly considered adding serial number level information to /api/v1/accounts/{id}/allowances/nft in order for an NFT marketplace to view which spender has approvedForAll for particular serial numbers. However, this idea was rejected due to the unbounded nature of the data. When a token has a very high number of serials and allowances, implementing this feature could become a performance concern.
  • There was a consideration to add approve_for_all to /api/v1/tokens/{id}/nfts/{id}. This idea was rejected because it is possible to have an unbounded number of approve_for_all allowances and it is not feasible to return this data in a single response payload.
  • There was a consideration to add approve_for_all to /api/v1/accounts/{id}/tokens. This idea was rejected because it is possible to have an unbounded number of approve_for_all allowances and it is not feasible to return this data in a single response payload.

Open Issues

No known open issues exist.

References

Epic
HIP 336
Design

Copyright/license

This document is licensed under the Apache License, Version 2.0 – see LICENSE or (https://www.apache.org/licenses/LICENSE-2.0)

Citation

Please cite this document as: