xiongzhu 2 tahun lalu
induk
melakukan
5fd7890ec1

+ 1 - 1
src/accounts/accounts.service.ts

@@ -43,7 +43,7 @@ export class AccountsService {
         return account
     }
 
-    @Cron('0/30 * * * * *')
+    // @Cron('0/30 * * * * *')
     async handleCron() {
         for (let account of await this.findAll()) {
             Logger.log(`fetching balances for ${account.address}`)

+ 2 - 3
src/app.module.ts

@@ -14,7 +14,6 @@ import { UserBalanceModule } from './user-balance/user-balance.module'
 import { SysConfigModule } from './sys-config/sys-config.module'
 import { AllExceptionsFilter } from './filters/all-exceptions-filter.filter'
 import { DownloadModule } from './download/download.module'
-import { GalleryModule } from './gallery/gallery.module'
 import { AccountsModule } from './accounts/accounts.module'
 import { Web3Module } from './web3/web3.module'
 import { ScheduleModule } from '@nestjs/schedule'
@@ -60,7 +59,8 @@ import { TaskModule } from './task/task.module'
                 cli: {
                     migrationsDir: config.get<string>('TYPEORM_MIGRATIONS_DIR'),
                     subscribersDir: config.get<string>('TYPEORM_SUBSCRIBERS_DIR')
-                }
+                },
+                logging: false
             })
         }),
         ScheduleModule.forRoot(),
@@ -72,7 +72,6 @@ import { TaskModule } from './task/task.module'
         UserBalanceModule,
         SysConfigModule,
         DownloadModule,
-        GalleryModule,
         AccountsModule,
         Web3Module,
         TaskModule

+ 0 - 29
src/gallery/entities/gallery.entity.ts

@@ -1,29 +0,0 @@
-import { ArrayTransformer } from '../../transformers/array.transformer'
-import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn } from 'typeorm'
-
-@Entity()
-export class Gallery {
-    @PrimaryGeneratedColumn()
-    id: number
-
-    @Column()
-    title: string
-
-    @Column()
-    thumb: string
-
-    @Column()
-    character: string
-
-    @Column()
-    tag: string
-
-    @Column()
-    artist: string
-
-    @Column({ type: 'text', transformer: new ArrayTransformer() })
-    details: string[]
-
-    @CreateDateColumn()
-    createdAt: Date
-}

+ 0 - 21
src/gallery/gallery.controller.ts

@@ -1,21 +0,0 @@
-import { Body, Controller, Get, Post, Put } from '@nestjs/common'
-import { Public } from '../auth/public.decorator'
-import { GalleryService } from './gallery.service'
-import { Gallery } from './entities/gallery.entity'
-import { PageRequest } from '../common/dto/page-request'
-
-@Controller('gallery')
-@Public()
-export class GalleryController {
-    constructor(private galleryService: GalleryService) {}
-
-    @Post()
-    async findAll(@Body() page: PageRequest<Gallery>) {
-        return await this.galleryService.findAll(page)
-    }
-
-    @Put()
-    async save(@Body() gallery: Partial<Gallery>) {
-        return await this.galleryService.save(gallery)
-    }
-}

+ 0 - 12
src/gallery/gallery.module.ts

@@ -1,12 +0,0 @@
-import { Module } from '@nestjs/common'
-import { GalleryController } from './gallery.controller'
-import { GalleryService } from './gallery.service'
-import { TypeOrmModule } from '@nestjs/typeorm'
-import { Gallery } from './entities/gallery.entity'
-
-@Module({
-    imports: [TypeOrmModule.forFeature([Gallery])],
-    controllers: [GalleryController],
-    providers: [GalleryService]
-})
-export class GalleryModule {}

+ 0 - 22
src/gallery/gallery.service.ts

@@ -1,22 +0,0 @@
-import { Injectable } from '@nestjs/common'
-import { Repository } from 'typeorm'
-import { Gallery } from './entities/gallery.entity'
-import { InjectRepository } from '@nestjs/typeorm'
-import { PageRequest } from '../common/dto/page-request'
-import { Pagination, paginate } from 'nestjs-typeorm-paginate'
-
-@Injectable()
-export class GalleryService {
-    constructor(
-        @InjectRepository(Gallery)
-        private readonly galleryRepository: Repository<Gallery>
-    ) {}
-
-    async findAll(req: PageRequest<Gallery>): Promise<Pagination<Gallery>> {
-        return await paginate<Gallery>(this.galleryRepository, req.page, req.search)
-    }
-
-    async save(gallery: Partial<Gallery>): Promise<Gallery> {
-        return await this.galleryRepository.save(gallery)
-    }
-}

