Skip to content

Commit

Permalink
Merge pull request #41 from sotatek-dev/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
Sotatek-TanHoang authored Sep 17, 2024
2 parents 5339a89 + 78b5008 commit ede77ca
Show file tree
Hide file tree
Showing 21 changed files with 1,178 additions and 150 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ ETH_BRIDGE_START_BLOCK=4863742
ETH_BRIDGE_CONTRACT_ADDRESS=0x83e21AccD43Bb7C23C51e68fFa345fab3983FfeC
ETH_TOKEN_BRIDGE_ADDRESS=0x0000000000000000000000000000000000000000
ETH_BRIDGE_RPC_OPTIONS=https://ethereum-sepolia.publicnode.com
ETH_BRIDGE_DOMAIN_NAME=MinaBridge
ETH_BRIDGE_DOMAIN_VERSION=1.0.0


MINA_BRIDGE_START_BLOCK=0
MINA_BRIDGE_CONTRACT_ADDRESS=B62qkttesK1uAJU5iL8vqcfyoHX8KqVVAiK6VUWvro9EafSACYdZHbg
Expand Down
11 changes: 11 additions & 0 deletions docker-compose.dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,17 @@ services:
networks:
- myNetwork
user: node
validate-evm-signature-1:
image: mina-bridge:1.0.0
command: >
sh -c "npm run console validate-eth-bridge-unlock"
tty: true
restart: always
depends_on:
- postgres
networks:
- myNetwork
user: node
postgres:
container_name: mina-bridge-${NODE_ENV}-postgres
image: postgres:15.3-alpine3.18
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"class-validator": "^0.14.0",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.10",
"ethers": "^5.7.2",
"ioredis": "^5.3.2",
"joi": "^17.11.0",
"log4js": "^6.9.1",
Expand Down
3 changes: 2 additions & 1 deletion src/config/config.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ import redisConfig from './redis.config';
[EEnvKey.MINA_TOKEN_BRIDGE_ADDRESS]: Joi.string().required(),
[EEnvKey.ADMIN_MESSAGE_FOR_SIGN]: Joi.string().required(),
[EEnvKey.MINA_BRIDGE_SC_PRIVATE_KEY]: Joi.string().required(),
[EEnvKey.ETH_BRIDGE_DOMAIN_NAME]: Joi.string().required(),
[EEnvKey.ETH_BRIDGE_DOMAIN_VERSION]: Joi.string().required(),
// coinmarketcap
[EEnvKey.COINMARKET_KEY]: Joi.string().required(),
[EEnvKey.COINMARKET_URL]: Joi.string().required(),
Expand All @@ -60,7 +62,6 @@ import redisConfig from './redis.config';
value[EEnvKey.MINA_BRIDGE_START_BLOCK] = Number(value[EEnvKey.MINA_BRIDGE_START_BLOCK]).valueOf();
value[EEnvKey.MINA_BRIDGE_RPC_OPTIONS] = value[EEnvKey.MINA_BRIDGE_RPC_OPTIONS].split(',');
value[EEnvKey.ETH_BRIDGE_RPC_OPTIONS] = value[EEnvKey.ETH_BRIDGE_RPC_OPTIONS].split(',');
value[EEnvKey.SIGNER_PRIVATE_KEY] = value[EEnvKey.SIGNER_PRIVATE_KEY].split(',');

return value;
}),
Expand Down
1 change: 1 addition & 0 deletions src/constants/entity.constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export enum ETableName {
TOKEN_PAIRS = 'token_pairs',
COMMON_CONFIGURATION = 'common_configuration',
TOKEN_PRICES = 'token_prices',
MULTI_SIGNATURE = 'multi_signature',
}
4 changes: 4 additions & 0 deletions src/constants/env.constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ export enum EEnvKey {
COINMARKET_KEY = 'COINMARKET_KEY',
COINMARKET_URL = 'COINMARKET_URL',
BASE_MINA_BRIDGE_FEE = 'BASE_MINA_BRIDGE_FEE',
ETH_BRIDGE_DOMAIN_NAME = 'ETH_BRIDGE_DOMAIN_NAME',
ETH_BRIDGE_DOMAIN_VERSION = 'ETH_BRIDGE_DOMAIN_VERSION',
GAS_FEE_EVM = 'GAS_FEE_EVM',
DECIMAL_TOKEN_EVM = 'DECIMAL_TOKEN_EVM',
}

