Skip to content

Commit c537ee4

Browse files
authored
Revert "chore!: remove deprecated /nft_events endpoint (#1329)" (#1343)
This reverts commit 65bb4e5.
1 parent 95b9595 commit c537ee4

File tree

6 files changed

+429
-0
lines changed

6 files changed

+429
-0
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"limit": 20,
3+
"offset": 0,
4+
"total": 1,
5+
"nft_events": [
6+
{
7+
"sender": "none",
8+
"recipient": "ST1HB64MAJ1MBV4CQ80GF01DZS4T1DSMX20ADCRA4",
9+
"asset_identifier": "some-asset",
10+
"value": { "hex": "0x00", "repr": "0" }
11+
}
12+
]
13+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"type": "object",
3+
"title": "AddressNftListResponse",
4+
"additionalProperties": false,
5+
"required": [
6+
"limit",
7+
"offset",
8+
"total",
9+
"nft_events"
10+
],
11+
"properties": {
12+
"limit": {
13+
"type": "integer"
14+
},
15+
"offset": {
16+
"type": "integer"
17+
},
18+
"total": {
19+
"type": "integer"
20+
},
21+
"nft_events": {
22+
"type": "array",
23+
"items": {
24+
"$ref": "../../entities/nft-events/nft-event.schema.json"
25+
}
26+
}
27+
}
28+
}

docs/openapi.yaml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1643,6 +1643,63 @@ paths:
16431643
example:
16441644
$ref: ./api/address/get-address-stx-inbound.example.json
16451645

1646+
/extended/v1/address/{principal}/nft_events:
1647+
get:
1648+
summary: Get nft events
1649+
deprecated: true
1650+
description: |
1651+
**NOTE:** This endpoint is deprecated in favor of [Non-Fungible Token holdings](#operation/get_nft_holdings).
1652+
1653+
Retrieves a list of all nfts owned by an address, contains the clarity value of the identifier of the nft.
1654+
tags:
1655+
- Accounts
1656+
operationId: get_account_nft
1657+
parameters:
1658+
- name: principal
1659+
in: path
1660+
description: Stacks address or a Contract identifier
1661+
required: true
1662+
schema:
1663+
type: string
1664+
example: "SP31DA6FTSJX2WGTZ69SFY11BH51NZMB0ZW97B5P0"
1665+
- name: limit
1666+
in: query
1667+
description: number of items to return
1668+
required: false
1669+
schema:
1670+
type: integer
1671+
- name: offset
1672+
in: query
1673+
description: number of items to skip
1674+
required: false
1675+
schema:
1676+
type: integer
1677+
example: 42000
1678+
- name: unanchored
1679+
in: query
1680+
description: Include transaction data from unanchored (i.e. unconfirmed) microblocks
1681+
required: false
1682+
schema:
1683+
type: boolean
1684+
example: true
1685+
default: false
1686+
- name: until_block
1687+
in: query
1688+
description: returned data representing the state up until that point in time, rather than the current block. Note - Use either of the query parameters but not both at a time.
1689+
required: false
1690+
schema:
1691+
type: string
1692+
example: 60000
1693+
responses:
1694+
200:
1695+
description: Success
1696+
content:
1697+
application/json:
1698+
schema:
1699+
$ref: ./api/address/get-address-nft-events.schema.json
1700+
example:
1701+
$ref: ./api/address/get-address-nft-events.example.json
1702+
16461703
/v2/accounts/{principal}:
16471704
get:
16481705
summary: Get account info

src/api/routes/address.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,59 @@ export function createAddressRouter(db: PgStore, chainId: ChainID): express.Rout
476476
})
477477
);
478478

