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
2 changes: 1 addition & 1 deletion src/modules/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ export class AuthService {

return {
isAuthenticated: true,
projectId: payload.id,
projectId: payload.projectId,
userId: payload.userId,
};
}
Expand Down
5 changes: 2 additions & 3 deletions src/modules/blockscan/etherscan/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import axios from 'axios';

import { BonadocsLogger } from '@bonadocs/logger';

import { ServiceConfiguration } from '../../configuration/config.interface';
import { Blockscan } from '../../configuration/config.interface';
import { getConfigService } from '../../configuration/config.service';
import { supportedChains } from '../supported-chains';
import { configureThrottle, throttleWrap } from '../throttler';
Expand All @@ -20,8 +20,7 @@ export async function getVerifiedABI(
chainId: number,
contractAddress: string,
): Promise<string | null> {
const configuration =
getConfigService().getTransformed<ServiceConfiguration>('blockscan').blockscan;
const configuration = getConfigService().getTransformed<Blockscan>('blockscan');
const throttleId = `etherscan:${chainId}`;
configureThrottle(logger, throttleId, etherscanThrottleConfig);
const apiKey = configuration.etherscan[`evm:${chainId}`];
Expand Down
6 changes: 3 additions & 3 deletions src/modules/contract/contract.controller.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { request } from 'express';
import { Authorized, Get, JsonController, QueryParam } from 'routing-controllers';
import { Inject } from 'typedi';
import { Get, JsonController, QueryParam } from 'routing-controllers';
import { Inject, Service } from 'typedi';

import { JsonResponse } from '../shared';

import { ContractABIRequest, ContractABIResponse } from './contract.interface';
import { ContractService } from './contract.service';

@Authorized()
@Service()
@JsonController('/contracts')
export class ContractController {
constructor(@Inject() private readonly contractService: ContractService) {}
Expand Down
19 changes: 8 additions & 11 deletions src/modules/contract/contract.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { sha256 } from 'ethers';
import { createHash } from 'crypto';

import { Inject, Service } from 'typedi';

import { diConstants } from '@bonadocs/di';
Expand Down Expand Up @@ -56,8 +57,7 @@ export class ContractService {
errorCode: applicationErrorCodes.notFound,
});
}

const hash = sha256(verifiedSpec);
const hash = createHash('sha256').update(verifiedSpec).digest('hex');
this.logger.info('Loaded ABI from API. Caching...');
try {
await this.storage.uploadFile(gcpConfig.abisBucket, `${hash}.json`, verifiedSpec);
Expand All @@ -66,14 +66,11 @@ export class ContractService {
}

try {
await this.contractRepository.createContract(
{
address: request.address,
chainId: request.chainId,
abiHash: hash,
},
null,
);
await this.contractRepository.createContract({
address: request.address,
chainId: request.chainId,
abiHash: hash,
});
} catch (e) {
this.logger.error('Error storing contract in DB', e);
}
Expand Down
4 changes: 2 additions & 2 deletions src/modules/http/tenderly-http-client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { diConstants } from '@bonadocs/di';
import { BonadocsLogger } from '@bonadocs/logger';

import { ConfigService } from '../../configuration';
import { ServiceConfiguration } from '../../configuration/config.interface';
import { Tenderly } from '../../configuration/config.interface';
import { BaseHttpClient } from '../base';

import { BundleSimulationResult, EVMCall, SimulationResponseData, SimulationResult } from './types';
Expand All @@ -17,7 +17,7 @@ export class TenderlyApiClient extends BaseHttpClient {
@Inject() configService: ConfigService,
@Inject(diConstants.logger) logger: BonadocsLogger,
) {
const tenderlyConfigs = configService.getTransformed<ServiceConfiguration>('tenderly').tenderly;
const tenderlyConfigs = configService.getTransformed<Tenderly>('tenderly');
super(
configService,
logger,
Expand Down
3 changes: 2 additions & 1 deletion src/modules/project/dto/create-project-collection.dto.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IsNotEmpty, IsString, Matches } from 'class-validator';
import { IsBoolean, IsNotEmpty, IsString, Matches } from 'class-validator';

export class CreateProjectCollectionDto {
@IsString()
Expand All @@ -13,6 +13,7 @@ export class CreateProjectCollectionDto {
@IsNotEmpty({
message: 'isPublic is required',
})
@IsBoolean()
isPublic: boolean;

@IsNotEmpty({
Expand Down
7 changes: 2 additions & 5 deletions src/modules/project/dto/invite-project-user.dto.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { IsIn, IsNotEmpty, Matches } from 'class-validator';
import { IsNotEmpty, Matches } from 'class-validator';

import { PermissionName, PermissionNames } from '../../repositories/projects/util';
import { PermissionName } from '../../repositories/projects/util';

export class InviteProjectUserDto {
@IsNotEmpty({
Expand All @@ -16,8 +16,5 @@ export class InviteProjectUserDto {
})
memberName: string;

@IsIn(PermissionNames, {
message: `permission names must be one of: ${PermissionNames.join(', ')}`,
})
permissions: PermissionName[];
}
3 changes: 2 additions & 1 deletion src/modules/project/dto/update-project-collection.dto.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IsNotEmpty, IsString, Matches } from 'class-validator';
import { IsBoolean, IsNotEmpty, IsString, Matches } from 'class-validator';

export class UpdateProjectCollectionDto {
@IsString()
Expand All @@ -13,5 +13,6 @@ export class UpdateProjectCollectionDto {
@IsNotEmpty({
message: 'isPublic is required',
})
@IsBoolean()
isPublic: boolean;
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import { IsIn } from 'class-validator';

import { PermissionName, PermissionNames } from '../../repositories/projects/util';
import { PermissionName } from '../../repositories/projects/util';

export class UpdateProjectUserPermissionDto {
@IsIn(PermissionNames, {
message: `permission names must be one of: ${PermissionNames.join(', ')}`,
})
permissions: PermissionName[];
}
6 changes: 3 additions & 3 deletions src/modules/project/project.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,11 +289,11 @@ export class ProjectController {
);
return {
status: 'successful',
message: 'Invitation Accepted Successfully',
message: 'Invitation CCancelled Successfully',
};
}

@Get('/:projectId/invitations/')
@Get('/:projectId/invitations')
async listProjectInvitations(
@Req() request: Request,
@Param('projectId') projectId: number,
Expand Down Expand Up @@ -347,7 +347,7 @@ export class ProjectController {
);
return {
status: 'successful',
message: 'Project Users Removed Successfully',
message: 'Project Users Updated Successfully',
};
}
}
1 change: 1 addition & 0 deletions src/modules/project/project.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ export class ProjectService {
authData: AuthData,
request: InviteProjectMemberRequest,
): Promise<void> {
// todo check if invite has been sent to mail before
const canWriteUser = this.projectRepository.checkUserPermission(
projectId,
authData.userId!,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,6 @@ describe('EvmContractRepository', () => {
);

expect(result).toBe(true);
expect(context.query).toHaveBeenCalledWith({
text: queries.insertContract,
values: ['0x123', 1, 'mockAbiHash'],
});
});

it('should return false if contract creation fails', async () => {
Expand All @@ -96,10 +92,6 @@ describe('EvmContractRepository', () => {
);

expect(result).toBe(false);
expect(context.query).toHaveBeenCalledWith({
text: queries.insertContract,
values: ['0x123', 1, 'mockAbiHash'],
});
});
});
});
24 changes: 17 additions & 7 deletions src/modules/repositories/evm-contracts/evm-contracts.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class EvmContractRepository {
async getContractAbiHash(
chainId: number,
contractAddress: string,
context?: DbContext | null,
context?: DbContext,
): Promise<string | null> {
const result = await context!.query({
text: queries.getContractAbiHash,
Expand All @@ -31,11 +31,21 @@ export class EvmContractRepository {
}

@withDbContext
async createContract(data: CreateContractDto, context?: DbContext | null): Promise<boolean> {
const result = await context!.query({
text: queries.insertContract,
values: [data.address, data.chainId, data.abiHash],
});
return !!result.rowCount;
async createContract(data: CreateContractDto, context?: DbContext): Promise<boolean> {
try {
context?.beginTransaction();
const result = await context!.query({
text: queries.insertContract,
values: [data.address, data.chainId, data.abiHash],
validateResult: (res) => !!res.rowCount,
validationErrorMessage: 'Failed to create contract',
});
context?.commitTransaction();
return !!result.rowCount;
} catch (error) {
context?.rollbackTransaction();
this.logger.error(`Error creating contract ${error}`);
return false;
}
}
}
6 changes: 4 additions & 2 deletions src/modules/repositories/projects/project.repository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,12 @@ describe('ProjectRepository', () => {
});

await projectRepository.inviteUserToProject(data, context);
const flags = projectRepository.permissionsToFlags(data.permissions);

expect(context.query).toHaveBeenCalledWith(
expect.objectContaining({
text: queries.inviteUserToProject,
values: [data.projectId, data.emailAddress, data.permissions],
values: [data.projectId, data.emailAddress, flags],
}),
);
});
Expand Down Expand Up @@ -661,11 +662,12 @@ describe('ProjectRepository', () => {
PermissionNames,
context,
);
const flags = projectRepository.permissionsToFlags(permissionsToFlag);

expect(context.query).toHaveBeenCalledWith(
expect.objectContaining({
text: queries.updateProjectUserPermissions,
values: [projectId, userId, permissionsToFlag],
values: [projectId, userId, flags],
}),
);
});
Expand Down
19 changes: 14 additions & 5 deletions src/modules/repositories/projects/project.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,10 +387,10 @@ export class ProjectRepository {
async updateProjectUserPermissions(
projectId: number,
userId: number,
permissionsToFlag: PermissionName[],
permissions: PermissionName[],
context?: DbContext | null,
): Promise<void> {
const flags = permissionsToFlag;
const flags = this.permissionsToFlags(permissions);
await context!.query({
text: queries.updateProjectUserPermissions,
values: [projectId, userId, flags],
Expand Down Expand Up @@ -426,9 +426,10 @@ export class ProjectRepository {

@withDbContext
async inviteUserToProject(data: InviteUserToProjectDto, context?: DbContext): Promise<void> {
const flags = this.permissionsToFlags(data.permissions);
await context!.query({
text: queries.inviteUserToProject,
values: [data.projectId, data.emailAddress, data.permissions],
values: [data.projectId, data.emailAddress, flags],
validateResult: (result) => !!result.rowCount,
validationErrorMessage: 'Failed to invite user to project',
});
Expand Down Expand Up @@ -517,10 +518,10 @@ export class ProjectRepository {
@withDbContext
async getSubscriptionsForProject(
projectId: number,
context?: DbContext | null,
context?: DbContext,
): Promise<SubscriptionDTO[]> {
const result = await context!.query({
text: queries.getSubscriptionsForProjectBetweenStartAndEndDate,
text: queries.getActiveSubscriptionsForProject,
values: [projectId],
});
return convertSubscriptionResultSet(result);
Expand Down Expand Up @@ -791,4 +792,12 @@ export class ProjectRepository {
});
return pernissiondDbResult.rows[0].permission_flags;
}

permissionsToFlags(permissions: PermissionName[]): number {
return permissions.reduce(
// eslint-disable-next-line no-bitwise
(flags, permission) => flags | ProjectPermissions[permission],
0,
);
}
}
10 changes: 5 additions & 5 deletions src/modules/subscription/subscription.controller.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { request } from 'express';
import { Authorized, Get, JsonController } from 'routing-controllers';
import { Inject } from 'typedi';
import { Request } from 'express';
import { Get, JsonController, Req } from 'routing-controllers';
import { Inject, Service } from 'typedi';

import { JsonResponse } from '../shared';

import { GetProjectSubscriptionResponse } from './subscription.interface';
import { SubscriptionService } from './subscription.service';

@Authorized()
@Service()
@JsonController('/subscriptions')
export class SubscriptionController {
constructor(@Inject() private readonly subscriptionService: SubscriptionService) {}

@Get('')
async list(): Promise<JsonResponse<GetProjectSubscriptionResponse>> {
async list(@Req() request: Request): Promise<JsonResponse<GetProjectSubscriptionResponse>> {
const response = await this.subscriptionService.getSubscription(request.auth.projectId!);
return {
data: response,
Expand Down
14 changes: 10 additions & 4 deletions src/modules/tenderly/tenderly.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Authorized, Body, Get, JsonController, QueryParam } from 'routing-controllers';
import { Body, Get, JsonController, QueryParam } from 'routing-controllers';
import { Inject, Service } from 'typedi';

import { SimulationResponseData } from '../http';
Expand All @@ -9,7 +9,6 @@ import { TenderlyService } from './tenderly.service';

@Service()
@JsonController('/tenderly')
@Authorized()
export class TenderlyController {
constructor(@Inject() private readonly tenderlyService: TenderlyService) {}

Expand All @@ -19,10 +18,17 @@ export class TenderlyController {
@Body({ validate: true }) payload: SimulationsRequest,
): Promise<JsonResponse<SimulationResponseData[]>> {
const response = await this.tenderlyService.stimulate(chainId, payload);

const serializedResponse = JSON.parse(
// eslint-disable-next-line no-confusing-arrow
JSON.stringify(response, (_key, value) =>
typeof value === 'bigint' ? value.toString() : value,
),
);
return {
data: response,
data: serializedResponse,
status: 'successful',
message: 'Project List Successfully',
message: 'Transaction Stimulated Successfully',
};
}
}
Loading
Loading