export enum EEnvironments {
Expand Down
63 changes: 63 additions & 0 deletions src/database/migrations/1725867149224-add-multi-signature-table.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { MigrationInterface, QueryRunner, Table } from 'typeorm';

import { ENetworkName } from '@constants/blockchain.constant';

export class AddMultiSignatureTable1725867149224 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
return queryRunner.createTable(
new Table({
name: 'multi_signature',
columns: [
{
name: 'id',
type: 'int',
isPrimary: true,
isGenerated: true,
},
{
name: 'validator',
type: 'varchar',
length: '255',
isNullable: true,
},
{
name: 'tx_id',
type: 'bigint',
isNullable: true,
},
{
name: 'signature',
type: 'text',
isNullable: true,
},
{
name: 'chain',
type: 'varchar',
length: '255',
enum: Object.values(ENetworkName),
isNullable: true,
},
{
name: 'created_at',
type: 'timestamp',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updated_at',
type: 'timestamp',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'deleted_at',
type: 'timestamp',
isNullable: true,
},
],
}),
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
return queryRunner.dropTable('multi_signature');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class AddErrorRetryMultiSignatureTable1726107274721 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE multi_signature ADD COLUMN retry BIGINT NULL`);
await queryRunner.query(`ALTER TABLE multi_signature ADD COLUMN error_code TEXT NULL`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn('multi_signature', 'retry');
await queryRunner.dropColumn('multi_signature', 'error_code');
}
}
50 changes: 44 additions & 6 deletions src/database/repositories/event-log.repository.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { EntityRepository } from 'nestjs-typeorm-custom-repository';
import { Brackets } from 'typeorm';

import { EDirection } from '@constants/api.constant';
import { EEventStatus, ENetworkName } from '@constants/blockchain.constant';
Expand All @@ -14,15 +15,30 @@ import { endOfDayUnix, startOfDayUnix } from '@shared/utils/time';
export class EventLogRepository extends BaseRepository<EventLog> {
protected alias: ETableName = ETableName.EVENT_LOGS;

public async getEventLockWithNetwork(network: ENetworkName): Promise<EventLog> {
return this.createQueryBuilder(`${this.alias}`)
.where(`${this.alias}.networkReceived = :network`, { network })
.andWhere(`${this.alias}.status IN (:...status)`, { status: [EEventStatus.WAITING, EEventStatus.FAILED] })
public async getEventLockWithNetwork(network: ENetworkName, threshold?: number): Promise<EventLog> {
const qb = this.createQueryBuilder(`${this.alias}`);
qb.innerJoinAndSelect(`${this.alias}.validator`, 'signature');

qb.where(`${this.alias}.networkReceived = :network`, { network });

if (threshold) {
qb.andWhere(
`(SELECT COUNT(${ETableName.MULTI_SIGNATURE}.id)
FROM ${ETableName.MULTI_SIGNATURE}
WHERE ${ETableName.MULTI_SIGNATURE}.tx_id = ${this.alias}.id
AND ${ETableName.MULTI_SIGNATURE}.signature IS NOT NULL) >= :threshold `,
{
threshold,
},
);
}
qb.andWhere(`${this.alias}.status IN (:...status)`, { status: [EEventStatus.WAITING, EEventStatus.FAILED] })
.andWhere(`${this.alias}.retry < :retryNumber`, { retryNumber: 3 })
.orderBy(`${this.alias}.status`, EDirection.DESC)
.addOrderBy(`${this.alias}.id`, EDirection.ASC)
.addOrderBy(`${this.alias}.retry`, EDirection.ASC)
.getOne();
.addOrderBy(`${this.alias}.retry`, EDirection.ASC);

return qb.getOne();
}

public async updateStatusAndRetryEvenLog(
Expand Down Expand Up @@ -112,4 +128,26 @@ export class EventLogRepository extends BaseRepository<EventLog> {
.groupBy(`${this.alias}.sender_address`);
return qb.getRawOne();
}

async getValidatorPendingSignature(validator: string, network: ENetworkName) {
const qb = this.createQueryBuilder(`${this.alias}`);
qb.leftJoinAndSelect(`${this.alias}.validator`, 'signature');
qb.where(`${this.alias}.networkReceived = :network`, { network });
qb.andWhere(
new Brackets(qb => {
qb.where(`signature.validator IS NULL`)
.orWhere(`signature.validator != :validator`, { validator })
.orWhere(
new Brackets(qb => {
qb.where(`signature.signature IS NULL`).andWhere(`signature.retry < 3`);
}),
);
}),
);
qb.andWhere(`${this.alias}.status = :status`, { status: EEventStatus.WAITING })
.addOrderBy(`${this.alias}.id`, EDirection.ASC)
.addOrderBy(`${this.alias}.retry`, EDirection.ASC);

return qb.getOne();
}
}
14 changes: 14 additions & 0 deletions src/database/repositories/multi-signature.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { EntityRepository } from 'nestjs-typeorm-custom-repository';

import { EDirection } from '@constants/api.constant';
import { EEventStatus, ENetworkName } from '@constants/blockchain.constant';
import { ETableName } from '@constants/entity.constant';

import { BaseRepository } from '@core/base-repository';

import { MultiSignature } from '@modules/crawler/entities/multi-signature.entity';

@EntityRepository(MultiSignature)
export class MultiSignatureRepository extends BaseRepository<MultiSignature> {
protected alias: ETableName = ETableName.MULTI_SIGNATURE;
}
15 changes: 15 additions & 0 deletions src/modules/crawler/crawler.console.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@ export class CrawlerConsole {
}
}

@Command({
command: 'validate-eth-bridge-unlock',
description: 'validate ETH Bridge unlock',
})
async handleValidateMinaLockTx() {
try {
while (true) {
this.senderEVMBridge.unlockEVMTransaction();
await sleep(15);
}
} catch (error) {
this.logger.error(error);
}
}

@Command({
command: 'sender-eth-bridge-unlock',
description: 'sender ETH Bridge unlock',
Expand Down
5 changes: 2 additions & 3 deletions src/modules/crawler/crawler.minabridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,11 @@ export class SCBridgeMinaCrawler {
};
}

public async handlerLockEvent(event, queryRunner: QueryRunner) {
public async handlerLockEvent(event: any, queryRunner: QueryRunner) {
const field = Field.from(event.event.data.receipt.toString());
const receiveAddress = DEFAULT_ADDRESS_PREFIX + field.toBigInt().toString(16);

const eventUnlock = {
senderAddress: event.event.data.locker,
senderAddress: JSON.parse(JSON.stringify(event.event.data.locker)),
amountFrom: event.event.data.amount.toString(),
tokenFromAddress: this.configService.get(EEnvKey.MINA_TOKEN_BRIDGE_ADDRESS),
networkFrom: ENetworkName.MINA,
Expand Down
2 changes: 2 additions & 0 deletions src/modules/crawler/crawler.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Module } from '@nestjs/common';
import { CommonConfigRepository } from 'database/repositories/common-configuration.repository';
import { CrawlContractRepository } from 'database/repositories/crawl-contract.repository';
import { EventLogRepository } from 'database/repositories/event-log.repository';
import { MultiSignatureRepository } from 'database/repositories/multi-signature.repository';
import { TokenPairRepository } from 'database/repositories/token-pair.repository';
import { TokenPriceRepository } from 'database/repositories/token-price.repository';
import { CustomRepositoryModule } from 'nestjs-typeorm-custom-repository';
Expand All @@ -22,6 +23,7 @@ import { SenderMinaBridge } from './sender.minabridge';
CommonConfigRepository,
TokenPairRepository,
TokenPriceRepository,
MultiSignatureRepository,
]),
],
providers: [
Expand Down
7 changes: 6 additions & 1 deletion src/modules/crawler/entities/event-logs.entity.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Column, Entity } from 'typeorm';
import { Column, Entity, JoinColumn, OneToMany } from 'typeorm';

import { EEventName, ENetworkName } from '@constants/blockchain.constant';
import { ETableName } from '@constants/entity.constant';

import { BaseEntityIncludeTime } from '@core/base.entity';

import { EEventStatus } from '../../../constants/blockchain.constant';
import { MultiSignature } from './multi-signature.entity';

@Entity(ETableName.EVENT_LOGS)
export class EventLog extends BaseEntityIncludeTime {
Expand Down Expand Up @@ -75,6 +76,10 @@ export class EventLog extends BaseEntityIncludeTime {
@Column({ name: 'retry', type: 'int', nullable: false, default: 0 })
retry: number;

@OneToMany<MultiSignature>(() => MultiSignature, multiSignature => multiSignature.transaction)
@JoinColumn({ name: 'id' })
validator: MultiSignature[];

constructor(value: Partial<EventLog>) {
super();
Object.assign(this, value);
Expand Down
40 changes: 40 additions & 0 deletions src/modules/crawler/entities/multi-signature.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm';

import { ENetworkName } from '@constants/blockchain.constant';
import { ETableName } from '@constants/entity.constant';

import { BaseEntityIncludeTime } from '@core/base.entity';

import { EventLog } from './event-logs.entity';

@Entity(ETableName.MULTI_SIGNATURE)
export class MultiSignature extends BaseEntityIncludeTime {
@Column({ name: 'validator', type: 'varchar', nullable: true })
validator: string;

@Column({ name: 'tx_id', type: 'bigint', nullable: true })
txId: number;

@Column({ name: 'retry', type: 'bigint', nullable: true })
retry: number;

@Column({ name: 'signature', type: 'text', nullable: true })
signature: string;

@Column({ name: 'error_code', type: 'text', nullable: true })
errorCode: string | unknown;

@Column({ name: 'chain', type: 'varchar', enum: ENetworkName, nullable: true })
chain: ENetworkName;

@ManyToOne<EventLog>(() => EventLog, eventLog => eventLog.validator, {
onDelete: 'CASCADE',
})
@JoinColumn({ name: 'tx_id' })
transaction: EventLog;

constructor(value: Partial<MultiSignature>) {
super();
Object.assign(this, value);
}
}
Loading

0 comments on commit ede77ca

Please sign in to comment.