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 { Interface } from '@ethersproject/abi'
|
||||||
import { ERC20 } from '../abi'
|
import { ERC20 } from '../abi'
|
||||||
import { createWaku } from '../utils/createWaku'
|
import { createWaku } from '../utils/createWaku'
|
||||||
|
import { WakuMessagesSetup } from '../types/WakuMessagesSetup'
|
||||||
const ABI = [
|
const ABI = [
|
||||||
'function aggregate(tuple(address target, bytes callData)[] calls) view returns (uint256 blockNumber, bytes[] returnData)',
|
'function aggregate(tuple(address target, bytes callData)[] calls) view returns (uint256 blockNumber, bytes[] returnData)',
|
||||||
]
|
]
|
||||||
|
@ -39,6 +40,7 @@ export class WakuMessaging {
|
||||||
provider: Web3Provider,
|
provider: Web3Provider,
|
||||||
chainId: number,
|
chainId: number,
|
||||||
multicall: string,
|
multicall: string,
|
||||||
|
wakuMessagesSetup: WakuMessagesSetup<any>[],
|
||||||
waku?: Waku
|
waku?: Waku
|
||||||
) {
|
) {
|
||||||
this.appName = appName
|
this.appName = appName
|
||||||
|
@ -47,6 +49,17 @@ export class WakuMessaging {
|
||||||
this.chainId = chainId
|
this.chainId = chainId
|
||||||
this.token = new Contract(tokenAddress, ERC20, this.provider)
|
this.token = new Contract(tokenAddress, ERC20, this.provider)
|
||||||
this.multicall = new Contract(multicall, ABI, 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() {
|
public cleanUp() {
|
||||||
|
@ -61,9 +74,7 @@ export class WakuMessaging {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
Object.values(this.wakuMessages).map(async (msgObj) => {
|
Object.values(this.wakuMessages).map(async (msgObj) => {
|
||||||
const storeMessages = await this.waku?.store.queryHistory([msgObj.topic])
|
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?.waku?.relay.addObserver((msg) => msgObj.updateFunction([msg]), [msgObj.topic])
|
||||||
this.observers.push({ callback: (msg) => msgObj.updateFunction([msg]), topics: [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 }>(
|
protected decodeMsgAndSetArray<T extends { id: string; timestamp: number }>(
|
||||||
messages: WakuMessage[],
|
messages: WakuMessage[],
|
||||||
decode: (payload: Uint8Array | undefined, timestamp: Date | undefined, chainId: number) => T | undefined,
|
setupData: WakuMessagesSetup<T>
|
||||||
msgObj: WakuMessageStore,
|
|
||||||
filterFunction?: (e: T) => boolean
|
|
||||||
) {
|
) {
|
||||||
|
const { decodeFunction, filterFunction, name } = setupData
|
||||||
|
const { arr, hashMap } = this.wakuMessages[name]
|
||||||
messages
|
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))
|
.sort((a, b) => ((a?.timestamp ?? new Date(0)) > (b?.timestamp ?? new Date(0)) ? 1 : -1))
|
||||||
.forEach((e) => {
|
.forEach((e) => {
|
||||||
if (e) {
|
if (e) {
|
||||||
if (filterFunction ? filterFunction(e) : true && !msgObj.hashMap?.[e.id]) {
|
if (filterFunction ? filterFunction(e) : true && !hashMap?.[e.id]) {
|
||||||
msgObj.arr.unshift(e)
|
arr.unshift(e)
|
||||||
msgObj.hashMap[e.id] = true
|
hashMap[e.id] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { DetailedTimedPoll } from '../models/DetailedTimedPoll'
|
||||||
import { createWaku } from '../utils/createWaku'
|
import { createWaku } from '../utils/createWaku'
|
||||||
import { WakuMessaging } from './WakuMessaging'
|
import { WakuMessaging } from './WakuMessaging'
|
||||||
import { Web3Provider } from '@ethersproject/providers'
|
import { Web3Provider } from '@ethersproject/providers'
|
||||||
|
import { WakuMessagesSetup } from '../types/WakuMessagesSetup'
|
||||||
|
|
||||||
export enum MESSEGAGE_SENDING_RESULT {
|
export enum MESSEGAGE_SENDING_RESULT {
|
||||||
ok = 0,
|
ok = 0,
|
||||||
|
@ -26,29 +27,27 @@ export class WakuPolling extends WakuMessaging {
|
||||||
multicall: string,
|
multicall: string,
|
||||||
waku?: Waku
|
waku?: Waku
|
||||||
) {
|
) {
|
||||||
super(appName, tokenAddress, provider, chainId, multicall, waku)
|
super(
|
||||||
this.wakuMessages['pollInit'] = {
|
appName,
|
||||||
topic: `/${this.appName}/waku-polling/timed-polls-init/proto/`,
|
tokenAddress,
|
||||||
hashMap: {},
|
provider,
|
||||||
tokenCheckArray: ['owner'],
|
chainId,
|
||||||
arr: [],
|
multicall,
|
||||||
updateFunction: (msg: WakuMessage[]) =>
|
[
|
||||||
this.decodeMsgAndSetArray(
|
{
|
||||||
msg,
|
name: 'pollInit',
|
||||||
PollInitMsg.decode,
|
tokenCheckArray: ['owner'],
|
||||||
this.wakuMessages['pollInit'],
|
decodeFunction: (wakuMessage) => PollInitMsg.decode(wakuMessage, chainId),
|
||||||
(e) => e.endTime > Date.now()
|
filterFunction: (e: PollInitMsg) => e.endTime > Date.now(),
|
||||||
),
|
},
|
||||||
}
|
{
|
||||||
this.wakuMessages['pollVote'] = {
|
name: 'pollVote',
|
||||||
topic: `/${this.appName}/waku-polling/votes/proto/`,
|
tokenCheckArray: ['voter'],
|
||||||
hashMap: {},
|
decodeFunction: (wakuMessage) => TimedPollVoteMsg.decode(wakuMessage, chainId),
|
||||||
tokenCheckArray: ['voter'],
|
},
|
||||||
arr: [],
|
],
|
||||||
updateFunction: (msg: WakuMessage[]) =>
|
waku
|
||||||
this.decodeMsgAndSetArray(msg, TimedPollVoteMsg.decode, this.wakuMessages['pollVote']),
|
)
|
||||||
}
|
|
||||||
this.setObserver()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async create(
|
public static async create(
|
||||||
|
|
|
@ -23,21 +23,22 @@ export class WakuVoting extends WakuMessaging {
|
||||||
multicallAddress: string,
|
multicallAddress: string,
|
||||||
waku?: Waku
|
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.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(
|
public static async create(
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { JsonRpcSigner } from '@ethersproject/providers'
|
||||||
import protons, { PollInit } from 'protons'
|
import protons, { PollInit } from 'protons'
|
||||||
import { createSignFunction } from '../utils/createSignFunction'
|
import { createSignFunction } from '../utils/createSignFunction'
|
||||||
import { verifySignature } from '../utils/verifySignature'
|
import { verifySignature } from '../utils/verifySignature'
|
||||||
|
import { WakuMessage } from 'js-waku'
|
||||||
|
|
||||||
const proto = protons(`
|
const proto = protons(`
|
||||||
message PollInit {
|
message PollInit {
|
||||||
|
@ -173,14 +174,10 @@ export class PollInitMsg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static decode(
|
static decode(wakuMessage: WakuMessage, chainId: number, verifyFunction?: (params: any, address: string) => boolean) {
|
||||||
rawPayload: Uint8Array | undefined,
|
|
||||||
timestamp: Date | undefined,
|
|
||||||
chainId: number,
|
|
||||||
verifyFunction?: (params: any, address: string) => boolean
|
|
||||||
) {
|
|
||||||
try {
|
try {
|
||||||
const payload = proto.PollInit.decode(rawPayload)
|
const timestamp = wakuMessage.timestamp
|
||||||
|
const payload = proto.PollInit.decode(wakuMessage.payload)
|
||||||
if (!timestamp || timestamp.getTime() != payload.timestamp) {
|
if (!timestamp || timestamp.getTime() != payload.timestamp) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import protons, { TimedPollVote } from 'protons'
|
||||||
import { Wallet } from 'ethers'
|
import { Wallet } from 'ethers'
|
||||||
import { createSignFunction } from '../utils/createSignFunction'
|
import { createSignFunction } from '../utils/createSignFunction'
|
||||||
import { verifySignature } from '../utils/verifySignature'
|
import { verifySignature } from '../utils/verifySignature'
|
||||||
|
import { WakuMessage } from 'js-waku'
|
||||||
|
|
||||||
const proto = protons(`
|
const proto = protons(`
|
||||||
message TimedPollVote {
|
message TimedPollVote {
|
||||||
|
@ -122,14 +123,10 @@ export class TimedPollVoteMsg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static decode(
|
static decode(wakuMessage: WakuMessage, chainId: number, verifyFunction?: (params: any, address: string) => boolean) {
|
||||||
rawPayload: Uint8Array | undefined,
|
|
||||||
timestamp: Date | undefined,
|
|
||||||
chainId: number,
|
|
||||||
verifyFunction?: (params: any, address: string) => boolean
|
|
||||||
) {
|
|
||||||
try {
|
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) {
|
if (!timestamp || !payload.timestamp || timestamp?.getTime() != payload.timestamp) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { BigNumber, Wallet } from 'ethers'
|
||||||
import { JsonRpcSigner } from '@ethersproject/providers'
|
import { JsonRpcSigner } from '@ethersproject/providers'
|
||||||
import { createSignFunction } from '../utils/createSignFunction'
|
import { createSignFunction } from '../utils/createSignFunction'
|
||||||
import { verifySignature } from '../utils/verifySignature'
|
import { verifySignature } from '../utils/verifySignature'
|
||||||
|
import { WakuMessage } from 'js-waku'
|
||||||
|
|
||||||
const proto = protons(`
|
const proto = protons(`
|
||||||
message Vote {
|
message Vote {
|
||||||
|
@ -121,14 +122,14 @@ export class VoteMsg {
|
||||||
}
|
}
|
||||||
|
|
||||||
static decode(
|
static decode(
|
||||||
rawPayload: Uint8Array | undefined,
|
wakuMessage: WakuMessage,
|
||||||
timestamp: Date | undefined,
|
|
||||||
chainId: number,
|
chainId: number,
|
||||||
contractAddress: string,
|
contractAddress: string,
|
||||||
verifyFunction?: (params: any, address: string) => boolean
|
verifyFunction?: (params: any, address: string) => boolean
|
||||||
) {
|
) {
|
||||||
try {
|
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) {
|
if (!timestamp || !payload.timestamp || timestamp?.getTime() != payload.timestamp) {
|
||||||
return undefined
|
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 { MockProvider } from 'ethereum-waffle'
|
||||||
import { PollType } from '../../src/types/PollType'
|
import { PollType } from '../../src/types/PollType'
|
||||||
import { BigNumber } from 'ethers'
|
import { BigNumber } from 'ethers'
|
||||||
|
import { WakuMessage } from 'js-waku'
|
||||||
|
|
||||||
describe('PollInitMsg', () => {
|
describe('PollInitMsg', () => {
|
||||||
const provider = new MockProvider()
|
const provider = new MockProvider()
|
||||||
|
@ -95,13 +96,20 @@ describe('PollInitMsg', () => {
|
||||||
const payload = data.encode()
|
const payload = data.encode()
|
||||||
expect(payload).to.not.be.undefined
|
expect(payload).to.not.be.undefined
|
||||||
if (payload) {
|
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 () => {
|
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 () => {
|
it('NON_WEIGHTED init', async () => {
|
||||||
|
@ -119,7 +127,9 @@ describe('PollInitMsg', () => {
|
||||||
const payload = data.encode()
|
const payload = data.encode()
|
||||||
expect(payload).to.not.be.undefined
|
expect(payload).to.not.be.undefined
|
||||||
if (payload) {
|
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
|
expect(payload).to.not.be.undefined
|
||||||
if (payload) {
|
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,
|
...data,
|
||||||
minToken: BigNumber.from(1),
|
minToken: BigNumber.from(1),
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { expect } from 'chai'
|
||||||
import { TimedPollVoteMsg } from '../../src/models/TimedPollVoteMsg'
|
import { TimedPollVoteMsg } from '../../src/models/TimedPollVoteMsg'
|
||||||
import { MockProvider } from 'ethereum-waffle'
|
import { MockProvider } from 'ethereum-waffle'
|
||||||
import { BigNumber } from 'ethers'
|
import { BigNumber } from 'ethers'
|
||||||
|
import { WakuMessage } from 'js-waku'
|
||||||
|
|
||||||
describe('TimedPollVoteMsg', () => {
|
describe('TimedPollVoteMsg', () => {
|
||||||
const provider = new MockProvider()
|
const provider = new MockProvider()
|
||||||
|
@ -52,14 +53,24 @@ describe('TimedPollVoteMsg', () => {
|
||||||
|
|
||||||
expect(payload).to.not.be.undefined
|
expect(payload).to.not.be.undefined
|
||||||
if (payload) {
|
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 () => {
|
it('random decode', async () => {
|
||||||
expect(TimedPollVoteMsg.decode(new Uint8Array([12, 12, 3, 32, 31, 212, 31, 32, 23]), new Date(10), 0)).to.be
|
expect(
|
||||||
.undefined
|
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 () => {
|
it('data with token', async () => {
|
||||||
|
@ -77,7 +88,9 @@ describe('TimedPollVoteMsg', () => {
|
||||||
|
|
||||||
expect(payload).to.not.be.undefined
|
expect(payload).to.not.be.undefined
|
||||||
if (payload) {
|
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,
|
...data,
|
||||||
tokenAmount: BigNumber.from(120),
|
tokenAmount: BigNumber.from(120),
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue