Skip to content

Commit

Permalink
fix: return eth token even if it's not in DB
Browse files Browse the repository at this point in the history
  • Loading branch information
vasyl-ivanchuk committed Oct 18, 2023
1 parent bda4115 commit 52ae700
Show file tree
Hide file tree
Showing 10 changed files with 622 additions and 79 deletions.
11 changes: 0 additions & 11 deletions docker-compose-cli.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ services:
build:
context: .
dockerfile: ./packages/app/Dockerfile
environment:
- VITE_APP_ENVIRONMENT=local
ports:
- '3010:3010'
depends_on:
Expand All @@ -27,10 +25,6 @@ services:
- DATABASE_NAME=block-explorer
- BLOCKCHAIN_RPC_URL=http://host.docker.internal:3050
- BATCHES_PROCESSING_POLLING_INTERVAL=1000
ports:
- '3001:3001'
- '9229:9229'
- '9230:9230'
restart: unless-stopped

api:
Expand All @@ -45,9 +39,6 @@ services:
- DATABASE_URL=postgres://postgres:postgres@postgres:5432/block-explorer
ports:
- '3020:3020'
- '3005:3005'
- '9231:9229'
- '9232:9230'
depends_on:
- worker
restart: unless-stopped
Expand All @@ -58,8 +49,6 @@ services:
driver: none
volumes:
- postgres:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U postgres" ]
interval: 5s
Expand Down
15 changes: 11 additions & 4 deletions packages/api/src/balance/balance.entity.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Entity, Column, PrimaryColumn, Index, ManyToOne, JoinColumn } from "typeorm";
import { Entity, Column, PrimaryColumn, Index, ManyToOne, JoinColumn, AfterLoad } from "typeorm";
import { BaseEntity } from "../common/entities/base.entity";
import { Token } from "../token/token.entity";
import { Token, ETH_TOKEN } from "../token/token.entity";
import { normalizeAddressTransformer } from "../common/transformers/normalizeAddress.transformer";
import { bigIntNumberTransformer } from "../common/transformers/bigIntNumber.transformer";

Expand All @@ -9,9 +9,9 @@ export class Balance extends BaseEntity {
@PrimaryColumn({ type: "bytea", transformer: normalizeAddressTransformer })
public readonly address: string;

@ManyToOne(() => Token)
@ManyToOne(() => Token, { createForeignKeyConstraints: false })
@JoinColumn({ name: "tokenAddress" })
public readonly token?: Token;
public token?: Token;

@PrimaryColumn({ type: "bytea", transformer: normalizeAddressTransformer })
public readonly tokenAddress: string;
Expand All @@ -22,4 +22,11 @@ export class Balance extends BaseEntity {

@Column({ type: "varchar", length: 128 })
public readonly balance: string;

@AfterLoad()
populateEthToken() {
if (this.tokenAddress === ETH_TOKEN.l2Address && !this.token) {
this.token = ETH_TOKEN;
}
}
}
8 changes: 8 additions & 0 deletions packages/api/src/token/token.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ export enum TokenType {
ERC721 = "ERC721",
}

export const ETH_TOKEN: Token = {
l2Address: "0x000000000000000000000000000000000000800A",
l1Address: null,
symbol: "ETH",
name: "Ether",
decimals: 18,
} as Token;

@Entity({ name: "tokens" })
@Index(["blockNumber", "logIndex"])
export class Token extends BaseEntity {
Expand Down
40 changes: 36 additions & 4 deletions packages/api/src/token/token.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,28 @@ describe("TokenService", () => {
const result = await service.findOne(tokenAddress);
expect(result).toBe(token);
});

describe("when requested token does not exist", () => {
beforeEach(() => {
(repositoryMock.findOneBy as jest.Mock).mockResolvedValue(null);
});

it("returns ETH token for ETH address", async () => {
const result = await service.findOne("0x000000000000000000000000000000000000800a");
expect(result).toEqual({
decimals: 18,
l1Address: null,
l2Address: "0x000000000000000000000000000000000000800A",
name: "Ether",
symbol: "ETH",
});
});

it("returns null for non ETH address", async () => {
const result = await service.findOne("0x000000000000000000000000000000000000800b");
expect(result).toBeNull();
});
});
});

