Refactor waku messaging setup (#74)

This commit is contained in:
Szymon Szlachtowicz 2021-09-15 15:10:12 +02:00 committed by GitHub
parent d4c8a3c35e
commit e70c0801d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 111 additions and 72 deletions

View File

@ -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<any>[],
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<T extends { id: string; timestamp: number }>(
messages: WakuMessage[],
decode: (payload: Uint8Array | undefined, timestamp: Date | undefined, chainId: number) => T | undefined,
msgObj: WakuMessageStore,
filterFunction?: (e: T) => boolean
setupData: WakuMessagesSetup<T>
) {
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
}
}
})

View File

@ -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(

View File

@ -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(

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -0,0 +1,8 @@
import { WakuMessage } from 'js-waku'
export type WakuMessagesSetup<T> = {
name: string
tokenCheckArray: string[]
decodeFunction: (wakuMessage: WakuMessage) => T | undefined
filterFunction?: (e: T) => boolean
}

View File

@ -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),
})

View File

@ -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),
})