diff --git a/packages/contracts/deploy/deploy.ts b/packages/contracts/deploy/deploy.ts index 2cf05d9..c1c7c9b 100644 --- a/packages/contracts/deploy/deploy.ts +++ b/packages/contracts/deploy/deploy.ts @@ -12,7 +12,7 @@ const deploy = async () => { const provider = ethers.getDefaultProvider(process.env.ETHEREUM_PROVIDER) const wallet = new ethers.Wallet(privateKey, provider) - const votingContract = await deployContract(wallet, VotingContract,[process.env.ETHEREUM_TOKEN_ADDRESS]) + const votingContract = await deployContract(wallet, VotingContract,[process.env.ETHEREUM_TOKEN_ADDRESS,1000]) console.log(`Voting contract deployed with address: ${votingContract.address}`) } diff --git a/packages/core/package.json b/packages/core/package.json index 16cde94..e20e16e 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -41,6 +41,7 @@ "typescript": "^4.3.5" }, "dependencies": { + "@status-waku-voting/contracts": "^0.0.1", "eth-sig-util": "^3.0.1", "ethers": "^5.4.4", "js-waku": "^0.11.0", diff --git a/packages/core/src/classes/WakuMessaging.ts b/packages/core/src/classes/WakuMessaging.ts new file mode 100644 index 0000000..66bdbcf --- /dev/null +++ b/packages/core/src/classes/WakuMessaging.ts @@ -0,0 +1,83 @@ +import { Waku } from 'js-waku' +import { WakuMessage } from 'js-waku' +import { Provider } from '@ethersproject/providers' + +type WakuMessageStore = { + topic: string + hashMap: { [id: string]: boolean } + arr: any[] + updateFunction: (msg: WakuMessage[]) => void +} + +type WakuMessageStores = { + [messageType: string]: WakuMessageStore +} + +export class WakuMessaging { + protected appName: string + protected waku: Waku + public tokenAddress: string + protected provider: Provider + protected chainId = 0 + protected wakuMessages: WakuMessageStores = {} + protected observers: { callback: (msg: WakuMessage) => void; topics: string[] }[] = [] + + protected constructor(appName: string, tokenAddress: string, waku: Waku, provider: Provider, chainId: number) { + this.appName = appName + this.tokenAddress = tokenAddress + this.waku = waku + this.provider = provider + this.chainId = chainId + } + + public cleanUp() { + this.observers.forEach((observer) => this.waku.relay.deleteObserver(observer.callback, observer.topics)) + this.wakuMessages = {} + } + + 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, chainId: number) => T | undefined, + msgObj: WakuMessageStore, + filterFunction?: (e: T) => boolean + ) { + messages + .map((msg) => decode(msg.payload, msg.timestamp, this.chainId)) + .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/classes/WakuPolling.ts b/packages/core/src/classes/WakuPolling.ts index 6a4a539..6947bf1 100644 --- a/packages/core/src/classes/WakuPolling.ts +++ b/packages/core/src/classes/WakuPolling.ts @@ -7,7 +7,7 @@ import { WakuMessage } from 'js-waku' import { TimedPollVoteMsg } from '../models/TimedPollVoteMsg' import { DetailedTimedPoll } from '../models/DetailedTimedPoll' import { createWaku } from '../utils/createWaku' -import { WakuVoting } from './WakuVoting' +import { WakuMessaging } from './WakuMessaging' import { Provider } from '@ethersproject/providers' import { Contract } from '@ethersproject/contracts' import { Interface } from '@ethersproject/abi' @@ -23,7 +23,7 @@ export enum MESSEGAGE_SENDING_RESULT { pollNotFound = 3, } -export class WakuPolling extends WakuVoting { +export class WakuPolling extends WakuMessaging { protected multicall: string protected constructor( diff --git a/packages/core/src/classes/WakuVoting.ts b/packages/core/src/classes/WakuVoting.ts index 60e23f8..b0004bd 100644 --- a/packages/core/src/classes/WakuVoting.ts +++ b/packages/core/src/classes/WakuVoting.ts @@ -1,83 +1,102 @@ -import { Waku } from 'js-waku' -import { WakuMessage } from 'js-waku' +import { VotingContract } from '@status-waku-voting/contracts/abi' +import { WakuMessaging } from './WakuMessaging' +import { Contract, Wallet, BigNumber } from 'ethers' +import { Waku, WakuMessage } from 'js-waku' +import { Provider } from '@ethersproject/abstract-provider' import { createWaku } from '../utils/createWaku' -import { Provider } from '@ethersproject/providers' +import { JsonRpcSigner } from '@ethersproject/providers' +import { VoteMsg } from '../models/VoteMsg' -type WakuMessageStore = { - topic: string - hashMap: { [id: string]: boolean } - arr: any[] - updateFunction: (msg: WakuMessage[]) => void -} +const ABI = [ + 'function aggregate(tuple(address target, bytes callData)[] calls) view returns (uint256 blockNumber, bytes[] returnData)', +] -type WakuMessageStores = { - [messageType: string]: WakuMessageStore -} +export class WakuVoting extends WakuMessaging { + private multicall: Contract + private votingContract: Contract -export class WakuVoting { - protected appName: string - protected waku: Waku - public tokenAddress: string - protected provider: Provider - protected chainId = 0 - protected wakuMessages: WakuMessageStores = {} - protected observers: { callback: (msg: WakuMessage) => void; topics: string[] }[] = [] - protected constructor(appName: string, tokenAddress: string, waku: Waku, provider: Provider, chainId: number) { - this.appName = appName - this.tokenAddress = tokenAddress - this.waku = waku - this.provider = provider - this.chainId = chainId + constructor( + appName: string, + votingContract: Contract, + token: string, + waku: Waku, + provider: Provider, + chainId: number, + multicallAddress: string + ) { + super(appName, token, waku, provider, chainId) + this.votingContract = votingContract + this.multicall = new Contract(multicallAddress, ABI, this.provider) + this.wakuMessages['vote'] = { + topic: `/${this.appName}/waku-voting/votes/proto/`, + hashMap: {}, + arr: [], + updateFunction: (msg: WakuMessage[]) => + this.decodeMsgAndSetArray( + msg, + (payload, timestamp, chainId) => VoteMsg.decode(payload, timestamp, chainId, this.votingContract.address), + this.wakuMessages['vote'] + ), + } } - public cleanUp() { - this.observers.forEach((observer) => this.waku.relay.deleteObserver(observer.callback, observer.topics)) - this.wakuMessages = {} - } - - 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] }) - }) + public static async create( + appName: string, + contractAddress: string, + provider: Provider, + multicall: string, + waku?: Waku + ) { + const network = await provider.getNetwork() + const votingContract = new Contract(contractAddress, VotingContract.abi, provider) + const tokenAddress = await votingContract.token() + return new WakuVoting( + appName, + votingContract, + tokenAddress, + await createWaku(waku), + provider, + network.chainId, + multicall ) } - protected decodeMsgAndSetArray( - messages: WakuMessage[], - decode: (payload: Uint8Array | undefined, timestamp: Date | undefined, chainId: number) => T | undefined, - msgObj: WakuMessageStore, - filterFunction?: (e: T) => boolean + public async createVote( + signer: JsonRpcSigner | Wallet, + question: string, + descripiton: string, + tokenAmount: BigNumber ) { - messages - .map((msg) => decode(msg.payload, msg.timestamp, this.chainId)) - .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 - } - } - }) + this.votingContract = await this.votingContract.connect(signer) + await this.votingContract.initializeVotingRoom(question, descripiton, tokenAmount) } - 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]) + private lastPolls: any[] = [] + private lastGetPollsBlockNumber = 0 + + public async getVotes() { + const blockNumber = await this.provider.getBlockNumber() + if (blockNumber != this.lastGetPollsBlockNumber) { + this.lastGetPollsBlockNumber = blockNumber + this.lastPolls = await this.votingContract.getVotingRooms() } + return this.lastPolls + } + + public async sendVote( + signer: JsonRpcSigner | Wallet, + roomId: number, + selectedAnswer: number, + tokenAmount: BigNumber + ) { + const vote = await VoteMsg._createWithSignFunction( + signer, + roomId, + selectedAnswer, + this.chainId, + tokenAmount, + this.votingContract.address + ) + await this.sendWakuMessage(this.wakuMessages['vote'], vote) } } diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index df39e7e..56d5bb1 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,4 +1,4 @@ import { WakuPolling } from './classes/WakuPolling' +import { WakuMessaging } from './classes/WakuMessaging' import { WakuVoting } from './classes/WakuVoting' - -export { WakuVoting, WakuPolling } +export { WakuMessaging, WakuPolling, WakuVoting } diff --git a/packages/core/src/models/VoteMsg.ts b/packages/core/src/models/VoteMsg.ts new file mode 100644 index 0000000..8f25cce --- /dev/null +++ b/packages/core/src/models/VoteMsg.ts @@ -0,0 +1,163 @@ +import { utils } from 'ethers' +import protons, { Vote } from 'protons' +import { BigNumber, Wallet } from 'ethers' +import { JsonRpcSigner } from '@ethersproject/providers' +import { createSignFunction } from '../utils/createSignFunction' +import { verifySignature } from '../utils/verifySignature' + +const proto = protons(` +message Vote { + bytes voter = 1; + int64 timestamp = 2; + int64 answer = 3; + bytes roomId = 4; + bytes tokenAmount = 5; + bytes signature = 6; +} +`) + +type Message = { + roomIdAndType: string + tokenAmount: string + voter: string +} + +export function createSignMsgParams(message: Message, chainId: number, verifyingContract: string) { + const msgParams: any = { + domain: { + name: 'Waku proposal', + version: '1', + chainId, + verifyingContract, + }, + message: { + ...message, + }, + primaryType: 'Vote', + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ], + Vote: [ + { name: 'roomIdAndType', type: 'string' }, + { name: 'tokenAmount', type: 'string' }, + { name: 'voter', type: 'string' }, + ], + }, + } + return msgParams +} + +export class VoteMsg { + public roomId: number + public voter: string + public timestamp: number + public answer: number + public tokenAmount: BigNumber + public signature: string + public id: string + public chainId: number + + constructor( + signature: string, + roomId: number, + voter: string, + answer: number, + tokenAmount: BigNumber, + chainId: number, + timestamp: number + ) { + this.id = utils.id([voter, timestamp, signature].join()) + this.roomId = roomId + this.voter = voter + this.timestamp = timestamp + this.answer = answer + this.tokenAmount = tokenAmount + this.signature = signature + this.chainId = chainId + } + + static async _createWithSignFunction( + signer: JsonRpcSigner | Wallet, + roomId: number, + answer: number, + chainId: number, + tokenAmount: BigNumber, + contractAddress: string + ): Promise { + const signFunction = createSignFunction(signer) + const voter = await signer.getAddress() + const msg = { + roomIdAndType: BigNumber.from(roomId).mul(2).add(answer).toHexString(), + tokenAmount: tokenAmount.toHexString(), + voter, + } + const params = [msg.voter, JSON.stringify(createSignMsgParams(msg, chainId, contractAddress))] + const signature = await signFunction(params) + if (signature) { + return new VoteMsg(signature, roomId, voter, answer, tokenAmount, chainId, Date.now()) + } else { + return undefined + } + } + + encode() { + try { + const voteProto: Vote = { + voter: utils.arrayify(this.voter), + timestamp: this.timestamp, + answer: this.answer, + tokenAmount: utils.arrayify(this.tokenAmount), + roomId: utils.arrayify(BigNumber.from(this.roomId)), + signature: utils.arrayify(this.signature), + } + return proto.Vote.encode(voteProto) + } catch { + return undefined + } + } + + static decode( + rawPayload: Uint8Array | undefined, + timestamp: Date | undefined, + chainId: number, + contractAddress: string, + verifyFunction?: (params: any, address: string) => boolean + ) { + try { + const payload = proto.Vote.decode(rawPayload) + if (!timestamp || !payload.timestamp || timestamp?.getTime() != payload.timestamp) { + return undefined + } + const signature = utils.hexlify(payload.signature) + + const msg = { + roomIdAndType: BigNumber.from(payload.roomId).mul(2).add(payload.answer).toHexString(), + tokenAmount: utils.hexlify(payload.tokenAmount), + voter: utils.getAddress(utils.hexlify(payload.voter)), + } + + const params = { + data: createSignMsgParams(msg, chainId, contractAddress), + sig: signature, + } + if (verifyFunction ? !verifyFunction : !verifySignature(params, msg.voter)) { + return undefined + } + return new VoteMsg( + signature, + BigNumber.from(payload.roomId).toNumber(), + utils.getAddress(utils.hexlify(payload.voter)), + payload.answer, + BigNumber.from(payload.tokenAmount), + chainId, + payload.timestamp + ) + } catch { + return undefined + } + } +} diff --git a/packages/core/test/index.test.ts b/packages/core/test/index.test.ts index 88883d3..b6668f4 100644 --- a/packages/core/test/index.test.ts +++ b/packages/core/test/index.test.ts @@ -1,7 +1,7 @@ import { MockProvider } from '@ethereum-waffle/provider' import { expect } from 'chai' import { Waku } from 'js-waku' -import { WakuVoting } from '../src' +import { WakuMessaging } from '../src' describe('WakuVoting', () => { it('success', async () => { diff --git a/packages/core/types/protons/index.d.ts b/packages/core/types/protons/index.d.ts index 6d48679..aa8b02e 100644 --- a/packages/core/types/protons/index.d.ts +++ b/packages/core/types/protons/index.d.ts @@ -23,6 +23,15 @@ declare module 'protons' { signature: Uint8Array } + export type Vote = { + voter: Uint8Array + timestamp:number + answer: number + roomId: Uint8Array + tokenAmount: Uint8Array + signature: Uint8Array + } + function protons(init: string): { PollInit: { encode: (pollInit: PollInit) => Uint8Array, @@ -32,6 +41,10 @@ declare module 'protons' { encode: (timedPollVote: TimedPollVote) => Uint8Array, decode: (payload: Uint8Array | undefined) => TimedPollVote } + Vote:{ + encode: (vote: Vote) => Uint8Array, + decode: (payload: Uint8Array | undefined) => Vote + } } export = protons } \ No newline at end of file diff --git a/packages/proposal-components/package.json b/packages/proposal-components/package.json index bd77afa..6063099 100644 --- a/packages/proposal-components/package.json +++ b/packages/proposal-components/package.json @@ -35,6 +35,7 @@ "@status-waku-voting/core": "^0.1.0", "@status-waku-voting/proposal-hooks": "^0.1.0", "@status-waku-voting/react-components": "^0.1.0", + "@usedapp/core": "^0.4.7", "ethers": "^5.4.4", "humanize-duration": "^3.27.0", "react": "^17.0.2", diff --git a/packages/proposal-components/src/components/Proposal.tsx b/packages/proposal-components/src/components/Proposal.tsx index 0305e60..0720f90 100644 --- a/packages/proposal-components/src/components/Proposal.tsx +++ b/packages/proposal-components/src/components/Proposal.tsx @@ -3,16 +3,18 @@ import styled from 'styled-components' import { ProposalHeader } from './ProposalHeader' import { blueTheme } from '@status-waku-voting/react-components/dist/esm/src/style/themes' import { ProposalList } from './ProposalList' -import { VotingEmpty } from './VotingEmpty' import { NotificationItem } from './NotificationItem' +import { WakuVoting } from '@status-waku-voting/core' -export function Proposal() { +type ProposalProps = { + wakuVoting: WakuVoting +} + +export function Proposal({ wakuVoting }: ProposalProps) { return ( - - - - {/* */} + + ) diff --git a/packages/proposal-components/src/components/ProposalHeader.tsx b/packages/proposal-components/src/components/ProposalHeader.tsx index e9f8b88..bdcedb5 100644 --- a/packages/proposal-components/src/components/ProposalHeader.tsx +++ b/packages/proposal-components/src/components/ProposalHeader.tsx @@ -5,13 +5,16 @@ import { Modal, Networks, CreateButton } from '@status-waku-voting/react-compone import { Theme } from '@status-waku-voting/react-components/dist/esm/src/style/themes' import { ProposeModal } from './ProposeModal' import { ProposeVoteModal } from './ProposeVoteModal' +import { WakuVoting } from '@status-waku-voting/core' +import { BigNumber } from 'ethers' type ProposalHeaderProps = { theme: Theme + wakuVoting: WakuVoting } -export function ProposalHeader({ theme }: ProposalHeaderProps) { - const { activateBrowserWallet, account } = useEthers() +export function ProposalHeader({ theme, wakuVoting }: ProposalHeaderProps) { + const { activateBrowserWallet, account, library } = useEthers() const [selectConnect, setSelectConnect] = useState(false) const [showProposeModal, setShowProposeModal] = useState(false) const [showProposeVoteModal, setShowProposeVoteModal] = useState(false) @@ -46,6 +49,7 @@ export function ProposalHeader({ theme }: ProposalHeaderProps) { {showProposeVoteModal && ( setShowProposeModal(true)}> + { + setShowProposeModal(true) + }} + > Create proposal ) : ( diff --git a/packages/proposal-components/src/components/ProposalList.tsx b/packages/proposal-components/src/components/ProposalList.tsx index dc5ae3d..c9328e2 100644 --- a/packages/proposal-components/src/components/ProposalList.tsx +++ b/packages/proposal-components/src/components/ProposalList.tsx @@ -1,32 +1,30 @@ -import React from 'react' +import React, { useEffect, useState } from 'react' import styled from 'styled-components' import { Theme } from '@status-waku-voting/react-components' import { ProposalCard } from './ProposalCard' +import { WakuVoting } from '@status-waku-voting/core' +import { VotingEmpty } from './VotingEmpty' type ProposalListProps = { theme: Theme + wakuVoting: WakuVoting } -export function ProposalList({ theme }: ProposalListProps) { +export function ProposalList({ theme, wakuVoting }: ProposalListProps) { + const [votes, setVotes] = useState([]) + + useEffect(() => { + const interval = setInterval(async () => { + setVotes(await wakuVoting.getVotes()) + }, 10000) + return () => clearInterval(interval) + }, []) + return ( - - + {votes.map((vote, idx) => { + return + })} + {votes && votes?.length === 0 && } ) } diff --git a/packages/proposal-components/src/components/ProposeVoteModal.tsx b/packages/proposal-components/src/components/ProposeVoteModal.tsx index 00318c0..450a0f2 100644 --- a/packages/proposal-components/src/components/ProposeVoteModal.tsx +++ b/packages/proposal-components/src/components/ProposeVoteModal.tsx @@ -1,11 +1,15 @@ +import { WakuVoting } from '@status-waku-voting/core' +import { useEthers } from '@usedapp/core' import React, { useState } from 'react' import styled from 'styled-components' import { ProposingBtn } from './Buttons' import { CardHeading, CardText } from './ProposalInfo' import { ProposingData } from './ProposeModal' import { VotePropose } from './VotePropose' +import { BigNumber } from 'ethers' interface ProposeVoteModalProps { + wakuVoting: WakuVoting availableAmount: number title: string text: string @@ -15,6 +19,7 @@ interface ProposeVoteModalProps { } export function ProposeVoteModal({ + wakuVoting, availableAmount, title, text, @@ -22,6 +27,7 @@ export function ProposeVoteModal({ setTitle, setText, }: ProposeVoteModalProps) { + const { library } = useEthers() const [proposingAmount, setProposingAmount] = useState(0) return ( @@ -38,7 +44,10 @@ export function ProposeVoteModal({ { - setShowModal(false), setTitle(''), setText('') + if (library) wakuVoting.createVote(library.getSigner(), title, text, BigNumber.from(proposingAmount)) + setShowModal(false) + setTitle('') + setText('') }} > Create proposal diff --git a/packages/proposal-components/src/components/VotingEmpty.tsx b/packages/proposal-components/src/components/VotingEmpty.tsx index bba225c..00cca83 100644 --- a/packages/proposal-components/src/components/VotingEmpty.tsx +++ b/packages/proposal-components/src/components/VotingEmpty.tsx @@ -4,12 +4,14 @@ import styled from 'styled-components' import { CreateButton, Modal, Networks, Theme } from '@status-waku-voting/react-components' import { ProposeModal } from './ProposeModal' import { ProposeVoteModal } from './ProposeVoteModal' +import { WakuVoting } from '@status-waku-voting/core' type VotingEmptyProps = { theme: Theme + wakuVoting: WakuVoting } -export function VotingEmpty({ theme }: VotingEmptyProps) { +export function VotingEmpty({ wakuVoting, theme }: VotingEmptyProps) { const { account, activateBrowserWallet } = useEthers() const [selectConnect, setSelectConnect] = useState(false) const [showProposeModal, setShowProposeModal] = useState(false) @@ -46,6 +48,7 @@ export function VotingEmpty({ theme }: VotingEmptyProps) { {showProposeVoteModal && ( window.location.reload()) + const [waku, setWaku] = useState(undefined) + + useEffect(() => { + const createWaku = async () => { + const provider = new providers.Web3Provider((window as any).ethereum) + const wak = await WakuVoting.create( + 'test', + '0x5795A64A70cde4073DBa9EEBC5C6b675B15C815a', + provider, + '0x53c43764255c17bd724f74c4ef150724ac50a3ed' + ) + setWaku(wak) + } + createWaku() + }, []) + + return waku +} diff --git a/packages/proposal-hooks/src/index.ts b/packages/proposal-hooks/src/index.ts index 3066c3f..0189719 100644 --- a/packages/proposal-hooks/src/index.ts +++ b/packages/proposal-hooks/src/index.ts @@ -1,3 +1,3 @@ -import { useTest } from './hooks/useTest' +import { useWakuProposal } from './hooks/useWakuProposal' -export { useTest } +export { useWakuProposal } diff --git a/packages/proposal-page/src/index.tsx b/packages/proposal-page/src/index.tsx index 8f81283..5a2bf9b 100644 --- a/packages/proposal-page/src/index.tsx +++ b/packages/proposal-page/src/index.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { useTest } from '@status-waku-voting/proposal-hooks' +import { useWakuProposal } from '@status-waku-voting/proposal-hooks' import { Proposal } from '@status-waku-voting/proposal-components' import { TopBar, GlobalStyle } from '@status-waku-voting/react-components' import votingIcon from './assets/images/voting.svg' @@ -26,6 +26,8 @@ const config = { function Proposals() { const { account, library, activateBrowserWallet, deactivate } = useEthers() + const waku = useWakuProposal() + return ( - + {waku && } ) }