Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { TransactionScanResponse } from '@blockaid/client/resources/evm/evm
import type { Address } from 'viem';
import { faker } from '@faker-js/faker';
import type Blockaid from '@blockaid/client';
import type { ILoggingService } from '@/logging/logging.interface';

const createMockWithResponse = (
data: TransactionScanResponse,
Expand Down Expand Up @@ -36,13 +37,17 @@ const mockBlockaidClient = {
},
} as jest.MockedObjectDeep<Blockaid>;

const mockLoggingService = {
info: jest.fn(),
} as jest.MockedObjectDeep<ILoggingService>;

describe('BlockaidApi', () => {
let service: BlockaidApi;

beforeEach(() => {
jest.resetAllMocks();

service = new BlockaidApi();
service = new BlockaidApi(mockLoggingService);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(service as any).blockaidClient = mockBlockaidClient;
});
Expand Down Expand Up @@ -99,9 +104,14 @@ describe('BlockaidApi', () => {
const request_id = faker.string.uuid();

const mockScanResponse: TransactionScanResponse = {
block: faker.string.numeric(),
chain: `0x${chainId}`,
status: 'Success',
block: faker.string.numeric(),
validation: {
status: 'Success',
result_type: 'Benign',
description: 'No issues detected',
features: [],
},
} as TransactionScanResponse;

mockBlockaidClient.evm.jsonRpc.scan.mockReturnValue(
Expand Down Expand Up @@ -132,6 +142,20 @@ describe('BlockaidApi', () => {
...mockScanResponse,
request_id,
});
expect(mockLoggingService.info).toHaveBeenCalledWith({
message: 'Blockaid scan response',
response: {
chain: mockScanResponse.chain,
request_id,
validation: {
status: mockScanResponse.validation?.status,
result_type: mockScanResponse.validation?.result_type,
description: mockScanResponse.validation?.description,
features: [],
},
simulation: undefined,
},
});
});

it('should call blockaid client without domain parameter/ with non_dapp', async () => {
Expand All @@ -140,7 +164,6 @@ describe('BlockaidApi', () => {
const mockScanResponse: TransactionScanResponse = {
block: faker.string.numeric(),
chain: `0x${chainId}`,
status: 'Success',
} as TransactionScanResponse;

mockBlockaidClient.evm.jsonRpc.scan.mockReturnValue(
Expand Down Expand Up @@ -176,7 +199,6 @@ describe('BlockaidApi', () => {
const mockScanResponse: TransactionScanResponse = {
block: faker.string.numeric(),
chain: `0x${chainId}`,
status: 'Success',
} as TransactionScanResponse;

mockBlockaidClient.evm.jsonRpc.scan.mockReturnValue(
Expand All @@ -194,6 +216,16 @@ describe('BlockaidApi', () => {
...mockScanResponse,
request_id: undefined,
});

expect(mockLoggingService.info).toHaveBeenCalledWith({
message: 'Blockaid scan response',
response: {
chain: mockScanResponse.chain,
request_id: undefined,
validation: undefined,
simulation: undefined,
},
});
});

it('should forward errors from blockaid client', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,19 @@ import { ReportEvent } from '@/modules/safe-shield/entities/dtos/report-false-re
import { BLOCKAID_REQUEST_ID_HEADER } from '@/modules/safe-shield/threat-analysis/blockaid/blockaid-api.constants';
import Blockaid from '@blockaid/client';
import { JsonRpcScanParams } from '@blockaid/client/resources/evm/json-rpc';
import { Injectable } from '@nestjs/common';
import { Inject, Injectable } from '@nestjs/common';
import { Address, numberToHex } from 'viem';
import { ILoggingService, LoggingService } from '@/logging/logging.interface';
import { BlockaidScanLogSchema } from '@/modules/safe-shield/threat-analysis/blockaid/schemas/blockaid-scan-log.schema';

@Injectable()
export class BlockaidApi implements IBlockaidApi {
private readonly blockaidClient: Blockaid;

constructor() {
constructor(
@Inject(LoggingService)
private readonly loggingService: ILoggingService,
) {
this.blockaidClient = new Blockaid();
}

Expand Down Expand Up @@ -54,6 +59,7 @@ export class BlockaidApi implements IBlockaidApi {
const request_id =
response.headers.get(BLOCKAID_REQUEST_ID_HEADER) ?? undefined;

this.logScanResponse({ ...data, request_id });
return { ...data, request_id };
}

Expand All @@ -71,4 +77,14 @@ export class BlockaidApi implements IBlockaidApi {
},
});
}

private logScanResponse(
response: TransactionScanResponseWithRequestId,
): void {
const logData = BlockaidScanLogSchema.parse({ ...response });
this.loggingService.info({
message: 'Blockaid scan response',
response: logData,
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { z } from 'zod';

export const BlockaidScanLogSchema = z.object({
chain: z.string(),
request_id: z.string().optional(),
validation: z
.object({
status: z.string(),
result_type: z.string(),
description: z.string().optional(),
features: z
.array(
z.object({
type: z.string(),
feature_id: z.string(),
}),
)
.optional(),
})
.optional(),
simulation: z
.object({
status: z.string(),
})
.optional(),
});

export type BlockaidScanLog = z.infer<typeof BlockaidScanLogSchema>;