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

Feature/scan 432 parse ethereum executed event #166

Merged
merged 3 commits into from
Nov 29, 2022
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
5 changes: 5 additions & 0 deletions apps/crawler/src/config/config.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export type Config = {
prometheusPort: number;

batchSize: number;

rpcProviderUrl: string;
};

const loadConfig = (): Config => ({
Expand Down Expand Up @@ -59,6 +61,9 @@ const loadConfig = (): Config => ({
prometheusPort: +process.env.PROMETHEUS_PORT || 9090,

batchSize: +process.env.BATCH_SIZE || 10,

rpcProviderUrl:
process.env.RPC_PROVIDER_URL || 'https://rpc-opal.unique.network',
});

export const GlobalConfigModule = ConfigModule.forRoot({
Expand Down
1 change: 1 addition & 0 deletions apps/crawler/src/sdk/sdk.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CACHE_MANAGER, Inject, Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Cache } from 'cache-manager';
import { Client } from '@unique-nft/substrate-client';
import {
CollectionInfoWithSchema,
Expand Down
14 changes: 13 additions & 1 deletion apps/crawler/src/services/event/event.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ import {
import { EventArgumentsService } from './event.arguments.service';
import { EventArgs } from './event.types';
import { AccountRecord } from '../account/account.types';
import { EvmService } from '../evm/evm.service';

@Injectable()
export class EventService {
constructor(
private eventArgumentsService: EventArgumentsService,
private evmService: EvmService,

@InjectRepository(Event)
private eventsRepository: Repository<Event>,
Expand All @@ -29,7 +31,7 @@ export class EventService {
private extractEventItems(blockItems: IBlockItem[]): IEvent[] {
return blockItems
.map((item) => {
if (item.kind == 'event') {
if (item.kind === 'event') {
return item.event as IEvent;
}
return null;
Expand Down Expand Up @@ -105,6 +107,16 @@ export class EventService {
eventItems,
});

const ethereumEvents = eventsData.filter(
({ section, method }) =>
section === EventSection.ETHEREUM && method === EventMethod.EXECUTED,
);

await this.evmService.parseEvents(
ethereumEvents,
blockCommonData.blockTimestamp,
);

await this.eventsRepository.upsert(eventsData, [
'block_number',
'event_index',
Expand Down
102 changes: 102 additions & 0 deletions apps/crawler/src/services/evm/evm.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { Repository } from 'typeorm';
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Event } from '@entities/Event';
import { ethers } from 'ethers';
import { ConfigService } from '@nestjs/config';
import { EvmTransaction } from '@entities/EvmTransaction';
import { SentryService } from '@ntegral/nestjs-sentry';
import { normalizeTimestamp } from '@common/utils';
import { Config } from '../../config/config.module';

@Injectable()
export class EvmService {
provider: ethers.providers.JsonRpcProvider;

constructor(
@InjectRepository(EvmTransaction)
private transactionRepository: Repository<EvmTransaction>,
private configService: ConfigService<Config>,
private readonly sentry: SentryService,
) {
this.provider = new ethers.providers.JsonRpcProvider(
this.configService.get('rpcProviderUrl'),
);

this.sentry.setContext(EvmService.name);
}

public async parseEvents(events: Event[], timestamp: number) {
try {
const transactions: ethers.providers.TransactionReceipt[] = [];

for (const event of events) {
const [, , transactionHash] = event.data.split(',');
if (transactionHash && typeof transactionHash === 'string') {
const hash = transactionHash.replaceAll('"', '');

const transaction = await (
await this.provider.getTransaction(hash)
).wait();

transactions.push({ ...transaction });
}
}

if (transactions.length) {
await this.transactionRepository.upsert(
this.convertForDb(transactions, timestamp),
['block_hash', 'transaction_hash'],
);
}
} catch (error) {
this.sentry.instance().captureException({ error });
}
}

private convertForDb(
transactions: ethers.providers.TransactionReceipt[],
timestamp: number,
) {
const utcTimestamp = String(normalizeTimestamp(timestamp));

return transactions.map((transaction) => {
const {
to,
from,
byzantium,
transactionHash,
confirmations,
cumulativeGasUsed,
status,
type,
blockNumber,
gasUsed,
effectiveGasPrice,
blockHash,
logsBloom,
transactionIndex,
contractAddress,
} = transaction;

return {
to,
from,
contract_address: contractAddress,
transaction_index: transactionIndex,
gas_used: gasUsed.toNumber(),
logs_bloom: logsBloom,
block_hash: blockHash,
transaction_hash: transactionHash,
block_number: blockNumber,
confirmations,
cumulative_gas_used: cumulativeGasUsed.toNumber(),
effective_gas_price: effectiveGasPrice.toNumber(),
status,
type,
byzantium,
timestamp: utcTimestamp,
};
});
}
}
9 changes: 7 additions & 2 deletions apps/crawler/src/services/services.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { Block } from '@entities/Block';
import { Collections } from '@entities/Collections';
import { Tokens } from '@entities/Tokens';
import { Event } from '@entities/Event';
import { EvmTransaction } from '@entities/EvmTransaction';
import { Extrinsic } from '@entities/Extrinsic';
import { Account } from '@entities/Account';
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Extrinsic } from '@entities/Extrinsic';
import { Account } from '@entities/Account';
import { CollectionService } from './collection.service';
import { AccountService } from './account/account.service';
import { TokenService } from './token/token.service';
Expand All @@ -16,6 +17,7 @@ import { ExtrinsicService } from './extrinsic.service';
import { EventArgumentsService } from './event/event.arguments.service';
import { SdkModule } from '../sdk/sdk.module';
import { TokenNestingService } from './token/nesting.service';
import { EvmService } from './evm/evm.service';

@Module({
imports: [
Expand All @@ -26,6 +28,7 @@ import { TokenNestingService } from './token/nesting.service';
Event,
Extrinsic,
Tokens,
EvmTransaction,
]),
ConfigModule,
SdkModule,
Expand All @@ -39,6 +42,7 @@ import { TokenNestingService } from './token/nesting.service';
ExtrinsicService,
TokenService,
TokenNestingService,
EvmService,
],
exports: [
AccountService,
Expand All @@ -48,6 +52,7 @@ import { TokenNestingService } from './token/nesting.service';
ExtrinsicService,
TokenService,
TokenNestingService,
EvmService,
],
})
export class ServicesModule {}
2 changes: 2 additions & 0 deletions apps/web-api/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { TransactionModule } from './transaction/transaction.module';
import { SentryModule } from '@ntegral/nestjs-sentry';
import { ContractModule } from './contract/contract.module';
import { AttributesModule } from './attributes/attributes.module';
import { EvmTransactionModule } from './evm-transactions/evm-transaction.module';

@Module({
imports: [
Expand Down Expand Up @@ -59,6 +60,7 @@ import { AttributesModule } from './attributes/attributes.module';
StatisticsModule,
TransactionModule,
AttributesModule,
EvmTransactionModule,
],
providers: [
{
Expand Down
5 changes: 2 additions & 3 deletions apps/web-api/src/event/event.service.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { Event } from '@entities/Event';
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { In, Not, Repository, SelectQueryBuilder } from 'typeorm';
import { Repository, SelectQueryBuilder } from 'typeorm';
import { GraphQLResolveInfo } from 'graphql';
import { BaseService } from '../utils/base.service';
import { IDataListResponse, IGQLQueryArgs } from '../utils/gql-query-args';
import { EventDTO } from './event.dto';
import { EventMethod, EventSection } from '@common/constants';
import { GraphQLResolveInfo } from 'graphql';

const customQueryFields = {
amount: `
Expand Down
53 changes: 53 additions & 0 deletions apps/web-api/src/evm-transactions/evm-transaction.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Field, Float, Int, ObjectType } from '@nestjs/graphql';
import { EvmTransaction } from '@entities/EvmTransaction';

@ObjectType('evmTransaction')
export class EvmTransactionDTO implements Partial<EvmTransaction> {
@Field()
to?: string;

@Field()
from?: string;

@Field({ nullable: true })
contract_address?: string | null;

@Field(() => Int)
transaction_index?: number;

@Field(() => Float)
gas_used?: number;

@Field()
logs_bloom?: string;

@Field()
block_hash?: string;

@Field()
transaction_hash?: string;

@Field(() => Int)
block_number?: number;

@Field(() => Int)
confirmations?: number;

@Field(() => Float)
cumulative_gas_used?: number;

@Field(() => Float)
effective_gas_price?: number;

@Field(() => Int)
status?: number;

@Field(() => Int)
type?: number;

@Field(() => Boolean)
byzantium?: boolean;

@Field(() => Int, { nullable: true })
timestamp?: string;
}
11 changes: 11 additions & 0 deletions apps/web-api/src/evm-transactions/evm-transaction.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { EvmTransaction } from '@entities/EvmTransaction';
import { EvmTransactionResolver } from './evm-transaction.resolver';
import { EvmTransactionService } from './evm-transaction.service';

@Module({
imports: [TypeOrmModule.forFeature([EvmTransaction])],
providers: [EvmTransactionResolver, EvmTransactionService],
})
export class EvmTransactionModule {}
84 changes: 84 additions & 0 deletions apps/web-api/src/evm-transactions/evm-transaction.resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import {
Args,
ArgsType,
Field,
Info,
InputType,
ObjectType,
Query,
Resolver,
} from '@nestjs/graphql';
import {
GQLOrderByParamsArgs,
GQLQueryPaginationArgs,
GQLWhereOpsInt,
GQLWhereOpsString,
IDataListResponse,
IGQLQueryArgs,
ListDataType,
TOrderByParams,
TWhereParams,
} from '../utils/gql-query-args';
import { EvmTransactionDTO } from './evm-transaction.dto';
import { EvmTransactionService } from './evm-transaction.service';

@InputType()
class EvmTransactionWhereParams implements TWhereParams<EvmTransactionDTO> {
@Field(() => GQLWhereOpsString, { nullable: true })
from?: GQLWhereOpsString;

@Field(() => GQLWhereOpsString, { nullable: true })
to?: GQLWhereOpsString;

@Field(() => GQLWhereOpsInt, { nullable: true })
block_number?: GQLWhereOpsInt;

@Field(() => GQLWhereOpsString, { nullable: true })
block_hash?: GQLWhereOpsString;

@Field(() => GQLWhereOpsString, { nullable: true })
transaction_hash?: GQLWhereOpsString;

@Field(() => [EvmTransactionWhereParams], { nullable: true })
_and?: EvmTransactionWhereParams[];

@Field(() => [EvmTransactionWhereParams], { nullable: true })
_or?: EvmTransactionWhereParams[];
}

@InputType()
class EvmTransactionOrderByParams implements TOrderByParams<EvmTransactionDTO> {
@Field(() => GQLOrderByParamsArgs, { nullable: true })
block_number?: GQLOrderByParamsArgs;

@Field(() => GQLOrderByParamsArgs, { nullable: true })
timestamp?: GQLOrderByParamsArgs;
}

@ObjectType()
class EmvTransactionDataResponse extends ListDataType(EvmTransactionDTO) {}

@ArgsType()
export class QueryArgs
extends GQLQueryPaginationArgs
implements IGQLQueryArgs<EvmTransactionDTO>
{
@Field(() => EvmTransactionWhereParams, { nullable: true })
where?: EvmTransactionWhereParams;

@Field(() => EvmTransactionOrderByParams, { nullable: true })
order_by?: EvmTransactionOrderByParams;
}

@Resolver(() => EvmTransactionDTO)
export class EvmTransactionResolver {
constructor(private service: EvmTransactionService) {}

@Query(() => EmvTransactionDataResponse)
public async evmTransactions(
@Args() args: QueryArgs,
@Info() info,
): Promise<IDataListResponse<EvmTransactionDTO>> {
return this.service.find(args, info);
}
}
Loading