+ 9 - 3
src/task/dto/create-task.dto.ts

@@ -1,12 +1,18 @@
-import { IsString, IsArray, IsDate } from 'class-validator'
+import { IsString, IsArray, IsDate, IsEnum, IsOptional, ArrayMinSize } from 'class-validator'
+import { TaskType } from '../enums/task-type.enum'
 
 export class CreateTaskDto {
-    @IsString()
+    @IsEnum(TaskType)
     type: TaskType
 
     @IsArray()
+    @ArrayMinSize(1)
     accounts: number[]
 
     @IsDate()
-    startTime: Date
+    @IsOptional()
+    startTime?: Date
+
+    @IsOptional()
+    params?: any
 }

+ 32 - 0
src/task/entities/task-item.entity.ts

@@ -0,0 +1,32 @@
+import { Column, CreateDateColumn, PrimaryGeneratedColumn } from 'typeorm'
+import { TaskStatus } from '../enums/task-status.enum'
+import { TaskType } from '../enums/task-type.enum'
+
+export class TaskItem {
+    @PrimaryGeneratedColumn()
+    id: number
+
+    @Column()
+    taskId: number
+
+    @Column()
+    userId: number
+
+    @Column({ type: 'enum', enum: TaskType })
+    type: TaskType
+
+    @Column({ type: 'enum', enum: TaskStatus, default: TaskStatus.Pending })
+    status: TaskStatus
+
+    @CreateDateColumn()
+    createdAt: Date
+
+    @Column()
+    accountId: number
+
+    @Column()
+    startTime: Date
+
+    @Column()
+    endTime: Date
+}

+ 9 - 2
src/task/entities/task-log.entity.ts

@@ -1,5 +1,6 @@
 import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn } from 'typeorm'
 import { LogStatus } from '../enums/log-status.enum'
