mirror of
https://github.com/alexgo-io/stacks-blockchain-api.git
synced 2026-04-28 12:55:41 +08:00
chore!: remove deprecated /nft_events endpoint (#1329)
* fix: remove deprecated /nft_events endpoint * chore: remove endpoint from openapi
This commit is contained in:
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"limit": 20,
|
|
||||||
"offset": 0,
|
|
||||||
"total": 1,
|
|
||||||
"nft_events": [
|
|
||||||
{
|
|
||||||
"sender": "none",
|
|
||||||
"recipient": "ST1HB64MAJ1MBV4CQ80GF01DZS4T1DSMX20ADCRA4",
|
|
||||||
"asset_identifier": "some-asset",
|
|
||||||
"value": { "hex": "0x00", "repr": "0" }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"title": "AddressNftListResponse",
|
|
||||||
"additionalProperties": false,
|
|
||||||
"required": [
|
|
||||||
"limit",
|
|
||||||
"offset",
|
|
||||||
"total",
|
|
||||||
"nft_events"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"limit": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"offset": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"total": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"nft_events": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "../../entities/nft-events/nft-event.schema.json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1643,63 +1643,6 @@ paths:
|
|||||||
example:
|
example:
|
||||||
$ref: ./api/address/get-address-stx-inbound.example.json
|
$ref: ./api/address/get-address-stx-inbound.example.json
|
||||||
|
|
||||||
/extended/v1/address/{principal}/nft_events:
|
|
||||||
get:
|
|
||||||
summary: Get nft events
|
|
||||||
deprecated: true
|
|
||||||
description: |
|
|
||||||
**NOTE:** This endpoint is deprecated in favor of [Non-Fungible Token holdings](#operation/get_nft_holdings).
|
|
||||||
|
|
||||||
Retrieves a list of all nfts owned by an address, contains the clarity value of the identifier of the nft.
|
|
||||||
tags:
|
|
||||||
- Accounts
|
|
||||||
operationId: get_account_nft
|
|
||||||
parameters:
|
|
||||||
- name: principal
|
|
||||||
in: path
|
|
||||||
description: Stacks address or a Contract identifier
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
example: "SP31DA6FTSJX2WGTZ69SFY11BH51NZMB0ZW97B5P0"
|
|
||||||
- name: limit
|
|
||||||
in: query
|
|
||||||
description: number of items to return
|
|
||||||
required: false
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
- name: offset
|
|
||||||
in: query
|
|
||||||
description: number of items to skip
|
|
||||||
required: false
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
example: 42000
|
|
||||||
- name: unanchored
|
|
||||||
in: query
|
|
||||||
description: Include transaction data from unanchored (i.e. unconfirmed) microblocks
|
|
||||||
required: false
|
|
||||||
schema:
|
|
||||||
type: boolean
|
|
||||||
example: true
|
|
||||||
default: false
|
|
||||||
- name: until_block
|
|
||||||
in: query
|
|
||||||
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.
|
|
||||||
required: false
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
example: 60000
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: Success
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: ./api/address/get-address-nft-events.schema.json
|
|
||||||
example:
|
|
||||||
$ref: ./api/address/get-address-nft-events.example.json
|
|
||||||
|
|
||||||
/v2/accounts/{principal}:
|
/v2/accounts/{principal}:
|
||||||
get:
|
get:
|
||||||
summary: Get account info
|
summary: Get account info
|
||||||
|
|||||||
@@ -476,59 +476,6 @@ export function createAddressRouter(db: PgStore, chainId: ChainID): express.Rout
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use `/extended/v1/tokens/nft/holdings` instead.
|
|
||||||
*/
|
|
||||||
router.get(
|
|
||||||
'/:stx_address/nft_events',
|
|
||||||
cacheHandler,
|
|
||||||
asyncHandler(async (req, res, next) => {
|
|
||||||
// get recent asset event associated with address
|
|
||||||
const stxAddress = req.params['stx_address'];
|
|
||||||
validatePrincipal(stxAddress);
|
|
||||||
|
|
||||||
const untilBlock = parseUntilBlockQuery(req, res, next);
|
|
||||||
const blockHeight = await getBlockHeight(untilBlock, req, res, next, db);
|
|
||||||
const limit = parseAssetsQueryLimit(req.query.limit ?? 20);
|
|
||||||
const offset = parsePagingQueryInput(req.query.offset ?? 0);
|
|
||||||
const includeUnanchored = isUnanchoredRequest(req, res, next);
|
|
||||||
|
|
||||||
const response = await db.getAddressNFTEvent({
|
|
||||||
stxAddress,
|
|
||||||
limit,
|
|
||||||
offset,
|
|
||||||
blockHeight,
|
|
||||||
includeUnanchored,
|
|
||||||
});
|
|
||||||
const nft_events = response.results.map(row => {
|
|
||||||
const parsedClarityValue = decodeClarityValueToRepr(row.value);
|
|
||||||
const r: NftEvent = {
|
|
||||||
sender: row.sender,
|
|
||||||
recipient: row.recipient,
|
|
||||||
asset_identifier: row.asset_identifier,
|
|
||||||
value: {
|
|
||||||
hex: row.value,
|
|
||||||
repr: parsedClarityValue,
|
|
||||||
},
|
|
||||||
tx_id: row.tx_id,
|
|
||||||
block_height: row.block_height,
|
|
||||||
event_index: row.event_index,
|
|
||||||
asset_event_type: getAssetEventTypeString(row.asset_event_type_id),
|
|
||||||
tx_index: row.tx_index,
|
|
||||||
};
|
|
||||||
return r;
|
|
||||||
});
|
|
||||||
const nftListResponse: AddressNftListResponse = {
|
|
||||||
nft_events: nft_events,
|
|
||||||
total: response.total,
|
|
||||||
limit: limit,
|
|
||||||
offset: offset,
|
|
||||||
};
|
|
||||||
setETagCacheHeaders(res);
|
|
||||||
res.json(nftListResponse);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
'/:address/mempool',
|
'/:address/mempool',
|
||||||
mempoolCacheHandler,
|
mempoolCacheHandler,
|
||||||
|
|||||||
@@ -3066,56 +3066,6 @@ export class PgStore {
|
|||||||
return { found: true, result: result[0] } as const;
|
return { found: true, result: result[0] } as const;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use `getNftHoldings` instead.
|
|
||||||
*/
|
|
||||||
async getAddressNFTEvent(args: {
|
|
||||||
stxAddress: string;
|
|
||||||
limit: number;
|
|
||||||
offset: number;
|
|
||||||
blockHeight: number;
|
|
||||||
includeUnanchored: boolean;
|
|
||||||
}): Promise<{ results: AddressNftEventIdentifier[]; total: number }> {
|
|
||||||
// Join against `nft_custody` materialized view only if we're looking for canonical results.
|
|
||||||
const result = await this.sql<(AddressNftEventIdentifier & { count: number })[]>`
|
|
||||||
WITH address_transfers AS (
|
|
||||||
SELECT asset_identifier, value, sender, recipient, block_height, microblock_sequence, tx_index, event_index, tx_id, asset_event_type_id
|
|
||||||
FROM nft_events
|
|
||||||
WHERE canonical = true AND microblock_canonical = true
|
|
||||||
AND recipient = ${args.stxAddress} AND block_height <= ${args.blockHeight}
|
|
||||||
),
|
|
||||||
last_nft_transfers AS (
|
|
||||||
SELECT DISTINCT ON(asset_identifier, value) asset_identifier, value, recipient
|
|
||||||
FROM nft_events
|
|
||||||
WHERE canonical = true AND microblock_canonical = true
|
|
||||||
AND block_height <= ${args.blockHeight}
|
|
||||||
ORDER BY asset_identifier, value, block_height DESC, microblock_sequence DESC, tx_index DESC, event_index DESC
|
|
||||||
)
|
|
||||||
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
|
|
||||||
FROM address_transfers
|
|
||||||
INNER JOIN ${args.includeUnanchored ? this.sql`last_nft_transfers` : this.sql`nft_custody`}
|
|
||||||
USING (asset_identifier, value, recipient)
|
|
||||||
ORDER BY block_height DESC, microblock_sequence DESC, tx_index DESC, event_index DESC
|
|
||||||
LIMIT ${args.limit} OFFSET ${args.offset}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const count = result.length > 0 ? result[0].count : 0;
|
|
||||||
|
|
||||||
const nftEvents = result.map(row => ({
|
|
||||||
sender: row.sender,
|
|
||||||
recipient: row.recipient,
|
|
||||||
asset_identifier: row.asset_identifier,
|
|
||||||
value: row.value,
|
|
||||||
block_height: row.block_height,
|
|
||||||
tx_id: row.tx_id,
|
|
||||||
event_index: row.event_index,
|
|
||||||
asset_event_type_id: row.asset_event_type_id,
|
|
||||||
tx_index: row.tx_index,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return { results: nftEvents, total: count };
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTxListDetails({
|
async getTxListDetails({
|
||||||
txIds,
|
txIds,
|
||||||
includeUnanchored,
|
includeUnanchored,
|
||||||
|
|||||||
@@ -2235,7 +2235,6 @@ describe('address tests', () => {
|
|||||||
'/transactions_with_transfers',
|
'/transactions_with_transfers',
|
||||||
'/assets',
|
'/assets',
|
||||||
'/stx_inbound',
|
'/stx_inbound',
|
||||||
'/nft_events',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
//check for mutually exclusive unachored and and until_block
|
//check for mutually exclusive unachored and and until_block
|
||||||
@@ -2257,233 +2256,6 @@ describe('address tests', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Success: nft events for address', async () => {
|
|
||||||
const addr1 = 'ST3J8EVYHVKH6XXPD61EE8XEHW4Y2K83861225AB1';
|
|
||||||
const addr2 = 'ST1HB64MAJ1MBV4CQ80GF01DZS4T1DSMX20ADCRA4';
|
|
||||||
|
|
||||||
const dbBlock: DbBlock = {
|
|
||||||
block_hash: '0xff',
|
|
||||||
index_block_hash: '0x1234',
|
|
||||||
parent_index_block_hash: '0x5678',
|
|
||||||
parent_block_hash: '0x5678',
|
|
||||||
parent_microblock_hash: '',
|
|
||||||
parent_microblock_sequence: 0,
|
|
||||||
block_height: 1,
|
|
||||||
burn_block_time: 1594647995,
|
|
||||||
burn_block_hash: '0x1234',
|
|
||||||
burn_block_height: 123,
|
|
||||||
miner_txid: '0x4321',
|
|
||||||
canonical: true,
|
|
||||||
execution_cost_read_count: 0,
|
|
||||||
execution_cost_read_length: 0,
|
|
||||||
execution_cost_runtime: 0,
|
|
||||||
execution_cost_write_count: 0,
|
|
||||||
execution_cost_write_length: 0,
|
|
||||||
};
|
|
||||||
const stxTx: DbTx = {
|
|
||||||
tx_id: '0x1111000000000000000000000000000000000000000000000000000000000000',
|
|
||||||
tx_index: 0,
|
|
||||||
anchor_mode: 3,
|
|
||||||
nonce: 0,
|
|
||||||
raw_tx: '0x',
|
|
||||||
index_block_hash: dbBlock.index_block_hash,
|
|
||||||
block_hash: dbBlock.block_hash,
|
|
||||||
block_height: dbBlock.block_height,
|
|
||||||
burn_block_time: dbBlock.burn_block_time,
|
|
||||||
parent_burn_block_time: 1626122935,
|
|
||||||
type_id: DbTxTypeId.TokenTransfer,
|
|
||||||
token_transfer_amount: 1n,
|
|
||||||
token_transfer_memo: bufferToHexPrefixString(Buffer.from('hi')),
|
|
||||||
token_transfer_recipient_address: 'none',
|
|
||||||
status: 1,
|
|
||||||
raw_result: '0x0100000000000000000000000000000001', // u1
|
|
||||||
canonical: true,
|
|
||||||
microblock_canonical: true,
|
|
||||||
microblock_sequence: I32_MAX,
|
|
||||||
microblock_hash: '',
|
|
||||||
parent_index_block_hash: dbBlock.parent_index_block_hash,
|
|
||||||
parent_block_hash: dbBlock.parent_block_hash,
|
|
||||||
post_conditions: '0x01f5',
|
|
||||||
fee_rate: 1234n,
|
|
||||||
sponsored: false,
|
|
||||||
sponsor_address: undefined,
|
|
||||||
sender_address: addr1,
|
|
||||||
origin_hash_mode: 1,
|
|
||||||
event_count: 10,
|
|
||||||
execution_cost_read_count: 0,
|
|
||||||
execution_cost_read_length: 0,
|
|
||||||
execution_cost_runtime: 0,
|
|
||||||
execution_cost_write_count: 0,
|
|
||||||
execution_cost_write_length: 0,
|
|
||||||
};
|
|
||||||
const nftEvents: DbNftEvent[] = [];
|
|
||||||
for (let i = 0; i < 10; i++) {
|
|
||||||
nftEvents.push({
|
|
||||||
canonical: true,
|
|
||||||
event_type: DbEventTypeId.NonFungibleTokenAsset,
|
|
||||||
asset_event_type_id: DbAssetEventTypeId.Transfer,
|
|
||||||
event_index: 0,
|
|
||||||
tx_id: stxTx.tx_id,
|
|
||||||
tx_index: 1,
|
|
||||||
block_height: dbBlock.block_height,
|
|
||||||
asset_identifier: 'some-asset',
|
|
||||||
value: '0x0000000000000000000000000000000000',
|
|
||||||
recipient: addr1,
|
|
||||||
sender: 'none',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
await db.update({
|
|
||||||
block: dbBlock,
|
|
||||||
microblocks: [],
|
|
||||||
minerRewards: [],
|
|
||||||
txs: [
|
|
||||||
{
|
|
||||||
tx: stxTx,
|
|
||||||
stxLockEvents: [],
|
|
||||||
stxEvents: [],
|
|
||||||
ftEvents: [],
|
|
||||||
nftEvents: nftEvents,
|
|
||||||
contractLogEvents: [],
|
|
||||||
smartContracts: [],
|
|
||||||
names: [],
|
|
||||||
namespaces: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
const limit = 2;
|
|
||||||
const offset = 0;
|
|
||||||
// test nft for given addresses
|
|
||||||
const result = await supertest(api.server).get(
|
|
||||||
`/extended/v1/address/${addr1}/nft_events?limit=${limit}&offset=${offset}`
|
|
||||||
);
|
|
||||||
expect(result.status).toBe(200);
|
|
||||||
expect(result.type).toBe('application/json');
|
|
||||||
expect(result.body.total).toEqual(10);
|
|
||||||
expect(result.body.nft_events.length).toEqual(2);
|
|
||||||
expect(result.body.nft_events[0].recipient).toBe(addr1);
|
|
||||||
expect(result.body.nft_events[0].tx_id).toBe(
|
|
||||||
'0x1111000000000000000000000000000000000000000000000000000000000000'
|
|
||||||
);
|
|
||||||
expect(result.body.nft_events[0].block_height).toBe(1);
|
|
||||||
expect(result.body.nft_events[0].value.repr).toBe('0');
|
|
||||||
|
|
||||||
const dbBlock2: DbBlock = {
|
|
||||||
block_hash: '0xffff',
|
|
||||||
index_block_hash: '0x123466',
|
|
||||||
parent_index_block_hash: '0x1234',
|
|
||||||
parent_block_hash: '0xff',
|
|
||||||
parent_microblock_hash: '',
|
|
||||||
parent_microblock_sequence: 0,
|
|
||||||
block_height: 2,
|
|
||||||
burn_block_time: 1594649995,
|
|
||||||
burn_block_hash: '0x123456',
|
|
||||||
burn_block_height: 124,
|
|
||||||
miner_txid: '0x4321',
|
|
||||||
canonical: true,
|
|
||||||
execution_cost_read_count: 0,
|
|
||||||
execution_cost_read_length: 0,
|
|
||||||
execution_cost_runtime: 0,
|
|
||||||
execution_cost_write_count: 0,
|
|
||||||
execution_cost_write_length: 0,
|
|
||||||
};
|
|
||||||
const stxTx1: DbTx = {
|
|
||||||
tx_id: '0x1111100000000000000000000000000000000000000000000000000000000001',
|
|
||||||
tx_index: 0,
|
|
||||||
anchor_mode: 3,
|
|
||||||
nonce: 0,
|
|
||||||
raw_tx: '0x',
|
|
||||||
index_block_hash: dbBlock2.index_block_hash,
|
|
||||||
block_hash: dbBlock2.block_hash,
|
|
||||||
block_height: dbBlock2.block_height,
|
|
||||||
burn_block_time: dbBlock2.burn_block_time,
|
|
||||||
parent_burn_block_time: 1626124935,
|
|
||||||
type_id: DbTxTypeId.TokenTransfer,
|
|
||||||
token_transfer_amount: 1n,
|
|
||||||
token_transfer_memo: bufferToHexPrefixString(Buffer.from('hi')),
|
|
||||||
token_transfer_recipient_address: 'none',
|
|
||||||
status: 1,
|
|
||||||
raw_result: '0x0100000000000000000000000000000001', // u1
|
|
||||||
canonical: true,
|
|
||||||
microblock_canonical: true,
|
|
||||||
microblock_sequence: I32_MAX,
|
|
||||||
microblock_hash: '',
|
|
||||||
parent_index_block_hash: dbBlock2.parent_index_block_hash,
|
|
||||||
parent_block_hash: dbBlock2.parent_block_hash,
|
|
||||||
post_conditions: '0x01f5',
|
|
||||||
fee_rate: 1234n,
|
|
||||||
sponsored: false,
|
|
||||||
sponsor_address: undefined,
|
|
||||||
sender_address: addr2,
|
|
||||||
origin_hash_mode: 1,
|
|
||||||
event_count: 1,
|
|
||||||
execution_cost_read_count: 0,
|
|
||||||
execution_cost_read_length: 0,
|
|
||||||
execution_cost_runtime: 0,
|
|
||||||
execution_cost_write_count: 0,
|
|
||||||
execution_cost_write_length: 0,
|
|
||||||
};
|
|
||||||
const nftEvent2: DbNftEvent = {
|
|
||||||
canonical: true,
|
|
||||||
event_type: DbEventTypeId.NonFungibleTokenAsset,
|
|
||||||
asset_event_type_id: DbAssetEventTypeId.Transfer,
|
|
||||||
event_index: 1,
|
|
||||||
tx_id: stxTx1.tx_id,
|
|
||||||
tx_index: 2,
|
|
||||||
block_height: dbBlock2.block_height,
|
|
||||||
asset_identifier: 'some-asset',
|
|
||||||
value: '0x0000000000000000000000000000000000',
|
|
||||||
recipient: addr2,
|
|
||||||
sender: 'none',
|
|
||||||
};
|
|
||||||
await db.update({
|
|
||||||
block: dbBlock2,
|
|
||||||
microblocks: [],
|
|
||||||
minerRewards: [],
|
|
||||||
txs: [
|
|
||||||
{
|
|
||||||
tx: stxTx1,
|
|
||||||
stxLockEvents: [],
|
|
||||||
stxEvents: [],
|
|
||||||
ftEvents: [],
|
|
||||||
nftEvents: [nftEvent2],
|
|
||||||
contractLogEvents: [],
|
|
||||||
smartContracts: [],
|
|
||||||
names: [],
|
|
||||||
namespaces: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
const result1 = await supertest(api.server).get(`/extended/v1/address/${addr2}/nft_events`);
|
|
||||||
expect(result1.status).toBe(200);
|
|
||||||
expect(result1.type).toBe('application/json');
|
|
||||||
expect(result1.body.total).toEqual(1);
|
|
||||||
expect(result1.body.nft_events.length).toEqual(1);
|
|
||||||
expect(result1.body.nft_events[0].recipient).toBe(addr2);
|
|
||||||
expect(result1.body.nft_events[0].tx_id).toBe(
|
|
||||||
'0x1111100000000000000000000000000000000000000000000000000000000001'
|
|
||||||
);
|
|
||||||
expect(result1.body.nft_events[0].block_height).toBe(2);
|
|
||||||
expect(result.body.nft_events[0].value.repr).toBe('0');
|
|
||||||
|
|
||||||
//check ownership for addr
|
|
||||||
const result2 = await supertest(api.server).get(`/extended/v1/address/${addr1}/nft_events`);
|
|
||||||
expect(result2.status).toBe(200);
|
|
||||||
expect(result2.type).toBe('application/json');
|
|
||||||
expect(result2.body.nft_events.length).toEqual(0);
|
|
||||||
expect(result2.body.total).toEqual(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('nft invalid address', async () => {
|
|
||||||
const result = await supertest(api.server).get(
|
|
||||||
`/extended/v1/address/invalid-address/nft_events`
|
|
||||||
);
|
|
||||||
expect(result.status).toBe(400);
|
|
||||||
expect(result.type).toBe('application/json');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('/transactions materialized view separates anchored and unanchored counts correctly', async () => {
|
test('/transactions materialized view separates anchored and unanchored counts correctly', async () => {
|
||||||
const contractId = 'SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.megapont-ape-club-nft';
|
const contractId = 'SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.megapont-ape-club-nft';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user