Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

contracts deploys endpoints #1336

Merged
merged 6 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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[]> {
cfaur09 marked this conversation as resolved.
Show resolved Hide resolved
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
Loading