diff --git a/packages/core/src/classes/WakuMessaging.ts b/packages/core/src/classes/WakuMessaging.ts index f44ad69..7931be7 100644 --- a/packages/core/src/classes/WakuMessaging.ts +++ b/packages/core/src/classes/WakuMessaging.ts @@ -6,6 +6,7 @@ import { Contract } from '@ethersproject/contracts' import { Interface } from '@ethersproject/abi' import { ERC20 } from '../abi' import { createWaku } from '../utils/createWaku' +import { WakuMessagesSetup } from '../types/WakuMessagesSetup' const ABI = [ 'function aggregate(tuple(address target, bytes callData)[] calls) view returns (uint256 blockNumber, bytes[] returnData)', ] @@ -39,6 +40,7 @@ export class WakuMessaging { provider: Web3Provider, chainId: number, multicall: string, + wakuMessagesSetup: WakuMessagesSetup[], waku?: Waku ) { this.appName = appName @@ -47,6 +49,17 @@ export class WakuMessaging { this.chainId = chainId this.token = new Contract(tokenAddress, ERC20, this.provider) this.multicall = new Contract(multicall, ABI, this.provider) + + wakuMessagesSetup.forEach((setupData) => { + this.wakuMessages[setupData.name] = { + topic: `/${this.appName}/0.1/${setupData.name}/proto/`, + tokenCheckArray: setupData.tokenCheckArray, + hashMap: {}, + arr: [], + updateFunction: (msg) => this.decodeMsgAndSetArray(msg, setupData), + } + }) + this.setObserver() } public cleanUp() { @@ -61,9 +74,7 @@ export class WakuMessaging { await Promise.all( Object.values(this.wakuMessages).map(async (msgObj) => { const storeMessages = await this.waku?.store.queryHistory([msgObj.topic]) - if (storeMessages) { - msgObj.updateFunction(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] }) }) @@ -72,18 +83,18 @@ export class WakuMessaging { protected decodeMsgAndSetArray( messages: WakuMessage[], - decode: (payload: Uint8Array | undefined, timestamp: Date | undefined, chainId: number) => T | undefined, - msgObj: WakuMessageStore, - filterFunction?: (e: T) => boolean + setupData: WakuMessagesSetup ) { + const { decodeFunction, filterFunction, name } = setupData + const { arr, hashMap } = this.wakuMessages[name] messages - .map((msg) => decode(msg.payload, msg.timestamp, this.chainId)) + .map(decodeFunction) .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 + if (filterFunction ? filterFunction(e) : true && !hashMap?.[e.id]) { + arr.unshift(e) + hashMap[e.id] = true } } }) diff --git a/packages/core/src/classes/WakuPolling.ts b/packages/core/src/classes/WakuPolling.ts index 4d2a653..ad18856 100644 --- a/packages/core/src/classes/WakuPolling.ts +++ b/packages/core/src/classes/WakuPolling.ts @@ -9,6 +9,7 @@ import { DetailedTimedPoll } from '../models/DetailedTimedPoll' import { createWaku } from '../utils/createWaku' import { WakuMessaging } from './WakuMessaging' import { Web3Provider } from '@ethersproject/providers' +import { WakuMessagesSetup } from '../types/WakuMessagesSetup' export enum MESSEGAGE_SENDING_RESULT { ok = 0, @@ -26,29 +27,27 @@ export class WakuPolling extends WakuMessaging { multicall: string, waku?: Waku ) { - super(appName, tokenAddress, provider, chainId, multicall, waku) - this.wakuMessages['pollInit'] = { - topic: `/${this.appName}/waku-polling/timed-polls-init/proto/`, - hashMap: {}, - tokenCheckArray: ['owner'], - 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: {}, - tokenCheckArray: ['voter'], - arr: [], - updateFunction: (msg: WakuMessage[]) => - this.decodeMsgAndSetArray(msg, TimedPollVoteMsg.decode, this.wakuMessages['pollVote']), - } - this.setObserver() + super( + appName, + tokenAddress, + provider, + chainId, + multicall, + [ + { + name: 'pollInit', + tokenCheckArray: ['owner'], + decodeFunction: (wakuMessage) => PollInitMsg.decode(wakuMessage, chainId), + filterFunction: (e: PollInitMsg) => e.endTime > Date.now(), + }, + { + name: 'pollVote', + tokenCheckArray: ['voter'], + decodeFunction: (wakuMessage) => TimedPollVoteMsg.decode(wakuMessage, chainId), + }, + ], + waku + ) } public static async create( diff --git a/packages/core/src/classes/WakuVoting.ts b/packages/core/src/classes/WakuVoting.ts index 6471e6c..b734228 100644 --- a/packages/core/src/classes/WakuVoting.ts +++ b/packages/core/src/classes/WakuVoting.ts @@ -23,21 +23,22 @@ export class WakuVoting extends WakuMessaging { multicallAddress: string, waku?: Waku ) { - super(appName, token, provider, chainId, multicallAddress, waku) + super( + appName, + token, + provider, + chainId, + multicallAddress, + [ + { + name: 'vote', + tokenCheckArray: ['voter'], + decodeFunction: (wakuMessage) => VoteMsg.decode(wakuMessage, chainId, votingContract.address), + }, + ], + waku + ) this.votingContract = votingContract - this.wakuMessages['vote'] = { - topic: `/${this.appName}/waku-voting/votes/proto/`, - hashMap: {}, - arr: [], - tokenCheckArray: ['voter'], - updateFunction: (msg: WakuMessage[]) => - this.decodeMsgAndSetArray( - msg, - (payload, timestamp, chainId) => VoteMsg.decode(payload, timestamp, chainId, this.votingContract.address), - this.wakuMessages['vote'] - ), - } - this.setObserver() } public static async create( diff --git a/packages/core/src/models/PollInitMsg.ts b/packages/core/src/models/PollInitMsg.ts index cb1471c..7633acc 100644 --- a/packages/core/src/models/PollInitMsg.ts +++ b/packages/core/src/models/PollInitMsg.ts @@ -4,6 +4,7 @@ import { JsonRpcSigner } from '@ethersproject/providers' import protons, { PollInit } from 'protons' import { createSignFunction } from '../utils/createSignFunction' import { verifySignature } from '../utils/verifySignature' +import { WakuMessage } from 'js-waku' const proto = protons(` message PollInit { @@ -173,14 +174,10 @@ export class PollInitMsg { } } - static decode( - rawPayload: Uint8Array | undefined, - timestamp: Date | undefined, - chainId: number, - verifyFunction?: (params: any, address: string) => boolean - ) { + static decode(wakuMessage: WakuMessage, chainId: number, verifyFunction?: (params: any, address: string) => boolean) { try { - const payload = proto.PollInit.decode(rawPayload) + const timestamp = wakuMessage.timestamp + const payload = proto.PollInit.decode(wakuMessage.payload) if (!timestamp || timestamp.getTime() != payload.timestamp) { return undefined } diff --git a/packages/core/src/models/TimedPollVoteMsg.ts b/packages/core/src/models/TimedPollVoteMsg.ts index 61cee7f..ad5ff36 100644 --- a/packages/core/src/models/TimedPollVoteMsg.ts +++ b/packages/core/src/models/TimedPollVoteMsg.ts @@ -4,6 +4,7 @@ import protons, { TimedPollVote } from 'protons' import { Wallet } from 'ethers' import { createSignFunction } from '../utils/createSignFunction' import { verifySignature } from '../utils/verifySignature' +import { WakuMessage } from 'js-waku' const proto = protons(` message TimedPollVote { @@ -122,14 +123,10 @@ export class TimedPollVoteMsg { } } - static decode( - rawPayload: Uint8Array | undefined, - timestamp: Date | undefined, - chainId: number, - verifyFunction?: (params: any, address: string) => boolean - ) { + static decode(wakuMessage: WakuMessage, chainId: number, verifyFunction?: (params: any, address: string) => boolean) { try { - const payload = proto.TimedPollVote.decode(rawPayload) + const timestamp = wakuMessage.timestamp + const payload = proto.TimedPollVote.decode(wakuMessage.payload) if (!timestamp || !payload.timestamp || timestamp?.getTime() != payload.timestamp) { return undefined } diff --git a/packages/core/src/models/VoteMsg.ts b/packages/core/src/models/VoteMsg.ts index 8f25cce..257d7f4 100644 --- a/packages/core/src/models/VoteMsg.ts +++ b/packages/core/src/models/VoteMsg.ts @@ -4,6 +4,7 @@ import { BigNumber, Wallet } from 'ethers' import { JsonRpcSigner } from '@ethersproject/providers' import { createSignFunction } from '../utils/createSignFunction' import { verifySignature } from '../utils/verifySignature' +import { WakuMessage } from 'js-waku' const proto = protons(` message Vote { @@ -121,14 +122,14 @@ export class VoteMsg { } static decode( - rawPayload: Uint8Array | undefined, - timestamp: Date | undefined, + wakuMessage: WakuMessage, chainId: number, contractAddress: string, verifyFunction?: (params: any, address: string) => boolean ) { try { - const payload = proto.Vote.decode(rawPayload) + const timestamp = wakuMessage.timestamp + const payload = proto.Vote.decode(wakuMessage.payload) if (!timestamp || !payload.timestamp || timestamp?.getTime() != payload.timestamp) { return undefined } diff --git a/packages/core/src/types/WakuMessagesSetup.ts b/packages/core/src/types/WakuMessagesSetup.ts new file mode 100644 index 0000000..36a28a0 --- /dev/null +++ b/packages/core/src/types/WakuMessagesSetup.ts @@ -0,0 +1,8 @@ +import { WakuMessage } from 'js-waku' + +export type WakuMessagesSetup = { + name: string + tokenCheckArray: string[] + decodeFunction: (wakuMessage: WakuMessage) => T | undefined + filterFunction?: (e: T) => boolean +} diff --git a/packages/core/test/models/PollInitMsg.test.ts b/packages/core/test/models/PollInitMsg.test.ts index 1f94bc9..f53c2d8 100644 --- a/packages/core/test/models/PollInitMsg.test.ts +++ b/packages/core/test/models/PollInitMsg.test.ts @@ -3,6 +3,7 @@ import { PollInitMsg } from '../../src/models/PollInitMsg' import { MockProvider } from 'ethereum-waffle' import { PollType } from '../../src/types/PollType' import { BigNumber } from 'ethers' +import { WakuMessage } from 'js-waku' describe('PollInitMsg', () => { const provider = new MockProvider() @@ -95,13 +96,20 @@ describe('PollInitMsg', () => { const payload = data.encode() expect(payload).to.not.be.undefined if (payload) { - expect(PollInitMsg.decode(payload, new Date(data.timestamp), 0, () => true)).to.deep.eq(data) + expect( + PollInitMsg.decode({ payload, timestamp: new Date(data.timestamp) } as WakuMessage, 0, () => true) + ).to.deep.eq(data) } } }) it('random decode', async () => { - expect(PollInitMsg.decode(new Uint8Array([12, 12, 3, 32, 31, 212, 31, 32, 23]), new Date(10), 0)).to.be.undefined + expect( + PollInitMsg.decode( + { payload: new Uint8Array([12, 12, 3, 32, 31, 212, 31, 32, 23]), timestamp: new Date(10) } as WakuMessage, + 0 + ) + ).to.be.undefined }) it('NON_WEIGHTED init', async () => { @@ -119,7 +127,9 @@ describe('PollInitMsg', () => { const payload = data.encode() expect(payload).to.not.be.undefined if (payload) { - expect(PollInitMsg.decode(payload, new Date(data.timestamp), 0, () => true)).to.deep.eq(data) + expect( + PollInitMsg.decode({ payload, timestamp: new Date(data.timestamp) } as WakuMessage, 0, () => true) + ).to.deep.eq(data) } } }) @@ -139,7 +149,9 @@ describe('PollInitMsg', () => { expect(payload).to.not.be.undefined if (payload) { - expect(PollInitMsg.decode(payload, new Date(data.timestamp), 0, () => true)).to.deep.eq({ + expect( + PollInitMsg.decode({ payload, timestamp: new Date(data.timestamp) } as WakuMessage, 0, () => true) + ).to.deep.eq({ ...data, minToken: BigNumber.from(1), }) diff --git a/packages/core/test/models/TimedPollVoteMsg.test.ts b/packages/core/test/models/TimedPollVoteMsg.test.ts index 595cb51..567596e 100644 --- a/packages/core/test/models/TimedPollVoteMsg.test.ts +++ b/packages/core/test/models/TimedPollVoteMsg.test.ts @@ -2,6 +2,7 @@ import { expect } from 'chai' import { TimedPollVoteMsg } from '../../src/models/TimedPollVoteMsg' import { MockProvider } from 'ethereum-waffle' import { BigNumber } from 'ethers' +import { WakuMessage } from 'js-waku' describe('TimedPollVoteMsg', () => { const provider = new MockProvider() @@ -52,14 +53,24 @@ describe('TimedPollVoteMsg', () => { expect(payload).to.not.be.undefined if (payload) { - expect(await TimedPollVoteMsg.decode(payload, new Date(data.timestamp), 0, () => true)).to.deep.eq(data) + expect( + await TimedPollVoteMsg.decode( + { payload, timestamp: new Date(data.timestamp) } as WakuMessage, + 0, + () => true + ) + ).to.deep.eq(data) } } }) it('random decode', async () => { - expect(TimedPollVoteMsg.decode(new Uint8Array([12, 12, 3, 32, 31, 212, 31, 32, 23]), new Date(10), 0)).to.be - .undefined + expect( + TimedPollVoteMsg.decode( + { payload: new Uint8Array([12, 12, 3, 32, 31, 212, 31, 32, 23]), timestamp: new Date(10) } as WakuMessage, + 0 + ) + ).to.be.undefined }) it('data with token', async () => { @@ -77,7 +88,9 @@ describe('TimedPollVoteMsg', () => { expect(payload).to.not.be.undefined if (payload) { - expect(TimedPollVoteMsg.decode(payload, new Date(data.timestamp), 0, () => true)).to.deep.eq({ + expect( + TimedPollVoteMsg.decode({ payload, timestamp: new Date(data.timestamp) } as WakuMessage, 0, () => true) + ).to.deep.eq({ ...data, tokenAmount: BigNumber.from(120), })