Skip to content

Commit

Permalink
fix: return eth token even if it does not exist in db (#59)
Browse files Browse the repository at this point in the history
# What ❔

API changes to return ETH token even if it does not exist in DB yet.

## Why ❔

ETH transfers might appear before we get information about system
contract deployment so even if ETH is not in DB we should return it from
API endpoints for ETH token and ETH transfers endpoints.

## Checklist

<!-- Check your PR fulfills the following items. -->
<!-- For draft PRs check the boxes as you complete them. -->

- [X] PR title corresponds to the body of PR (we generate changelog
entries from PRs).
- [X] Tests for the changes have been added / updated.
- [ ] Documentation comments have been added / updated.
  • Loading branch information
vasyl-ivanchuk authored Oct 18, 2023
1 parent e5e2cf3 commit aa44f3a
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 aa44f3a

Please sign in to comment.