Skip to content

Commit

Permalink
contracts deploys endpoints (#1336)
Browse files Browse the repository at this point in the history
* replace account contracts with account deploys

* add account contracts

* add AccountContract Entity instead of any

* Update mex.token.charts.spec.ts

---------

Co-authored-by: tanghel <tanghel@live.com>
  • Loading branch information
cfaur09 and tanghel authored Oct 8, 2024
1 parent e409dd6 commit 081bd5a
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 35 deletions.
20 changes: 18 additions & 2 deletions src/common/indexer/elastic/elastic.indexer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class ElasticIndexerService implements IndexerInterface {
return await this.elasticService.getCount('operations', query);
}

async getAccountContractsCount(address: string): Promise<number> {
async getAccountDeploysCount(address: string): Promise<number> {
const elasticQuery: ElasticQuery = ElasticQuery.create()
.withCondition(QueryConditionOptions.must, [QueryType.Match("deployer", address)]);

Expand Down Expand Up @@ -435,7 +435,7 @@ export class ElasticIndexerService implements IndexerInterface {
);
}

async getAccountContracts(pagination: QueryPagination, address: string): Promise<any[]> {
async getAccountDeploys(pagination: QueryPagination, address: string): Promise<any[]> {
const elasticQuery: ElasticQuery = ElasticQuery.create()
.withPagination(pagination)
.withCondition(QueryConditionOptions.must, [QueryType.Match("deployer", address)])
Expand All @@ -444,6 +444,22 @@ export class ElasticIndexerService implements IndexerInterface {
return await this.elasticService.getList('scdeploys', "contract", elasticQuery);
}

async getAccountContracts(pagination: QueryPagination, address: string): Promise<any[]> {
const elasticQuery: ElasticQuery = ElasticQuery.create()
.withPagination(pagination)
.withCondition(QueryConditionOptions.must, [QueryType.Match("currentOwner", address)])
.withSort([{ name: 'timestamp', order: ElasticSortOrder.descending }]);

return await this.elasticService.getList('scdeploys', "contract", elasticQuery);
}

async getAccountContractsCount(address: string): Promise<number> {
const elasticQuery: ElasticQuery = ElasticQuery.create()
.withCondition(QueryConditionOptions.must, [QueryType.Match("currentOwner", address)]);

return await this.elasticService.getCount('scdeploys', elasticQuery);
}

async getProviderDelegators(address: string, pagination: QueryPagination): Promise<any[]> {
const elasticQuery: ElasticQuery = ElasticQuery.create()
.withPagination(pagination)
Expand Down
8 changes: 6 additions & 2 deletions src/common/indexer/indexer.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export interface IndexerInterface {

getScResultsCount(filter: SmartContractResultFilter): Promise<number>

getAccountContractsCount(address: string): Promise<number>
getAccountDeploysCount(address: string): Promise<number>

getBlocksCount(filter: BlockFilter): Promise<number>

Expand Down Expand Up @@ -104,7 +104,11 @@ export interface IndexerInterface {

getAccounts(queryPagination: QueryPagination, filter: AccountQueryOptions): Promise<Account[]>

getAccountContracts(pagination: QueryPagination, address: string): Promise<ScDeploy[]>
getAccountDeploys(pagination: QueryPagination, address: string): Promise<ScDeploy[]>

getAccountContracts(pagination: QueryPagination, address: string): Promise<any[]>

getAccountContractsCount( address: string): Promise<number>

getAccountHistory(address: string, pagination: QueryPagination, filter: AccountHistoryFilter): Promise<AccountHistory[]>

Expand Down
16 changes: 13 additions & 3 deletions src/common/indexer/indexer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ export class IndexerService implements IndexerInterface {
}

@LogPerformanceAsync(MetricsEvents.SetIndexerDuration)
async getAccountContractsCount(address: string): Promise<number> {
return await this.indexerInterface.getAccountContractsCount(address);
async getAccountDeploysCount(address: string): Promise<number> {
return await this.indexerInterface.getAccountDeploysCount(address);
}

@LogPerformanceAsync(MetricsEvents.SetIndexerDuration)
Expand Down Expand Up @@ -230,10 +230,20 @@ export class IndexerService implements IndexerInterface {
}

@LogPerformanceAsync(MetricsEvents.SetIndexerDuration)
async getAccountContracts(pagination: QueryPagination, address: string): Promise<ScDeploy[]> {
async getAccountDeploys(pagination: QueryPagination, address: string): Promise<ScDeploy[]> {
return await this.indexerInterface.getAccountDeploys(pagination, address);
}

@LogPerformanceAsync(MetricsEvents.SetIndexerDuration)
async getAccountContracts(pagination: QueryPagination, address: string): Promise<any[]> {
return await this.indexerInterface.getAccountContracts(pagination, address);
}

@LogPerformanceAsync(MetricsEvents.SetIndexerDuration)
async getAccountContractsCount(address: string): Promise<number> {
return await this.indexerInterface.getAccountContractsCount(address);
}

@LogPerformanceAsync(MetricsEvents.SetIndexerDuration)
async getAccountHistory(address: string, pagination: QueryPagination, filter: AccountHistoryFilter): Promise<AccountHistory[]> {
return await this.indexerInterface.getAccountHistory(address, pagination, filter);
Expand Down
20 changes: 11 additions & 9 deletions src/common/indexer/postgres/postgres.indexer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { TokenFilter } from "src/endpoints/tokens/entities/token.filter";
import { TokenWithRolesFilter } from "src/endpoints/tokens/entities/token.with.roles.filter";
import { TransactionFilter } from "src/endpoints/transactions/entities/transaction.filter";
import { Repository } from "typeorm";
import { Collection, ScResult, Account, MiniBlock, Tag, TokenType, Block } from "../entities";
import { Collection, ScResult, Account, MiniBlock, Tag, TokenType, Block, ScDeploy } from "../entities";
import { IndexerInterface } from "../indexer.interface";
import { AccountDb, AccountsEsdtDb, BlockDb, LogDb, MiniBlockDb, ReceiptDb, RoundInfoDb, ScDeployInfoDb, ScResultDb, TagDb, TokenInfoDb, TransactionDb, ValidatorPublicKeysDb } from "./entities";
import { PostgresIndexerHelper } from "./postgres.indexer.helper";
Expand Down Expand Up @@ -53,6 +53,10 @@ export class PostgresIndexerService implements IndexerInterface {
private readonly validatorPublicKeysRepository: Repository<ValidatorPublicKeysDb>,
private readonly indexerHelper: PostgresIndexerHelper,
) { }

getAccountDeploys(_pagination: QueryPagination, _address: string): Promise<ScDeploy[]> {
throw new Error("Method not implemented.");
}
getApplicationCount(): Promise<number> {
throw new Error("Method not implemented.");
}
Expand Down Expand Up @@ -118,7 +122,7 @@ export class PostgresIndexerService implements IndexerInterface {
return await this.scResultsRepository.count();
}

async getAccountContractsCount(address: string): Promise<number> {
async getAccountDeploysCount(address: string): Promise<number> {
const query = this.scDeploysRepository
.createQueryBuilder()
.where('creator = :address', { address });
Expand Down Expand Up @@ -398,14 +402,12 @@ export class PostgresIndexerService implements IndexerInterface {
return await query.getMany();
}

async getAccountContracts({ from, size }: QueryPagination, address: string): Promise<any[]> {
const query = this.scDeploysRepository
.createQueryBuilder()
.skip(from).take(size)
.where('creator = :address', { address })
.orderBy('timestamp', 'DESC');
getAccountContracts(): Promise<any[]> {
throw new Error("Method not implemented.");
}

return await query.getMany();
getAccountContractsCount(): Promise<number> {
throw new Error("Method not implemented.");
}

async getAccountHistory(address: string, { from, size }: QueryPagination): Promise<any[]> {
Expand Down
33 changes: 30 additions & 3 deletions src/endpoints/accounts/account.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import { AccountKeyFilter } from './entities/account.key.filter';
import { ScamType } from 'src/common/entities/scam-type.enum';
import { DeepHistoryInterceptor } from 'src/interceptors/deep-history.interceptor';
import { MexPairType } from '../mex/entities/mex.pair.type';
import { AccountContract } from './entities/account.contract';

@Controller()
@ApiTags('accounts')
Expand Down Expand Up @@ -1080,21 +1081,47 @@ export class AccountController {
}));
}

@Get("/accounts/:address/deploys")
@ApiOperation({ summary: 'Account deploys details', description: 'Returns deploys details for a given account' })
@ApiQuery({ name: 'from', description: 'Number of items to skip for the result set', required: false })
@ApiQuery({ name: 'size', description: 'Number of items to retrieve', required: false })
@ApiOkResponse({ type: [DeployedContract] })
getAccountDeploys(
@Param('address', ParseAddressPipe) address: string,
@Query('from', new DefaultValuePipe(0), ParseIntPipe) from: number,
@Query('size', new DefaultValuePipe(25), ParseIntPipe) size: number,
): Promise<DeployedContract[]> {
return this.accountService.getAccountDeploys(new QueryPagination({ from, size }), address);
}

@Get("/accounts/:address/deploys/count")
@ApiOperation({ summary: 'Account deploys count', description: 'Returns total number of deploys for a given address' })
@ApiOkResponse({ type: Number })
getAccountDeploysCount(@Param('address', ParseAddressPipe) address: string): Promise<number> {
return this.accountService.getAccountDeploysCount(address);
}

@Get("/accounts/:address/deploys/c")
@ApiExcludeEndpoint()
getAccountDeploysCountAlternative(@Param('address', ParseAddressPipe) address: string): Promise<number> {
return this.accountService.getAccountDeploysCount(address);
}

@Get("/accounts/:address/contracts")
@ApiOperation({ summary: 'Account smart contracts details', description: 'Returns smart contracts details for a given account' })
@ApiOperation({ summary: 'Account contracts details', description: 'Returns contracts details for a given account' })
@ApiQuery({ name: 'from', description: 'Number of items to skip for the result set', required: false })
@ApiQuery({ name: 'size', description: 'Number of items to retrieve', required: false })
@ApiOkResponse({ type: [DeployedContract] })
getAccountContracts(
@Param('address', ParseAddressPipe) address: string,
@Query('from', new DefaultValuePipe(0), ParseIntPipe) from: number,
@Query('size', new DefaultValuePipe(25), ParseIntPipe) size: number,
): Promise<DeployedContract[]> {
): Promise<AccountContract[]> {
return this.accountService.getAccountContracts(new QueryPagination({ from, size }), address);
}

@Get("/accounts/:address/contracts/count")
@ApiOperation({ summary: 'Account contracts count', description: 'Returns total number of deployed contracts for a given address' })
@ApiOperation({ summary: 'Account contracts count', description: 'Returns total number of contracts for a given address' })
@ApiOkResponse({ type: Number })
getAccountContractsCount(@Param('address', ParseAddressPipe) address: string): Promise<number> {
return this.accountService.getAccountContractsCount(address);
Expand Down
23 changes: 21 additions & 2 deletions src/endpoints/accounts/account.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { NodeStatusRaw } from '../nodes/entities/node.status';
import { AccountKeyFilter } from './entities/account.key.filter';
import { Provider } from '../providers/entities/provider';
import { ApplicationMostUsed } from './entities/application.most.used';
import { AccountContract } from './entities/account.contract';

@Injectable()
export class AccountService {
Expand Down Expand Up @@ -614,8 +615,8 @@ export class AccountService {
}
}

async getAccountContracts(pagination: QueryPagination, address: string): Promise<DeployedContract[]> {
const accountDeployedContracts = await this.indexerService.getAccountContracts(pagination, address);
async getAccountDeploys(pagination: QueryPagination, address: string): Promise<DeployedContract[]> {
const accountDeployedContracts = await this.indexerService.getAccountDeploys(pagination, address);
const assets = await this.assetsService.getAllAccountAssets();

const accounts: DeployedContract[] = accountDeployedContracts.map(contract => ({
Expand All @@ -628,6 +629,24 @@ export class AccountService {
return accounts;
}

async getAccountDeploysCount(address: string): Promise<number> {
return await this.indexerService.getAccountDeploysCount(address);
}

async getAccountContracts(pagination: QueryPagination, address: string): Promise<AccountContract[]> {
const accountContracts = await this.indexerService.getAccountContracts(pagination, address);
const assets = await this.assetsService.getAllAccountAssets();

const accounts: DeployedContract[] = accountContracts.map(contract => ({
address: contract.contract,
deployTxHash: contract.deployTxHash,
timestamp: contract.timestamp,
assets: assets[contract.contract],
}));

return accounts;
}

async getAccountContractsCount(address: string): Promise<number> {
return await this.indexerService.getAccountContractsCount(address);
}
Expand Down
26 changes: 26 additions & 0 deletions src/endpoints/accounts/entities/account.contract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Field, Float, ObjectType } from "@nestjs/graphql";
import { ApiProperty } from "@nestjs/swagger";
import { AccountAssets } from "src/common/assets/entities/account.assets";

@ObjectType("AccountContract", { description: "Account contract object type." })
export class AccountContract {
constructor(init?: Partial<AccountContract>) {
Object.assign(this, init);
}

@Field(() => String, { description: 'Address for the given account.' })
@ApiProperty({ type: String })
address: string = "";

@Field(() => String, { description: 'DeployTxHash for the given account.' })
@ApiProperty({ type: String })
deployTxHash: string = "";

@Field(() => Float, { description: 'Timestamp for the given account.' })
@ApiProperty({ type: Number })
timestamp: number = 0;

@Field(() => AccountAssets, { description: 'Assets for the given account.', nullable: true })
@ApiProperty({ type: AccountAssets, nullable: true, description: 'Contract assets' })
assets: AccountAssets | undefined = undefined;
}
Original file line number Diff line number Diff line change
Expand Up @@ -124,19 +124,19 @@ export class AccountDetailedResolver extends AccountDetailedQuery {
}));
}

@ResolveField("contractAccount", () => [DeployedContract], { name: "contractAccount", description: "Contracts for the given detailed account.", nullable: true })
public async getAccountContracts(@Args("input", { description: "Input to retrieve the given contracts for." }) input: GetFromAndSizeInput, @Parent() account: AccountDetailed) {
return await this.accountService.getAccountContracts(
@ResolveField("deploysAccount", () => [DeployedContract], { name: "deploysAccount", description: "Deploys for the given detailed account.", nullable: true })
public async getAccountDeploys(@Args("input", { description: "Input to retrieve the given deploys for." }) input: GetFromAndSizeInput, @Parent() account: AccountDetailed) {
return await this.accountService.getAccountDeploys(
new QueryPagination({
from: input.from,
size: input.size,
}), account.address
);
}

@ResolveField("contractAccountCount", () => Float, { name: "contractAccountCount", description: "Contracts count for the given detailed account." })
public async getAccountContractsCount(@Parent() account: AccountDetailed) {
return await this.accountService.getAccountContractsCount(account.address);
@ResolveField("deployAccountCount", () => Float, { name: "deployAccountCount", description: "Contracts count for the given detailed account." })
public async getAccountDeploysCount(@Parent() account: AccountDetailed) {
return await this.accountService.getAccountDeploysCount(account.address);
}

@ResolveField("nftCollections", () => [NftCollectionAccountFlat], { name: "nftCollections", description: "NFT collections for the given detailed account.", nullable: true })
Expand Down
16 changes: 8 additions & 8 deletions src/test/unit/services/accounts.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ describe('Account Service', () => {
getAccounts: jest.fn(),
getAccountsCount: jest.fn(),
getAccountsForAddresses: jest.fn(),
getAccountContracts: jest.fn(),
getAccountContractsCount: jest.fn(),
getAccountDeploys: jest.fn(),
getAccountDeploysCount: jest.fn(),
getAccountHistory: jest.fn(),
getAccountTokenHistory: jest.fn(),
getAccountHistoryCount: jest.fn(),
Expand Down Expand Up @@ -556,11 +556,11 @@ describe('Account Service', () => {
const address = 'erd1qga7ze0l03chfgru0a32wxqf2226nzrxnyhzer9lmudqhjgy7ycqjjyknz';
const contractsCount = 5;

jest.spyOn(indexerService, 'getAccountContractsCount').mockResolvedValue(contractsCount);
jest.spyOn(indexerService, 'getAccountDeploysCount').mockResolvedValue(contractsCount);

const result = await service.getAccountContractsCount(address);
const result = await service.getAccountDeploysCount(address);

expect(indexerService.getAccountContractsCount).toHaveBeenCalledWith(address);
expect(indexerService.getAccountDeploysCount).toHaveBeenCalledWith(address);
expect(result).toEqual(contractsCount);
});
});
Expand Down Expand Up @@ -860,12 +860,12 @@ describe('Account Service', () => {
};

it('should return the account contracts', async () => {
jest.spyOn(indexerService, 'getAccountContracts').mockResolvedValue(details);
jest.spyOn(indexerService, 'getAccountDeploys').mockResolvedValue(details);
jest.spyOn(assetsService, 'getAllAccountAssets').mockResolvedValue(assets);

const result = await service.getAccountContracts(pagination, address);
const result = await service.getAccountDeploys(pagination, address);

expect(indexerService.getAccountContracts).toHaveBeenCalledWith(pagination, address);
expect(indexerService.getAccountDeploys).toHaveBeenCalledWith(pagination, address);
expect(assetsService.getAllAccountAssets).toHaveBeenCalled();

const expectedAccounts = details.map(contract => ({
Expand Down

0 comments on commit 081bd5a

Please sign in to comment.