Skip to content

Commit

Permalink
Add tracker api
Browse files Browse the repository at this point in the history
  • Loading branch information
opcatdev committed Nov 25, 2024
1 parent d399cfc commit 8d019a4
Show file tree
Hide file tree
Showing 3 changed files with 256 additions and 16 deletions.
89 changes: 83 additions & 6 deletions packages/tracker/src/routes/collection/collection.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,9 @@ export class CollectionController {
}
}

@Get(':collectionIdOrAddr/addresses/:ownerAddrOrPkh/utxoCount')
@Get(':collectionIdOrAddr/addresses/:ownerAddrOrPkh/nftAmount')
@ApiTags('collection')
@ApiOperation({ summary: 'Get collection utxo count by owner address' })
@ApiOperation({ summary: 'Get collection nft amount by owner address' })
@ApiParam({
name: 'collectionIdOrAddr',
required: true,
Expand Down Expand Up @@ -277,22 +277,23 @@ export class CollectionController {
}
}

@Get(':collectionIdOrAddr/mintCount')
@Get(':collectionIdOrAddr/mintAmount')
@ApiTags('collection')
@ApiOperation({
summary: 'Get collection mint count by collection id or collection address',
summary:
'Get collection total mint amount by collection id or collection address',
})
@ApiParam({
name: 'collectionIdOrAddr',
required: true,
type: String,
description: 'collection id or collection address',
})
async getCollectionMintCount(
async getCollectionMintAmount(
@Param('collectionIdOrAddr') collectionIdOrAddr: string,
) {
try {
const mintCount = await this.tokenService.getTokenMintCount(
const mintCount = await this.tokenService.getTokenMintAmount(
collectionIdOrAddr,
TokenTypeScope.NonFungible,
);
Expand All @@ -301,4 +302,80 @@ export class CollectionController {
return errorResponse(e);
}
}

@Get(':collectionIdOrAddr/circulation')
@ApiTags('collection')
@ApiOperation({
summary:
'Get collection current circulation by collection id or collection address',
})
@ApiParam({
name: 'collectionIdOrAddr',
required: true,
type: String,
description: 'collection id or collection address',
})
async getCollectionCirculation(
@Param('collectionIdOrAddr') collectionIdOrAddr: string,
) {
try {
const circulation = await this.tokenService.getTokenCirculation(
collectionIdOrAddr,
TokenTypeScope.NonFungible,
);
return okResponse(circulation);
} catch (e) {
return errorResponse(e);
}
}

@Get(':collectionIdOrAddr/holders')
@ApiTags('collection')
@ApiOperation({
summary: 'Get collection holders by collection id or collection address',
})
@ApiParam({
name: 'collectionIdOrAddr',
required: true,
type: String,
description: 'collection id or collection address',
})
@ApiQuery({
name: 'offset',
required: false,
type: Number,
description: 'paging offset',
})
@ApiQuery({
name: 'limit',
required: false,
type: Number,
description: 'paging limit',
})
async getCollectionHolders(
@Param('collectionIdOrAddr') collectionIdOrAddr: string,
@Query('offset') offset?: number,
@Query('limit') limit?: number,
) {
try {
const r = await this.tokenService.getTokenHolders(
collectionIdOrAddr,
TokenTypeScope.NonFungible,
offset,
limit,
);
const holders = r.holders.map((holder) => {
return {
ownerPubKeyHash: holder.ownerPubKeyHash,
nftAmount: holder.nftAmount!,
};
});
return okResponse({
holders,
trackerBlockHeight: r.trackerBlockHeight,
});
} catch (e) {
return errorResponse(e);
}
}
}
83 changes: 79 additions & 4 deletions packages/tracker/src/routes/token/token.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,22 +108,22 @@ export class TokenController {
}
}

@Get(':tokenIdOrTokenAddr/mintCount')
@Get(':tokenIdOrTokenAddr/mintAmount')
@ApiTags('token')
@ApiOperation({
summary: 'Get token mint count by token id or token address',
summary: 'Get token total mint amount by token id or token address',
})
@ApiParam({
name: 'tokenIdOrTokenAddr',
required: true,
type: String,
description: 'token id or token address',
})
async getTokenMintCount(
async getTokenMintAmount(
@Param('tokenIdOrTokenAddr') tokenIdOrTokenAddr: string,
) {
try {
const mintCount = await this.tokenService.getTokenMintCount(
const mintCount = await this.tokenService.getTokenMintAmount(
tokenIdOrTokenAddr,
TokenTypeScope.Fungible,
);
Expand All @@ -132,4 +132,79 @@ export class TokenController {
return errorResponse(e);
}
}

@Get(':tokenIdOrTokenAddr/circulation')
@ApiTags('token')
@ApiOperation({
summary: 'Get token current circulation by token id or token address',
})
@ApiParam({
name: 'tokenIdOrTokenAddr',
required: true,
type: String,
description: 'token id or token address',
})
async getTokenCirculation(
@Param('tokenIdOrTokenAddr') tokenIdOrTokenAddr: string,
) {
try {
const circulation = await this.tokenService.getTokenCirculation(
tokenIdOrTokenAddr,
TokenTypeScope.Fungible,
);
return okResponse(circulation);
} catch (e) {
return errorResponse(e);
}
}

@Get(':tokenIdOrTokenAddr/holders')
@ApiTags('token')
@ApiOperation({
summary: 'Get token holders by token id or token address',
})
@ApiParam({
name: 'tokenIdOrTokenAddr',
required: true,
type: String,
description: 'token id or token address',
})
@ApiQuery({
name: 'offset',
required: false,
type: Number,
description: 'paging offset',
})
@ApiQuery({
name: 'limit',
required: false,
type: Number,
description: 'paging limit',
})
async getTokenHolders(
@Param('tokenIdOrTokenAddr') tokenIdOrTokenAddr: string,
@Query('offset') offset?: number,
@Query('limit') limit?: number,
) {
try {
const r = await this.tokenService.getTokenHolders(
tokenIdOrTokenAddr,
TokenTypeScope.Fungible,
offset,
limit,
);
const holders = r.holders.map((holder) => {
return {
ownerPubKeyHash: holder.ownerPubKeyHash,
balance: holder.tokenAmount!,
};
});
return okResponse({
holders,
trackerBlockHeight: r.trackerBlockHeight,
});
} catch (e) {
return errorResponse(e);
}
}
}
100 changes: 94 additions & 6 deletions packages/tracker/src/routes/token/token.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,11 +318,11 @@ export class TokenService {
return renderedUtxos;
}

async getTokenMintCount(
async getTokenMintAmount(
tokenIdOrTokenAddr: string,
scope: TokenTypeScope.Fungible | TokenTypeScope.NonFungible,
): Promise<{
count: string;
amount: string;
trackerBlockHeight: number;
}> {
const lastProcessedHeight =
Expand All @@ -331,7 +331,7 @@ export class TokenService {
tokenIdOrTokenAddr,
scope,
);
let count = '0';
let amount = '0';
if (tokenInfo && tokenInfo.tokenPubKey && lastProcessedHeight) {
const where = {
tokenPubKey: tokenInfo.tokenPubKey,
Expand All @@ -343,14 +343,102 @@ export class TokenService {
.select('SUM(token_amount)', 'count')
.where(where)
.getRawOne();
count = r?.count || '0';
amount = r?.count || '0';
} else {
const r = await this.tokenMintRepository.count({ where });
count = (r || 0).toString();
amount = (r || 0).toString();
}
}
return {
count,
amount,
trackerBlockHeight: lastProcessedHeight,
};
}

async getTokenCirculation(
tokenIdOrTokenAddr: string,
scope: TokenTypeScope.Fungible | TokenTypeScope.NonFungible,
): Promise<{
amount: string;
trackerBlockHeight: number;
}> {
const lastProcessedHeight =
await this.commonService.getLastProcessedBlockHeight();
const tokenInfo = await this.getTokenInfoByTokenIdOrTokenAddress(
tokenIdOrTokenAddr,
scope,
);
let amount = '0';
if (tokenInfo && tokenInfo.tokenPubKey && lastProcessedHeight) {
const where = {
xOnlyPubKey: tokenInfo.tokenPubKey,
spendTxid: IsNull(),
};
if (scope === TokenTypeScope.Fungible) {
const r = await this.txOutRepository
.createQueryBuilder()
.select('SUM(token_amount)', 'count')
.where(where)
.getRawOne();
amount = r?.count || '0';
} else {
const r = await this.txOutRepository.count({ where });
amount = (r || 0).toString();
}
}
return {
amount,
trackerBlockHeight: lastProcessedHeight,
};
}

async getTokenHolders(
tokenIdOrTokenAddr: string,
scope: TokenTypeScope.Fungible | TokenTypeScope.NonFungible,
offset: number | null = null,
limit: number | null = null,
): Promise<{
holders: {
ownerPubKeyHash: string;
tokenAmount?: string;
nftAmount?: number;
}[];
trackerBlockHeight: number;
}> {
const lastProcessedHeight =
await this.commonService.getLastProcessedBlockHeight();
const tokenInfo = await this.getTokenInfoByTokenIdOrTokenAddress(
tokenIdOrTokenAddr,
scope,
);
let holders = [];
if (tokenInfo && tokenInfo.tokenPubKey && lastProcessedHeight) {
const query = this.txOutRepository
.createQueryBuilder()
.select('owner_pkh', 'ownerPubKeyHash')
.where('spend_txid IS NULL')
.andWhere('xonly_pubkey = :xonlyPubkey', {
xonlyPubkey: tokenInfo.tokenPubKey,
})
.groupBy('owner_pkh')
.limit(
Math.min(
limit || Constants.QUERY_PAGING_DEFAULT_LIMIT,
Constants.QUERY_PAGING_MAX_LIMIT,
),
)
.offset(offset || Constants.QUERY_PAGING_DEFAULT_OFFSET);
if (scope === TokenTypeScope.Fungible) {
query
.addSelect('SUM(token_amount)', 'tokenAmount')
.orderBy('SUM(token_amount)', 'DESC');
} else {
query.addSelect('COUNT(1)', 'nftAmount').orderBy('COUNT(1)', 'DESC');
}
holders = await query.getRawMany();
}
return {
holders,
trackerBlockHeight: lastProcessedHeight,
};
}
Expand Down

0 comments on commit 8d019a4

Please sign in to comment.