From 427e2cb1bd275786c26db5b877a339b31e21816a Mon Sep 17 00:00:00 2001 From: Szymon Szlachtowicz <38212223+Szymx95@users.noreply.github.com> Date: Fri, 3 Sep 2021 12:14:08 +0200 Subject: [PATCH] Refactor core (#49) --- packages/core/src/classes/WakuPolling.ts | 73 +++++++++ packages/core/src/classes/WakuVoting.ts | 82 ++++++++++ packages/core/src/index.ts | 151 +------------------ packages/core/src/models/PollInitMsg.ts | 1 - packages/core/src/models/TimedPollVoteMsg.ts | 1 - 5 files changed, 157 insertions(+), 151 deletions(-) create mode 100644 packages/core/src/classes/WakuPolling.ts create mode 100644 packages/core/src/classes/WakuVoting.ts diff --git a/packages/core/src/classes/WakuPolling.ts b/packages/core/src/classes/WakuPolling.ts new file mode 100644 index 0000000..7eb0205 --- /dev/null +++ b/packages/core/src/classes/WakuPolling.ts @@ -0,0 +1,73 @@ +import { Waku } from 'js-waku' +import { JsonRpcSigner } from '@ethersproject/providers' +import { PollInitMsg } from '../models/PollInitMsg' +import { PollType } from '../types/PollType' +import { BigNumber, Wallet } from 'ethers' +import { WakuMessage } from 'js-waku' +import { TimedPollVoteMsg } from '../models/TimedPollVoteMsg' +import { DetailedTimedPoll } from '../models/DetailedTimedPoll' +import { createWaku } from '../utils/createWaku' +import { WakuVoting } from './WakuVoting' + +export class WakuPolling extends WakuVoting { + protected constructor(appName: string, tokenAddress: string, waku: Waku) { + super(appName, tokenAddress, waku) + this.wakuMessages['pollInit'] = { + topic: `/${this.appName}/waku-polling/timed-polls-init/proto/`, + hashMap: {}, + arr: [], + updateFunction: (msg: WakuMessage[]) => + this.decodeMsgAndSetArray( + msg, + PollInitMsg.decode, + this.wakuMessages['pollInit'], + (e) => e.endTime > Date.now() + ), + } + this.wakuMessages['pollVote'] = { + topic: `/${this.appName}/waku-polling/votes/proto/`, + hashMap: {}, + arr: [], + updateFunction: (msg: WakuMessage[]) => + this.decodeMsgAndSetArray(msg, TimedPollVoteMsg.decode, this.wakuMessages['pollVote']), + } + this.setObserver() + } + + public static async create(appName: string, tokenAddress: string, waku?: Waku) { + const wakuPolling = new WakuPolling(appName, tokenAddress, await createWaku(waku)) + return wakuPolling + } + + public async createTimedPoll( + signer: JsonRpcSigner | Wallet, + question: string, + answers: string[], + pollType: PollType, + minToken?: BigNumber, + endTime?: number + ) { + const pollInit = await PollInitMsg.create(signer, question, answers, pollType, minToken, endTime) + await this.sendWakuMessage(this.wakuMessages['pollInit'], pollInit) + } + + public async sendTimedPollVote( + signer: JsonRpcSigner | Wallet, + pollId: string, + selectedAnswer: number, + tokenAmount?: BigNumber + ) { + const pollVote = await TimedPollVoteMsg.create(signer, pollId, selectedAnswer, tokenAmount) + await this.sendWakuMessage(this.wakuMessages['pollVote'], pollVote) + } + + public async getDetailedTimedPolls() { + return this.wakuMessages['pollInit'].arr.map( + (poll) => + new DetailedTimedPoll( + poll, + this.wakuMessages['pollVote'].arr.filter((vote) => vote.pollId === poll.id) + ) + ) + } +} diff --git a/packages/core/src/classes/WakuVoting.ts b/packages/core/src/classes/WakuVoting.ts new file mode 100644 index 0000000..61a8a86 --- /dev/null +++ b/packages/core/src/classes/WakuVoting.ts @@ -0,0 +1,82 @@ +import { Waku } from 'js-waku' +import { WakuMessage } from 'js-waku' +import { createWaku } from '../utils/createWaku' + +type WakuMessageStore = { + topic: string + hashMap: { [id: string]: boolean } + arr: any[] + updateFunction: (msg: WakuMessage[]) => void +} + +type WakuMessageStores = { + [messageType: string]: WakuMessageStore +} + +export class WakuVoting { + protected appName: string + protected waku: Waku + public tokenAddress: string + + protected wakuMessages: WakuMessageStores = {} + protected observers: { callback: (msg: WakuMessage) => void; topics: string[] }[] = [] + protected constructor(appName: string, tokenAddress: string, waku: Waku) { + this.appName = appName + this.tokenAddress = tokenAddress + this.waku = waku + } + + public static async create(appName: string, tokenAddress: string, waku?: Waku) { + return new WakuVoting(appName, tokenAddress, await createWaku(waku)) + } + + public cleanUp() { + this.observers.forEach((observer) => this.waku.relay.deleteObserver(observer.callback, observer.topics)) + } + + protected async setObserver() { + await Promise.all( + Object.values(this.wakuMessages).map(async (msgObj) => { + const storeMessages = await this.waku?.store.queryHistory([msgObj.topic]) + if (storeMessages) { + msgObj.updateFunction(storeMessages) + } + this.waku.relay.addObserver((msg) => msgObj.updateFunction([msg]), [msgObj.topic]) + this.observers.push({ callback: (msg) => msgObj.updateFunction([msg]), topics: [msgObj.topic] }) + }) + ) + } + + protected decodeMsgAndSetArray( + messages: WakuMessage[], + decode: (payload: Uint8Array | undefined, timestamp: Date | undefined) => T | undefined, + msgObj: WakuMessageStore, + filterFunction?: (e: T) => boolean + ) { + messages + .map((msg) => decode(msg.payload, msg.timestamp)) + .sort((a, b) => ((a?.timestamp ?? new Date(0)) > (b?.timestamp ?? new Date(0)) ? 1 : -1)) + .forEach((e) => { + if (e) { + if (filterFunction ? filterFunction(e) : true && !msgObj.hashMap?.[e.id]) { + msgObj.arr.unshift(e) + msgObj.hashMap[e.id] = true + } + } + }) + } + + protected async sendWakuMessage Uint8Array | undefined; timestamp: number }>( + msgObj: WakuMessageStore, + decodedMsg: T | undefined + ) { + const payload = decodedMsg?.encode() + if (payload && decodedMsg) { + const wakuMessage = await WakuMessage.fromBytes(payload, msgObj.topic, { + timestamp: new Date(decodedMsg.timestamp), + }) + await this.waku?.relay.send(wakuMessage) + msgObj.updateFunction([wakuMessage]) + } + } +} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 87b9131..df39e7e 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,151 +1,4 @@ -import { Waku } from 'js-waku' -import { JsonRpcSigner } from '@ethersproject/providers' -import { PollInitMsg } from './models/PollInitMsg' -import { PollType } from './types/PollType' -import { BigNumber, Wallet } from 'ethers' -import { WakuMessage, StoreCodec } from 'js-waku' -import { TimedPollVoteMsg } from './models/TimedPollVoteMsg' -import { DetailedTimedPoll } from './models/DetailedTimedPoll' -import { isTruthy } from './utils' -import { createWaku } from './utils/createWaku' - -type WakuMessageStore = { - topic: string - hashMap: { [id: string]: boolean } - arr: any[] - updateFunction: (msg: WakuMessage[]) => void -} - -type WakuMessageStores = { - [messageType: string]: WakuMessageStore -} - -class WakuVoting { - protected appName: string - protected waku: Waku - public tokenAddress: string - - protected wakuMessages: WakuMessageStores = {} - protected observers: { callback: (msg: WakuMessage) => void; topics: string[] }[] = [] - protected constructor(appName: string, tokenAddress: string, waku: Waku) { - this.appName = appName - this.tokenAddress = tokenAddress - this.waku = waku - } - - public static async create(appName: string, tokenAddress: string, waku?: Waku) { - return new WakuVoting(appName, tokenAddress, await createWaku(waku)) - } - - public cleanUp() { - this.observers.forEach((observer) => this.waku.relay.deleteObserver(observer.callback, observer.topics)) - } - - protected async setObserver(msgObj: WakuMessageStore) { - const storeMessages = await this.waku?.store.queryHistory([msgObj.topic]) - if (storeMessages) { - msgObj.updateFunction(storeMessages) - } - this.waku.relay.addObserver((msg) => msgObj.updateFunction([msg]), [msgObj.topic]) - this.observers.push({ callback: (msg) => msgObj.updateFunction([msg]), topics: [msgObj.topic] }) - } - - protected decodeMsgAndSetArray( - messages: WakuMessage[], - decode: (payload: Uint8Array | undefined, timestamp: Date | undefined) => T | undefined, - msgObj: WakuMessageStore, - filterFunction?: (e: T) => boolean - ) { - messages - .map((msg) => decode(msg.payload, msg.timestamp)) - .sort((a, b) => ((a?.timestamp ?? new Date(0)) > (b?.timestamp ?? new Date(0)) ? 1 : -1)) - .forEach((e) => { - if (e) { - if (filterFunction ? filterFunction(e) : true && !msgObj.hashMap?.[e.id]) { - msgObj.arr.unshift(e) - msgObj.hashMap[e.id] = true - } - } - }) - } - - protected async sendWakuMessage Uint8Array | undefined; timestamp: number }>( - msgObj: WakuMessageStore, - decodedMsg: T | undefined - ) { - const payload = decodedMsg?.encode() - if (payload && decodedMsg) { - const wakuMessage = await WakuMessage.fromBytes(payload, msgObj.topic, { - timestamp: new Date(decodedMsg.timestamp), - }) - await this.waku?.relay.send(wakuMessage) - msgObj.updateFunction([wakuMessage]) - } - } -} - -class WakuPolling extends WakuVoting { - protected constructor(appName: string, tokenAddress: string, waku: Waku) { - super(appName, tokenAddress, waku) - this.wakuMessages['pollInit'] = { - topic: `/${this.appName}/waku-polling/timed-polls-init/proto/`, - hashMap: {}, - arr: [], - updateFunction: (msg: WakuMessage[]) => - this.decodeMsgAndSetArray( - msg, - PollInitMsg.decode, - this.wakuMessages['pollInit'], - (e) => e.endTime > Date.now() - ), - } - this.wakuMessages['pollVote'] = { - topic: `/${this.appName}/waku-polling/votes/proto/`, - hashMap: {}, - arr: [], - updateFunction: (msg: WakuMessage[]) => - this.decodeMsgAndSetArray(msg, TimedPollVoteMsg.decode, this.wakuMessages['pollVote']), - } - } - - public static async create(appName: string, tokenAddress: string, waku?: Waku) { - const wakuPolling = new WakuPolling(appName, tokenAddress, await createWaku(waku)) - wakuPolling.setObserver(wakuPolling.wakuMessages['pollInit']) - wakuPolling.setObserver(wakuPolling.wakuMessages['pollVote']) - return wakuPolling - } - - public async createTimedPoll( - signer: JsonRpcSigner | Wallet, - question: string, - answers: string[], - pollType: PollType, - minToken?: BigNumber, - endTime?: number - ) { - const pollInit = await PollInitMsg.create(signer, question, answers, pollType, minToken, endTime) - await this.sendWakuMessage(this.wakuMessages['pollInit'], pollInit) - } - - public async sendTimedPollVote( - signer: JsonRpcSigner | Wallet, - pollId: string, - selectedAnswer: number, - tokenAmount?: BigNumber - ) { - const pollVote = await TimedPollVoteMsg.create(signer, pollId, selectedAnswer, tokenAmount) - await this.sendWakuMessage(this.wakuMessages['pollVote'], pollVote) - } - - public async getDetailedTimedPolls() { - return this.wakuMessages['pollInit'].arr.map( - (poll) => - new DetailedTimedPoll( - poll, - this.wakuMessages['pollVote'].arr.filter((vote) => vote.pollId === poll.id) - ) - ) - } -} +import { WakuPolling } from './classes/WakuPolling' +import { WakuVoting } from './classes/WakuVoting' export { WakuVoting, WakuPolling } diff --git a/packages/core/src/models/PollInitMsg.ts b/packages/core/src/models/PollInitMsg.ts index db08c48..46a6e88 100644 --- a/packages/core/src/models/PollInitMsg.ts +++ b/packages/core/src/models/PollInitMsg.ts @@ -3,7 +3,6 @@ import { BigNumber, utils, Wallet } from 'ethers' import { JsonRpcSigner } from '@ethersproject/providers' import protons, { PollInit } from 'protons' import { createSignedMsg } from '../utils/createSignedMsg' -import { recoverTypedSignature_v4 } from 'eth-sig-util' import { verifySignature } from '../utils/verifySignature' const proto = protons(` diff --git a/packages/core/src/models/TimedPollVoteMsg.ts b/packages/core/src/models/TimedPollVoteMsg.ts index 841e09b..0dbe00d 100644 --- a/packages/core/src/models/TimedPollVoteMsg.ts +++ b/packages/core/src/models/TimedPollVoteMsg.ts @@ -3,7 +3,6 @@ import { JsonRpcSigner } from '@ethersproject/providers' import protons, { TimedPollVote } from 'protons' import { Wallet } from 'ethers' import { createSignedMsg } from '../utils/createSignedMsg' -import { recoverTypedSignature_v4 } from 'eth-sig-util' import { verifySignature } from '../utils/verifySignature' const proto = protons(`