diff --git a/server/src/app.module.ts b/server/src/app.module.ts index fa4a626..290e642 100644 --- a/server/src/app.module.ts +++ b/server/src/app.module.ts @@ -21,4 +21,5 @@ import {DatabaseModule} from './port/module/database.module'; controllers: [AppController], providers: [AppService], }) -export class AppModule {} +export class AppModule { +} diff --git a/server/src/config/auction.ts b/server/src/config/auction.ts new file mode 100644 index 0000000..a9bd750 --- /dev/null +++ b/server/src/config/auction.ts @@ -0,0 +1,7 @@ +export default { + abi: [{ + name: 'auction', + type: 'function', + }], + address: 'ax1234', +}; diff --git a/server/src/config/ghost.ts b/server/src/config/ghost.ts new file mode 100644 index 0000000..e06b0ba --- /dev/null +++ b/server/src/config/ghost.ts @@ -0,0 +1,7 @@ +export default { + abi: [{ + name: 'ghost', + type: 'function', + }], + address: 'ax1234', +}; diff --git a/server/src/config/subscriber.ts b/server/src/config/subscriber.ts new file mode 100644 index 0000000..7edd576 --- /dev/null +++ b/server/src/config/subscriber.ts @@ -0,0 +1,5 @@ +export default { + startBlock: 5853011, + endBlock: 'latest', + network: 'testNet', +}; diff --git a/server/src/port/adapter/service/blockchain/ethereum/contract/auction.contract.service.spec.ts b/server/src/port/adapter/service/blockchain/ethereum/contract/auction.contract.service.spec.ts new file mode 100644 index 0000000..0e501e4 --- /dev/null +++ b/server/src/port/adapter/service/blockchain/ethereum/contract/auction.contract.service.spec.ts @@ -0,0 +1,35 @@ +import {Test} from '@nestjs/testing'; +import {ConfigModule} from 'nestjs-config'; +import * as path from 'path'; +import {Web3Module} from '../web3/web3.module'; +import {instance, mock} from 'ts-mockito'; +import {AuctionHandler} from '../event/handler/auction.event.handler'; +import {AuctionContractService} from './auction.contract.service'; + +describe('AuctionContractService', () => { + let auctionContractService: AuctionContractService; + const mockAuctionEventHandler = mock(AuctionHandler); + + beforeAll( async () => { + const module = await Test.createTestingModule({ + imports: [ + Web3Module, + ConfigModule.load(path.resolve(__dirname, 'config', '**/!(*.d).{ts,js}')), + ], + providers: [ + AuctionContractService, + { + provide: 'AuctionHandler', + useValue: instance(mockAuctionEventHandler), + }, + ], + }).compile(); + auctionContractService = module.get(AuctionContractService); + }); + describe('#watchAuctionEvents()', () => { + it('should check blockNum increase by one', async () => { + await auctionContractService.watchAuctionEvents(); + }); + }); + }, +); diff --git a/server/src/port/adapter/service/blockchain/ethereum/contract/auction.contract.service.ts b/server/src/port/adapter/service/blockchain/ethereum/contract/auction.contract.service.ts new file mode 100644 index 0000000..99d8b59 --- /dev/null +++ b/server/src/port/adapter/service/blockchain/ethereum/contract/auction.contract.service.ts @@ -0,0 +1,42 @@ +import {Contract} from 'web3-eth-contract'; +import Web3 from 'web3'; +import {Inject, Injectable} from '@nestjs/common'; +import {EventData} from 'web3-eth-contract'; +import {InjectConfig} from 'nestjs-config'; +import {AuctionHandler} from '../event/handler/auction.event.handler'; + +@Injectable() +export class AuctionContractService { + private auctionContract: Contract; + private currentNum: number; + + constructor(@Inject('WEB3') private web3: Web3, @InjectConfig() private config, + private auctionEventHandler: AuctionHandler) { + this.createContract(); + } + + private createContract(): void { + this.auctionContract = new this.web3.eth.Contract(this.config.get('auction.abi'), this.config.get('auction.address')); + } + + watchAuctionEvents() { + setInterval(async () => { + const blockNum = await this.web3.eth.getBlockNumber(); + if (blockNum === this.currentNum) { + // Nothing happen + } else { + const eventData: EventData[] + = await this.auctionContract.getPastEvents('allEvents', { + fromBlock: this.currentNum, + toBlock: this.currentNum, + }); + await this.auctionEventHandler.callService(eventData); + this.currentNum++; + } + }, 1000); + } + + public watch() { + this.watchAuctionEvents(); + } +} diff --git a/server/src/port/adapter/service/blockchain/ethereum/contract/ghost.contract.service.spec.ts b/server/src/port/adapter/service/blockchain/ethereum/contract/ghost.contract.service.spec.ts new file mode 100644 index 0000000..9295d14 --- /dev/null +++ b/server/src/port/adapter/service/blockchain/ethereum/contract/ghost.contract.service.spec.ts @@ -0,0 +1,35 @@ +import {Test} from '@nestjs/testing'; +import {ConfigModule} from 'nestjs-config'; +import * as path from 'path'; +import {GhostContractService} from './ghost.contract.service'; +import {Web3Module} from '../web3/web3.module'; +import {GhostHandler} from '../event/handler/ghost.event.handler'; +import {instance, mock} from 'ts-mockito'; + +describe('GhostContractService', () => { + let ghostContractService: GhostContractService; + const mockGhostEventHandler = mock(GhostHandler); + + beforeAll( async () => { + const module = await Test.createTestingModule({ + imports: [ + Web3Module, + ConfigModule.load(path.resolve(__dirname, 'config', '**/!(*.d).{ts,js}')), + ], + providers: [ + GhostContractService, + { + provide: 'GhostHandler', + useValue: instance(mockGhostEventHandler), + }, + ], + }).compile(); + ghostContractService = module.get(GhostContractService); + }); + describe('#watchGhostEvents()', () => { + it('should check blockNum increase by one', async () => { + await ghostContractService.watchGhostEvents(); + }); + }); + }, +); diff --git a/server/src/port/adapter/service/blockchain/ethereum/contract/ghost.contract.service.ts b/server/src/port/adapter/service/blockchain/ethereum/contract/ghost.contract.service.ts new file mode 100644 index 0000000..3d08259 --- /dev/null +++ b/server/src/port/adapter/service/blockchain/ethereum/contract/ghost.contract.service.ts @@ -0,0 +1,42 @@ +import {Contract} from 'web3-eth-contract'; +import Web3 from 'web3'; +import {Inject, Injectable} from '@nestjs/common'; +import {EventData} from 'web3-eth-contract'; +import {InjectConfig} from 'nestjs-config'; +import {GhostHandler} from '../event/handler/ghost.event.handler'; + +@Injectable() +export class GhostContractService { + private ghostContract: Contract; + private currentNum: number; + + constructor(@Inject('WEB3') private web3: Web3, @InjectConfig() private config, + private ghostEventHandler: GhostHandler) { + this.createContract(); + } + + private createContract(): void { + this.ghostContract = new this.web3.eth.Contract(this.config.get('ghost.abi'), this.config.get('ghost.address')); + } + + watchGhostEvents() { + setInterval(async () => { + const blockNum = await this.web3.eth.getBlockNumber(); + if (blockNum === this.currentNum) { + console.log('nothing'); + } else { + const eventData: EventData[] + = await this.ghostContract.getPastEvents('allEvents', { + fromBlock: this.currentNum, + toBlock: this.currentNum, + }); + await this.ghostEventHandler.callService(eventData); + this.currentNum++; + } + }); + } + + public watch() { + this.watchGhostEvents(); + } +} diff --git a/server/src/port/adapter/service/blockchain/ethereum/event/event.module.ts b/server/src/port/adapter/service/blockchain/ethereum/event/event.module.ts deleted file mode 100644 index 48f7f64..0000000 --- a/server/src/port/adapter/service/blockchain/ethereum/event/event.module.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Module } from '@nestjs/common'; - -@Module({}) -export class EventModule {} diff --git a/server/src/port/adapter/service/blockchain/ethereum/event/event.service.spec.ts b/server/src/port/adapter/service/blockchain/ethereum/event/event.service.spec.ts deleted file mode 100644 index 78cb816..0000000 --- a/server/src/port/adapter/service/blockchain/ethereum/event/event.service.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { EventService } from './event.service'; - -describe('EventService', () => { - let service: EventService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [EventService], - }).compile(); - - service = module.get(EventService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/server/src/port/adapter/service/blockchain/ethereum/event/event.service.ts b/server/src/port/adapter/service/blockchain/ethereum/event/event.service.ts deleted file mode 100644 index 04be74e..0000000 --- a/server/src/port/adapter/service/blockchain/ethereum/event/event.service.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -@Injectable() -export class EventService { - constructor() {} -} diff --git a/server/src/port/adapter/service/blockchain/ethereum/event/handler/auction.event.handler.ts b/server/src/port/adapter/service/blockchain/ethereum/event/handler/auction.event.handler.ts new file mode 100644 index 0000000..0786d13 --- /dev/null +++ b/server/src/port/adapter/service/blockchain/ethereum/event/handler/auction.event.handler.ts @@ -0,0 +1,59 @@ +import {Inject, Injectable} from '@nestjs/common'; +import {EventHandler} from './event.handler'; +import {AuctionService} from '../../../../../../../app/auction/auction.service'; +import {EventData} from 'web3-eth-contract'; +import {AuctionDto} from '../../../../../../../app/auction/dto/auction.dto'; + +@Injectable() +export class AuctionHandler implements EventHandler { + constructor(@Inject('AuctionService') private auctionService: AuctionService) { + } + + public async callService(eventData: EventData[]): Promise { + for (const data of eventData) { + if (data.event === 'AuctionCreated') { + await this.createAuction(data); + } + if (data.event === 'AuctionSuccessful') { + await this.updateWinner(data); + } + if (data.event === 'AuctionCancelled') { + await this.cancelAuction(data); + } + // if (data.event === 'AuctionEnded') { + // await this.endAuction(data); + // } + } + } + + async createAuction(event: EventData): Promise { + const { + gene, + seller, + duration, + type, + winner, + bidAmount, + } = event.returnValues; + await this.auctionService.createAuction(new AuctionDto(gene, seller, duration, type, winner, bidAmount)); + } + + async updateWinner(event: EventData): Promise { + const { + gene, + winner, + bidAmount, + } = event.returnValues; + await this.auctionService.updateWinner(gene, winner, bidAmount); + } + + async cancelAuction(event: EventData): Promise { + const { gene } = event.returnValues; + await this.auctionService.cancelAuction(gene); + } + + async endAuction(event: EventData): Promise { + const gene = event.returnValues.gene; + await this.auctionService.endAuction(gene); + } +} diff --git a/server/src/port/adapter/service/blockchain/ethereum/event/handler/event.handler.ts b/server/src/port/adapter/service/blockchain/ethereum/event/handler/event.handler.ts new file mode 100644 index 0000000..4551609 --- /dev/null +++ b/server/src/port/adapter/service/blockchain/ethereum/event/handler/event.handler.ts @@ -0,0 +1,5 @@ +import {EventData} from 'web3-eth-contract'; + +export interface EventHandler { + callService(eventData: EventData[]): void; +} diff --git a/server/src/port/adapter/service/blockchain/ethereum/event/handler/ghost.event.handler.ts b/server/src/port/adapter/service/blockchain/ethereum/event/handler/ghost.event.handler.ts new file mode 100644 index 0000000..06667a9 --- /dev/null +++ b/server/src/port/adapter/service/blockchain/ethereum/event/handler/ghost.event.handler.ts @@ -0,0 +1,50 @@ +import {Inject, Injectable} from '@nestjs/common'; +import {GhostService} from '../../../../../../../app/ghost/ghost.service'; +import {EventData} from 'web3-eth-contract'; +import {EventHandler} from './event.handler'; +import {GhostDto} from '../../../../../../../app/ghost/dto/ghost.dto'; + +@Injectable() +export class GhostHandler implements EventHandler { + constructor(@Inject('GhostService') private ghostService: GhostService) { + } + + public async callService(eventData: EventData[]): Promise { + for (const data of eventData) { + if (data.event === 'Birth') { + await this.createEgg(data); + } + if (data.event === 'LevelUp') { + await this.levelUp(data); + } + if (data.event === 'Transfer') { + await this.transfer(data); + } + } + } + + async createEgg(event: EventData): Promise { + const { + owner, + gene, + } = event.returnValues; + await this.ghostService.createEgg(new GhostDto(owner, gene)); + } + + async levelUp(event: EventData): Promise { + const { + gene, + level, + } = event.returnValues; + await this.ghostService.levelUp(gene, level); + } + + async transfer(event: EventData): Promise { + const { + from, + to, + gene, + } = event.returnValues; + await this.ghostService.transfer(from, to, gene); + } +} diff --git a/server/src/port/adapter/service/blockchain/ethereum/event/test/config/subscriber.ts b/server/src/port/adapter/service/blockchain/ethereum/event/test/config/subscriber.ts new file mode 100644 index 0000000..8188223 --- /dev/null +++ b/server/src/port/adapter/service/blockchain/ethereum/event/test/config/subscriber.ts @@ -0,0 +1,4 @@ +export default { + startBlock: 5853011, + endBlock: 'latest', +}; diff --git a/server/src/port/adapter/service/blockchain/ethereum/web3/test/socket/config/auction.ts b/server/src/port/adapter/service/blockchain/ethereum/web3/test/socket/config/auction.ts new file mode 100644 index 0000000..5f9d8f2 --- /dev/null +++ b/server/src/port/adapter/service/blockchain/ethereum/web3/test/socket/config/auction.ts @@ -0,0 +1,5 @@ +export default { + abi : [{ + test: 'test', + }], +}; diff --git a/server/src/port/adapter/service/blockchain/ethereum/web3/test/socket/config/ghost.ts b/server/src/port/adapter/service/blockchain/ethereum/web3/test/socket/config/ghost.ts new file mode 100644 index 0000000..3c7943e --- /dev/null +++ b/server/src/port/adapter/service/blockchain/ethereum/web3/test/socket/config/ghost.ts @@ -0,0 +1,5 @@ +export default { + abi: [{ + test: 'test', + }], +}; diff --git a/server/src/port/adapter/service/blockchain/ethereum/web3/test/socket/config/web3.ts b/server/src/port/adapter/service/blockchain/ethereum/web3/test/socket/config/web3.ts index d83afa3..6afb8f2 100644 --- a/server/src/port/adapter/service/blockchain/ethereum/web3/test/socket/config/web3.ts +++ b/server/src/port/adapter/service/blockchain/ethereum/web3/test/socket/config/web3.ts @@ -1,4 +1,7 @@ export default { - url: 'localhost:8545', + url: 'ws://localhost:8545', type: 'socket', + abi : [{ + test: 'test', + }], };