Refactor waku messaging setup (#74)
This commit is contained in:
parent
d4c8a3c35e
commit
e70c0801d7
|
@ -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
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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),
|
||||
})
|
||||
|
|
|
@ -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),
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue