Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
@bonadocs:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=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
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { afterEach, beforeEach, describe, expect, it, jest } from '@jest/globals';
import { QueryResult } from 'pg';

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

import { getMockLogger } from '../../../test/util';
import { DbContext } from '../../connection/dbcontext';

import { EvmContractRepository } from './evm-contracts.repository';
import { queries } from './queries';

describe('EvmContractRepository', () => {
let evmContractsRepository: EvmContractRepository;
let context: DbContext;
let logger: BonadocsLogger;

beforeEach(() => {
logger = getMockLogger();
evmContractsRepository = new EvmContractRepository(logger);
context = {
isDbContext: true as boolean,
entrypoint: 'test',
logger: createLogger({ context: 'test' }) as BonadocsLogger,

// Mock query method
query: jest.fn().mockImplementation(() =>
Promise.resolve({
rowCount: 0,
rows: [],
oid: 0,
fields: [],
command: '',
} as QueryResult),
),

// Mock transaction methods
beginTransaction: jest.fn().mockImplementation(() => Promise.resolve()),
commitTransaction: jest.fn().mockImplementation(() => Promise.resolve()),
rollbackTransaction: jest.fn().mockImplementation(() => Promise.resolve()),
} as unknown as DbContext;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a test utility function to provide a mock DbContext

});

afterEach(() => {
jest.clearAllMocks();
});

describe('getContractAbiHash', () => {
it('should return null if no contract is found', async () => {
(context.query as jest.Mock).mockImplementation(() =>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you use jest.Mocked from above, this cast is unnecessary

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make the update across all of your test functions

Promise.resolve({
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use mockResolvedValue rather than mockImplementation. It's a utility to achieve the same thing but it's neater.

rowCount: 0,
rows: [],
oid: 0,
fields: [],
command: '',
} as QueryResult),
);

const result = await evmContractsRepository.getContractAbiHash(1, '0x123', context);

expect(result).toBeNull();
expect(context.query).toHaveBeenCalledWith({
text: queries.getContractAbiHash,
values: [1, '0x123'],
});
});

it('should return abi_hash if contract is found', async () => {
const mockAbiHash = 'mockAbiHash';
(context.query as jest.Mock).mockImplementation(() =>
Promise.resolve({
rowCount: 1,
rows: [{ abi_hash: mockAbiHash }],
oid: 0,
fields: [],
command: '',
} as QueryResult),
);

const result = await evmContractsRepository.getContractAbiHash(1, '0x123', context);

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

describe('createContract', () => {
it('should return true if contract is created successfully', async () => {
(context.query as jest.Mock).mockImplementation(() =>
Promise.resolve({
rowCount: 1,
rows: [{ id: 1 }],
oid: 0,
fields: [],
command: '',
} as QueryResult),
);

const result = await evmContractsRepository.createContract(
{ address: '0x123', chainId: 1, abiHash: 'mockAbiHash' },
context,
);

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

it('should return false if contract creation fails', async () => {
(context.query as jest.Mock).mockImplementation(() =>
Promise.resolve({
rowCount: 0,
rows: [],
oid: 0,
fields: [],
command: '',
} as QueryResult),
);

const result = await evmContractsRepository.createContract(
{ address: '0x123', chainId: 1, abiHash: 'mockAbiHash' },
context,
);

expect(result).toBe(false);
expect(context.query).toHaveBeenCalledWith({
text: queries.insertContract,
values: ['0x123', 1, 'mockAbiHash'],
});
});
});
});
40 changes: 40 additions & 0 deletions src/modules/repositories/evm-contracts/evm-contracts.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Inject } from 'typedi';

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

import { DbContext, withDbContext } from '../../connection/dbcontext';

import { queries } from './queries';
import { CreateContractDto } from './types';

export class EvmContractRepository {
constructor(@Inject(diConstants.logger) private readonly logger: BonadocsLogger) {}

@withDbContext
async getContractAbiHash(
chainId: number,
contractAddress: string,
context: DbContext,
): Promise<string | null> {
const result = await context.query({
text: queries.getContractAbiHash,
values: [chainId, contractAddress],
});

if (!result.rowCount) {
return null;
}
this.logger.info(`Getting contract api hash with chanId ${chainId}`);
return result.rows[0].abi_hash;
}

@withDbContext
async createContract(data: CreateContractDto, context: DbContext): Promise<boolean> {
const result = await context.query({
text: queries.insertContract,
values: [data.address, data.chainId, data.abiHash],
});
return !!result.rowCount;
}
}
2 changes: 2 additions & 0 deletions src/modules/repositories/evm-contracts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { EvmContractRepository } from './evm-contracts.repository';
export * from './types';
10 changes: 10 additions & 0 deletions src/modules/repositories/evm-contracts/queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const queries = {
getContractAbiHash: `SELECT contract.abi_hash
FROM "bonadocs"."evm_contracts" contract
WHERE contract.chain_id = $1
AND contract.address = $2
LIMIT 1`,

insertContract:
'INSERT INTO "bonadocs"."evm_contracts" (address, chain_id, abi_hash) VALUES ($1, $2, $3)',
};
5 changes: 5 additions & 0 deletions src/modules/repositories/evm-contracts/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface CreateContractDto {
chainId: number;
address: string;
abiHash: string;
}
2 changes: 2 additions & 0 deletions src/modules/repositories/projects/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { ProjectRepository } from './project.repository';
export * from './types';