mirror of
https://github.com/alexgo-io/stacks-blockchain-api.git
synced 2026-01-12 22:43:34 +08:00
feat: start returning tx metadata
This commit is contained in:
@@ -470,7 +470,7 @@ export function createAddressRouter(db: DataStore, chainId: ChainID): express.Ro
|
||||
);
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `/extended/v1/tokens/nft/holdings`.
|
||||
* @deprecated Use `/extended/v1/tokens/nft/holdings` instead.
|
||||
*/
|
||||
router.get(
|
||||
'/:stx_address/nft_events',
|
||||
|
||||
@@ -13,8 +13,9 @@ import {
|
||||
isNftMetadataEnabled,
|
||||
} from '../../../event-stream/tokens-contract-handler';
|
||||
import { bufferToHexPrefixString, isValidPrincipal } from '../../../helpers';
|
||||
import { isUnanchoredRequest } from '../../../api/query-helpers';
|
||||
import { booleanValueForParam, isUnanchoredRequest } from '../../../api/query-helpers';
|
||||
import { cvToString, deserializeCV } from '@stacks/transactions';
|
||||
import { getTxFromDataStore } from 'src/api/controllers/db-controller';
|
||||
|
||||
const MAX_TOKENS_PER_REQUEST = 200;
|
||||
const parseTokenQueryLimit = parseLimitQuery({
|
||||
@@ -29,7 +30,7 @@ export function createTokenRouter(db: DataStore): express.Router {
|
||||
router.get(
|
||||
'/nft/holdings',
|
||||
asyncHandler(async (req, res, next) => {
|
||||
const principal = req.query.principal ?? '';
|
||||
const principal = req.query.principal;
|
||||
if (typeof principal !== 'string' || !isValidPrincipal(principal)) {
|
||||
res.status(400).json({ error: `Invalid or missing principal` });
|
||||
return;
|
||||
@@ -37,6 +38,7 @@ export function createTokenRouter(db: DataStore): express.Router {
|
||||
const limit = parseTokenQueryLimit(req.query.limit ?? 50);
|
||||
const offset = parsePagingQueryInput(req.query.offset ?? 0);
|
||||
const includeUnanchored = isUnanchoredRequest(req, res, next);
|
||||
const includeTxMetadata = booleanValueForParam(req, res, next, 'tx_metadata');
|
||||
|
||||
const { results, total } = await db.getNftHoldings({
|
||||
principal: principal,
|
||||
@@ -44,14 +46,23 @@ export function createTokenRouter(db: DataStore): express.Router {
|
||||
limit: limit,
|
||||
includeUnanchored: includeUnanchored,
|
||||
});
|
||||
const parsedResults = results.map(result => ({
|
||||
asset_identifier: result.asset_identifier,
|
||||
value: {
|
||||
hex: bufferToHexPrefixString(result.value),
|
||||
repr: cvToString(deserializeCV(result.value)),
|
||||
},
|
||||
tx_id: bufferToHexPrefixString(result.tx_id),
|
||||
}));
|
||||
const parsedResults = await Promise.all(
|
||||
results.map(async result => {
|
||||
const txId = bufferToHexPrefixString(result.tx_id);
|
||||
return {
|
||||
asset_identifier: result.asset_identifier,
|
||||
value: {
|
||||
hex: bufferToHexPrefixString(result.value),
|
||||
repr: cvToString(deserializeCV(result.value)),
|
||||
},
|
||||
tx_id: txId,
|
||||
tx: includeTxMetadata
|
||||
? (await getTxFromDataStore(db, { txId: txId, includeUnanchored: includeUnanchored }))
|
||||
.result
|
||||
: undefined,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
const response = {
|
||||
limit: limit,
|
||||
|
||||
@@ -810,6 +810,11 @@ export interface DataStore extends DataStoreEventEmitter {
|
||||
|
||||
getRawTx(txId: string): Promise<FoundOrNot<RawTxQueryResult>>;
|
||||
|
||||
/**
|
||||
* Returns a list of NFTs owned by the given principal with the optional transaction
|
||||
* that gave them the ownership of said token.
|
||||
* @param args - Query arguments
|
||||
*/
|
||||
getNftHoldings(args: {
|
||||
principal: string;
|
||||
limit: number;
|
||||
@@ -817,6 +822,9 @@ export interface DataStore extends DataStoreEventEmitter {
|
||||
includeUnanchored: boolean;
|
||||
}): Promise<{ results: NftHoldingInfo[]; total: number }>;
|
||||
|
||||
/**
|
||||
* @deprecated Use `getNftHoldings` instead.
|
||||
*/
|
||||
getAddressNFTEvent(args: {
|
||||
stxAddress: string;
|
||||
blockHeight: number;
|
||||
|
||||
@@ -3681,22 +3681,13 @@ export class PgDataStore
|
||||
const maxBlockHeight = await this.getMaxBlockHeight(client, { includeUnanchored });
|
||||
const result = await client.query<ContractTxQueryResult>(
|
||||
`
|
||||
SELECT ${TX_COLUMNS},
|
||||
CASE
|
||||
WHEN txs.type_id = $3 THEN (
|
||||
SELECT abi
|
||||
FROM smart_contracts
|
||||
WHERE smart_contracts.contract_id = txs.contract_call_contract_id
|
||||
ORDER BY abi != 'null' DESC, canonical DESC, microblock_canonical DESC, block_height DESC
|
||||
LIMIT 1
|
||||
)
|
||||
END as abi
|
||||
SELECT ${TX_COLUMNS}, ${abiColumn()}
|
||||
FROM txs
|
||||
WHERE tx_id = $1 AND block_height <= $2
|
||||
ORDER BY canonical DESC, microblock_canonical DESC, block_height DESC
|
||||
LIMIT 1
|
||||
`,
|
||||
[hexToBuffer(txId), maxBlockHeight, DbTxTypeId.ContractCall]
|
||||
[hexToBuffer(txId), maxBlockHeight]
|
||||
);
|
||||
if (result.rowCount === 0) {
|
||||
return { found: false } as const;
|
||||
@@ -5933,7 +5924,7 @@ export class PgDataStore
|
||||
includeUnanchored: boolean;
|
||||
}): Promise<{ results: NftHoldingInfo[]; total: number }> {
|
||||
return this.queryTx(async client => {
|
||||
const dbResults = await client.query<NftHoldingInfo & { count: string }>(
|
||||
const nftResults = await client.query<NftHoldingInfo & { count: number }>(
|
||||
`
|
||||
SELECT *, (COUNT(*) OVER())::integer
|
||||
FROM ${args.includeUnanchored ? 'nft_custody_unanchored' : 'nft_custody'}
|
||||
@@ -5943,20 +5934,17 @@ export class PgDataStore
|
||||
`,
|
||||
[args.principal, args.limit, args.offset]
|
||||
);
|
||||
const count: number = dbResults.rows.length > 0 ? parseInt(dbResults.rows[0].count) : 0;
|
||||
const holdings: NftHoldingInfo[] = dbResults.rows.map(row => ({
|
||||
const holdings: NftHoldingInfo[] = nftResults.rows.map(row => ({
|
||||
asset_identifier: row.asset_identifier,
|
||||
value: row.value,
|
||||
recipient: row.recipient,
|
||||
tx_id: row.tx_id,
|
||||
}));
|
||||
const count: number = nftResults.rows.length > 0 ? nftResults.rows[0].count : 0;
|
||||
return { results: holdings, total: count };
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getNftHoldings`.
|
||||
*/
|
||||
async getAddressNFTEvent(args: {
|
||||
stxAddress: string;
|
||||
limit: number;
|
||||
|
||||
Reference in New Issue
Block a user