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

fix: fe fixes, refactoring, show deployed contract for non evm-eq chains #362

Merged
merged 3 commits into from
Dec 19, 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
4 changes: 3 additions & 1 deletion packages/api/src/api/dtos/account/accountTransaction.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ export class AccountTransactionDto {
type: String,
description: "The to address of this transaction",
example: "0xc7e0220d02d549c4846A6EC31D89C3B670Ebe35C",
examples: ["0xc7e0220d02d549c4846A6EC31D89C3B670Ebe35C", null],
nullable: true,
})
public readonly to: string;
public readonly to?: string;

@ApiProperty({
type: String,
Expand Down
13 changes: 6 additions & 7 deletions packages/api/src/api/transaction/transaction.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import { mock } from "jest-mock-extended";
import { Logger } from "@nestjs/common";
import { TransactionService } from "../../transaction/transaction.service";
import { TransactionReceiptService } from "../../transaction/transactionReceipt.service";
import { TransactionStatus } from "../../transaction/entities/transaction.entity";
import { TransactionDetails } from "../../transaction/entities/transactionDetails.entity";
import { TransactionStatus, Transaction } from "../../transaction/entities/transaction.entity";
import { TransactionReceipt } from "../../transaction/entities/transactionReceipt.entity";
import { ResponseStatus, ResponseMessage } from "../dtos/common/responseBase.dto";
import { TransactionController } from "./transaction.controller";
Expand Down Expand Up @@ -57,7 +56,7 @@ describe("TransactionController", () => {
it("returns isError as 0 when transaction is successful", async () => {
jest
.spyOn(transactionServiceMock, "findOne")
.mockResolvedValue({ status: TransactionStatus.Included } as TransactionDetails);
.mockResolvedValue({ status: TransactionStatus.Included } as Transaction);

const response = await controller.getTransactionStatus(transactionHash);
expect(response).toEqual({
Expand All @@ -73,7 +72,7 @@ describe("TransactionController", () => {
it("returns isError as 1 when transaction is failed", async () => {
jest
.spyOn(transactionServiceMock, "findOne")
.mockResolvedValue({ status: TransactionStatus.Failed } as TransactionDetails);
.mockResolvedValue({ status: TransactionStatus.Failed } as Transaction);

const response = await controller.getTransactionStatus(transactionHash);
expect(response).toEqual({
Expand All @@ -91,7 +90,7 @@ describe("TransactionController", () => {
status: TransactionStatus.Failed,
error: "Error",
revertReason: "Reverted",
} as TransactionDetails);
} as Transaction);

const response = await controller.getTransactionStatus(transactionHash);
expect(response).toEqual({
Expand All @@ -107,7 +106,7 @@ describe("TransactionController", () => {
it("returns transaction revert reason in errDescription when transaction is failed and transaction revert reason is present", async () => {
jest
.spyOn(transactionServiceMock, "findOne")
.mockResolvedValue({ status: TransactionStatus.Failed, revertReason: "Reverted" } as TransactionDetails);
.mockResolvedValue({ status: TransactionStatus.Failed, revertReason: "Reverted" } as Transaction);

const response = await controller.getTransactionStatus(transactionHash);
expect(response).toEqual({
Expand All @@ -123,7 +122,7 @@ describe("TransactionController", () => {
it("returns empty errDescription when transaction is failed and transaction error and revert reason are not present", async () => {
jest
.spyOn(transactionServiceMock, "findOne")
.mockResolvedValue({ status: TransactionStatus.Failed } as TransactionDetails);
.mockResolvedValue({ status: TransactionStatus.Failed } as Transaction);

const response = await controller.getTransactionStatus(transactionHash);
expect(response).toEqual({
Expand Down
17 changes: 9 additions & 8 deletions packages/api/src/transaction/dtos/transaction.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export class TransactionDto {
@ApiProperty({
type: String,
description: "The address this transaction is to",
example: ["0xc7e0220d02d549c4846A6EC31D89C3B670Ebe35C", null],
example: "0xc7e0220d02d549c4846A6EC31D89C3B670Ebe35C",
examples: ["0xc7e0220d02d549c4846A6EC31D89C3B670Ebe35C", null],
nullable: true,
})
public readonly to?: string;
Expand Down Expand Up @@ -207,17 +208,17 @@ export class TransactionDto {
public readonly revertReason?: string;

@ApiProperty({
type: Boolean,
description: "Is the transaction EVM-like",
example: true,
nullable: true,
type: String,
description: "Gas used by the transaction",
example: "50000000",
})
public readonly isEvmLike?: boolean;
public readonly gasUsed: string;

@ApiProperty({
type: String,
description: "Address of the first deployed EVM contract",
example: ["0xc7e0220d02d549c4846A6EC31D89C3B670Ebe35C", null],
description: "Address of the deployed contract",
example: "50000000",
examples: ["0xc7e0220d02d549c4846A6EC31D89C3B670Ebe35C", null],
nullable: true,
})
public readonly contractAddress?: string;
Expand Down
11 changes: 0 additions & 11 deletions packages/api/src/transaction/dtos/transactionDetails.dto.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ export class AddressTransaction extends BaseEntity {
@Column({ type: "bytea", transformer: hexTransformer })
public readonly transactionHash: string;

@Column({ type: "bytea", transformer: normalizeAddressTransformer })
public readonly address: string;
@Column({ type: "bytea", transformer: normalizeAddressTransformer, nullable: true })
public readonly address?: string;

@Index()
@Column({ type: "bigint", transformer: bigIntNumberTransformer })
Expand Down
18 changes: 11 additions & 7 deletions packages/api/src/transaction/entities/transaction.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,6 @@ export class Transaction extends BaseEntity {
@Column({ nullable: true })
public readonly revertReason?: string;

@Column({ type: "boolean", nullable: true })
public readonly isEvmLike?: boolean;

@Column({ type: "bytea", transformer: normalizeAddressTransformer, nullable: true })
public readonly contractAddress?: string;

public get status(): TransactionStatus {
if (this.receiptStatus === 0) {
return TransactionStatus.Failed;
Expand Down Expand Up @@ -147,16 +141,26 @@ export class Transaction extends BaseEntity {
return !!this.batch;
}

public get gasUsed(): string {
return this.transactionReceipt ? this.transactionReceipt.gasUsed : null;
}

public get contractAddress(): string {
return this.transactionReceipt ? this.transactionReceipt.contractAddress : null;
}

toJSON(): any {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { number, receiptStatus, batch, ...restFields } = this;
const { number, receiptStatus, batch, transactionReceipt, ...restFields } = this;
return {
...restFields,
status: this.status,
commitTxHash: this.commitTxHash,
executeTxHash: this.executeTxHash,
proveTxHash: this.proveTxHash,
isL1BatchSealed: this.isL1BatchSealed,
gasUsed: this.gasUsed,
contractAddress: this.contractAddress,
};
}
}
18 changes: 0 additions & 18 deletions packages/api/src/transaction/entities/transactionDetails.entity.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export class TransactionReceipt extends BaseEntity {
@Column({ type: "bytea", transformer: normalizeAddressTransformer })
public readonly from: string;

@Column({ type: "bytea", transformer: hexTransformer, nullable: true })
public readonly to?: string;

@Index()
@Column({ type: "bytea", nullable: true, transformer: normalizeAddressTransformer })
public readonly contractAddress?: string;
Expand Down
3 changes: 1 addition & 2 deletions packages/api/src/transaction/transaction.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { buildDateFilter } from "../common/utils";
import { FilterTransactionsOptionsDto } from "./dtos/filterTransactionsOptions.dto";
import { TransferDto } from "../transfer/transfer.dto";
import { TransactionDto } from "./dtos/transaction.dto";
import { TransactionDetailsDto } from "./dtos/transactionDetails.dto";
import { TransferService } from "../transfer/transfer.service";
import { LogDto } from "../log/log.dto";
import { LogService } from "../log/log.service";
Expand Down Expand Up @@ -74,7 +73,7 @@ export class TransactionController {
@ApiNotFoundResponse({ description: "Transaction with the specified hash does not exist" })
public async getTransaction(
@Param("transactionHash", new ParseTransactionHashPipe()) transactionHash: string
): Promise<TransactionDetailsDto> {
): Promise<TransactionDto> {
const transactionDetail = await this.transactionService.findOne(transactionHash);
if (!transactionDetail) {
throw new NotFoundException();
Expand Down
3 changes: 1 addition & 2 deletions packages/api/src/transaction/transaction.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { TransactionController } from "./transaction.controller";
import { TransactionService } from "./transaction.service";
import { TransactionReceiptService } from "./transactionReceipt.service";
import { Transaction } from "./entities/transaction.entity";
import { TransactionDetails } from "./entities/transactionDetails.entity";
import { AddressTransaction } from "./entities/addressTransaction.entity";
import { TransactionReceipt } from "./entities/transactionReceipt.entity";
import { Batch } from "../batch/batch.entity";
Expand All @@ -14,7 +13,7 @@ import { LogModule } from "../log/log.module";

@Module({
imports: [
TypeOrmModule.forFeature([Transaction, TransactionDetails, AddressTransaction, TransactionReceipt, Batch]),
TypeOrmModule.forFeature([Transaction, AddressTransaction, TransactionReceipt, Batch]),
TransferModule,
LogModule,
CounterModule,
Expand Down
45 changes: 35 additions & 10 deletions packages/api/src/transaction/transaction.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { SortingOrder } from "../common/types";
import { CounterService } from "../counter/counter.service";
import { TransactionService, FilterTransactionsOptions } from "./transaction.service";
import { Transaction } from "./entities/transaction.entity";
import { TransactionDetails } from "./entities/transactionDetails.entity";
import { AddressTransaction } from "./entities/addressTransaction.entity";
import { Batch } from "../batch/batch.entity";

Expand All @@ -18,7 +17,6 @@ describe("TransactionService", () => {
let transaction;
let service: TransactionService;
let repositoryMock: typeorm.Repository<Transaction>;
let repositoryDetailMock: typeorm.Repository<TransactionDetails>;
let addressTransactionRepositoryMock: typeorm.Repository<AddressTransaction>;
let batchRepositoryMock: typeorm.Repository<Batch>;
let counterServiceMock: CounterService;
Expand All @@ -27,7 +25,6 @@ describe("TransactionService", () => {
beforeEach(async () => {
counterServiceMock = mock<CounterService>();
repositoryMock = mock<typeorm.Repository<Transaction>>();
repositoryDetailMock = mock<typeorm.Repository<TransactionDetails>>();
addressTransactionRepositoryMock = mock<typeorm.Repository<AddressTransaction>>();
batchRepositoryMock = mock<typeorm.Repository<Batch>>();
transaction = {
Expand All @@ -41,10 +38,6 @@ describe("TransactionService", () => {
provide: getRepositoryToken(Transaction),
useValue: repositoryMock,
},
{
provide: getRepositoryToken(TransactionDetails),
useValue: repositoryDetailMock,
},
{
provide: getRepositoryToken(AddressTransaction),
useValue: addressTransactionRepositoryMock,
Expand Down Expand Up @@ -73,13 +66,13 @@ describe("TransactionService", () => {

beforeEach(() => {
queryBuilderMock = mock<typeorm.SelectQueryBuilder<Transaction>>();
(repositoryDetailMock.createQueryBuilder as jest.Mock).mockReturnValue(queryBuilderMock);
(repositoryMock.createQueryBuilder as jest.Mock).mockReturnValue(queryBuilderMock);
(queryBuilderMock.getOne as jest.Mock).mockResolvedValue(null);
});

it("creates query builder with proper params", async () => {
await service.findOne(hash);
expect(repositoryDetailMock.createQueryBuilder).toHaveBeenCalledWith("transaction");
expect(repositoryMock.createQueryBuilder).toHaveBeenCalledWith("transaction");
});

it("filters transactions by the specified hash", async () => {
Expand All @@ -99,7 +92,10 @@ describe("TransactionService", () => {

it("selects only needed transactionReceipt fields", async () => {
await service.findOne(hash);
expect(queryBuilderMock.addSelect).toHaveBeenCalledWith(["transactionReceipt.gasUsed"]);
expect(queryBuilderMock.addSelect).toHaveBeenCalledWith([
"transactionReceipt.gasUsed",
"transactionReceipt.contractAddress",
]);
});

it("returns paginated result", async () => {
Expand Down Expand Up @@ -172,6 +168,19 @@ describe("TransactionService", () => {
expect(queryBuilderMock.where).toHaveBeenCalledWith(filterTransactionsOptions);
});

it("joins transactionReceipt record to get receipt specific fields", async () => {
await service.findAll(filterTransactionsOptions, pagingOptions);
expect(queryBuilderMock.leftJoin).toHaveBeenCalledWith("transaction.transactionReceipt", "transactionReceipt");
});

it("selects only needed transactionReceipt fields", async () => {
await service.findAll(filterTransactionsOptions, pagingOptions);
expect(queryBuilderMock.addSelect).toHaveBeenCalledWith([
"transactionReceipt.gasUsed",
"transactionReceipt.contractAddress",
]);
});

it("joins batch record to get batch specific fields", async () => {
await service.findAll(filterTransactionsOptions, pagingOptions);
expect(queryBuilderMock.leftJoin).toHaveBeenCalledWith("transaction.batch", "batch");
Expand Down Expand Up @@ -243,6 +252,22 @@ describe("TransactionService", () => {
);
});

it("joins transactionReceipt record to get receipt specific fields", async () => {
await service.findAll(filterTransactionsOptions, pagingOptions);
expect(addressTransactionsQueryBuilderMock.leftJoin).toHaveBeenCalledWith(
"transaction.transactionReceipt",
"transactionReceipt"
);
});

it("selects only needed transactionReceipt fields", async () => {
await service.findAll(filterTransactionsOptions, pagingOptions);
expect(addressTransactionsQueryBuilderMock.addSelect).toHaveBeenCalledWith([
"transactionReceipt.gasUsed",
"transactionReceipt.contractAddress",
]);
});

it("joins batch records", async () => {
await service.findAll(filterTransactionsOptions, pagingOptions);
expect(addressTransactionsQueryBuilderMock.leftJoinAndSelect).toBeCalledTimes(1);
Expand Down
13 changes: 7 additions & 6 deletions packages/api/src/transaction/transaction.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { Pagination } from "nestjs-typeorm-paginate";
import { paginate } from "../common/utils";
import { IPaginationOptions, CounterCriteria, SortingOrder } from "../common/types";
import { Transaction } from "./entities/transaction.entity";
import { TransactionDetails } from "./entities/transactionDetails.entity";
import { AddressTransaction } from "./entities/addressTransaction.entity";
import { Batch } from "../batch/batch.entity";
import { CounterService } from "../counter/counter.service";
Expand All @@ -30,20 +29,18 @@ export class TransactionService {
constructor(
@InjectRepository(Transaction)
private readonly transactionRepository: Repository<Transaction>,
@InjectRepository(TransactionDetails)
private readonly transactionDetailsRepository: Repository<TransactionDetails>,
@InjectRepository(AddressTransaction)
private readonly addressTransactionRepository: Repository<AddressTransaction>,
@InjectRepository(Batch)
private readonly batchRepository: Repository<Batch>,
private readonly counterService: CounterService
) {}

public async findOne(hash: string): Promise<TransactionDetails> {
const queryBuilder = this.transactionDetailsRepository.createQueryBuilder("transaction");
public async findOne(hash: string): Promise<Transaction> {
const queryBuilder = this.transactionRepository.createQueryBuilder("transaction");
queryBuilder.leftJoinAndSelect("transaction.batch", "batch");
queryBuilder.leftJoin("transaction.transactionReceipt", "transactionReceipt");
queryBuilder.addSelect(["transactionReceipt.gasUsed"]);
queryBuilder.addSelect(["transactionReceipt.gasUsed", "transactionReceipt.contractAddress"]);
queryBuilder.where({ hash });
return await queryBuilder.getOne();
}
Expand All @@ -60,6 +57,8 @@ export class TransactionService {
const queryBuilder = this.addressTransactionRepository.createQueryBuilder("addressTransaction");
queryBuilder.select("addressTransaction.number");
queryBuilder.leftJoinAndSelect("addressTransaction.transaction", "transaction");
queryBuilder.leftJoin("transaction.transactionReceipt", "transactionReceipt");
queryBuilder.addSelect(["transactionReceipt.gasUsed", "transactionReceipt.contractAddress"]);
queryBuilder.leftJoin("transaction.batch", "batch");
queryBuilder.addSelect(["batch.commitTxHash", "batch.executeTxHash", "batch.proveTxHash"]);
queryBuilder.where({
Expand Down Expand Up @@ -87,6 +86,8 @@ export class TransactionService {
};
} else {
const queryBuilder = this.transactionRepository.createQueryBuilder("transaction");
queryBuilder.leftJoin("transaction.transactionReceipt", "transactionReceipt");
queryBuilder.addSelect(["transactionReceipt.gasUsed", "transactionReceipt.contractAddress"]);
queryBuilder.leftJoin("transaction.batch", "batch");
queryBuilder.addSelect(["batch.commitTxHash", "batch.executeTxHash", "batch.proveTxHash"]);
queryBuilder.where(filterOptions);
Expand Down
Loading
Loading