479+
/**
480+
* @deprecated Use `/extended/v1/tokens/nft/holdings` instead.
481+
*/
482+
router.get(
483+
'/:stx_address/nft_events',
484+
cacheHandler,
485+
asyncHandler(async (req, res, next) => {
486+
// get recent asset event associated with address
487+
const stxAddress = req.params['stx_address'];
488+
validatePrincipal(stxAddress);
489+
490+
const untilBlock = parseUntilBlockQuery(req, res, next);
491+
const blockHeight = await getBlockHeight(untilBlock, req, res, next, db);
492+
const limit = parseAssetsQueryLimit(req.query.limit ?? 20);
493+
const offset = parsePagingQueryInput(req.query.offset ?? 0);
494+
const includeUnanchored = isUnanchoredRequest(req, res, next);
495+
496+
const response = await db.getAddressNFTEvent({
497+
stxAddress,
498+
limit,
499+
offset,
500+
blockHeight,
501+
includeUnanchored,
502+
});
503+
const nft_events = response.results.map(row => {
504+
const parsedClarityValue = decodeClarityValueToRepr(row.value);
505+
const r: NftEvent = {
506+
sender: row.sender,
507+
recipient: row.recipient,
508+
asset_identifier: row.asset_identifier,
509+
value: {
510+
hex: row.value,
511+
repr: parsedClarityValue,
512+
},
513+
tx_id: row.tx_id,
514+
block_height: row.block_height,
515+
event_index: row.event_index,
516+
asset_event_type: getAssetEventTypeString(row.asset_event_type_id),
517+
tx_index: row.tx_index,
518+
};
519+
return r;
520+
});
521+
const nftListResponse: AddressNftListResponse = {
522+
nft_events: nft_events,
523+
total: response.total,
524+
limit: limit,
525+
offset: offset,
526+
};
527+
setETagCacheHeaders(res);
528+
res.json(nftListResponse);
529+
})
530+
);
531+
479532
router.get(
480533
'/:address/mempool',
481534
mempoolCacheHandler,

src/datastore/pg-store.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3066,6 +3066,56 @@ export class PgStore {
30663066
return { found: true, result: result[0] } as const;
30673067
}
30683068

3069+
/**
3070+
* @deprecated Use `getNftHoldings` instead.
3071+
*/
3072+
async getAddressNFTEvent(args: {
3073+
stxAddress: string;
3074+
limit: number;
3075+
offset: number;
3076+
blockHeight: number;
3077+
includeUnanchored: boolean;
3078+
}): Promise<{ results: AddressNftEventIdentifier[]; total: number }> {
3079+
// Join against `nft_custody` materialized view only if we're looking for canonical results.
3080+
const result = await this.sql<(AddressNftEventIdentifier & { count: number })[]>`
3081+
WITH address_transfers AS (
3082+
SELECT asset_identifier, value, sender, recipient, block_height, microblock_sequence, tx_index, event_index, tx_id, asset_event_type_id
3083+
FROM nft_events
3084+
WHERE canonical = true AND microblock_canonical = true
3085+
AND recipient = ${args.stxAddress} AND block_height <= ${args.blockHeight}
3086+
),
3087+
last_nft_transfers AS (
3088+
SELECT DISTINCT ON(asset_identifier, value) asset_identifier, value, recipient
3089+
FROM nft_events
3090+
WHERE canonical = true AND microblock_canonical = true
3091+
AND block_height <= ${args.blockHeight}
3092+
ORDER BY asset_identifier, value, block_height DESC, microblock_sequence DESC, tx_index DESC, event_index DESC
3093+
)
3094+
SELECT sender, recipient, asset_identifier, value, event_index, asset_event_type_id, address_transfers.block_height, address_transfers.tx_id, (COUNT(*) OVER())::INTEGER AS count
3095+
FROM address_transfers
3096+
INNER JOIN ${args.includeUnanchored ? this.sql`last_nft_transfers` : this.sql`nft_custody`}
3097+
USING (asset_identifier, value, recipient)
3098+
ORDER BY block_height DESC, microblock_sequence DESC, tx_index DESC, event_index DESC
3099+
LIMIT ${args.limit} OFFSET ${args.offset}
3100+
`;
3101+
3102+
const count = result.length > 0 ? result[0].count : 0;
3103+
3104+
const nftEvents = result.map(row => ({
3105+
sender: row.sender,
3106+
recipient: row.recipient,
3107+
asset_identifier: row.asset_identifier,
3108+
value: row.value,
3109+
block_height: row.block_height,
3110+
tx_id: row.tx_id,
3111+
event_index: row.event_index,
3112+
asset_event_type_id: row.asset_event_type_id,
3113+
tx_index: row.tx_index,
3114+
}));
3115+
3116+
return { results: nftEvents, total: count };
3117+
}
3118+
30693119
async getTxListDetails({
30703120
txIds,
30713121
includeUnanchored,

0 commit comments

Comments
 (0)