Run prettier (#29)

This commit is contained in:
Franck R 2022-01-24 12:17:00 +11:00 committed by GitHub
parent 23ba3e4829
commit 41bc0a9d80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 765 additions and 675 deletions

View File

@ -3,11 +3,11 @@ title: Cryptographic Libraries
date: 2021-12-09T14:00:00+01:00 date: 2021-12-09T14:00:00+01:00
weight: 50 weight: 50
--- ---
# Cryptographic Libraries # Cryptographic Libraries
A note on the cryptographic libraries used as it is a not a straightforward affair. A note on the cryptographic libraries used as it is a not a straightforward affair.
## Asymmetric encryption ## Asymmetric encryption
Uses [ecies-geth](https://github.com/cyrildever/ecies-geth/) Uses [ecies-geth](https://github.com/cyrildever/ecies-geth/)
@ -15,7 +15,6 @@ which in turns uses [SubtleCrypto](https://developer.mozilla.org/en-US/docs/Web/
[secp256k1](https://www.npmjs.com/package/secp256k1) (native binding for node) [secp256k1](https://www.npmjs.com/package/secp256k1) (native binding for node)
or [elliptic](https://www.npmjs.com/package/elliptic) (pure JS if none of the other libraries are available). or [elliptic](https://www.npmjs.com/package/elliptic) (pure JS if none of the other libraries are available).
## Symmetric encryption ## Symmetric encryption
Uses [SubtleCrypto](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) Web API (browser) Uses [SubtleCrypto](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) Web API (browser)

View File

@ -3,6 +3,7 @@ title: Examples
date: 2021-12-09T14:00:00+01:00 date: 2021-12-09T14:00:00+01:00
weight: 40 weight: 40
--- ---
# Examples # Examples
Here is the list of the code examples and the features they demonstrate. Here is the list of the code examples and the features they demonstrate.
@ -34,7 +35,7 @@ Demonstrates:
Repo: [unpkg-js-store](https://github.com/status-im/js-waku/tree/main/examples/unpkg-js-store). Repo: [unpkg-js-store](https://github.com/status-im/js-waku/tree/main/examples/unpkg-js-store).
Demonstrates: Demonstrates:
- How to stop retrieving results from Waku Store on condition - How to stop retrieving results from Waku Store on condition
- Use minified bundle from Unpkg.com - Use minified bundle from Unpkg.com

View File

@ -3,6 +3,7 @@ title: Receive and Send Messages Using Waku Relay
date: 2021-12-09T14:00:00+01:00 date: 2021-12-09T14:00:00+01:00
weight: 2 weight: 2
--- ---
# Receive and Send Messages Using Waku Relay # Receive and Send Messages Using Waku Relay
Waku Relay is a gossip protocol that enables you to send and receive messages. Waku Relay is a gossip protocol that enables you to send and receive messages.
@ -26,22 +27,22 @@ npm install js-waku
In order to interact with the Waku network, you first need a Waku instance: In order to interact with the Waku network, you first need a Waku instance:
```js ```js
import {Waku} from 'js-waku'; import { Waku } from "js-waku";
const waku = await Waku.create({bootstrap: {default: true}}); const waku = await Waku.create({ bootstrap: { default: true } });
``` ```
Passing the `bootstrap` option will connect your node to predefined Waku nodes. Passing the `bootstrap` option will connect your node to predefined Waku nodes.
If you want to bootstrap to your own nodes, you can pass an array of multiaddresses instead: If you want to bootstrap to your own nodes, you can pass an array of multiaddresses instead:
```js ```js
import { Waku } from 'js-waku'; import { Waku } from "js-waku";
const waku = await Waku.create({ const waku = await Waku.create({
bootstrap: [ bootstrap: [
'/dns4/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm', "/dns4/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm",
'/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ' "/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ",
] ],
}); });
``` ```
@ -67,7 +68,7 @@ const processIncomingMessage = (wakuMessage) => {
console.log(`Message Received: ${wakuMessage.payloadAsUtf8}`); console.log(`Message Received: ${wakuMessage.payloadAsUtf8}`);
}; };
waku.relay.addObserver(processIncomingMessage, ['/relay-guide/1/chat/proto']); waku.relay.addObserver(processIncomingMessage, ["/relay-guide/1/chat/proto"]);
``` ```
# Send Messages # Send Messages
@ -79,9 +80,12 @@ To send a message, you need to wrap the message in a `WakuMessage`.
When using a basic string payload, you can use the `WakuMessage.fromUtf8String` helper: When using a basic string payload, you can use the `WakuMessage.fromUtf8String` helper:
```js ```js
import { WakuMessage } from 'js-waku'; import { WakuMessage } from "js-waku";
const wakuMessage = await WakuMessage.fromUtf8String('Here is a message', `/relay-guide/1/chat/proto`); const wakuMessage = await WakuMessage.fromUtf8String(
"Here is a message",
`/relay-guide/1/chat/proto`
);
``` ```
Then, use the `relay` module to send the message to our peers, Then, use the `relay` module to send the message to our peers,
@ -124,7 +128,7 @@ npm install protons
Then define the simple chat message: Then define the simple chat message:
```js ```js
import protons from 'protons'; import protons from "protons";
const proto = protons(` const proto = protons(`
message SimpleChatMessage { message SimpleChatMessage {
@ -147,7 +151,7 @@ First, encode the object:
```js ```js
const payload = proto.SimpleChatMessage.encode({ const payload = proto.SimpleChatMessage.encode({
timestamp: Date.now(), timestamp: Date.now(),
text: 'Here is a message' text: "Here is a message",
}); });
``` ```
@ -184,7 +188,7 @@ const processIncomingMessage = (wakuMessage) => {
Like before, add this callback as an observer to Waku Relay: Like before, add this callback as an observer to Waku Relay:
```js ```js
waku.relay.addObserver(processIncomingMessage, ['/relay-guide/1/chat/proto']); waku.relay.addObserver(processIncomingMessage, ["/relay-guide/1/chat/proto"]);
``` ```
# Conclusion # Conclusion
@ -194,8 +198,8 @@ That is it! Now, you know how to send and receive messages over Waku using the W
Here is the final code: Here is the final code:
```js ```js
import { getBootstrapNodes, Waku, WakuMessage } from 'js-waku'; import { getBootstrapNodes, Waku, WakuMessage } from "js-waku";
import protons from 'protons'; import protons from "protons";
const proto = protons(` const proto = protons(`
message SimpleChatMessage { message SimpleChatMessage {
@ -220,11 +224,11 @@ const processIncomingMessage = (wakuMessage) => {
console.log(`Message Received: ${text}, sent at ${timestamp.toString()}`); console.log(`Message Received: ${text}, sent at ${timestamp.toString()}`);
}; };
waku.relay.addObserver(processIncomingMessage, ['/relay-guide/1/chat/proto']); waku.relay.addObserver(processIncomingMessage, ["/relay-guide/1/chat/proto"]);
const payload = proto.SimpleChatMessage.encode({ const payload = proto.SimpleChatMessage.encode({
timestamp: Date.now(), timestamp: Date.now(),
text: 'Here is a message' text: "Here is a message",
}); });
const wakuMessage = await WakuMessage.fromBytes(payload, ContentTopic); const wakuMessage = await WakuMessage.fromBytes(payload, ContentTopic);
await waku.relay.send(wakuMessage); await waku.relay.send(wakuMessage);

View File

@ -3,6 +3,7 @@ title: Retrieve Messages Using Waku Store
date: 2021-12-09T14:00:00+01:00 date: 2021-12-09T14:00:00+01:00
weight: 3 weight: 3
--- ---
# Retrieve Messages Using Waku Store # Retrieve Messages Using Waku Store
DApps running on a phone or in a browser are often offline: DApps running on a phone or in a browser are often offline:
@ -40,22 +41,22 @@ npm install js-waku
In order to interact with the Waku network, you first need a Waku instance: In order to interact with the Waku network, you first need a Waku instance:
```js ```js
import {Waku} from 'js-waku'; import { Waku } from "js-waku";
const wakuNode = await Waku.create({bootstrap: {default: true}}); const wakuNode = await Waku.create({ bootstrap: { default: true } });
``` ```
Passing the `bootstrap` option will connect your node to predefined Waku nodes. Passing the `bootstrap` option will connect your node to predefined Waku nodes.
If you want to bootstrap to your own nodes, you can pass an array of multiaddresses instead: If you want to bootstrap to your own nodes, you can pass an array of multiaddresses instead:
```js ```js
import { Waku } from 'js-waku'; import { Waku } from "js-waku";
const wakuNode = await Waku.create({ const wakuNode = await Waku.create({
bootstrap: [ bootstrap: [
'/dns4/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm', "/dns4/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm",
'/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ' "/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ",
] ],
}); });
``` ```
@ -103,7 +104,7 @@ npm install protons
Then specify the data structure: Then specify the data structure:
```js ```js
import protons from 'protons'; import protons from "protons";
const proto = protons(` const proto = protons(`
message ArticleMessage { message ArticleMessage {
@ -150,7 +151,7 @@ The `WakuStore.queryHistory` API automatically query all the pages in a sequenti
To process messages as soon as they received (page by page), use the `callback` option: To process messages as soon as they received (page by page), use the `callback` option:
```js ```js
const ContentTopic = '/store-guide/1/news/proto'; const ContentTopic = "/store-guide/1/news/proto";
const callback = (retrievedMessages) => { const callback = (retrievedMessages) => {
const articles = retrievedMessages const articles = retrievedMessages
@ -160,12 +161,10 @@ const callback = (retrievedMessages) => {
console.log(`${articles.length} articles have been retrieved`); console.log(`${articles.length} articles have been retrieved`);
}; };
waku.store waku.store.queryHistory([ContentTopic], { callback }).catch((e) => {
.queryHistory([ContentTopic], { callback }) // Catch any potential error
.catch((e) => { console.log("Failed to retrieve messages from store", e);
// Catch any potential error });
console.log('Failed to retrieve messages from store', e);
});
``` ```
Note that `WakuStore.queryHistory` select an available store node for you. Note that `WakuStore.queryHistory` select an available store node for you.
@ -195,10 +194,10 @@ startTime.setTime(startTime.getTime() - 7 * 24 * 60 * 60 * 1000);
waku.store waku.store
.queryHistory([ContentTopic], { .queryHistory([ContentTopic], {
callback, callback,
timeFilter: { startTime, endTime: new Date() } timeFilter: { startTime, endTime: new Date() },
}) })
.catch((e) => { .catch((e) => {
console.log('Failed to retrieve messages from store', e); console.log("Failed to retrieve messages from store", e);
}); });
``` ```

View File

@ -3,6 +3,7 @@ title: Encrypt Messages Using Waku Message Version 1
date: 2021-12-09T14:00:00+01:00 date: 2021-12-09T14:00:00+01:00
weight: 4 weight: 4
--- ---
# Encrypt Messages Using Waku Message Version 1 # Encrypt Messages Using Waku Message Version 1
The Waku Message format provides an easy way to encrypt messages using symmetric or asymmetric encryption. The Waku Message format provides an easy way to encrypt messages using symmetric or asymmetric encryption.
@ -71,7 +72,7 @@ To use symmetric encryption, you first need to generate a key.
Use `generateSymmetricKey` for secure key generation: Use `generateSymmetricKey` for secure key generation:
```js ```js
import { generateSymmetricKey } from 'js-waku'; import { generateSymmetricKey } from "js-waku";
const symmetricKey = generateSymmetricKey(); const symmetricKey = generateSymmetricKey();
``` ```
@ -86,10 +87,10 @@ Same as Waku Messages version 0 (unencrypted),
See [Receive and Send Messages Using Waku Relay](/docs/guides/02_relay_receive_send_messages/) for details. See [Receive and Send Messages Using Waku Relay](/docs/guides/02_relay_receive_send_messages/) for details.
```js ```js
import { WakuMessage } from 'js-waku'; import { WakuMessage } from "js-waku";
const message = await WakuMessage.fromBytes(payload, contentTopic, { const message = await WakuMessage.fromBytes(payload, contentTopic, {
symKey: symmetricKey symKey: symmetricKey,
}); });
``` ```
@ -108,10 +109,11 @@ add the symmetric key as a decryption key to your Waku instance.
```js ```js
waku.addDecryptionKey(symmetricKey); waku.addDecryptionKey(symmetricKey);
``` ```
Alternatively, you can pass the key when creating the instance: Alternatively, you can pass the key when creating the instance:
```js ```js
import { Waku } from 'js-waku'; import { Waku } from "js-waku";
const waku = Waku.create({ decryptionKeys: [symmetricKey] }); const waku = Waku.create({ decryptionKeys: [symmetricKey] });
``` ```
@ -131,7 +133,7 @@ To use asymmetric encryption, you first need to generate a private key and calcu
Use `generatePrivateKey` for secure key generation: Use `generatePrivateKey` for secure key generation:
```js ```js
import { generatePrivateKey, getPublicKey } from 'js-waku'; import { generatePrivateKey, getPublicKey } from "js-waku";
const privateKey = generatePrivateKey(); const privateKey = generatePrivateKey();
const publicKey = getPublicKey(privateKey); const publicKey = getPublicKey(privateKey);
@ -153,10 +155,10 @@ Same as clear Waku Messages,
See [Receive and Send Messages Using Waku Relay](/docs/guides/02_relay_receive_send_messages/) for details. See [Receive and Send Messages Using Waku Relay](/docs/guides/02_relay_receive_send_messages/) for details.
```js ```js
import { WakuMessage } from 'js-waku'; import { WakuMessage } from "js-waku";
const message = await WakuMessage.fromBytes(payload, contentTopic, { const message = await WakuMessage.fromBytes(payload, contentTopic, {
encPublicKey: publicKey encPublicKey: publicKey,
}); });
``` ```
@ -177,10 +179,11 @@ add the private key as a decryption key to your Waku instance.
```js ```js
waku.addDecryptionKey(privateKey); waku.addDecryptionKey(privateKey);
``` ```
Alternatively, you can pass the key when creating the instance: Alternatively, you can pass the key when creating the instance:
```js ```js
import { Waku } from 'js-waku'; import { Waku } from "js-waku";
const waku = Waku.create({ decryptionKeys: [privateKey] }); const waku = Waku.create({ decryptionKeys: [privateKey] });
``` ```
@ -199,10 +202,10 @@ the payload gets encrypted.
Which means that `wakuMessage.payload` returns an encrypted payload: Which means that `wakuMessage.payload` returns an encrypted payload:
```js ```js
import { WakuMessage } from 'js-waku'; import { WakuMessage } from "js-waku";
const message = await WakuMessage.fromBytes(payload, contentTopic, { const message = await WakuMessage.fromBytes(payload, contentTopic, {
encPublicKey: publicKey encPublicKey: publicKey,
}); });
console.log(message.payload); // This is encrypted console.log(message.payload); // This is encrypted
@ -216,7 +219,7 @@ If a message was not successfully decrypted, then it will be dropped from the re
Which means that `WakuMessage` instances returned by `WakuRelay` and `WakuStore` always have a clear payload (in regard to Waku Message version 1): Which means that `WakuMessage` instances returned by `WakuRelay` and `WakuStore` always have a clear payload (in regard to Waku Message version 1):
```js ```js
import { Waku } from 'js-waku'; import { Waku } from "js-waku";
const waku = Waku.create({ decryptionKeys: [privateKey] }); const waku = Waku.create({ decryptionKeys: [privateKey] });
@ -226,12 +229,14 @@ if (messages && messages[0]) {
console.log(messages[0].payload); // This payload is decrypted console.log(messages[0].payload); // This payload is decrypted
} }
waku.relay.addObserver((message) => { waku.relay.addObserver(
console.log(message.payload); // This payload is decrypted (message) => {
}, [contentTopic]); console.log(message.payload); // This payload is decrypted
},
[contentTopic]
);
``` ```
## Code Example ## Code Example
The [Eth-PM](https://github.com/status-im/js-waku/tree/main/examples/eth-pm) Web App example demonstrates both the use of symmetric and asymmetric encryption. The [Eth-PM](https://github.com/status-im/js-waku/tree/main/examples/eth-pm) Web App example demonstrates both the use of symmetric and asymmetric encryption.

View File

@ -3,6 +3,7 @@ title: Sign Messages Using Waku Message Version 1
date: 2021-12-09T14:00:00+01:00 date: 2021-12-09T14:00:00+01:00
weight: 5 weight: 5
--- ---
# Sign Messages Using Waku Message Version 1 # Sign Messages Using Waku Message Version 1
The Waku Message format provides an easy way to sign messages using elliptic curve cryptography. The Waku Message format provides an easy way to sign messages using elliptic curve cryptography.
@ -19,7 +20,7 @@ See [Cryptographic Libraries](/docs/crypto_libraries/) for more details on the c
Generate a new keypair to sign your messages: Generate a new keypair to sign your messages:
```ts ```ts
import { generatePrivateKey, getPublicKey } from 'js-waku'; import { generatePrivateKey, getPublicKey } from "js-waku";
const privateKey = generatePrivateKey(); const privateKey = generatePrivateKey();
const publicKey = getPublicKey(privateKey); const publicKey = getPublicKey(privateKey);
@ -37,11 +38,11 @@ You can learn more about encryption at [Encrypt Messages Using Waku Message Vers
Given `symKey` the symmetric key used for encryption: Given `symKey` the symmetric key used for encryption:
```ts ```ts
import { WakuMessage } from 'js-waku'; import { WakuMessage } from "js-waku";
const message = await WakuMessage.fromBytes(payload, myAppContentTopic, { const message = await WakuMessage.fromBytes(payload, myAppContentTopic, {
encPublicKey: symKey, encPublicKey: symKey,
sigPrivKey: privateKey sigPrivKey: privateKey,
}); });
``` ```
@ -49,12 +50,10 @@ If encryption is not needed for your use case,
then you can create a symmetric key from the content topic: then you can create a symmetric key from the content topic:
```ts ```ts
import { hexToBuf } from 'js-waku/lib/utils'; import { hexToBuf } from "js-waku/lib/utils";
import { keccak256 } from 'ethers/lib/utils'; import { keccak256 } from "ethers/lib/utils";
const symKey = hexToBuf( const symKey = hexToBuf(keccak256(Buffer.from(myAppContentTopic, "utf-8")));
keccak256(Buffer.from(myAppContentTopic, 'utf-8'))
);
``` ```
`symKey` can then be used to encrypt and decrypt messages on `myAppContentTopic` content topic. `symKey` can then be used to encrypt and decrypt messages on `myAppContentTopic` content topic.
@ -62,14 +61,14 @@ Read [How to Choose a Content Topic](/docs/guides/01_choose_content_topic/) to l
### Using asymmetric encryption ### Using asymmetric encryption
Given `recipientPublicKey` the public key of the message's recipient: Given `recipientPublicKey` the public key of the message's recipient:
```ts ```ts
import { WakuMessage } from 'js-waku'; import { WakuMessage } from "js-waku";
const message = await WakuMessage.fromBytes(payload, myAppContentTopic, { const message = await WakuMessage.fromBytes(payload, myAppContentTopic, {
encPublicKey: recipientPublicKey, encPublicKey: recipientPublicKey,
sigPrivKey: privateKey sigPrivKey: privateKey,
}); });
``` ```
@ -86,13 +85,13 @@ As comparing hex string can lead to issues (is the `0x` prefix present?),
simply use helper function `equalByteArrays`. simply use helper function `equalByteArrays`.
```ts ```ts
import { equalByteArrays } from 'js-waku/lib/utils'; import { equalByteArrays } from "js-waku/lib/utils";
const sigPubKey = wakuMessage.signaturePublicKey; const sigPubKey = wakuMessage.signaturePublicKey;
const isSignedByAlice = sigPubKey && equalByteArrays(sigPubKey, alicePublicKey); const isSignedByAlice = sigPubKey && equalByteArrays(sigPubKey, alicePublicKey);
if (!isSignedByAlice) { if (!isSignedByAlice) {
// Message is not signed by Alice // Message is not signed by Alice
} }
``` ```

View File

@ -3,6 +3,7 @@ title: Send Messages Using Waku Light Push
date: 2021-12-09T14:00:00+01:00 date: 2021-12-09T14:00:00+01:00
weight: 6 weight: 6
--- ---
# Send Messages Using Waku Light Push # Send Messages Using Waku Light Push
Waku Light Push enables a client to receive a confirmation when sending a message. Waku Light Push enables a client to receive a confirmation when sending a message.
@ -40,22 +41,22 @@ npm install js-waku
In order to interact with the Waku network, you first need a Waku instance: In order to interact with the Waku network, you first need a Waku instance:
```js ```js
import {Waku} from 'js-waku'; import { Waku } from "js-waku";
const wakuNode = await Waku.create({bootstrap: {default: true}}); const wakuNode = await Waku.create({ bootstrap: { default: true } });
``` ```
Passing the `bootstrap` option will connect your node to predefined Waku nodes. Passing the `bootstrap` option will connect your node to predefined Waku nodes.
If you want to bootstrap to your own nodes, you can pass an array of multiaddresses instead: If you want to bootstrap to your own nodes, you can pass an array of multiaddresses instead:
```js ```js
import { Waku } from 'js-waku'; import { Waku } from "js-waku";
const waku = await Waku.create({ const waku = await Waku.create({
bootstrap: [ bootstrap: [
'/dns4/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm', "/dns4/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm",
'/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ' "/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ",
] ],
}); });
``` ```
@ -80,12 +81,15 @@ The peer is selected among the dApp's connected peers.
If the dApp is not connected to any light push peer, an error is thrown. If the dApp is not connected to any light push peer, an error is thrown.
```ts ```ts
import {WakuMessage} from 'js-waku'; import { WakuMessage } from "js-waku";
const wakuMessage = await WakuMessage.fromUtf8String('Here is a message', `/light-push-guide/1/guide/proto`); const wakuMessage = await WakuMessage.fromUtf8String(
"Here is a message",
`/light-push-guide/1/guide/proto`
);
const ack = await waku.lightPush.push(wakuMessage); const ack = await waku.lightPush.push(wakuMessage);
if (!ack?.isSuccess) { if (!ack?.isSuccess) {
// Message was not sent // Message was not sent
} }
``` ```

View File

@ -3,10 +3,11 @@ title: Receive and Send Messages Using Waku Relay With ReactJS
date: 2021-12-09T14:00:00+01:00 date: 2021-12-09T14:00:00+01:00
weight: 7 weight: 7
--- ---
# Receive and Send Messages Using Waku Relay With ReactJS # Receive and Send Messages Using Waku Relay With ReactJS
It is easy to use WakuConnect with ReactJS. It is easy to use WakuConnect with ReactJS.
In this guide, we will demonstrate how your ReactJS dApp can use Waku Relay to send and receive messages. In this guide, we will demonstrate how your ReactJS dApp can use Waku Relay to send and receive messages.
Before starting, you need to choose a _Content Topic_ for your dApp. Before starting, you need to choose a _Content Topic_ for your dApp.
Check out the [how to choose a content topic guide](/docs/guides/01_choose_content_topic/) to learn more about content topics. Check out the [how to choose a content topic guide](/docs/guides/01_choose_content_topic/) to learn more about content topics.
@ -76,65 +77,65 @@ npm install -D cra-webpack-rewired
Create a `config/webpack.extend.js` file at the root of your app: Create a `config/webpack.extend.js` file at the root of your app:
```js ```js
const webpack = require('webpack'); const webpack = require("webpack");
module.exports = { module.exports = {
dev: (config) => { dev: (config) => {
// Override webpack 5 config from react-scripts to load polyfills // Override webpack 5 config from react-scripts to load polyfills
if (!config.resolve) config.resolve = {}; if (!config.resolve) config.resolve = {};
if (!config.resolve.fallback) config.resolve.fallback = {}; if (!config.resolve.fallback) config.resolve.fallback = {};
Object.assign(config.resolve.fallback, { Object.assign(config.resolve.fallback, {
buffer: require.resolve('buffer'), buffer: require.resolve("buffer"),
crypto: require.resolve('crypto-browserify'), crypto: require.resolve("crypto-browserify"),
stream: require.resolve('stream-browserify'), stream: require.resolve("stream-browserify"),
}); });
if (!config.plugins) config.plugins = []; if (!config.plugins) config.plugins = [];
config.plugins.push( config.plugins.push(
new webpack.DefinePlugin({ new webpack.DefinePlugin({
'process.env.ENV': JSON.stringify('dev'), "process.env.ENV": JSON.stringify("dev"),
}) })
); );
config.plugins.push( config.plugins.push(
new webpack.ProvidePlugin({ new webpack.ProvidePlugin({
process: 'process/browser.js', process: "process/browser.js",
Buffer: ['buffer', 'Buffer'], Buffer: ["buffer", "Buffer"],
}) })
); );
if (!config.ignoreWarnings) config.ignoreWarnings = []; if (!config.ignoreWarnings) config.ignoreWarnings = [];
config.ignoreWarnings.push(/Failed to parse source map/); config.ignoreWarnings.push(/Failed to parse source map/);
return config; return config;
}, },
prod: (config) => { prod: (config) => {
// Override webpack 5 config from react-scripts to load polyfills // Override webpack 5 config from react-scripts to load polyfills
if (!config.resolve) config.resolve = {}; if (!config.resolve) config.resolve = {};
if (!config.resolve.fallback) config.resolve.fallback = {}; if (!config.resolve.fallback) config.resolve.fallback = {};
Object.assign(config.resolve.fallback, { Object.assign(config.resolve.fallback, {
buffer: require.resolve('buffer'), buffer: require.resolve("buffer"),
crypto: require.resolve('crypto-browserify'), crypto: require.resolve("crypto-browserify"),
stream: require.resolve('stream-browserify'), stream: require.resolve("stream-browserify"),
}); });
if (!config.plugins) config.plugins = []; if (!config.plugins) config.plugins = [];
config.plugins.push( config.plugins.push(
new webpack.DefinePlugin({ new webpack.DefinePlugin({
'process.env.ENV': JSON.stringify('prod'), "process.env.ENV": JSON.stringify("prod"),
}) })
); );
config.plugins.push( config.plugins.push(
new webpack.ProvidePlugin({ new webpack.ProvidePlugin({
process: 'process/browser.js', process: "process/browser.js",
Buffer: ['buffer', 'Buffer'], Buffer: ["buffer", "Buffer"],
}) })
); );
if (!config.ignoreWarnings) config.ignoreWarnings = []; if (!config.ignoreWarnings) config.ignoreWarnings = [];
config.ignoreWarnings.push(/Failed to parse source map/); config.ignoreWarnings.push(/Failed to parse source map/);
return config; return config;
}, },
}; };
``` ```
@ -171,38 +172,38 @@ In order to interact with the Waku network, you first need a Waku instance.
Go to `App.js` and modify the `App` function: Go to `App.js` and modify the `App` function:
```js ```js
import {Waku} from 'js-waku'; import { Waku } from "js-waku";
import * as React from 'react'; import * as React from "react";
function App() { function App() {
const [waku, setWaku] = React.useState(undefined); const [waku, setWaku] = React.useState(undefined);
const [wakuStatus, setWakuStatus] = React.useState('None'); const [wakuStatus, setWakuStatus] = React.useState("None");
// Start Waku // Start Waku
React.useEffect(() => { React.useEffect(() => {
// If Waku is already assigned, the job is done // If Waku is already assigned, the job is done
if (!!waku) return; if (!!waku) return;
// If Waku status not None, it means we are already starting Waku // If Waku status not None, it means we are already starting Waku
if (wakuStatus !== 'None') return; if (wakuStatus !== "None") return;
setWakuStatus('Starting'); setWakuStatus("Starting");
// Create Waku // Create Waku
Waku.create({bootstrap: {default: true}}).then((waku) => { Waku.create({ bootstrap: { default: true } }).then((waku) => {
// Once done, put it in the state // Once done, put it in the state
setWaku(waku); setWaku(waku);
// And update the status // And update the status
setWakuStatus('Started'); setWakuStatus("Started");
}); });
}, [waku, wakuStatus]); }, [waku, wakuStatus]);
return ( return (
<div className='App'> <div className="App">
<header className='App-header'> <header className="App-header">
<p>Waku node's status: {wakuStatus}</p> <p>Waku node's status: {wakuStatus}</p>
</header> </header>
</div> </div>
); );
} }
export default App; export default App;
@ -216,18 +217,18 @@ use the `Waku.waitForConnectedPeer()` async function:
```js ```js
React.useEffect(() => { React.useEffect(() => {
if (!!waku) return; if (!!waku) return;
if (wakuStatus !== 'None') return; if (wakuStatus !== "None") return;
setWakuStatus('Starting'); setWakuStatus("Starting");
Waku.create({bootstrap: {default: true}}).then((waku) => { Waku.create({ bootstrap: { default: true } }).then((waku) => {
setWaku(waku); setWaku(waku);
setWakuStatus('Connecting'); setWakuStatus("Connecting");
waku.waitForConnectedPeer().then(() => { waku.waitForConnectedPeer().then(() => {
setWakuStatus('Ready'); setWakuStatus("Ready");
});
}); });
});
}, [waku, wakuStatus]); }, [waku, wakuStatus]);
``` ```
@ -243,7 +244,7 @@ npm install protons
Define `SimpleChatMessage` with two fields: `timestamp` and `text`. Define `SimpleChatMessage` with two fields: `timestamp` and `text`.
```js ```js
import protons from 'protons'; import protons from "protons";
const proto = protons(` const proto = protons(`
message SimpleChatMessage { message SimpleChatMessage {
@ -258,7 +259,7 @@ message SimpleChatMessage {
Create a function that takes the Waku instance and a message to send: Create a function that takes the Waku instance and a message to send:
```js ```js
import { WakuMessage } from 'js-waku'; import { WakuMessage } from "js-waku";
const ContentTopic = `/relay-reactjs-chat/1/chat/proto`; const ContentTopic = `/relay-reactjs-chat/1/chat/proto`;
@ -268,7 +269,7 @@ function sendMessage(message, waku, timestamp) {
// Encode to protobuf // Encode to protobuf
const payload = proto.SimpleChatMessage.encode({ const payload = proto.SimpleChatMessage.encode({
timestamp: time, timestamp: time,
text: message text: message,
}); });
// Wrap in a Waku Message // Wrap in a Waku Message
@ -284,20 +285,20 @@ Then, add a button to the `App` function:
```js ```js
function App() { function App() {
const [waku, setWaku] = React.useState(undefined); const [waku, setWaku] = React.useState(undefined);
const [wakuStatus, setWakuStatus] = React.useState('None'); const [wakuStatus, setWakuStatus] = React.useState("None");
// Using a counter just for the messages to be different // Using a counter just for the messages to be different
const [sendCounter, setSendCounter] = React.useState(0); const [sendCounter, setSendCounter] = React.useState(0);
React.useEffect(() => { React.useEffect(() => {
// ... creates Waku // ... creates Waku
}, [waku, wakuStatus]); }, [waku, wakuStatus]);
const sendMessageOnClick = () => { const sendMessageOnClick = () => {
// Check Waku is started and connected first. // Check Waku is started and connected first.
if (wakuStatus !== 'Ready') return; if (wakuStatus !== "Ready") return;
sendMessage(`Here is message #${sendCounter}`, waku, new Date()).then(() => sendMessage(`Here is message #${sendCounter}`, waku, new Date()).then(() =>
console.log('Message sent') console.log("Message sent")
); );
// For demonstration purposes. // For demonstration purposes.
@ -308,7 +309,7 @@ function App() {
<div className="App"> <div className="App">
<header className="App-header"> <header className="App-header">
<p>{wakuStatus}</p> <p>{wakuStatus}</p>
<button onClick={sendMessageOnClick} disabled={wakuStatus !== 'Ready'}> <button onClick={sendMessageOnClick} disabled={wakuStatus !== "Ready"}>
Send Message Send Message
</button> </button>
</header> </header>
@ -393,6 +394,7 @@ function App() {
// ... // ...
} }
``` ```
Then, render the messages: Then, render the messages:
```js ```js
@ -403,7 +405,7 @@ function App() {
<div className="App"> <div className="App">
<header className="App-header"> <header className="App-header">
<p>{wakuStatus}</p> <p>{wakuStatus}</p>
<button onClick={sendMessageOnClick} disabled={wakuStatus !== 'Ready'}> <button onClick={sendMessageOnClick} disabled={wakuStatus !== "Ready"}>
Send Message Send Message
</button> </button>
<ul> <ul>

View File

@ -3,6 +3,7 @@ title: Retrieve Messages Using Waku Store With ReactJS
date: 2021-12-09T14:00:00+01:00 date: 2021-12-09T14:00:00+01:00
weight: 8 weight: 8
--- ---
# Retrieve Messages Using Waku Store With ReactJS # Retrieve Messages Using Waku Store With ReactJS
It is easy to use WakuConnect with ReactJS. It is easy to use WakuConnect with ReactJS.
@ -92,65 +93,65 @@ npm install -D cra-webpack-rewired
Create a `config/webpack.extend.js` file at the root of your app: Create a `config/webpack.extend.js` file at the root of your app:
```js ```js
const webpack = require('webpack'); const webpack = require("webpack");
module.exports = { module.exports = {
dev: (config) => { dev: (config) => {
// Override webpack 5 config from react-scripts to load polyfills // Override webpack 5 config from react-scripts to load polyfills
if (!config.resolve) config.resolve = {}; if (!config.resolve) config.resolve = {};
if (!config.resolve.fallback) config.resolve.fallback = {}; if (!config.resolve.fallback) config.resolve.fallback = {};
Object.assign(config.resolve.fallback, { Object.assign(config.resolve.fallback, {
buffer: require.resolve('buffer'), buffer: require.resolve("buffer"),
crypto: require.resolve('crypto-browserify'), crypto: require.resolve("crypto-browserify"),
stream: require.resolve('stream-browserify'), stream: require.resolve("stream-browserify"),
}); });
if (!config.plugins) config.plugins = []; if (!config.plugins) config.plugins = [];
config.plugins.push( config.plugins.push(
new webpack.DefinePlugin({ new webpack.DefinePlugin({
'process.env.ENV': JSON.stringify('dev'), "process.env.ENV": JSON.stringify("dev"),
}) })
); );
config.plugins.push( config.plugins.push(
new webpack.ProvidePlugin({ new webpack.ProvidePlugin({
process: 'process/browser.js', process: "process/browser.js",
Buffer: ['buffer', 'Buffer'], Buffer: ["buffer", "Buffer"],
}) })
); );
if (!config.ignoreWarnings) config.ignoreWarnings = []; if (!config.ignoreWarnings) config.ignoreWarnings = [];
config.ignoreWarnings.push(/Failed to parse source map/); config.ignoreWarnings.push(/Failed to parse source map/);
return config; return config;
}, },
prod: (config) => { prod: (config) => {
// Override webpack 5 config from react-scripts to load polyfills // Override webpack 5 config from react-scripts to load polyfills
if (!config.resolve) config.resolve = {}; if (!config.resolve) config.resolve = {};
if (!config.resolve.fallback) config.resolve.fallback = {}; if (!config.resolve.fallback) config.resolve.fallback = {};
Object.assign(config.resolve.fallback, { Object.assign(config.resolve.fallback, {
buffer: require.resolve('buffer'), buffer: require.resolve("buffer"),
crypto: require.resolve('crypto-browserify'), crypto: require.resolve("crypto-browserify"),
stream: require.resolve('stream-browserify'), stream: require.resolve("stream-browserify"),
}); });
if (!config.plugins) config.plugins = []; if (!config.plugins) config.plugins = [];
config.plugins.push( config.plugins.push(
new webpack.DefinePlugin({ new webpack.DefinePlugin({
'process.env.ENV': JSON.stringify('prod'), "process.env.ENV": JSON.stringify("prod"),
}) })
); );
config.plugins.push( config.plugins.push(
new webpack.ProvidePlugin({ new webpack.ProvidePlugin({
process: 'process/browser.js', process: "process/browser.js",
Buffer: ['buffer', 'Buffer'], Buffer: ["buffer", "Buffer"],
}) })
); );
if (!config.ignoreWarnings) config.ignoreWarnings = []; if (!config.ignoreWarnings) config.ignoreWarnings = [];
config.ignoreWarnings.push(/Failed to parse source map/); config.ignoreWarnings.push(/Failed to parse source map/);
return config; return config;
}, },
}; };
``` ```
@ -190,6 +191,7 @@ character not being valid, try cleaning up and re-installing your dependencies:
rm -rf node_modules package-lock.json rm -rf node_modules package-lock.json
npm install npm install
``` ```
{{< /hint >}} {{< /hint >}}
# Create Waku Instance # Create Waku Instance
@ -198,36 +200,36 @@ In order to interact with the Waku network, you first need a Waku instance.
Go to `App.js` and modify the `App` function: Go to `App.js` and modify the `App` function:
```js ```js
import {Waku} from 'js-waku'; import { Waku } from "js-waku";
import * as React from 'react'; import * as React from "react";
function App() { function App() {
const [waku, setWaku] = React.useState(undefined); const [waku, setWaku] = React.useState(undefined);
const [wakuStatus, setWakuStatus] = React.useState('None'); const [wakuStatus, setWakuStatus] = React.useState("None");
// Start Waku // Start Waku
React.useEffect(() => { React.useEffect(() => {
// If Waku status not None, it means we are already starting Waku // If Waku status not None, it means we are already starting Waku
if (wakuStatus !== 'None') return; if (wakuStatus !== "None") return;
setWakuStatus('Starting'); setWakuStatus("Starting");
// Create Waku // Create Waku
Waku.create({bootstrap: {default: true}}).then((waku) => { Waku.create({ bootstrap: { default: true } }).then((waku) => {
// Once done, put it in the state // Once done, put it in the state
setWaku(waku); setWaku(waku);
// And update the status // And update the status
setWakuStatus('Connecting'); setWakuStatus("Connecting");
}); });
}, [waku, wakuStatus]); }, [waku, wakuStatus]);
return ( return (
<div className='App'> <div className="App">
<header className='App-header'> <header className="App-header">
<p>{wakuStatus}</p> <p>{wakuStatus}</p>
</header> </header>
</div> </div>
); );
} }
export default App; export default App;
@ -243,10 +245,10 @@ use the `Waku.waitForConnectedPeer()` async function:
React.useEffect(() => { React.useEffect(() => {
if (!waku) return; if (!waku) return;
if (wakuStatus === 'Connected') return; if (wakuStatus === "Connected") return;
waku.waitForConnectedPeer().then(() => { waku.waitForConnectedPeer().then(() => {
setWakuStatus('Connected'); setWakuStatus("Connected");
}); });
}, [waku, wakuStatus]); }, [waku, wakuStatus]);
``` ```
@ -281,7 +283,7 @@ npm install protons
Define the data structure with protons: Define the data structure with protons:
```js ```js
import protons from 'protons'; import protons from "protons";
const proto = protons(` const proto = protons(`
message ChatMessage { message ChatMessage {
@ -314,11 +316,10 @@ function decodeMessage(wakuMessage) {
const time = new Date(); const time = new Date();
time.setTime(timestamp); time.setTime(timestamp);
const utf8Text = Buffer.from(text).toString('utf-8'); const utf8Text = Buffer.from(text).toString("utf-8");
return { text: utf8Text, timestamp: time, nick }; return { text: utf8Text, timestamp: time, nick };
} }
``` ```
## Retrieve messages ## Retrieve messages
@ -355,32 +356,31 @@ const processMessages = (retrievedMessages) => {
Pass `processMessage` in `WakuStore.queryHistory` as the `callback` value: Pass `processMessage` in `WakuStore.queryHistory` as the `callback` value:
```js ```js
waku.store waku.store.queryHistory([ContentTopic], { callback: processMessages });
.queryHistory([ContentTopic], { callback: processMessages });
``` ```
Finally, create a `Messages` component to render the messages: Finally, create a `Messages` component to render the messages:
```tsx ```tsx
function Messages(props) { function Messages(props) {
return props.messages.map(({ text, timestamp, nick }) => { return props.messages.map(({ text, timestamp, nick }) => {
return ( return (
<li> <li>
({formatDate(timestamp)}) {nick}: {text} ({formatDate(timestamp)}) {nick}: {text}
</li> </li>
); );
}); });
} }
function formatDate(timestamp) { function formatDate(timestamp) {
return timestamp.toLocaleString([], { return timestamp.toLocaleString([], {
month: 'short', month: "short",
day: 'numeric', day: "numeric",
hour: 'numeric', hour: "numeric",
minute: '2-digit', minute: "2-digit",
second: '2-digit', second: "2-digit",
hour12: false, hour12: false,
}); });
} }
``` ```
@ -391,8 +391,8 @@ function App() {
// [..] // [..]
return ( return (
<div className='App'> <div className="App">
<header className='App-header'> <header className="App-header">
<h2>{wakuStatus}</h2> <h2>{wakuStatus}</h2>
<h3>Messages</h3> <h3>Messages</h3>
<ul> <ul>
@ -407,11 +407,11 @@ function App() {
All together, you should now have: All together, you should now have:
```js ```js
import {Waku} from 'js-waku'; import { Waku } from "js-waku";
import * as React from 'react'; import * as React from "react";
import protons from 'protons'; import protons from "protons";
const ContentTopic = '/toy-chat/2/huilong/proto'; const ContentTopic = "/toy-chat/2/huilong/proto";
const proto = protons(` const proto = protons(`
message ChatMessage { message ChatMessage {
@ -422,107 +422,106 @@ message ChatMessage {
`); `);
function App() { function App() {
const [waku, setWaku] = React.useState(undefined); const [waku, setWaku] = React.useState(undefined);
const [wakuStatus, setWakuStatus] = React.useState('None'); const [wakuStatus, setWakuStatus] = React.useState("None");
const [messages, setMessages] = React.useState([]); const [messages, setMessages] = React.useState([]);
// Start Waku // Start Waku
React.useEffect(() => { React.useEffect(() => {
// If Waku status not None, it means we are already starting Waku // If Waku status not None, it means we are already starting Waku
if (wakuStatus !== 'None') return; if (wakuStatus !== "None") return;
setWakuStatus('Starting'); setWakuStatus("Starting");
// Create Waku // Create Waku
Waku.create({bootstrap: {default: true}}).then((waku) => { Waku.create({ bootstrap: { default: true } }).then((waku) => {
// Once done, put it in the state // Once done, put it in the state
setWaku(waku); setWaku(waku);
// And update the status // And update the status
setWakuStatus('Connecting'); setWakuStatus("Connecting");
}); });
}, [waku, wakuStatus]); }, [waku, wakuStatus]);
React.useEffect(() => {
if (!waku) return;
React.useEffect(() => { if (wakuStatus === "Connected") return;
if (!waku) return;
if (wakuStatus === 'Connected') return; waku.waitForConnectedPeer().then(() => {
setWakuStatus("Connected");
});
}, [waku, wakuStatus]);
waku.waitForConnectedPeer().then(() => { React.useEffect(() => {
setWakuStatus('Connected'); if (wakuStatus !== "Connected") return;
});
}, [waku, wakuStatus]);
React.useEffect(() => { const processMessages = (retrievedMessages) => {
if (wakuStatus !== 'Connected') return; const messages = retrievedMessages.map(decodeMessage).filter(Boolean);
const processMessages = (retrievedMessages) => { setMessages((currentMessages) => {
const messages = retrievedMessages.map(decodeMessage).filter(Boolean); return currentMessages.concat(messages.reverse());
});
};
setMessages((currentMessages) => { waku.store
return currentMessages.concat(messages.reverse()); .queryHistory([ContentTopic], { callback: processMessages })
}); .catch((e) => {
}; console.log("Failed to retrieve messages", e);
});
}, [waku, wakuStatus]);
waku.store return (
.queryHistory([ContentTopic], {callback: processMessages}) <div className="App">
.catch((e) => { <header className="App-header">
console.log('Failed to retrieve messages', e); <h2>{wakuStatus}</h2>
}); <h3>Messages</h3>
}, [waku, wakuStatus]); <ul>
<Messages messages={messages} />
return ( </ul>
<div className='App'> </header>
<header className='App-header'> </div>
<h2>{wakuStatus}</h2> );
<h3>Messages</h3>
<ul>
<Messages messages={messages}/>
</ul>
</header>
</div>
);
} }
export default App; export default App;
function decodeMessage(wakuMessage) { function decodeMessage(wakuMessage) {
if (!wakuMessage.payload) return; if (!wakuMessage.payload) return;
const {timestamp, nick, text} = proto.ChatMessage.decode( const { timestamp, nick, text } = proto.ChatMessage.decode(
wakuMessage.payload wakuMessage.payload
); );
// All fields in protobuf are optional so be sure to check // All fields in protobuf are optional so be sure to check
if (!timestamp || !text || !nick) return; if (!timestamp || !text || !nick) return;
const time = new Date(); const time = new Date();
time.setTime(timestamp); time.setTime(timestamp);
const utf8Text = Buffer.from(text).toString('utf-8'); const utf8Text = Buffer.from(text).toString("utf-8");
return {text: utf8Text, timestamp: time, nick}; return { text: utf8Text, timestamp: time, nick };
} }
function Messages(props) { function Messages(props) {
return props.messages.map(({text, timestamp, nick}) => { return props.messages.map(({ text, timestamp, nick }) => {
return ( return (
<li> <li>
({formatDate(timestamp)}) {nick}: {text} ({formatDate(timestamp)}) {nick}: {text}
</li> </li>
); );
}); });
} }
function formatDate(timestamp) { function formatDate(timestamp) {
return timestamp.toLocaleString([], { return timestamp.toLocaleString([], {
month: 'short', month: "short",
day: 'numeric', day: "numeric",
hour: 'numeric', hour: "numeric",
minute: '2-digit', minute: "2-digit",
second: '2-digit', second: "2-digit",
hour12: false, hour12: false,
}); });
} }
``` ```
@ -552,11 +551,10 @@ const startTime = new Date();
// 7 days/week, 24 hours/day, 60min/hour, 60secs/min, 100ms/sec // 7 days/week, 24 hours/day, 60min/hour, 60secs/min, 100ms/sec
startTime.setTime(startTime.getTime() - 7 * 24 * 60 * 60 * 1000); startTime.setTime(startTime.getTime() - 7 * 24 * 60 * 60 * 1000);
waku.store waku.store.queryHistory([ContentTopic], {
.queryHistory([ContentTopic], { callback: processMessages,
callback: processMessages, timeFilter: { startTime, endTime: new Date() },
timeFilter: { startTime, endTime: new Date() } });
});
``` ```
## End result ## End result

View File

@ -1,6 +1,7 @@
--- ---
weight: 30 weight: 30
--- ---
# Guides # Guides
## Waku Concepts ## Waku Concepts

View File

@ -1,6 +1,7 @@
--- ---
weight: 100 weight: 100
--- ---
# WakuConnect Vote & Poll SDK # WakuConnect Vote & Poll SDK
The WakuConnect Vote & Poll SDK enables developers to add Waku powered polling and voting features to their dApp. The WakuConnect Vote & Poll SDK enables developers to add Waku powered polling and voting features to their dApp.
@ -42,7 +43,7 @@ Only the party that starts an election and submit the end results need to intera
For example, it can be used by a DAO to manage proposals For example, it can be used by a DAO to manage proposals
where proposal creation and vote results must be committed to the blockchain. 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, 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. whereas the token holders do not spend gas when voting.
### Documentation ### Documentation

View File

@ -13,7 +13,6 @@ Install the Waku Poll SDK packages.
In this guide, we use [useDApp](https://usedapp.io/) to access the blockchain. In this guide, we use [useDApp](https://usedapp.io/) to access the blockchain.
```shell ```shell
yarn create react-app poll-dapp-ts --template typescript yarn create react-app poll-dapp-ts --template typescript
cd poll-dapp-ts cd poll-dapp-ts
@ -64,29 +63,28 @@ yarn add -D react-app-rewired
Create a `config-overrides.js` file at the root of your app: Create a `config-overrides.js` file at the root of your app:
```js ```js
const webpack = require('webpack'); const webpack = require("webpack");
module.exports = (config) => { 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"),
});
// Override webpack 5 config from react-scripts to load polyfills if (!config.plugins) config.plugins = [];
if (!config.resolve) config.resolve = {}; config.plugins.push(
if (!config.resolve.fallback) config.resolve.fallback = {}; new webpack.ProvidePlugin({
Object.assign(config.resolve.fallback, { Buffer: ["buffer", "Buffer"],
"buffer": require.resolve("buffer"), })
"crypto": require.resolve("crypto-browserify"), );
"stream": require.resolve("stream-browserify"),
"assert": require.resolve("assert")
}
)
if (!config.plugins) config.plugins = [] return config;
config.plugins.push( };
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
}));
return config;
}
``` ```
Use `react-app-rewired` in the `package.json`, instead of `react-scripts`: Use `react-app-rewired` in the `package.json`, instead of `react-scripts`:

View File

@ -25,31 +25,31 @@ The component uses `ethers` to connect to the user's wallet:
```tsx ```tsx
export function PollPage() { export function PollPage() {
const {account, library, activateBrowserWallet, deactivate} = useEthers() const { account, library, activateBrowserWallet, deactivate } = useEthers();
const [signer, setSigner] = useState<undefined | JsonRpcSigner>(undefined) const [signer, setSigner] = useState<undefined | JsonRpcSigner>(undefined);
useEffect(() => { useEffect(() => {
if (account) { if (account) {
setSigner(library?.getSigner()) setSigner(library?.getSigner());
} else { } else {
// Deactivate signer if signed out // Deactivate signer if signed out
setSigner(undefined) setSigner(undefined);
} }
}, [account]) }, [account]);
return ( return (
<div> <div>
<TopBar <TopBar
logo={""} logo={""}
logoWidth={84} logoWidth={84}
title={'Poll dApp'} title={"Poll dApp"}
theme={orangeTheme} theme={orangeTheme}
activate={activateBrowserWallet} activate={activateBrowserWallet}
account={account} account={account}
deactivate={deactivate} deactivate={deactivate}
/> />
</div> </div>
) );
} }
``` ```
@ -60,25 +60,27 @@ export function PollPage() {
Create a `config` variable that contains the Ethereum network parameters: Create a `config` variable that contains the Ethereum network parameters:
```tsx ```tsx
import {ChainId, DAppProvider, useEthers} from '@usedapp/core'; import { ChainId, DAppProvider, useEthers } from "@usedapp/core";
import {DEFAULT_CONFIG} from "@usedapp/core/dist/cjs/src/model/config/default"; import { DEFAULT_CONFIG } from "@usedapp/core/dist/cjs/src/model/config/default";
const config = { const config = {
readOnlyChainId: ChainId.Mainnet, readOnlyChainId: ChainId.Mainnet,
readOnlyUrls: { readOnlyUrls: {
[ChainId.Mainnet]: 'https://mainnet.infura.io/v3/your-infura-token', [ChainId.Mainnet]: "https://mainnet.infura.io/v3/your-infura-token",
}, },
multicallAddresses: { multicallAddresses: {
1: '0xeefba1e63905ef1d7acba5a8513c70307c1ce441', 1: "0xeefba1e63905ef1d7acba5a8513c70307c1ce441",
3: '0x53c43764255c17bd724f74c4ef150724ac50a3ed', 3: "0x53c43764255c17bd724f74c4ef150724ac50a3ed",
1337: process.env.GANACHE_MULTICALL_CONTRACT ?? '0x0000000000000000000000000000000000000000', 1337:
}, process.env.GANACHE_MULTICALL_CONTRACT ??
supportedChains: [...DEFAULT_CONFIG.supportedChains, 1337], "0x0000000000000000000000000000000000000000",
notifications: { },
checkInterval: 500, supportedChains: [...DEFAULT_CONFIG.supportedChains, 1337],
expirationPeriod: 50000, notifications: {
}, checkInterval: 500,
} expirationPeriod: 50000,
},
};
``` ```
Replace `your-infura-token` with your [Infura API token](https://infura.io/docs/ethereum). Replace `your-infura-token` with your [Infura API token](https://infura.io/docs/ethereum).
@ -89,12 +91,12 @@ Replace `your-infura-token` with your [Infura API token](https://infura.io/docs/
Create a `Wrapper` variable to use in the page component: Create a `Wrapper` variable to use in the page component:
```tsx ```tsx
import styled from 'styled-components' import styled from "styled-components";
const Wrapper = styled.div` const Wrapper = styled.div`
height: 100%; height: 100%;
width: 100%; width: 100%;
` `;
``` ```
### Render ### Render
@ -103,97 +105,99 @@ Finally, create the `App` component:
```tsx ```tsx
export function App() { export function App() {
return ( return (
<Wrapper> <Wrapper>
<GlobalStyle/> <GlobalStyle />
<DAppProvider config={config}> <DAppProvider config={config}>
<PollPage/> <PollPage />
</DAppProvider> </DAppProvider>
</Wrapper> </Wrapper>
) );
} }
``` ```
Your `index.tsx` should now be: Your `index.tsx` should now be:
```tsx ```tsx
import {ChainId, DAppProvider, useEthers} from '@usedapp/core'; import { ChainId, DAppProvider, useEthers } from "@usedapp/core";
import {GlobalStyle, TopBar} from '@waku/vote-poll-sdk-react-components'; import { GlobalStyle, TopBar } from "@waku/vote-poll-sdk-react-components";
import React, {useEffect, useState} from 'react'; import React, { useEffect, useState } from "react";
import ReactDOM from 'react-dom'; import ReactDOM from "react-dom";
import './index.css'; import "./index.css";
import {JsonRpcSigner} from "@ethersproject/providers"; import { JsonRpcSigner } from "@ethersproject/providers";
import {orangeTheme} from "@waku/vote-poll-sdk-react-components/dist/cjs/src/style/themes"; 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 { DEFAULT_CONFIG } from "@usedapp/core/dist/cjs/src/model/config/default";
import styled from 'styled-components' import styled from "styled-components";
const config = { const config = {
readOnlyChainId: ChainId.Mainnet, readOnlyChainId: ChainId.Mainnet,
readOnlyUrls: { readOnlyUrls: {
[ChainId.Mainnet]: 'https://mainnet.infura.io/v3/b4451d780cc64a078ccf2181e872cfcf', [ChainId.Mainnet]:
}, "https://mainnet.infura.io/v3/b4451d780cc64a078ccf2181e872cfcf",
multicallAddresses: { },
1: '0xeefba1e63905ef1d7acba5a8513c70307c1ce441', multicallAddresses: {
3: '0x53c43764255c17bd724f74c4ef150724ac50a3ed', 1: "0xeefba1e63905ef1d7acba5a8513c70307c1ce441",
1337: process.env.GANACHE_MULTICALL_CONTRACT ?? '0x0000000000000000000000000000000000000000', 3: "0x53c43764255c17bd724f74c4ef150724ac50a3ed",
}, 1337:
supportedChains: [...DEFAULT_CONFIG.supportedChains, 1337], process.env.GANACHE_MULTICALL_CONTRACT ??
notifications: { "0x0000000000000000000000000000000000000000",
checkInterval: 500, },
expirationPeriod: 50000, supportedChains: [...DEFAULT_CONFIG.supportedChains, 1337],
}, notifications: {
} checkInterval: 500,
expirationPeriod: 50000,
},
};
export function PollPage() { export function PollPage() {
const {account, library, activateBrowserWallet, deactivate} = useEthers() const { account, library, activateBrowserWallet, deactivate } = useEthers();
const [signer, setSigner] = useState<undefined | JsonRpcSigner>(undefined) const [signer, setSigner] = useState<undefined | JsonRpcSigner>(undefined);
useEffect(() => { useEffect(() => {
if (account) { if (account) {
setSigner(library?.getSigner()) setSigner(library?.getSigner());
} else { } else {
// Deactivate signer if signed out // Deactivate signer if signed out
setSigner(undefined) setSigner(undefined);
} }
}, [account]) }, [account]);
return ( return (
<div> <div>
<TopBar <TopBar
logo={""} logo={""}
logoWidth={84} logoWidth={84}
title={'Poll dApp'} title={"Poll dApp"}
theme={orangeTheme} theme={orangeTheme}
activate={activateBrowserWallet} activate={activateBrowserWallet}
account={account} account={account}
deactivate={deactivate} deactivate={deactivate}
/> />
</div> </div>
) );
} }
export function App() { export function App() {
return ( return (
<Wrapper> <Wrapper>
<GlobalStyle/> <GlobalStyle />
<DAppProvider config={config}> <DAppProvider config={config}>
<PollPage/> <PollPage />
</DAppProvider> </DAppProvider>
</Wrapper> </Wrapper>
) );
} }
const Wrapper = styled.div` const Wrapper = styled.div`
height: 100%; height: 100%;
width: 100%; width: 100%;
` `;
ReactDOM.render( ReactDOM.render(
<React.StrictMode> <React.StrictMode>
<App/> <App />
</React.StrictMode>, </React.StrictMode>,
document.getElementById('root') document.getElementById("root")
); );
``` ```

View File

@ -20,7 +20,7 @@ touch components/Poll.tsx
Again, create a `Wrapper` for styling: Again, create a `Wrapper` for styling:
```tsx ```tsx
import styled from 'styled-components' import styled from "styled-components";
const Wrapper = styled.div` const Wrapper = styled.div`
display: flex; display: flex;
@ -40,7 +40,7 @@ const Wrapper = styled.div`
@media (max-width: 425px) { @media (max-width: 425px) {
padding: 96px 16px 84px; padding: 96px 16px 84px;
} }
` `;
``` ```
## Button ## Button
@ -56,67 +56,74 @@ Upon clicking the button, we set `showPollCreation` to true.
`showPollCreation` will control when to render the poll creation modal. `showPollCreation` will control when to render the poll creation modal.
`components/Poll.tsx`: `components/Poll.tsx`:
```tsx ```tsx
import {useState} from 'react' import { useState } from "react";
import {JsonRpcSigner, Web3Provider} from '@ethersproject/providers' import { JsonRpcSigner, Web3Provider } from "@ethersproject/providers";
import {CreateButton} from '@waku/vote-poll-sdk-react-components' import { CreateButton } from "@waku/vote-poll-sdk-react-components";
import {Theme} from '@waku/vote-poll-sdk-react-components/dist/esm/src/style/themes' import { Theme } from "@waku/vote-poll-sdk-react-components/dist/esm/src/style/themes";
type PollProps = { type PollProps = {
signer: JsonRpcSigner | undefined signer: JsonRpcSigner | undefined;
theme: Theme theme: Theme;
} };
export function Poll({signer, theme}: PollProps) { export function Poll({ signer, theme }: PollProps) {
const [showPollCreation, setShowPollCreation] = useState(false) const [showPollCreation, setShowPollCreation] = useState(false);
const disabled = !signer; const disabled = !signer;
return ( return (
<Wrapper> <Wrapper>
{ {
<CreateButton style={{backgroundColor: disabled ? "lightgrey" : theme.primaryColor}} theme={theme} <CreateButton
disabled={disabled} style={{
onClick={() => setShowPollCreation(true)}> backgroundColor: disabled ? "lightgrey" : theme.primaryColor,
Create a poll }}
</CreateButton> theme={theme}
} disabled={disabled}
</Wrapper> onClick={() => setShowPollCreation(true)}
) >
Create a poll
</CreateButton>
}
</Wrapper>
);
} }
``` ```
Now update the `PollPage` component to render the new `Poll` component: Now update the `PollPage` component to render the new `Poll` component:
`index.tsx`: `index.tsx`:
```tsx ```tsx
export function PollPage() { export function PollPage() {
const {account, library, activateBrowserWallet, deactivate} = useEthers() const { account, library, activateBrowserWallet, deactivate } = useEthers();
const [signer, setSigner] = useState<undefined | JsonRpcSigner>(undefined) const [signer, setSigner] = useState<undefined | JsonRpcSigner>(undefined);
useEffect(() => { useEffect(() => {
if (account) { if (account) {
setSigner(library?.getSigner()) setSigner(library?.getSigner());
} else { } else {
// Deactivate signer if signed out // Deactivate signer if signed out
setSigner(undefined) setSigner(undefined);
} }
}, [account]) }, [account]);
return ( return (
<div> <div>
<TopBar <TopBar
logo={""} logo={""}
logoWidth={84} logoWidth={84}
title={'Poll dApp'} title={"Poll dApp"}
theme={orangeTheme} theme={orangeTheme}
activate={activateBrowserWallet} activate={activateBrowserWallet}
account={account} account={account}
deactivate={deactivate} deactivate={deactivate}
/> />
<Poll theme={orangeTheme} signer={signer}/> <Poll theme={orangeTheme} signer={signer} />
</div> </div>
) );
} }
``` ```

View File

@ -10,8 +10,9 @@ The Poll SDK provides an off-the-shelf component to create a new poll: `PollCrea
It takes in a `WakuPolling` hook that can created with `useWakuPolling`. It takes in a `WakuPolling` hook that can created with `useWakuPolling`.
`useWakuPolling` takes: `useWakuPolling` takes:
- `appName`: Your app name. - `appName`: Your app name.
It is used to generate a unique content topic for your polls. 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. See [How to Choose a Content Topic](/docs/guides/01_choose_content_topic/) for more information.
- `tokenAddress`: The address of your ERC-20 token. - `tokenAddress`: The address of your ERC-20 token.
Only token holders can create and answer polls. Only token holders can create and answer polls.
@ -21,46 +22,68 @@ It takes in a `WakuPolling` hook that can created with `useWakuPolling`.
Add these parameters to `PollProps` and call `useWakuPolling`. Add these parameters to `PollProps` and call `useWakuPolling`.
`components/Poll.tsx` `components/Poll.tsx`
```tsx ```tsx
import {useState} from 'react' import { useState } from "react";
import {useConfig} from '@usedapp/core' import { useConfig } from "@usedapp/core";
import {PollCreation} from '@waku/poll-sdk-react-components' import { PollCreation } from "@waku/poll-sdk-react-components";
import {JsonRpcSigner, Web3Provider} from '@ethersproject/providers' import { JsonRpcSigner, Web3Provider } from "@ethersproject/providers";
import {useWakuPolling} from '@waku/poll-sdk-react-hooks' import { useWakuPolling } from "@waku/poll-sdk-react-hooks";
import {CreateButton} from '@waku/vote-poll-sdk-react-components' import { CreateButton } from "@waku/vote-poll-sdk-react-components";
import {Theme} from '@waku/vote-poll-sdk-react-components/dist/esm/src/style/themes' import { Theme } from "@waku/vote-poll-sdk-react-components/dist/esm/src/style/themes";
import {ChainId} from "@usedapp/core/src/constants"; import { ChainId } from "@usedapp/core/src/constants";
type PollProps = { type PollProps = {
appName: string appName: string;
library: Web3Provider | undefined library: Web3Provider | undefined;
signer: JsonRpcSigner | undefined signer: JsonRpcSigner | undefined;
chainId: ChainId | undefined chainId: ChainId | undefined;
theme: Theme theme: Theme;
tokenAddress: string tokenAddress: string;
} };
export function Poll({appName, library, signer, chainId, theme, tokenAddress}: PollProps) { export function Poll({
const config = useConfig() appName,
const [showPollCreation, setShowPollCreation] = useState(false) library,
const wakuPolling = useWakuPolling(appName, tokenAddress, library, config?.multicallAddresses?.[chainId ?? 1337]) 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; const disabled = !signer;
return ( return (
<Wrapper> <Wrapper>
{showPollCreation && signer && ( {showPollCreation && signer && (
<PollCreation wakuPolling={wakuPolling} setShowPollCreation={setShowPollCreation} theme={theme}/> <PollCreation
)} wakuPolling={wakuPolling}
{ setShowPollCreation={setShowPollCreation}
<CreateButton style={{backgroundColor: disabled ? "lightgrey" : theme.primaryColor}} theme={theme} theme={theme}
disabled={disabled} />
onClick={() => setShowPollCreation(true)}> )}
Create a poll {
</CreateButton> <CreateButton
} style={{
</Wrapper> backgroundColor: disabled ? "lightgrey" : theme.primaryColor,
) }}
theme={theme}
disabled={disabled}
onClick={() => setShowPollCreation(true)}
>
Create a poll
</CreateButton>
}
</Wrapper>
);
} }
``` ```
@ -70,35 +93,43 @@ In this example, we use `demo-poll-dapp` for the app name and the mainnet SNT to
Replace those with your own. Replace those with your own.
`index.tsx` `index.tsx`
```tsx ```tsx
export function PollPage() { export function PollPage() {
const {account, library, activateBrowserWallet, deactivate, chainId} = useEthers() const { account, library, activateBrowserWallet, deactivate, chainId } =
const [signer, setSigner] = useState<undefined | JsonRpcSigner>(undefined) useEthers();
const [signer, setSigner] = useState<undefined | JsonRpcSigner>(undefined);
useEffect(() => { useEffect(() => {
if (account) { if (account) {
setSigner(library?.getSigner()) setSigner(library?.getSigner());
} else { } else {
// Deactivate signer if signed out // Deactivate signer if signed out
setSigner(undefined) setSigner(undefined);
} }
}, [account]) }, [account]);
return ( return (
<div> <div>
<TopBar <TopBar
logo={""} logo={""}
logoWidth={84} logoWidth={84}
title={'Poll dApp'} title={"Poll dApp"}
theme={orangeTheme} theme={orangeTheme}
activate={activateBrowserWallet} activate={activateBrowserWallet}
account={account} account={account}
deactivate={deactivate} deactivate={deactivate}
/> />
<Poll theme={orangeTheme} appName={'demo-poll-dapp'} library={library} signer={signer} chainId={chainId} <Poll
tokenAddress={'0x744d70FDBE2Ba4CF95131626614a1763DF805B9E'}/> theme={orangeTheme}
</div> appName={"demo-poll-dapp"}
) library={library}
signer={signer}
chainId={chainId}
tokenAddress={"0x744d70FDBE2Ba4CF95131626614a1763DF805B9E"}
/>
</div>
);
} }
``` ```

View File

@ -12,56 +12,86 @@ Simply add it to the `Poll` function to render it.
It needs the `account` variable that can be passed as a property to `Poll`: It needs the `account` variable that can be passed as a property to `Poll`:
`components/Poll.tsx`: `components/Poll.tsx`:
```tsx ```tsx
import {useState} from 'react' import { useState } from "react";
import {useConfig} from '@usedapp/core' import { useConfig } from "@usedapp/core";
import {PollCreation, PollList} from '@waku/poll-sdk-react-components' import { PollCreation, PollList } from "@waku/poll-sdk-react-components";
import {JsonRpcSigner, Web3Provider} from '@ethersproject/providers' import { JsonRpcSigner, Web3Provider } from "@ethersproject/providers";
import {useWakuPolling} from '@waku/poll-sdk-react-hooks' import { useWakuPolling } from "@waku/poll-sdk-react-hooks";
import {CreateButton} from '@waku/vote-poll-sdk-react-components' import { CreateButton } from "@waku/vote-poll-sdk-react-components";
import {Theme} from '@waku/vote-poll-sdk-react-components/dist/esm/src/style/themes' import { Theme } from "@waku/vote-poll-sdk-react-components/dist/esm/src/style/themes";
import {ChainId} from "@usedapp/core/src/constants"; import { ChainId } from "@usedapp/core/src/constants";
type PollProps = { type PollProps = {
appName: string appName: string;
library: Web3Provider | undefined library: Web3Provider | undefined;
signer: JsonRpcSigner | undefined signer: JsonRpcSigner | undefined;
chainId: ChainId | undefined chainId: ChainId | undefined;
account: string | null | undefined account: string | null | undefined;
theme: Theme theme: Theme;
tokenAddress: string tokenAddress: string;
} };
export function Poll({appName, library, signer, chainId, account, theme, tokenAddress}: PollProps) { export function Poll({
const config = useConfig() appName,
const [showPollCreation, setShowPollCreation] = useState(false) library,
const wakuPolling = useWakuPolling(appName, tokenAddress, library, config?.multicallAddresses?.[chainId ?? 1337]) 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; const disabled = !signer;
return ( return (
<Wrapper> <Wrapper>
{showPollCreation && signer && ( {showPollCreation && signer && (
<PollCreation wakuPolling={wakuPolling} setShowPollCreation={setShowPollCreation} theme={theme}/> <PollCreation
)} wakuPolling={wakuPolling}
{ setShowPollCreation={setShowPollCreation}
<CreateButton style={{backgroundColor: disabled ? "lightgrey" : theme.primaryColor}} theme={theme} theme={theme}
disabled={disabled} />
onClick={() => setShowPollCreation(true)}> )}
Create a poll {
</CreateButton> <CreateButton
} style={{
<PollList wakuPolling={wakuPolling} account={account} theme={theme} /> backgroundColor: disabled ? "lightgrey" : theme.primaryColor,
</Wrapper> }}
) 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`: Pass the `account` to `Poll` in `index.tsx`:
```tsx ```tsx
<Poll theme={orangeTheme} appName={'demo-poll-dapp'} library={library} signer={signer} chainId={chainId} <Poll
account={account} theme={orangeTheme}
tokenAddress={'0x744d70FDBE2Ba4CF95131626614a1763DF805B9E'}/> appName={"demo-poll-dapp"}
library={library}
signer={signer}
chainId={chainId}
account={account}
tokenAddress={"0x744d70FDBE2Ba4CF95131626614a1763DF805B9E"}
/>
``` ```
Et voila! Et voila!
@ -77,12 +107,11 @@ You can find the resulting code in the [examples folder](https://github.com/stat
{{< hint info >}} {{< hint info >}}
The example above uses webpack 5 instead of react-app-rewired. 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). 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 >}} {{< /hint >}}
The final gif: The final gif:
![Poll demo](/assets/poll_sdk/wakuconnect-poll-demo.gif) ![Poll demo](/assets/poll_sdk/wakuconnect-poll-demo.gif)
{{< button relref="./04_poll_creation" >}}Back{{< /button >}} {{< button relref="./04_poll_creation" >}}Back{{< /button >}}

View File

@ -3,6 +3,7 @@ title: Introduction
date: 2021-12-09T14:00:00+01:00 date: 2021-12-09T14:00:00+01:00
weight: 10 weight: 10
--- ---
# WakuConnect Docs # WakuConnect Docs
WakuConnect is a suite of libraries, SDKs and documentations to help you use Waku in your dApp. WakuConnect is a suite of libraries, SDKs and documentations to help you use Waku in your dApp.
@ -28,7 +29,7 @@ and how it can be used with popular web frameworks.
The js-waku repository also holds a number of [examples](https://github.com/status-im/js-waku/tree/main/examples). The js-waku repository also holds a number of [examples](https://github.com/status-im/js-waku/tree/main/examples).
The examples are working Proof-of-Concepts that demonstrate how to use js-waku. The examples are working Proof-of-Concepts that demonstrate how to use js-waku.
Check out the [example list](/docs/examples/) to see what usage each example demonstrates. Check out the [example list](/docs/examples/) to see what usage each example demonstrates.
Finally, if you want to learn how Waku works under the hoods, check the specs at [rfc.vac.dev](https://rfc.vac.dev/). Finally, if you want to learn how Waku works under the hoods, check the specs at [rfc.vac.dev](https://rfc.vac.dev/).

View File

@ -3,6 +3,7 @@ title: Presentations & Videos
date: 2022-01-12T01:00:00+01:00 date: 2022-01-12T01:00:00+01:00
weight: 22 weight: 22
--- ---
# Presentations & Videos # Presentations & Videos
## 17 Sep 2021 - EthOnline ## 17 Sep 2021 - EthOnline

View File

@ -3,6 +3,7 @@ title: Quick Start
date: 2021-12-09T14:00:00+01:00 date: 2021-12-09T14:00:00+01:00
weight: 20 weight: 20
--- ---
# Quick Start # Quick Start
In this section you will learn how to receive and send messages using Waku Relay. In this section you will learn how to receive and send messages using Waku Relay.
@ -22,9 +23,9 @@ yarn add js-waku
### Start a waku node ### Start a waku node
```ts ```ts
import {Waku} from 'js-waku'; import { Waku } from "js-waku";
const waku = await Waku.create({bootstrap: {default: true}}); const waku = await Waku.create({ bootstrap: { default: true } });
``` ```
### Listen for messages ### Listen for messages
@ -38,9 +39,12 @@ For example, if you were to use a new `contentTopic` such as `/my-cool-app/1/my-
here is how to listen to new messages received via [Waku v2 Relay](https://rfc.vac.dev/spec/11/): here is how to listen to new messages received via [Waku v2 Relay](https://rfc.vac.dev/spec/11/):
```ts ```ts
waku.relay.addObserver((msg) => { waku.relay.addObserver(
console.log("Message received:", msg.payloadAsUtf8) (msg) => {
}, ["/my-cool-app/1/my-use-case/proto"]); console.log("Message received:", msg.payloadAsUtf8);
},
["/my-cool-app/1/my-use-case/proto"]
);
``` ```
### Send messages ### Send messages
@ -48,12 +52,15 @@ waku.relay.addObserver((msg) => {
Messages are wrapped in a `WakuMessage` envelop. Messages are wrapped in a `WakuMessage` envelop.
```ts ```ts
import { WakuMessage } from 'js-waku'; import { WakuMessage } from "js-waku";
const msg = await WakuMessage.fromUtf8String("Here is a message!", "/my-cool-app/1/my-use-case/proto") const msg = await WakuMessage.fromUtf8String(
"Here is a message!",
"/my-cool-app/1/my-use-case/proto"
);
await waku.relay.send(msg); await waku.relay.send(msg);
``` ```
### Building an app ### Building an app
Check out the [ReactJS Waku Relay guide](/docs/guides/07_reactjs_relay/) to learn how you can use the code above in a React app. Check out the [ReactJS Waku Relay guide](/docs/guides/07_reactjs_relay/) to learn how you can use the code above in a React app.

View File

@ -15,11 +15,13 @@ If we are aware of other projects using js-waku and other use cases that could b
feel free to open a [PR](https://github.com/vacp2p/docs.wakuconnect.dev). feel free to open a [PR](https://github.com/vacp2p/docs.wakuconnect.dev).
Legend: Legend:
- _Live_: We are aware of projects who have implemented this use case. - _Live_: We are aware of projects who have implemented this use case.
- _SDK Available_: An SDK is available to easily implement this use case. - _SDK Available_: An SDK is available to easily implement this use case.
- _Work In Progress_: We are aware of projects working to implement this use case. - _Work In Progress_: We are aware of projects working to implement this use case.
- _Proof of Concept_: A Proof of concept was created, sometimes as part of a hackathon. - _Proof of Concept_: A Proof of concept was created, sometimes as part of a hackathon.
- _Idea_: This is an unexplored use case, more research and work may be needed. - _Idea_: This is an unexplored use case, more research and work may be needed.
--- ---
{{< columns >}} {{< columns >}}
@ -27,7 +29,7 @@ Legend:
## Chat Messenger ## Chat Messenger
| _Work In Progress_ | | _Work In Progress_ |
|--------------------| | ------------------ |
Waku can be used as the communication layer to a private, decentralized, censorship-resistant messenger. Waku can be used as the communication layer to a private, decentralized, censorship-resistant messenger.
@ -38,7 +40,7 @@ Waku can be used as the communication layer to a private, decentralized, censors
## Polls ## Polls
| _SDK Available_ | | _SDK Available_ |
|-----------------| | --------------- |
Create, answer and view polls which are censorship-resistant. Create, answer and view polls which are censorship-resistant.
@ -51,7 +53,7 @@ Create, answer and view polls which are censorship-resistant.
## NFT Marketplace ## NFT Marketplace
| _Live_ | | _Live_ |
|--------| | ------ |
Use Waku to take NFT bids and offers off-chain and save gas. Use Waku to take NFT bids and offers off-chain and save gas.
Add a social media layer, allowing NFT owners to like, comments, etc. Add a social media layer, allowing NFT owners to like, comments, etc.
@ -67,7 +69,7 @@ Add a social media layer, allowing NFT owners to like, comments, etc.
## State Channels ## State Channels
| _Idea_ | | _Idea_ |
|--------| | ------ |
Use Waku to enable two parties to setup and maintain a state channel. Use Waku to enable two parties to setup and maintain a state channel.
@ -78,7 +80,7 @@ Use Waku to enable two parties to setup and maintain a state channel.
## Voting and Proposals ## Voting and Proposals
| _SDK Available_ | | _SDK Available_ |
|-----------------| | --------------- |
For proposals submitted on the blockchain, For proposals submitted on the blockchain,
exchange votes over Waku to save gas. exchange votes over Waku to save gas.
@ -95,7 +97,7 @@ Create, answer and view polls which are censorship-resistant.
## Signature Exchange for Multi-Sig Wallets ## Signature Exchange for Multi-Sig Wallets
| _Idea_ | | _Idea_ |
|--------| | ------ |
Use Waku to enable several owners of a given multi-sig wallets to exchange signatures in a decentralized, Use Waku to enable several owners of a given multi-sig wallets to exchange signatures in a decentralized,
private & censorship-resistant manner to approve transactions. private & censorship-resistant manner to approve transactions.
@ -109,7 +111,7 @@ private & censorship-resistant manner to approve transactions.
## Gameplay Communication ## Gameplay Communication
| _Proof of Concept_ | | _Proof of Concept_ |
|--------------------| | ------------------ |
Use Waku as the communication layer for a peer-to-peer, decentralize game. Use Waku as the communication layer for a peer-to-peer, decentralize game.
Remove the need of a centralized infrastructure for gameplay communications. Remove the need of a centralized infrastructure for gameplay communications.
@ -121,7 +123,7 @@ Remove the need of a centralized infrastructure for gameplay communications.
## dApp to Wallet Communication ## dApp to Wallet Communication
| _Live_ | | _Live_ |
|--------| | ------ |
Communication between a user's wallet and a dApp can be used by dApp operators to notify users Communication between a user's wallet and a dApp can be used by dApp operators to notify users
(e.g. governance token holders get notified to vote on a proposal), (e.g. governance token holders get notified to vote on a proposal),
@ -135,7 +137,7 @@ or for a dApp to request transaction signature to the wallet.
## Layer 2 Communication ## Layer 2 Communication
| _Idea_ | | _Idea_ |
|--------| | ------ |
Use Waku as an existing communication network to broadcast and aggregate layer 2 transactions. Use Waku as an existing communication network to broadcast and aggregate layer 2 transactions.
Possibly increasing privacy, anonymity and resilience. Possibly increasing privacy, anonymity and resilience.
@ -149,7 +151,7 @@ Possibly increasing privacy, anonymity and resilience.
## Generalized Marketplace ## Generalized Marketplace
| _Proof of Concept_ | | _Proof of Concept_ |
|--------------------| | ------------------ |
Use Waku to enable users to offer, bid, accept and trade goods and services Use Waku to enable users to offer, bid, accept and trade goods and services
to create a ride-sharing or tradings apps. to create a ride-sharing or tradings apps.
@ -163,7 +165,7 @@ to create a ride-sharing or tradings apps.
## Social Media Platform ## Social Media Platform
| _Idea_ | | _Idea_ |
|--------| | ------ |
[Chat Messenger](#chat-messenger) is one form of social media that can be empowered by Waku to be decentralized [Chat Messenger](#chat-messenger) is one form of social media that can be empowered by Waku to be decentralized
and censorship-resistant. and censorship-resistant.

View File

@ -3,6 +3,7 @@ title: Implemented Waku Protocols
date: 2021-12-09T14:00:00+01:00 date: 2021-12-09T14:00:00+01:00
weight: 60 weight: 60
--- ---
## Waku Protocol Support ## Waku Protocol Support
You can track progress on the [project board](https://github.com/status-im/js-waku/projects/1). You can track progress on the [project board](https://github.com/status-im/js-waku/projects/1).
@ -11,24 +12,24 @@ You can track progress on the [project board](https://github.com/status-im/js-wa
- 🚧: Implementation in progress - 🚧: Implementation in progress
- ⛔: Support is not planned - ⛔: Support is not planned
| Spec | Implementation Status | | Spec | Implementation Status |
| ---- | -------------- | | ------------------------------------------------------- | ---------------------- |
|[6/WAKU1](https://rfc.vac.dev/spec/6)|⛔| | [6/WAKU1](https://rfc.vac.dev/spec/6) | |
|[7/WAKU-DATA](https://rfc.vac.dev/spec/7)|⛔| | [7/WAKU-DATA](https://rfc.vac.dev/spec/7) | |
|[8/WAKU-MAIL](https://rfc.vac.dev/spec/8)|⛔| | [8/WAKU-MAIL](https://rfc.vac.dev/spec/8) | |
|[9/WAKU-RPC](https://rfc.vac.dev/spec/9)|⛔| | [9/WAKU-RPC](https://rfc.vac.dev/spec/9) | |
|[10/WAKU2](https://rfc.vac.dev/spec/10)|🚧| | [10/WAKU2](https://rfc.vac.dev/spec/10) | 🚧 |
|[11/WAKU2-RELAY](https://rfc.vac.dev/spec/11)|✔| | [11/WAKU2-RELAY](https://rfc.vac.dev/spec/11) | |
|[12/WAKU2-FILTER](https://rfc.vac.dev/spec/12)|| | [12/WAKU2-FILTER](https://rfc.vac.dev/spec/12) | |
|[13/WAKU2-STORE](https://rfc.vac.dev/spec/13)|✔ (querying node only)| | [13/WAKU2-STORE](https://rfc.vac.dev/spec/13) | ✔ (querying node only) |
|[14/WAKU2-MESSAGE](https://rfc.vac.dev/spec/14)|✔| | [14/WAKU2-MESSAGE](https://rfc.vac.dev/spec/14) | |
|[15/WAKU2-BRIDGE](https://rfc.vac.dev/spec/15)|| | [15/WAKU2-BRIDGE](https://rfc.vac.dev/spec/15) | |
|[16/WAKU2-RPC](https://rfc.vac.dev/spec/16)|⛔| | [16/WAKU2-RPC](https://rfc.vac.dev/spec/16) | |
|[17/WAKU2-RLNRELAY](https://rfc.vac.dev/spec/17)|| | [17/WAKU2-RLNRELAY](https://rfc.vac.dev/spec/17) | |
|[18/WAKU2-SWAP](https://rfc.vac.dev/spec/18)|| | [18/WAKU2-SWAP](https://rfc.vac.dev/spec/18) | |
|[19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/)|✔| | [19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/) | |
|[20/TOY-ETH-PM](https://rfc.vac.dev/spec/20/)|✔ (as example)| | [20/TOY-ETH-PM](https://rfc.vac.dev/spec/20/) | ✔ (as example) |
|[21/WAKU2-FTSTORE](https://rfc.vac.dev/spec/21/)|✔| | [21/WAKU2-FTSTORE](https://rfc.vac.dev/spec/21/) | |
|[22/TOY-CHAT](https://rfc.vac.dev/spec/22/)|✔ (as example)| | [22/TOY-CHAT](https://rfc.vac.dev/spec/22/) | ✔ (as example) |
|[25/LIBP2P-DNS-DISCOVERY](https://rfc.vac.dev/spec/25/)|🚧| | [25/LIBP2P-DNS-DISCOVERY](https://rfc.vac.dev/spec/25/) | 🚧 |
|[26/WAKU2-PAYLOAD](https://rfc.vac.dev/spec/26/)|✔| | [26/WAKU2-PAYLOAD](https://rfc.vac.dev/spec/26/) | |

View File

@ -1,4 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1