-
Notifications
You must be signed in to change notification settings - Fork 145
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Mugdha Goel <[email protected]> Signed-off-by: Michael Garber <[email protected]> Co-authored-by: Steven Sheehy <[email protected]> Co-authored-by: Michael Garber <[email protected]>
- Loading branch information
1 parent
904db85
commit c72dcf9
Showing
1 changed file
with
236 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
--- | ||
hip: 857 | ||
title: NFT Allowances REST API | ||
author: Mugdha Goel <[email protected]> | ||
working-group: Steven Sheehy (@steven-sheehy),Ashe Oro (@Ashe-Oro) | ||
type: Standards Track | ||
category: Mirror | ||
needs-council-approval: Yes | ||
status: Last Call | ||
last-call-date-time: 2024-02-01T07:00:00Z | ||
created: 2023-12-07 | ||
discussions-to: https://github.com/hashgraph/hedera-improvement-proposal/discussions/858 | ||
updated: 2024-01-19 | ||
--- | ||
|
||
## 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` | ||
|
||
```json | ||
{ | ||
"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` | ||
|
||
```json | ||
{ | ||
"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` | ||
|
||
```json | ||
{ | ||
"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](https://github.com/hashgraph/hedera-mirror-node/issues/7480) 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](https://github.com/hashgraph/hedera-mirror-node/issues/7480) | ||
[HIP 336](https://hips.hedera.com/hip/hip-336) | ||
[Design](https://github.com/hashgraph/hedera-mirror-node/blob/main/docs/design/allowances.md) | ||
|
||
## Copyright/license | ||
|
||
This document is licensed under the Apache License, Version 2.0 -- see [LICENSE](../LICENSE) or (https://www.apache.org/licenses/LICENSE-2.0) |