describe("exists", () => {
Expand Down Expand Up @@ -82,10 +104,20 @@ describe("TokenService", () => {
expect(result).toBe(true);
});

it("returns false if there is no token with the specified address", async () => {
(repositoryMock.findOne as jest.Mock).mockResolvedValue(null);
const result = await service.exists(tokenAddress);
expect(result).toBe(false);
describe("when requested token does not exist", () => {
beforeEach(() => {
(repositoryMock.findOne as jest.Mock).mockResolvedValue(null);
});

it("returns true for ETH address", async () => {
const result = await service.exists("0x000000000000000000000000000000000000800a");
expect(result).toBe(true);
});

it("returns false for non ETH address", async () => {
const result = await service.exists(tokenAddress);
expect(result).toBe(false);
});
});
});

Expand Down
15 changes: 12 additions & 3 deletions packages/api/src/token/token.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { Pagination, IPaginationOptions } from "nestjs-typeorm-paginate";
import { paginate } from "../common/utils";
import { Token } from "./token.entity";
import { Token, ETH_TOKEN } from "./token.entity";

@Injectable()
export class TokenService {
Expand All @@ -13,11 +13,20 @@ export class TokenService {
) {}

public async findOne(address: string): Promise<Token> {
return await this.tokenRepository.findOneBy({ l2Address: address });
const token = await this.tokenRepository.findOneBy({ l2Address: address });
if (!token && address === ETH_TOKEN.l2Address.toLowerCase()) {
return ETH_TOKEN;
}
return token;
}

public async exists(address: string): Promise<boolean> {
return (await this.tokenRepository.findOne({ where: { l2Address: address }, select: { l2Address: true } })) != null;
const tokenExists =
(await this.tokenRepository.findOne({ where: { l2Address: address }, select: { l2Address: true } })) != null;
if (!tokenExists && address === ETH_TOKEN.l2Address.toLowerCase()) {
return true;
}
return tokenExists;
}

public async findAll(paginationOptions: IPaginationOptions): Promise<Pagination<Token>> {
Expand Down
15 changes: 11 additions & 4 deletions packages/api/src/transfer/transfer.entity.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Entity, Column, Index, ManyToOne, JoinColumn, PrimaryColumn } from "typeorm";
import { Entity, Column, Index, ManyToOne, JoinColumn, PrimaryColumn, AfterLoad } from "typeorm";
import { BaseEntity } from "../common/entities/base.entity";
import { Token, TokenType } from "../token/token.entity";
import { Token, TokenType, ETH_TOKEN } from "../token/token.entity";
import { normalizeAddressTransformer } from "../common/transformers/normalizeAddress.transformer";
import { bigIntNumberTransformer } from "../common/transformers/bigIntNumber.transformer";
import { hexTransformer } from "../common/transformers/hex.transformer";
Expand Down Expand Up @@ -53,9 +53,9 @@ export class Transfer extends BaseEntity {
@Column({ type: "varchar", length: 128, nullable: true })
public readonly amount?: string;

@ManyToOne(() => Token)
@ManyToOne(() => Token, { createForeignKeyConstraints: false })
@JoinColumn({ name: "tokenAddress" })
public readonly token?: Token;
public token?: Token;

@Index()
@Column({ type: "bytea", transformer: normalizeAddressTransformer })
Expand Down Expand Up @@ -84,4 +84,11 @@ export class Transfer extends BaseEntity {
const { number, ...restFields } = this;
return restFields;
}

@AfterLoad()
populateEthToken() {
if (!this.token && this.tokenAddress === ETH_TOKEN.l2Address) {
this.token = ETH_TOKEN;
}
}
}
Loading

0 comments on commit 52ae700

Please sign in to comment.