+import { TaskType } from '../enums/task-type.enum'
 
 @Entity()
 export class TaskLog {
@@ -9,7 +10,7 @@ export class TaskLog {
     @Column()
     taskId: number
 
-    @Column()
+    @Column({ type: 'enum', enum: TaskType })
     type: TaskType
 
     @Column()
@@ -27,9 +28,15 @@ export class TaskLog {
     @Column({ type: 'enum', enum: LogStatus })
     status: LogStatus
 
-    @Column()
+    @Column({ type: 'text', nullable: true })
     error: string
 
+    @Column()
+    startTime: Date
+
+    @Column()
+    finishTime: Date
+
     @CreateDateColumn()
     createdAt: Date
 }

+ 38 - 2
src/task/entities/task.entity.ts

@@ -1,5 +1,6 @@
 import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn } from 'typeorm'
 import { TaskStatus } from '../enums/task-status.enum'
+import { TaskType } from '../enums/task-type.enum'
 
 @Entity()
 export class Task {
@@ -9,16 +10,51 @@ export class Task {
     @Column()
     userId: number
 
-    @Column()
+    @Column({ type: 'enum', enum: TaskType })
     type: TaskType
 
+    @Column({
+        type: 'text',
+        transformer: {
+            from: (value: string) => {
+                if (!value) {
+                    return null
+                }
+                return JSON.parse(value)
+            },
+            to: (value: any) => {
+                if (!value) {
+                    return null
+                }
+                return JSON.stringify(value)
+            }
+        }
+    })
+    params: any
+
     @Column({ type: 'enum', enum: TaskStatus, default: TaskStatus.Pending })
     status: TaskStatus
 
     @CreateDateColumn()
     createdAt: Date
 
-    @Column({ type: 'text' })
+    @Column({
+        type: 'text',
+        transformer: {
+            from: (value: string) => {
+                if (!value) {
+                    return null
+                }
+                return JSON.parse(value)
+            },
+            to: (value: any) => {
+                if (!value) {
+                    return null
+                }
+                return JSON.stringify(value)
+            }
+        }
+    })
     accounts: number[]
 
     @Column({ default: -1 })

+ 11 - 0
src/task/enums/task-type.enum.ts

@@ -0,0 +1,11 @@
+export enum TaskType {
+    bridge2zk = 'bridge2zk',
+    bridge2eth = 'bridge2eth',
+    orbiter2zk = 'orbiter2zk',
+    orbiter2eth = 'orbiter2eth',
+    swapUsdc = 'swapUsdc',
+    swapEth = 'swapEth',
+    addLiquidity = 'addLiquidity',
+    removeLiquidity = 'removeLiquidity',
+    mint = 'mint'
+}

+ 11 - 0
src/task/model/task-progress.model.ts

@@ -0,0 +1,11 @@
+export class TaskProgress {
+    accounts: number[]
+
+    total: number
+
+    success: number
+
+    failed: number
+
+    detail: { [key: string]: { success: boolean } }
+}

+ 2 - 1
src/task/task.module.ts

@@ -5,9 +5,10 @@ import { Web3Module } from 'src/web3/web3.module'
 import { TypeOrmModule } from '@nestjs/typeorm'
 import { Task } from './entities/task.entity'
 import { TaskLog } from './entities/task-log.entity'
+import { AccountsModule } from 'src/accounts/accounts.module'
 
 @Module({
-    imports: [Web3Module, TypeOrmModule.forFeature([Task, TaskLog])],
+    imports: [Web3Module, TypeOrmModule.forFeature([Task, TaskLog]), AccountsModule],
     providers: [TaskService],
     controllers: [TaskController]
 })

+ 68 - 0
src/task/task.service.ts

@@ -8,11 +8,16 @@ import { TaskStatus } from './enums/task-status.enum'
 import { CreateTaskDto } from './dto/create-task.dto'
 import { Pagination, paginate } from 'nestjs-typeorm-paginate'
 import { PageRequest } from 'src/common/dto/page-request'
+import { TaskType } from './enums/task-type.enum'
+import { AccountsService } from 'src/accounts/accounts.service'
+import { LogStatus } from './enums/log-status.enum'
+import { Web3Result } from 'src/web3/model/web3-result'
 
 @Injectable()
 export class TaskService {
     constructor(
         private readonly web3Service: Web3Service,
+        private readonly accountsService: AccountsService,
         @InjectRepository(Task)
         private readonly taskRepository: Repository<Task>,
         @InjectRepository(TaskLog)
@@ -28,6 +33,69 @@ export class TaskService {
             userId,
             ...createTask
         })
+        if (!createTask.startTime) {
+            this.runTask(task)
+        }
         return task
     }
+
+    async runTask(task: Task) {
+        if (task.status == TaskStatus.Done) {
+            return
+        }
+        task.status = TaskStatus.InProgress
+        await this.taskRepository.save(task)
+        for (let accountId of task.accounts) {
+            const taskLog = new TaskLog()
+            taskLog.taskId = task.id
+            taskLog.accountId = accountId
+            taskLog.startTime = new Date()
+            try {
+                const account = await this.accountsService.findById(accountId)
+                taskLog.address = account.address
+                let web3Result: Web3Result
+                switch (task.type) {
+                    case TaskType.bridge2zk:
+                        web3Result = await this.web3Service.zkDeposit(accountId, task.params.amount)
+                        break
+                    case TaskType.bridge2eth:
+                        web3Result = await this.web3Service.zkWithdraw(accountId, task.params.amount)
+                        break
+                    case TaskType.orbiter2zk:
+                        web3Result = await this.web3Service.orbiterDeposit(accountId, task.params.amount)
+                        break
+                    case TaskType.orbiter2eth:
+                        web3Result = await this.web3Service.orbiterWithdraw(accountId, task.params.amount)
+                        break
+                    case TaskType.swapUsdc:
+                        web3Result = await this.web3Service.swapWithExactInput(accountId, task.params.amount)
+                        break
+                    case TaskType.swapEth:
+                        web3Result = await this.web3Service.swapWithExactOutput(accountId, task.params.amount)
+                        break
+                    case TaskType.addLiquidity:
+                        web3Result = await this.web3Service.addLiquidity(accountId, task.params.amount)
+                        break
+                    case TaskType.removeLiquidity:
+                        web3Result = await this.web3Service.removeLiquidity(accountId)
+                        break
+                    case TaskType.mint:
+                        web3Result = await this.web3Service.mint(accountId)
+                        break
+                }
+                taskLog.status = LogStatus.Success
+                taskLog.txHash = web3Result.hash
+                taskLog.url = web3Result.url
+            } catch (error) {
+                taskLog.status = LogStatus.Failed
+                taskLog.error = error.message
+            }
+            taskLog.finishTime = new Date()
+            await this.taskLogRepository.save(taskLog)
+            task.progress += 1
+            await this.taskRepository.save(task)
+        }
+        task.status = TaskStatus.Done
+        await this.taskRepository.save(task)
+    }
 }

+ 0 - 10
src/task/types.ts

@@ -1,10 +0,0 @@
-declare type TaskType =
-    | 'official_x2y'
-    | 'orbiter_x2y'
-    | 'official_y2x'
-    | 'orbiter_y2x'
-    | 'swap_x2y'
-    | 'swap_y2x'
-    | 'add_liquidity'
-    | 'remove_liquidity'
-    | 'mint'

+ 13 - 0
src/web3/model/web3-result.ts

@@ -0,0 +1,13 @@
+export class Web3Result {
+    address: string
+
+    hash: string
+
+    url: string
+
+    constructor(address: string, hash: string, config: Web3Config, zk: boolean) {
+        this.address = address
+        this.hash = hash
+        this.url = `${zk ? config.zksyncExplorer : config.ethereumExplorer}/tx/${hash}`
+    }
+}

+ 19 - 33
src/web3/web3.controller.ts

@@ -1,67 +1,53 @@
 import { Body, Controller, Post } from '@nestjs/common'
 import { Web3Service } from './web3.service'
-import { Network } from './network.enum';
+import { Network } from './network.enum'
 
 @Controller('web3')
 export class Web3Controller {
     constructor(private readonly web3Service: Web3Service) {}
 
     @Post('/zk-deposit')
-    public async zkDeposit(
-        @Body() { accountId, amount, network }: { accountId: string; amount: string; network: Network }
-    ) {
-        return await this.web3Service.zkDeposit(accountId, amount, network)
+    public async zkDeposit(@Body() { accountId, amount }: { accountId: string; amount: string }) {
+        return await this.web3Service.zkDeposit(accountId, amount)
     }
 
     @Post('/zk-withdraw')
-    public async zkWidthdraw(
-        @Body() { accountId, amount, network }: { accountId: string; amount: string; network: Network }
-    ) {
-        return await this.web3Service.zkWithdraw(accountId, amount, network)
+    public async zkWidthdraw(@Body() { accountId, amount }: { accountId: string; amount: string }) {
+        return await this.web3Service.zkWithdraw(accountId, amount)
     }
 
     @Post('/orbiter-deposit')
-    public async orbiterDeposit(
-        @Body() { accountId, amount, network }: { accountId: string; amount: string; network: Network }
-    ) {
-        return await this.web3Service.orbiterDeposit(accountId, amount, network)
+    public async orbiterDeposit(@Body() { accountId, amount }: { accountId: string; amount: string }) {
+        return await this.web3Service.orbiterDeposit(accountId, amount)
     }
 
     @Post('/orbiter-withdraw')
-    public async orbiterWidthdraw(
-        @Body() { accountId, amount, network }: { accountId: string; amount: string; network: Network }
-    ) {
-        return await this.web3Service.orbiterWithdraw(accountId, amount, network)
+    public async orbiterWidthdraw(@Body() { accountId, amount }: { accountId: string; amount: string }) {
+        return await this.web3Service.orbiterWithdraw(accountId, amount)
     }
 
     @Post('/add-liquidity')
-    public async addLiquidity(
-        @Body() { accountId, amount, network }: { accountId: string; amount: string; network: Network }
-    ) {
-        return await this.web3Service.addLiquidity(accountId, amount, network)
+    public async addLiquidity(@Body() { accountId, amount }: { accountId: string; amount: string }) {
+        return await this.web3Service.addLiquidity(accountId, amount)
     }
 
     @Post('/remove-liquidity')
-    public async removeLiquidity(@Body() { accountId, network }: { accountId: string; network: Network }) {
-        return await this.web3Service.removeLiquidity(accountId, network)
+    public async removeLiquidity(@Body() { accountId }: { accountId: string }) {
+        return await this.web3Service.removeLiquidity(accountId)
     }
 
     @Post('/swap-exact-out')
-    public async swap(
-        @Body() { accountId, amount, network }: { accountId: string; amount: string; network: Network }
-    ) {
-        return await this.web3Service.swapWithExactOutput(accountId, amount, network)
+    public async swap(@Body() { accountId, amount }: { accountId: string; amount: string }) {
+        return await this.web3Service.swapWithExactOutput(accountId, amount)
     }
 
     @Post('/swap-exact-in')
-    public async swapExactIn(
-        @Body() { accountId, amount, network }: { accountId: string; amount: string; network: Network }
-    ) {
-        return await this.web3Service.swapWithExactInput(accountId, amount, network)
+    public async swapExactIn(@Body() { accountId, amount }: { accountId: string; amount: string }) {
+        return await this.web3Service.swapWithExactInput(accountId, amount)
     }
 
     @Post('/mint')
-    public async mint(@Body() { accountId, network }: { accountId: string; network: Network }) {
-        return await this.web3Service.mint(accountId, network)
+    public async mint(@Body() { accountId }: { accountId: string }) {
+        return await this.web3Service.mint(accountId)
     }
 }

+ 23 - 5
src/web3/web3.service.ts

@@ -42,11 +42,14 @@ import { getSwapContract, getSwapChainWithExactOutputCall, getSwapChainWithExact
 import mintSquareAbi from './mintSquareAbi.json'
 import { Network } from './network.enum'
 import { Cron } from '@nestjs/schedule'
+import { Web3Result } from './model/web3-result'
 
 @Injectable()
 export class Web3Service {
     constructor(private readonly accountService: AccountsService) {}
 
+
+
     async zkDeposit(accountId, amount) {
         const account = await this.accountService.findById(accountId)
         const provider = new Provider(web3Config[account.network].zksyncRpcUrl)
@@ -60,6 +63,7 @@ export class Web3Service {
             amount: ethers.utils.parseEther(amount)
         })
         Logger.log('Deposit sent. Awaiting confirmation...')
+        return new Web3Result(account.address, deposit.hash, web3Config[account.network], false)
         // // Await processing of the deposit on L1
         // const ethereumTxReceipt = await deposit.waitL1Commit()
 
@@ -91,6 +95,7 @@ export class Web3Service {
             amount: ethers.utils.parseEther(amount)
         })
         Logger.log(`Widthdraw sent. ${web3Config[account.network].zksyncExplorer}/tx/${withdrawL2.hash}`)
+        return new Web3Result(account.address, withdrawL2.hash, web3Config[account.network], true)
         // // Await processing of the deposit on L1
         // const ethereumTxReceipt = await deposit.waitL1Commit()
 
@@ -121,14 +126,22 @@ export class Web3Service {
             to: web3Config[account.network].orbiterEthAddress,
             value: ethers.utils.parseEther(amount).add(web3Config[account.network].orbiterIdCodeZk)
         })
-        console.log('Mining transaction...')
-        // Waiting for the transaction to be mined
-        const receipt = await tx.wait()
-        console.log('Transaction mined!', receipt)
+        return new Web3Result(account.address, tx.hash, web3Config[account.network], false)
     }
 
     async orbiterWithdraw(accountId, amount) {
-        throw new Error('Method not implemented.')
+        const account = await this.accountService.findById(accountId)
+        const provider = new ethers.providers.InfuraProvider(
+            web3Config[account.network].ethereumNetwork,
+            web3Config[account.network].infuraApiKey
+        )
+        const wallet = new ethers.Wallet(account.privateKey, provider)
+        const tx = await wallet.sendTransaction({
+            from: wallet.address,
+            to: web3Config[account.network].orbiterZkAddress,
+            value: ethers.utils.parseEther(amount).add(web3Config[account.network].orbiterIdCodeEth)
+        })
+        return new Web3Result(account.address, tx.hash, web3Config[account.network], true)
     }
 
     async addLiquidity(accountId, amount) {
@@ -221,6 +234,7 @@ export class Web3Service {
             gasLimit
         })
         console.log('tx: ', tx)
+        return new Web3Result(account.address, tx.hash, web3Config[account.network], true)
     }
 
     async removeLiquidity(accountId) {
@@ -288,6 +302,7 @@ export class Web3Service {
             gasLimit
         })
         console.log('decLiquidityCalling tx: ', JSON.stringify(tx0, null, 4))
+        return new Web3Result(account.address, tx0.hash, web3Config[account.network], true)
     }
 
     async allowance(tokenAddress, spender, wallet: Wallet, network: Network): Promise<number> {
@@ -391,6 +406,7 @@ export class Web3Service {
             gasLimit
         })
         console.log(tx)
+        return new Web3Result(account.address, tx.hash, web3Config[account.network], true)
     }
 
     async swapWithExactInput(accountId, amount) {
@@ -454,6 +470,7 @@ export class Web3Service {
             gasLimit
         })
         console.log(JSON.stringify(tx, null, 4))
+        return new Web3Result(account.address, tx.hash, web3Config[account.network], true)
     }
 
     async mint(accountId) {
@@ -477,5 +494,6 @@ export class Web3Service {
             gasLimit
         })
         console.log(tx)
+        return new Web3Result(account.address, tx.hash, web3Config[account.network], true)
     }
 }