Add Poll SDK tutorial (#15)
@ -32,7 +32,7 @@ params:
|
|||||||
BookTheme: 'dark'
|
BookTheme: 'dark'
|
||||||
BookToC: true
|
BookToC: true
|
||||||
BookSection: 'docs'
|
BookSection: 'docs'
|
||||||
BookDateFormat: '2006/02/01'
|
BookDateFormat: 'Jan 2, 2006'
|
||||||
BookSearch: true
|
BookSearch: true
|
||||||
|
|
||||||
# GitHub edit links
|
# GitHub edit links
|
||||||
|
83
content/docs/guides/vote_poll_sdk/_index.md
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
---
|
||||||
|
weight: 100
|
||||||
|
---
|
||||||
|
# WakuConnect Vote & Poll SDK
|
||||||
|
|
||||||
|
The WakuConnect Vote & Poll SDK enables developers to add Waku powered polling and voting features to their dApp.
|
||||||
|
|
||||||
|
The repository can be found on GitHub: https://github.com/status-im/wakuconnect-vote-poll-sdk.
|
||||||
|
|
||||||
|
The SDK can be used in two different ways:
|
||||||
|
to vote (commitment to the blockchain) or poll (no interaction with the blockchain).
|
||||||
|
|
||||||
|
For both functionalities, only ERC-20 token holders can create or answer polls/votes.
|
||||||
|
The developer using the SDK can configure which ERC-20 token contract is used.
|
||||||
|
|
||||||
|
## Packages
|
||||||
|
|
||||||
|
### Common
|
||||||
|
|
||||||
|
- `@waku/vote-poll-sdk-core`: Common libraries to both vote and poll functionalities.
|
||||||
|
- `@waku/vote-poll-sdk-react-components`: Common React components to both vote and poll functionalities.
|
||||||
|
|
||||||
|
### Vote
|
||||||
|
|
||||||
|
- `@waku/vote-sdk-react-components`: React components.
|
||||||
|
- `@waku/vote-sdk-react-hooks`: React hooks.
|
||||||
|
- `@waku/vote-sdk-contracts`: Solidity contracts.
|
||||||
|
|
||||||
|
### Poll
|
||||||
|
|
||||||
|
- `@waku/poll-sdk-react-components`: React components.
|
||||||
|
- `@waku/poll-sdk-react-hooks`: React hooks.
|
||||||
|
|
||||||
|
## WakuConnect Vote SDK
|
||||||
|
|
||||||
|
The WakuConnect Vote SDK allows you to leverage Waku to save gas fees for most voters.
|
||||||
|
It uses Waku to broadcast and aggregates votes.
|
||||||
|
Most token holders will not need to spend gas to vote.
|
||||||
|
|
||||||
|
Only the party that starts an election and submit the end results need to interact with the blockchain.
|
||||||
|
|
||||||
|
For example, it can be used by a DAO to manage proposals
|
||||||
|
where proposal creation and vote results must be committed to the blockchain.
|
||||||
|
|
||||||
|
With WakuConnect Vote SDK, the DAO could be the one spending gas when creating the proposal and committing the votes,
|
||||||
|
whereas the token holders do not spend gas when voting.
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
{{< hint info >}}
|
||||||
|
The documentation effort is currently in progress.
|
||||||
|
It is tracked with [status-im/wakuconnect-vote-poll-sdk#11](https://github.com/status-im/wakuconnect-vote-poll-sdk/issues/11).
|
||||||
|
Contributions are welcome.
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
You can find more information about the Vote SDK's properties in the [README](https://github.com/status-im/wakuconnect-vote-poll-sdk#wakuconnect-vote-sdk).
|
||||||
|
|
||||||
|
A working example dApp that includes voting feature can be found in the [repo](https://github.com/status-im/wakuconnect-vote-poll-sdk/tree/main/packages/example).
|
||||||
|
|
||||||
|
{{< hint warning >}}
|
||||||
|
However, as the example is part of the yarn workspace, there may be issues with undeclared dependencies with this example.
|
||||||
|
Tracked with [status-im/wakuconnect-vote-poll-sdk#11](https://github.com/status-im/wakuconnect-vote-poll-sdk/issues/11).
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
## WakuConnect Poll SDK
|
||||||
|
|
||||||
|
The WakuConnect Poll SDK allows you to leverage Waku and enable token holder to create, answer and view polls.
|
||||||
|
The polls are not committed to the blockchain and hence do not cost gas.
|
||||||
|
|
||||||
|
As the polls use Waku, they do maintain properties expected from dApps: decentralized and censorship-resistant.
|
||||||
|
|
||||||
|
The high-level functionality is as follows:
|
||||||
|
|
||||||
|
- To create a poll, a token holder sends a message with the poll questions, possible answers and an end time over Waku,
|
||||||
|
- Other users receive the poll creation message and can view the poll,
|
||||||
|
- To avoid spam, only polls created by actual token holders are displayed,
|
||||||
|
- Any token holder can send their poll answer over Waku,
|
||||||
|
- Each user cumulates poll responses from Waku and can view them,
|
||||||
|
- To avoid spam, only responses sent by actual token holders are displayed.
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
See [How to Use the WakuConnect Poll SDK](./poll_sdk).
|
116
content/docs/guides/vote_poll_sdk/poll_sdk/01_create_dapp.md
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
---
|
||||||
|
title: Create the DApp and Install Dependencies
|
||||||
|
date: 2022-01-03T11:00:00+1100
|
||||||
|
weight: 11
|
||||||
|
---
|
||||||
|
|
||||||
|
# Create the DApp and Install Dependencies
|
||||||
|
|
||||||
|
## Create React App
|
||||||
|
|
||||||
|
Create the new React app using the `typescript` template.
|
||||||
|
Install the Waku Poll SDK packages.
|
||||||
|
|
||||||
|
In this guide, we use [useDApp](https://usedapp.io/) to access the blockchain.
|
||||||
|
|
||||||
|
|
||||||
|
```shell
|
||||||
|
yarn create react-app poll-dapp-ts --template typescript
|
||||||
|
cd poll-dapp-ts
|
||||||
|
yarn add \
|
||||||
|
@waku/poll-sdk-react-components @waku/poll-sdk-react-hooks @waku/vote-poll-sdk-react-components \
|
||||||
|
@usedapp/core@0.4.7
|
||||||
|
yarn add -D @types/styled-components
|
||||||
|
```
|
||||||
|
|
||||||
|
{{< hint warning >}}
|
||||||
|
`@usedapp/core` must be frozen to version `0.4.7` due to incompatibility between minor versions of `ethers`.
|
||||||
|
|
||||||
|
WakuConnect Vote & Poll SDK will be upgraded to the latest version of `@usedapp/core` and `ethers` once `ethereum-waffle`
|
||||||
|
is released with the [latest version of `ethers`](https://github.com/EthWorks/Waffle/pull/603).
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
## Setup polyfills
|
||||||
|
|
||||||
|
A number of Web3 dependencies need polyfills.
|
||||||
|
Said polyfills must be explicitly declared when using webpack 5.
|
||||||
|
|
||||||
|
The latest `react-scripts` version uses webpack 5.
|
||||||
|
|
||||||
|
We will describe below a method to configure polyfills when using `create-react-app`/`react-scripts` or webpack 5.
|
||||||
|
This may not be necessary if you do not use `react-scripts` or if you use webpack 4.
|
||||||
|
|
||||||
|
Start by installing the polyfill libraries:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
yarn add assert buffer crypto-browserify stream-browserify
|
||||||
|
```
|
||||||
|
|
||||||
|
### Webpack 5
|
||||||
|
|
||||||
|
If you directly use webpack 5,
|
||||||
|
then you can inspire yourself from this [webpack.config.js](https://github.com/status-im/wakuconnect-vote-poll-sdk/blob/main/examples/mainnet-poll/webpack.config.js).
|
||||||
|
|
||||||
|
### React-App-Rewired
|
||||||
|
|
||||||
|
An alternative is to let `react-scripts` control the webpack 5 config and only override some elements using `react-app-rewired`.
|
||||||
|
|
||||||
|
Install `react-app-rewired`:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
yarn add -D react-app-rewired
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a `config-overrides.js` file at the root of your app:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const webpack = require('webpack');
|
||||||
|
|
||||||
|
module.exports = (config) => {
|
||||||
|
|
||||||
|
// Override webpack 5 config from react-scripts to load polyfills
|
||||||
|
if (!config.resolve) config.resolve = {};
|
||||||
|
if (!config.resolve.fallback) config.resolve.fallback = {};
|
||||||
|
Object.assign(config.resolve.fallback, {
|
||||||
|
"buffer": require.resolve("buffer"),
|
||||||
|
"crypto": require.resolve("crypto-browserify"),
|
||||||
|
"stream": require.resolve("stream-browserify"),
|
||||||
|
"assert": require.resolve("assert")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!config.plugins) config.plugins = []
|
||||||
|
config.plugins.push(
|
||||||
|
new webpack.ProvidePlugin({
|
||||||
|
Buffer: ['buffer', 'Buffer'],
|
||||||
|
}));
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `react-app-rewired` in the `package.json`, instead of `react-scripts`:
|
||||||
|
|
||||||
|
```
|
||||||
|
"scripts": {
|
||||||
|
- "start": "react-scripts start",
|
||||||
|
- "build": "react-scripts build",
|
||||||
|
- "test": "react-scripts test",
|
||||||
|
- "eject": "react-scripts eject"
|
||||||
|
+ "start": "react-app-rewired start",
|
||||||
|
+ "build": "react-app-rewired build",
|
||||||
|
+ "test": "react-app-rewired test",
|
||||||
|
+ "eject": "react-app-rewired eject"
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
## Start development server
|
||||||
|
|
||||||
|
You can now start the development server to serve your dApp at http://localhost:3000/ while we code:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
yarn start
|
||||||
|
```
|
||||||
|
|
||||||
|
{{< button relref="./" >}}Back{{< /button >}}
|
||||||
|
{{< button relref="./02_connect_wallet" >}}Next: Connect to the Ethereum Wallet{{< /button >}}
|
201
content/docs/guides/vote_poll_sdk/poll_sdk/02_connect_wallet.md
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
---
|
||||||
|
title: Connect to the Ethereum Wallet
|
||||||
|
date: 2022-01-03T11:00:00+1100
|
||||||
|
weight: 12
|
||||||
|
---
|
||||||
|
|
||||||
|
# Connect to the Ethereum Wallet
|
||||||
|
|
||||||
|
{{< hint info >}}
|
||||||
|
This section may be skipped if you are adding the poll feature to an existing dApp
|
||||||
|
that already connects to the user's wallet.
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
Delete the template `App` component:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
rm -f App.tsx App.css App.test.tsx
|
||||||
|
```
|
||||||
|
|
||||||
|
## Top bar
|
||||||
|
|
||||||
|
Use `TopBar` component to display wallet information.
|
||||||
|
For that, create a `PollPage` component that includes the top bar and will include the poll elements.
|
||||||
|
The component uses `ethers` to connect to the user's wallet:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
export function PollPage() {
|
||||||
|
const {account, library, activateBrowserWallet, deactivate} = useEthers()
|
||||||
|
const [signer, setSigner] = useState<undefined | JsonRpcSigner>(undefined)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (account) {
|
||||||
|
setSigner(library?.getSigner())
|
||||||
|
} else {
|
||||||
|
// Deactivate signer if signed out
|
||||||
|
setSigner(undefined)
|
||||||
|
}
|
||||||
|
}, [account])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TopBar
|
||||||
|
logo={""}
|
||||||
|
logoWidth={84}
|
||||||
|
title={'Poll dApp'}
|
||||||
|
theme={orangeTheme}
|
||||||
|
activate={activateBrowserWallet}
|
||||||
|
account={account}
|
||||||
|
deactivate={deactivate}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Page
|
||||||
|
|
||||||
|
### UseDApp
|
||||||
|
|
||||||
|
Create a `config` variable that contains the Ethereum network parameters:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import {ChainId, DAppProvider, useEthers} from '@usedapp/core';
|
||||||
|
import {DEFAULT_CONFIG} from "@usedapp/core/dist/cjs/src/model/config/default";
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
readOnlyChainId: ChainId.Mainnet,
|
||||||
|
readOnlyUrls: {
|
||||||
|
[ChainId.Mainnet]: 'https://mainnet.infura.io/v3/your-infura-token',
|
||||||
|
},
|
||||||
|
multicallAddresses: {
|
||||||
|
1: '0xeefba1e63905ef1d7acba5a8513c70307c1ce441',
|
||||||
|
3: '0x53c43764255c17bd724f74c4ef150724ac50a3ed',
|
||||||
|
1337: process.env.GANACHE_MULTICALL_CONTRACT ?? '0x0000000000000000000000000000000000000000',
|
||||||
|
},
|
||||||
|
supportedChains: [...DEFAULT_CONFIG.supportedChains, 1337],
|
||||||
|
notifications: {
|
||||||
|
checkInterval: 500,
|
||||||
|
expirationPeriod: 50000,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace `your-infura-token` with your [Infura API token](https://infura.io/docs/ethereum).
|
||||||
|
|
||||||
|
### Styled-components
|
||||||
|
|
||||||
|
[`styled-components`](https://styled-components.com/) is used for easy styling.
|
||||||
|
Create a `Wrapper` variable to use in the page component:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import styled from 'styled-components'
|
||||||
|
|
||||||
|
const Wrapper = styled.div`
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
`
|
||||||
|
```
|
||||||
|
|
||||||
|
### Render
|
||||||
|
|
||||||
|
Finally, create the `App` component:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
export function App() {
|
||||||
|
return (
|
||||||
|
<Wrapper>
|
||||||
|
<GlobalStyle/>
|
||||||
|
<DAppProvider config={config}>
|
||||||
|
<PollPage/>
|
||||||
|
</DAppProvider>
|
||||||
|
</Wrapper>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Your `index.tsx` should now be:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import {ChainId, DAppProvider, useEthers} from '@usedapp/core';
|
||||||
|
import {GlobalStyle, TopBar} from '@waku/vote-poll-sdk-react-components';
|
||||||
|
import React, {useEffect, useState} from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import './index.css';
|
||||||
|
import {JsonRpcSigner} from "@ethersproject/providers";
|
||||||
|
import {orangeTheme} from "@waku/vote-poll-sdk-react-components/dist/cjs/src/style/themes";
|
||||||
|
import {DEFAULT_CONFIG} from "@usedapp/core/dist/cjs/src/model/config/default";
|
||||||
|
import styled from 'styled-components'
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
readOnlyChainId: ChainId.Mainnet,
|
||||||
|
readOnlyUrls: {
|
||||||
|
[ChainId.Mainnet]: 'https://mainnet.infura.io/v3/b4451d780cc64a078ccf2181e872cfcf',
|
||||||
|
},
|
||||||
|
multicallAddresses: {
|
||||||
|
1: '0xeefba1e63905ef1d7acba5a8513c70307c1ce441',
|
||||||
|
3: '0x53c43764255c17bd724f74c4ef150724ac50a3ed',
|
||||||
|
1337: process.env.GANACHE_MULTICALL_CONTRACT ?? '0x0000000000000000000000000000000000000000',
|
||||||
|
},
|
||||||
|
supportedChains: [...DEFAULT_CONFIG.supportedChains, 1337],
|
||||||
|
notifications: {
|
||||||
|
checkInterval: 500,
|
||||||
|
expirationPeriod: 50000,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PollPage() {
|
||||||
|
const {account, library, activateBrowserWallet, deactivate} = useEthers()
|
||||||
|
const [signer, setSigner] = useState<undefined | JsonRpcSigner>(undefined)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (account) {
|
||||||
|
setSigner(library?.getSigner())
|
||||||
|
} else {
|
||||||
|
// Deactivate signer if signed out
|
||||||
|
setSigner(undefined)
|
||||||
|
}
|
||||||
|
}, [account])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TopBar
|
||||||
|
logo={""}
|
||||||
|
logoWidth={84}
|
||||||
|
title={'Poll dApp'}
|
||||||
|
theme={orangeTheme}
|
||||||
|
activate={activateBrowserWallet}
|
||||||
|
account={account}
|
||||||
|
deactivate={deactivate}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function App() {
|
||||||
|
return (
|
||||||
|
<Wrapper>
|
||||||
|
<GlobalStyle/>
|
||||||
|
<DAppProvider config={config}>
|
||||||
|
<PollPage/>
|
||||||
|
</DAppProvider>
|
||||||
|
</Wrapper>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Wrapper = styled.div`
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
`
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<App/>
|
||||||
|
</React.StrictMode>,
|
||||||
|
document.getElementById('root')
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
{{< button relref="./01_create_dapp" >}}Back{{< /button >}}
|
||||||
|
{{< button relref="./03_create-a-poll_button" >}}Next: Create-A-Poll Button{{< /button >}}
|
@ -0,0 +1,128 @@
|
|||||||
|
---
|
||||||
|
title: Create-A-Poll Button
|
||||||
|
date: 2022-01-03T11:00:00+1100
|
||||||
|
weight: 13
|
||||||
|
---
|
||||||
|
|
||||||
|
# Create-A-Poll Button
|
||||||
|
|
||||||
|
Create the `Poll` component,
|
||||||
|
it will allow the user to create a new poll, view polls and answer them.
|
||||||
|
We'll start by adding a button to create a poll.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
mkdir components
|
||||||
|
touch components/Poll.tsx
|
||||||
|
```
|
||||||
|
|
||||||
|
## Styled-components
|
||||||
|
|
||||||
|
Again, create a `Wrapper` for styling:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import styled from 'styled-components'
|
||||||
|
|
||||||
|
const Wrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
max-width: 1146px;
|
||||||
|
position: relative;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 150px 32px 50px;
|
||||||
|
width: 100%;
|
||||||
|
@media (max-width: 1146px) {
|
||||||
|
max-width: 780px;
|
||||||
|
}
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
padding: 132px 16px 32px;
|
||||||
|
}
|
||||||
|
@media (max-width: 425px) {
|
||||||
|
padding: 96px 16px 84px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
```
|
||||||
|
|
||||||
|
## Button
|
||||||
|
|
||||||
|
Create a button that will display the `PollCreation` component on click.
|
||||||
|
To create a poll, we need access to the wallet,
|
||||||
|
thus the button must be disabled if the wallet is not connected.
|
||||||
|
|
||||||
|
The button is disabled if `signer` is undefined.
|
||||||
|
To give a visual clue to the user, also make the button grey when disabled.
|
||||||
|
|
||||||
|
Upon clicking the button, we set `showPollCreation` to true.
|
||||||
|
`showPollCreation` will control when to render the poll creation modal.
|
||||||
|
|
||||||
|
`components/Poll.tsx`:
|
||||||
|
```tsx
|
||||||
|
import {useState} from 'react'
|
||||||
|
import {JsonRpcSigner, Web3Provider} from '@ethersproject/providers'
|
||||||
|
import {CreateButton} from '@waku/vote-poll-sdk-react-components'
|
||||||
|
import {Theme} from '@waku/vote-poll-sdk-react-components/dist/esm/src/style/themes'
|
||||||
|
|
||||||
|
type PollProps = {
|
||||||
|
signer: JsonRpcSigner | undefined
|
||||||
|
theme: Theme
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Poll({signer, theme}: PollProps) {
|
||||||
|
const [showPollCreation, setShowPollCreation] = useState(false)
|
||||||
|
|
||||||
|
const disabled = !signer;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrapper>
|
||||||
|
{
|
||||||
|
<CreateButton style={{backgroundColor: disabled ? "lightgrey" : theme.primaryColor}} theme={theme}
|
||||||
|
disabled={disabled}
|
||||||
|
onClick={() => setShowPollCreation(true)}>
|
||||||
|
Create a poll
|
||||||
|
</CreateButton>
|
||||||
|
}
|
||||||
|
</Wrapper>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Now update the `PollPage` component to render the new `Poll` component:
|
||||||
|
|
||||||
|
`index.tsx`:
|
||||||
|
```tsx
|
||||||
|
export function PollPage() {
|
||||||
|
const {account, library, activateBrowserWallet, deactivate} = useEthers()
|
||||||
|
const [signer, setSigner] = useState<undefined | JsonRpcSigner>(undefined)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (account) {
|
||||||
|
setSigner(library?.getSigner())
|
||||||
|
} else {
|
||||||
|
// Deactivate signer if signed out
|
||||||
|
setSigner(undefined)
|
||||||
|
}
|
||||||
|
}, [account])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TopBar
|
||||||
|
logo={""}
|
||||||
|
logoWidth={84}
|
||||||
|
title={'Poll dApp'}
|
||||||
|
theme={orangeTheme}
|
||||||
|
activate={activateBrowserWallet}
|
||||||
|
account={account}
|
||||||
|
deactivate={deactivate}
|
||||||
|
/>
|
||||||
|
<Poll theme={orangeTheme} signer={signer}/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, you have a button:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
{{< button relref="./02_connect_wallet" >}}Back{{< /button >}}
|
||||||
|
{{< button relref="./04_poll_creation" >}}Next: Poll Creation Component{{< /button >}}
|
112
content/docs/guides/vote_poll_sdk/poll_sdk/04_poll_creation.md
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
---
|
||||||
|
title: Poll Creation Component
|
||||||
|
date: 2022-01-03T11:00:00+1100
|
||||||
|
weight: 14
|
||||||
|
---
|
||||||
|
|
||||||
|
# Poll Creation Component
|
||||||
|
|
||||||
|
The Poll SDK provide an off-the-shelf component to create a new poll: `PollCreation`.
|
||||||
|
It takes in a `WakuPolling` hook that can created with `useWakuPolling`.
|
||||||
|
|
||||||
|
`useWakuPolling` takes:
|
||||||
|
- `appName`: Your app name.
|
||||||
|
It is used to generate a unique content topic for your polls.
|
||||||
|
See [How to Choose a Content Topic](/docs/guides/01_choose_content_topic/) for more information.
|
||||||
|
- `tokenAddress`: The address of your ERC-20 token.
|
||||||
|
Only token holders can create and answer polls.
|
||||||
|
- `provider`: The Web3 provider to access the blockchain.
|
||||||
|
- `multicallAddress`: Address to this blockchain's multicall contract.
|
||||||
|
|
||||||
|
Add these parameters to `PollProps` and call `useWakuPolling`.
|
||||||
|
|
||||||
|
`components/Poll.tsx`
|
||||||
|
```tsx
|
||||||
|
import {useState} from 'react'
|
||||||
|
import {useConfig} from '@usedapp/core'
|
||||||
|
import {PollCreation} from '@waku/poll-sdk-react-components'
|
||||||
|
import {JsonRpcSigner, Web3Provider} from '@ethersproject/providers'
|
||||||
|
import {useWakuPolling} from '@waku/poll-sdk-react-hooks'
|
||||||
|
import {CreateButton} from '@waku/vote-poll-sdk-react-components'
|
||||||
|
import {Theme} from '@waku/vote-poll-sdk-react-components/dist/esm/src/style/themes'
|
||||||
|
import {ChainId} from "@usedapp/core/src/constants";
|
||||||
|
|
||||||
|
type PollProps = {
|
||||||
|
appName: string
|
||||||
|
library: Web3Provider | undefined
|
||||||
|
signer: JsonRpcSigner | undefined
|
||||||
|
chainId: ChainId | undefined
|
||||||
|
theme: Theme
|
||||||
|
tokenAddress: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Poll({appName, library, signer, chainId, theme, tokenAddress}: PollProps) {
|
||||||
|
const config = useConfig()
|
||||||
|
const [showPollCreation, setShowPollCreation] = useState(false)
|
||||||
|
const wakuPolling = useWakuPolling(appName, tokenAddress, library, config?.multicallAddresses?.[chainId ?? 1337])
|
||||||
|
|
||||||
|
const disabled = !signer;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrapper>
|
||||||
|
{showPollCreation && signer && (
|
||||||
|
<PollCreation wakuPolling={wakuPolling} setShowPollCreation={setShowPollCreation} theme={theme}/>
|
||||||
|
)}
|
||||||
|
{
|
||||||
|
<CreateButton style={{backgroundColor: disabled ? "lightgrey" : theme.primaryColor}} theme={theme}
|
||||||
|
disabled={disabled}
|
||||||
|
onClick={() => setShowPollCreation(true)}>
|
||||||
|
Create a poll
|
||||||
|
</CreateButton>
|
||||||
|
}
|
||||||
|
</Wrapper>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then pass them in `PollPage`.
|
||||||
|
|
||||||
|
In this example, we use `demo-poll-dapp` for the app name and the mainnet SNT token contract for the token address.
|
||||||
|
Replace those with your own.
|
||||||
|
|
||||||
|
`index.tsx`
|
||||||
|
```tsx
|
||||||
|
export function PollPage() {
|
||||||
|
const {account, library, activateBrowserWallet, deactivate, chainId} = useEthers()
|
||||||
|
const [signer, setSigner] = useState<undefined | JsonRpcSigner>(undefined)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (account) {
|
||||||
|
setSigner(library?.getSigner())
|
||||||
|
} else {
|
||||||
|
// Deactivate signer if signed out
|
||||||
|
setSigner(undefined)
|
||||||
|
}
|
||||||
|
}, [account])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TopBar
|
||||||
|
logo={""}
|
||||||
|
logoWidth={84}
|
||||||
|
title={'Poll dApp'}
|
||||||
|
theme={orangeTheme}
|
||||||
|
activate={activateBrowserWallet}
|
||||||
|
account={account}
|
||||||
|
deactivate={deactivate}
|
||||||
|
/>
|
||||||
|
<Poll theme={orangeTheme} appName={'demo-poll-dapp'} library={library} signer={signer} chainId={chainId}
|
||||||
|
tokenAddress={'0x744d70FDBE2Ba4CF95131626614a1763DF805B9E'}/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can now see the poll creation modal when clicking on the button:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
{{< button relref="./03_create-a-poll_button" >}}Back{{< /button >}}
|
||||||
|
{{< button relref="./05_poll_list" >}}Next: Poll List Component{{< /button >}}
|
88
content/docs/guides/vote_poll_sdk/poll_sdk/05_poll_list.md
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
---
|
||||||
|
title: Poll List Component
|
||||||
|
date: 2022-01-03T11:00:00+1100
|
||||||
|
weight: 15
|
||||||
|
---
|
||||||
|
|
||||||
|
# Poll List Component
|
||||||
|
|
||||||
|
To display existing polls, the `PollList` component is provided.
|
||||||
|
|
||||||
|
Simply add it to the `Poll` function to render it.
|
||||||
|
It needs the `account` variable that can be passed as a property to `Poll`:
|
||||||
|
|
||||||
|
`components/Poll.tsx`:
|
||||||
|
```tsx
|
||||||
|
import {useState} from 'react'
|
||||||
|
import {useConfig} from '@usedapp/core'
|
||||||
|
import {PollCreation, PollList} from '@waku/poll-sdk-react-components'
|
||||||
|
import {JsonRpcSigner, Web3Provider} from '@ethersproject/providers'
|
||||||
|
import {useWakuPolling} from '@waku/poll-sdk-react-hooks'
|
||||||
|
import {CreateButton} from '@waku/vote-poll-sdk-react-components'
|
||||||
|
import {Theme} from '@waku/vote-poll-sdk-react-components/dist/esm/src/style/themes'
|
||||||
|
import {ChainId} from "@usedapp/core/src/constants";
|
||||||
|
|
||||||
|
type PollProps = {
|
||||||
|
appName: string
|
||||||
|
library: Web3Provider | undefined
|
||||||
|
signer: JsonRpcSigner | undefined
|
||||||
|
chainId: ChainId | undefined
|
||||||
|
account: string | null | undefined
|
||||||
|
theme: Theme
|
||||||
|
tokenAddress: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Poll({appName, library, signer, chainId, account, theme, tokenAddress}: PollProps) {
|
||||||
|
const config = useConfig()
|
||||||
|
const [showPollCreation, setShowPollCreation] = useState(false)
|
||||||
|
const wakuPolling = useWakuPolling(appName, tokenAddress, library, config?.multicallAddresses?.[chainId ?? 1337])
|
||||||
|
|
||||||
|
const disabled = !signer;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrapper>
|
||||||
|
{showPollCreation && signer && (
|
||||||
|
<PollCreation wakuPolling={wakuPolling} setShowPollCreation={setShowPollCreation} theme={theme}/>
|
||||||
|
)}
|
||||||
|
{
|
||||||
|
<CreateButton style={{backgroundColor: disabled ? "lightgrey" : theme.primaryColor}} theme={theme}
|
||||||
|
disabled={disabled}
|
||||||
|
onClick={() => setShowPollCreation(true)}>
|
||||||
|
Create a poll
|
||||||
|
</CreateButton>
|
||||||
|
}
|
||||||
|
<PollList wakuPolling={wakuPolling} account={account} theme={theme} />
|
||||||
|
</Wrapper>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Pass the `account` to `Poll` in `index.tsx`:
|
||||||
|
```tsx
|
||||||
|
<Poll theme={orangeTheme} appName={'demo-poll-dapp'} library={library} signer={signer} chainId={chainId}
|
||||||
|
account={account}
|
||||||
|
tokenAddress={'0x744d70FDBE2Ba4CF95131626614a1763DF805B9E'}/>
|
||||||
|
```
|
||||||
|
|
||||||
|
Et voila!
|
||||||
|
The `PollList` component handles the display of polls:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
And answering them:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
You can find the resulting code in the [examples folder](https://github.com/status-im/wakuconnect-vote-poll-sdk/tree/main/examples/mainnet-poll).
|
||||||
|
|
||||||
|
{{< hint info >}}
|
||||||
|
The example above uses webpack 5 instead of react-app-rewired.
|
||||||
|
It also allows passing a token contract address in the url, as described in the [README](https://github.com/status-im/wakuconnect-vote-poll-sdk/blob/main/examples/mainnet-poll/README.md).
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
The final gif:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
{{< button relref="./04_poll_creation" >}}Back{{< /button >}}
|
20
content/docs/guides/vote_poll_sdk/poll_sdk/_index.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
title: Poll SDK
|
||||||
|
date: 2022-01-03T11:00:00+1100
|
||||||
|
weight: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
# How to Use the WakuConnect Poll SDK
|
||||||
|
|
||||||
|
To demonstrate how to use the WakuConnect Poll SDK in your dApp, we will create a TypeScript React app from scratch.
|
||||||
|
|
||||||
|
You can then adapt the steps depending on your dApp configuration and build setup.
|
||||||
|
|
||||||
|
The resulting code of this guide can be found at
|
||||||
|
https://github.com/status-im/wakuconnect-vote-poll-sdk/tree/main/examples/mainnet-poll.
|
||||||
|
|
||||||
|
Here is a preview of the end result:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
{{< button relref="./01_create_dapp" >}}Get Started{{< /button >}}
|
BIN
static/assets/poll_sdk/create-a-poll-component.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
static/assets/poll_sdk/create-poll-button.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
BIN
static/assets/poll_sdk/listed-polls-with-answer.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
static/assets/poll_sdk/listed-polls.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
static/assets/poll_sdk/poll-created.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/assets/poll_sdk/sign-message.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
static/assets/poll_sdk/wakuconnect-poll-demo.gif
Normal file
After Width: | Height: | Size: 568 KiB |