Run prettier (#29)
This commit is contained in:
parent
23ba3e4829
commit
41bc0a9d80
|
@ -3,11 +3,11 @@ title: Cryptographic Libraries
|
|||
date: 2021-12-09T14:00:00+01:00
|
||||
weight: 50
|
||||
---
|
||||
|
||||
# Cryptographic Libraries
|
||||
|
||||
A note on the cryptographic libraries used as it is a not a straightforward affair.
|
||||
|
||||
|
||||
## Asymmetric encryption
|
||||
|
||||
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)
|
||||
or [elliptic](https://www.npmjs.com/package/elliptic) (pure JS if none of the other libraries are available).
|
||||
|
||||
|
||||
## Symmetric encryption
|
||||
|
||||
Uses [SubtleCrypto](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) Web API (browser)
|
||||
|
|
|
@ -3,6 +3,7 @@ title: Examples
|
|||
date: 2021-12-09T14:00:00+01:00
|
||||
weight: 40
|
||||
---
|
||||
|
||||
# Examples
|
||||
|
||||
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).
|
||||
|
||||
Demonstrates:
|
||||
Demonstrates:
|
||||
|
||||
- How to stop retrieving results from Waku Store on condition
|
||||
- Use minified bundle from Unpkg.com
|
||||
|
|
|
@ -3,6 +3,7 @@ title: Receive and Send Messages Using Waku Relay
|
|||
date: 2021-12-09T14:00:00+01:00
|
||||
weight: 2
|
||||
---
|
||||
|
||||
# Receive and Send Messages Using Waku Relay
|
||||
|
||||
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:
|
||||
|
||||
```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.
|
||||
If you want to bootstrap to your own nodes, you can pass an array of multiaddresses instead:
|
||||
|
||||
```js
|
||||
import { Waku } from 'js-waku';
|
||||
import { Waku } from "js-waku";
|
||||
|
||||
const waku = await Waku.create({
|
||||
bootstrap: [
|
||||
'/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.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",
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
|
@ -67,7 +68,7 @@ const processIncomingMessage = (wakuMessage) => {
|
|||
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
|
||||
|
@ -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:
|
||||
|
||||
```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,
|
||||
|
@ -124,7 +128,7 @@ npm install protons
|
|||
Then define the simple chat message:
|
||||
|
||||
```js
|
||||
import protons from 'protons';
|
||||
import protons from "protons";
|
||||
|
||||
const proto = protons(`
|
||||
message SimpleChatMessage {
|
||||
|
@ -147,7 +151,7 @@ First, encode the object:
|
|||
```js
|
||||
const payload = proto.SimpleChatMessage.encode({
|
||||
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:
|
||||
|
||||
```js
|
||||
waku.relay.addObserver(processIncomingMessage, ['/relay-guide/1/chat/proto']);
|
||||
waku.relay.addObserver(processIncomingMessage, ["/relay-guide/1/chat/proto"]);
|
||||
```
|
||||
|
||||
# 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:
|
||||
|
||||
```js
|
||||
import { getBootstrapNodes, Waku, WakuMessage } from 'js-waku';
|
||||
import protons from 'protons';
|
||||
import { getBootstrapNodes, Waku, WakuMessage } from "js-waku";
|
||||
import protons from "protons";
|
||||
|
||||
const proto = protons(`
|
||||
message SimpleChatMessage {
|
||||
|
@ -220,11 +224,11 @@ const processIncomingMessage = (wakuMessage) => {
|
|||
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({
|
||||
timestamp: Date.now(),
|
||||
text: 'Here is a message'
|
||||
text: "Here is a message",
|
||||
});
|
||||
const wakuMessage = await WakuMessage.fromBytes(payload, ContentTopic);
|
||||
await waku.relay.send(wakuMessage);
|
||||
|
|
|
@ -3,6 +3,7 @@ title: Retrieve Messages Using Waku Store
|
|||
date: 2021-12-09T14:00:00+01:00
|
||||
weight: 3
|
||||
---
|
||||
|
||||
# Retrieve Messages Using Waku Store
|
||||
|
||||
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:
|
||||
|
||||
```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.
|
||||
If you want to bootstrap to your own nodes, you can pass an array of multiaddresses instead:
|
||||
|
||||
```js
|
||||
import { Waku } from 'js-waku';
|
||||
import { Waku } from "js-waku";
|
||||
|
||||
const wakuNode = await Waku.create({
|
||||
bootstrap: [
|
||||
'/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.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",
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
|
@ -103,7 +104,7 @@ npm install protons
|
|||
Then specify the data structure:
|
||||
|
||||
```js
|
||||
import protons from 'protons';
|
||||
import protons from "protons";
|
||||
|
||||
const proto = protons(`
|
||||
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:
|
||||
|
||||
```js
|
||||
const ContentTopic = '/store-guide/1/news/proto';
|
||||
const ContentTopic = "/store-guide/1/news/proto";
|
||||
|
||||
const callback = (retrievedMessages) => {
|
||||
const articles = retrievedMessages
|
||||
|
@ -160,12 +161,10 @@ const callback = (retrievedMessages) => {
|
|||
console.log(`${articles.length} articles have been retrieved`);
|
||||
};
|
||||
|
||||
waku.store
|
||||
.queryHistory([ContentTopic], { callback })
|
||||
.catch((e) => {
|
||||
// Catch any potential error
|
||||
console.log('Failed to retrieve messages from store', e);
|
||||
});
|
||||
waku.store.queryHistory([ContentTopic], { callback }).catch((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.
|
||||
|
@ -195,10 +194,10 @@ startTime.setTime(startTime.getTime() - 7 * 24 * 60 * 60 * 1000);
|
|||
waku.store
|
||||
.queryHistory([ContentTopic], {
|
||||
callback,
|
||||
timeFilter: { startTime, endTime: new Date() }
|
||||
timeFilter: { startTime, endTime: new Date() },
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log('Failed to retrieve messages from store', e);
|
||||
console.log("Failed to retrieve messages from store", e);
|
||||
});
|
||||
```
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ title: Encrypt Messages Using Waku Message Version 1
|
|||
date: 2021-12-09T14:00:00+01:00
|
||||
weight: 4
|
||||
---
|
||||
|
||||
# Encrypt Messages Using Waku Message Version 1
|
||||
|
||||
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:
|
||||
|
||||
```js
|
||||
import { generateSymmetricKey } from 'js-waku';
|
||||
import { generateSymmetricKey } from "js-waku";
|
||||
|
||||
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.
|
||||
|
||||
```js
|
||||
import { WakuMessage } from 'js-waku';
|
||||
import { WakuMessage } from "js-waku";
|
||||
|
||||
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
|
||||
waku.addDecryptionKey(symmetricKey);
|
||||
```
|
||||
|
||||
Alternatively, you can pass the key when creating the instance:
|
||||
|
||||
```js
|
||||
import { Waku } from 'js-waku';
|
||||
import { Waku } from "js-waku";
|
||||
|
||||
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:
|
||||
|
||||
```js
|
||||
import { generatePrivateKey, getPublicKey } from 'js-waku';
|
||||
import { generatePrivateKey, getPublicKey } from "js-waku";
|
||||
|
||||
const privateKey = generatePrivateKey();
|
||||
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.
|
||||
|
||||
```js
|
||||
import { WakuMessage } from 'js-waku';
|
||||
import { WakuMessage } from "js-waku";
|
||||
|
||||
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
|
||||
waku.addDecryptionKey(privateKey);
|
||||
```
|
||||
|
||||
Alternatively, you can pass the key when creating the instance:
|
||||
|
||||
```js
|
||||
import { Waku } from 'js-waku';
|
||||
import { Waku } from "js-waku";
|
||||
|
||||
const waku = Waku.create({ decryptionKeys: [privateKey] });
|
||||
```
|
||||
|
@ -199,10 +202,10 @@ the payload gets encrypted.
|
|||
Which means that `wakuMessage.payload` returns an encrypted payload:
|
||||
|
||||
```js
|
||||
import { WakuMessage } from 'js-waku';
|
||||
import { WakuMessage } from "js-waku";
|
||||
|
||||
const message = await WakuMessage.fromBytes(payload, contentTopic, {
|
||||
encPublicKey: publicKey
|
||||
encPublicKey: publicKey,
|
||||
});
|
||||
|
||||
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):
|
||||
|
||||
```js
|
||||
import { Waku } from 'js-waku';
|
||||
import { Waku } from "js-waku";
|
||||
|
||||
const waku = Waku.create({ decryptionKeys: [privateKey] });
|
||||
|
||||
|
@ -226,12 +229,14 @@ if (messages && messages[0]) {
|
|||
console.log(messages[0].payload); // This payload is decrypted
|
||||
}
|
||||
|
||||
waku.relay.addObserver((message) => {
|
||||
console.log(message.payload); // This payload is decrypted
|
||||
}, [contentTopic]);
|
||||
waku.relay.addObserver(
|
||||
(message) => {
|
||||
console.log(message.payload); // This payload is decrypted
|
||||
},
|
||||
[contentTopic]
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
## 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.
|
||||
|
|
|
@ -3,6 +3,7 @@ title: Sign Messages Using Waku Message Version 1
|
|||
date: 2021-12-09T14:00:00+01:00
|
||||
weight: 5
|
||||
---
|
||||
|
||||
# Sign Messages Using Waku Message Version 1
|
||||
|
||||
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:
|
||||
|
||||
```ts
|
||||
import { generatePrivateKey, getPublicKey } from 'js-waku';
|
||||
import { generatePrivateKey, getPublicKey } from "js-waku";
|
||||
|
||||
const privateKey = generatePrivateKey();
|
||||
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:
|
||||
|
||||
```ts
|
||||
import { WakuMessage } from 'js-waku';
|
||||
import { WakuMessage } from "js-waku";
|
||||
|
||||
const message = await WakuMessage.fromBytes(payload, myAppContentTopic, {
|
||||
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:
|
||||
|
||||
```ts
|
||||
import { hexToBuf } from 'js-waku/lib/utils';
|
||||
import { keccak256 } from 'ethers/lib/utils';
|
||||
import { hexToBuf } from "js-waku/lib/utils";
|
||||
import { keccak256 } from "ethers/lib/utils";
|
||||
|
||||
const symKey = hexToBuf(
|
||||
keccak256(Buffer.from(myAppContentTopic, 'utf-8'))
|
||||
);
|
||||
const symKey = hexToBuf(keccak256(Buffer.from(myAppContentTopic, "utf-8")));
|
||||
```
|
||||
|
||||
`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
|
||||
|
||||
Given `recipientPublicKey` the public key of the message's recipient:
|
||||
Given `recipientPublicKey` the public key of the message's recipient:
|
||||
|
||||
```ts
|
||||
import { WakuMessage } from 'js-waku';
|
||||
import { WakuMessage } from "js-waku";
|
||||
|
||||
const message = await WakuMessage.fromBytes(payload, myAppContentTopic, {
|
||||
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`.
|
||||
|
||||
```ts
|
||||
import { equalByteArrays } from 'js-waku/lib/utils';
|
||||
import { equalByteArrays } from "js-waku/lib/utils";
|
||||
|
||||
const sigPubKey = wakuMessage.signaturePublicKey;
|
||||
|
||||
const isSignedByAlice = sigPubKey && equalByteArrays(sigPubKey, alicePublicKey);
|
||||
|
||||
if (!isSignedByAlice) {
|
||||
// Message is not signed by Alice
|
||||
// Message is not signed by Alice
|
||||
}
|
||||
```
|
||||
|
|
|
@ -3,6 +3,7 @@ title: Send Messages Using Waku Light Push
|
|||
date: 2021-12-09T14:00:00+01:00
|
||||
weight: 6
|
||||
---
|
||||
|
||||
# Send Messages Using Waku Light Push
|
||||
|
||||
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:
|
||||
|
||||
```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.
|
||||
If you want to bootstrap to your own nodes, you can pass an array of multiaddresses instead:
|
||||
|
||||
```js
|
||||
import { Waku } from 'js-waku';
|
||||
import { Waku } from "js-waku";
|
||||
|
||||
const waku = await Waku.create({
|
||||
bootstrap: [
|
||||
'/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.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",
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
|
@ -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.
|
||||
|
||||
```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);
|
||||
if (!ack?.isSuccess) {
|
||||
// Message was not sent
|
||||
// Message was not sent
|
||||
}
|
||||
```
|
||||
|
|
|
@ -3,10 +3,11 @@ title: Receive and Send Messages Using Waku Relay With ReactJS
|
|||
date: 2021-12-09T14:00:00+01:00
|
||||
weight: 7
|
||||
---
|
||||
|
||||
# Receive and Send Messages Using Waku Relay 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.
|
||||
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:
|
||||
|
||||
```js
|
||||
const webpack = require('webpack');
|
||||
const webpack = require("webpack");
|
||||
|
||||
module.exports = {
|
||||
dev: (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'),
|
||||
});
|
||||
dev: (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"),
|
||||
});
|
||||
|
||||
if (!config.plugins) config.plugins = [];
|
||||
config.plugins.push(
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.ENV': JSON.stringify('dev'),
|
||||
})
|
||||
);
|
||||
config.plugins.push(
|
||||
new webpack.ProvidePlugin({
|
||||
process: 'process/browser.js',
|
||||
Buffer: ['buffer', 'Buffer'],
|
||||
})
|
||||
);
|
||||
if (!config.plugins) config.plugins = [];
|
||||
config.plugins.push(
|
||||
new webpack.DefinePlugin({
|
||||
"process.env.ENV": JSON.stringify("dev"),
|
||||
})
|
||||
);
|
||||
config.plugins.push(
|
||||
new webpack.ProvidePlugin({
|
||||
process: "process/browser.js",
|
||||
Buffer: ["buffer", "Buffer"],
|
||||
})
|
||||
);
|
||||
|
||||
if (!config.ignoreWarnings) config.ignoreWarnings = [];
|
||||
config.ignoreWarnings.push(/Failed to parse source map/);
|
||||
if (!config.ignoreWarnings) config.ignoreWarnings = [];
|
||||
config.ignoreWarnings.push(/Failed to parse source map/);
|
||||
|
||||
return config;
|
||||
},
|
||||
prod: (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'),
|
||||
});
|
||||
return config;
|
||||
},
|
||||
prod: (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"),
|
||||
});
|
||||
|
||||
if (!config.plugins) config.plugins = [];
|
||||
config.plugins.push(
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.ENV': JSON.stringify('prod'),
|
||||
})
|
||||
);
|
||||
config.plugins.push(
|
||||
new webpack.ProvidePlugin({
|
||||
process: 'process/browser.js',
|
||||
Buffer: ['buffer', 'Buffer'],
|
||||
})
|
||||
);
|
||||
if (!config.plugins) config.plugins = [];
|
||||
config.plugins.push(
|
||||
new webpack.DefinePlugin({
|
||||
"process.env.ENV": JSON.stringify("prod"),
|
||||
})
|
||||
);
|
||||
config.plugins.push(
|
||||
new webpack.ProvidePlugin({
|
||||
process: "process/browser.js",
|
||||
Buffer: ["buffer", "Buffer"],
|
||||
})
|
||||
);
|
||||
|
||||
if (!config.ignoreWarnings) config.ignoreWarnings = [];
|
||||
config.ignoreWarnings.push(/Failed to parse source map/);
|
||||
if (!config.ignoreWarnings) config.ignoreWarnings = [];
|
||||
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:
|
||||
|
||||
```js
|
||||
import {Waku} from 'js-waku';
|
||||
import * as React from 'react';
|
||||
import { Waku } from "js-waku";
|
||||
import * as React from "react";
|
||||
|
||||
function App() {
|
||||
const [waku, setWaku] = React.useState(undefined);
|
||||
const [wakuStatus, setWakuStatus] = React.useState('None');
|
||||
const [waku, setWaku] = React.useState(undefined);
|
||||
const [wakuStatus, setWakuStatus] = React.useState("None");
|
||||
|
||||
// Start Waku
|
||||
React.useEffect(() => {
|
||||
// If Waku is already assigned, the job is done
|
||||
if (!!waku) return;
|
||||
// If Waku status not None, it means we are already starting Waku
|
||||
if (wakuStatus !== 'None') return;
|
||||
// Start Waku
|
||||
React.useEffect(() => {
|
||||
// If Waku is already assigned, the job is done
|
||||
if (!!waku) return;
|
||||
// If Waku status not None, it means we are already starting Waku
|
||||
if (wakuStatus !== "None") return;
|
||||
|
||||
setWakuStatus('Starting');
|
||||
setWakuStatus("Starting");
|
||||
|
||||
// Create Waku
|
||||
Waku.create({bootstrap: {default: true}}).then((waku) => {
|
||||
// Once done, put it in the state
|
||||
setWaku(waku);
|
||||
// And update the status
|
||||
setWakuStatus('Started');
|
||||
});
|
||||
}, [waku, wakuStatus]);
|
||||
// Create Waku
|
||||
Waku.create({ bootstrap: { default: true } }).then((waku) => {
|
||||
// Once done, put it in the state
|
||||
setWaku(waku);
|
||||
// And update the status
|
||||
setWakuStatus("Started");
|
||||
});
|
||||
}, [waku, wakuStatus]);
|
||||
|
||||
return (
|
||||
<div className='App'>
|
||||
<header className='App-header'>
|
||||
<p>Waku node's status: {wakuStatus}</p>
|
||||
</header>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<p>Waku node's status: {wakuStatus}</p>
|
||||
</header>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
@ -216,18 +217,18 @@ use the `Waku.waitForConnectedPeer()` async function:
|
|||
|
||||
```js
|
||||
React.useEffect(() => {
|
||||
if (!!waku) return;
|
||||
if (wakuStatus !== 'None') return;
|
||||
if (!!waku) return;
|
||||
if (wakuStatus !== "None") return;
|
||||
|
||||
setWakuStatus('Starting');
|
||||
setWakuStatus("Starting");
|
||||
|
||||
Waku.create({bootstrap: {default: true}}).then((waku) => {
|
||||
setWaku(waku);
|
||||
setWakuStatus('Connecting');
|
||||
waku.waitForConnectedPeer().then(() => {
|
||||
setWakuStatus('Ready');
|
||||
});
|
||||
Waku.create({ bootstrap: { default: true } }).then((waku) => {
|
||||
setWaku(waku);
|
||||
setWakuStatus("Connecting");
|
||||
waku.waitForConnectedPeer().then(() => {
|
||||
setWakuStatus("Ready");
|
||||
});
|
||||
});
|
||||
}, [waku, wakuStatus]);
|
||||
```
|
||||
|
||||
|
@ -243,7 +244,7 @@ npm install protons
|
|||
Define `SimpleChatMessage` with two fields: `timestamp` and `text`.
|
||||
|
||||
```js
|
||||
import protons from 'protons';
|
||||
import protons from "protons";
|
||||
|
||||
const proto = protons(`
|
||||
message SimpleChatMessage {
|
||||
|
@ -258,7 +259,7 @@ message SimpleChatMessage {
|
|||
Create a function that takes the Waku instance and a message to send:
|
||||
|
||||
```js
|
||||
import { WakuMessage } from 'js-waku';
|
||||
import { WakuMessage } from "js-waku";
|
||||
|
||||
const ContentTopic = `/relay-reactjs-chat/1/chat/proto`;
|
||||
|
||||
|
@ -268,7 +269,7 @@ function sendMessage(message, waku, timestamp) {
|
|||
// Encode to protobuf
|
||||
const payload = proto.SimpleChatMessage.encode({
|
||||
timestamp: time,
|
||||
text: message
|
||||
text: message,
|
||||
});
|
||||
|
||||
// Wrap in a Waku Message
|
||||
|
@ -284,20 +285,20 @@ Then, add a button to the `App` function:
|
|||
```js
|
||||
function App() {
|
||||
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
|
||||
const [sendCounter, setSendCounter] = React.useState(0);
|
||||
|
||||
|
||||
React.useEffect(() => {
|
||||
// ... creates Waku
|
||||
}, [waku, wakuStatus]);
|
||||
|
||||
const sendMessageOnClick = () => {
|
||||
// Check Waku is started and connected first.
|
||||
if (wakuStatus !== 'Ready') return;
|
||||
if (wakuStatus !== "Ready") return;
|
||||
|
||||
sendMessage(`Here is message #${sendCounter}`, waku, new Date()).then(() =>
|
||||
console.log('Message sent')
|
||||
console.log("Message sent")
|
||||
);
|
||||
|
||||
// For demonstration purposes.
|
||||
|
@ -308,7 +309,7 @@ function App() {
|
|||
<div className="App">
|
||||
<header className="App-header">
|
||||
<p>{wakuStatus}</p>
|
||||
<button onClick={sendMessageOnClick} disabled={wakuStatus !== 'Ready'}>
|
||||
<button onClick={sendMessageOnClick} disabled={wakuStatus !== "Ready"}>
|
||||
Send Message
|
||||
</button>
|
||||
</header>
|
||||
|
@ -393,6 +394,7 @@ function App() {
|
|||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Then, render the messages:
|
||||
|
||||
```js
|
||||
|
@ -403,7 +405,7 @@ function App() {
|
|||
<div className="App">
|
||||
<header className="App-header">
|
||||
<p>{wakuStatus}</p>
|
||||
<button onClick={sendMessageOnClick} disabled={wakuStatus !== 'Ready'}>
|
||||
<button onClick={sendMessageOnClick} disabled={wakuStatus !== "Ready"}>
|
||||
Send Message
|
||||
</button>
|
||||
<ul>
|
||||
|
|
|
@ -3,6 +3,7 @@ title: Retrieve Messages Using Waku Store With ReactJS
|
|||
date: 2021-12-09T14:00:00+01:00
|
||||
weight: 8
|
||||
---
|
||||
|
||||
# Retrieve Messages Using Waku Store 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:
|
||||
|
||||
```js
|
||||
const webpack = require('webpack');
|
||||
const webpack = require("webpack");
|
||||
|
||||
module.exports = {
|
||||
dev: (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'),
|
||||
});
|
||||
dev: (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"),
|
||||
});
|
||||
|
||||
if (!config.plugins) config.plugins = [];
|
||||
config.plugins.push(
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.ENV': JSON.stringify('dev'),
|
||||
})
|
||||
);
|
||||
config.plugins.push(
|
||||
new webpack.ProvidePlugin({
|
||||
process: 'process/browser.js',
|
||||
Buffer: ['buffer', 'Buffer'],
|
||||
})
|
||||
);
|
||||
if (!config.plugins) config.plugins = [];
|
||||
config.plugins.push(
|
||||
new webpack.DefinePlugin({
|
||||
"process.env.ENV": JSON.stringify("dev"),
|
||||
})
|
||||
);
|
||||
config.plugins.push(
|
||||
new webpack.ProvidePlugin({
|
||||
process: "process/browser.js",
|
||||
Buffer: ["buffer", "Buffer"],
|
||||
})
|
||||
);
|
||||
|
||||
if (!config.ignoreWarnings) config.ignoreWarnings = [];
|
||||
config.ignoreWarnings.push(/Failed to parse source map/);
|
||||
if (!config.ignoreWarnings) config.ignoreWarnings = [];
|
||||
config.ignoreWarnings.push(/Failed to parse source map/);
|
||||
|
||||
return config;
|
||||
},
|
||||
prod: (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'),
|
||||
});
|
||||
return config;
|
||||
},
|
||||
prod: (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"),
|
||||
});
|
||||
|
||||
if (!config.plugins) config.plugins = [];
|
||||
config.plugins.push(
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.ENV': JSON.stringify('prod'),
|
||||
})
|
||||
);
|
||||
config.plugins.push(
|
||||
new webpack.ProvidePlugin({
|
||||
process: 'process/browser.js',
|
||||
Buffer: ['buffer', 'Buffer'],
|
||||
})
|
||||
);
|
||||
if (!config.plugins) config.plugins = [];
|
||||
config.plugins.push(
|
||||
new webpack.DefinePlugin({
|
||||
"process.env.ENV": JSON.stringify("prod"),
|
||||
})
|
||||
);
|
||||
config.plugins.push(
|
||||
new webpack.ProvidePlugin({
|
||||
process: "process/browser.js",
|
||||
Buffer: ["buffer", "Buffer"],
|
||||
})
|
||||
);
|
||||
|
||||
if (!config.ignoreWarnings) config.ignoreWarnings = [];
|
||||
config.ignoreWarnings.push(/Failed to parse source map/);
|
||||
if (!config.ignoreWarnings) config.ignoreWarnings = [];
|
||||
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
|
||||
npm install
|
||||
```
|
||||
|
||||
{{< /hint >}}
|
||||
|
||||
# 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:
|
||||
|
||||
```js
|
||||
import {Waku} from 'js-waku';
|
||||
import * as React from 'react';
|
||||
import { Waku } from "js-waku";
|
||||
import * as React from "react";
|
||||
|
||||
function App() {
|
||||
const [waku, setWaku] = React.useState(undefined);
|
||||
const [wakuStatus, setWakuStatus] = React.useState('None');
|
||||
const [waku, setWaku] = React.useState(undefined);
|
||||
const [wakuStatus, setWakuStatus] = React.useState("None");
|
||||
|
||||
// Start Waku
|
||||
React.useEffect(() => {
|
||||
// If Waku status not None, it means we are already starting Waku
|
||||
if (wakuStatus !== 'None') return;
|
||||
// Start Waku
|
||||
React.useEffect(() => {
|
||||
// If Waku status not None, it means we are already starting Waku
|
||||
if (wakuStatus !== "None") return;
|
||||
|
||||
setWakuStatus('Starting');
|
||||
setWakuStatus("Starting");
|
||||
|
||||
// Create Waku
|
||||
Waku.create({bootstrap: {default: true}}).then((waku) => {
|
||||
// Once done, put it in the state
|
||||
setWaku(waku);
|
||||
// And update the status
|
||||
setWakuStatus('Connecting');
|
||||
});
|
||||
}, [waku, wakuStatus]);
|
||||
// Create Waku
|
||||
Waku.create({ bootstrap: { default: true } }).then((waku) => {
|
||||
// Once done, put it in the state
|
||||
setWaku(waku);
|
||||
// And update the status
|
||||
setWakuStatus("Connecting");
|
||||
});
|
||||
}, [waku, wakuStatus]);
|
||||
|
||||
return (
|
||||
<div className='App'>
|
||||
<header className='App-header'>
|
||||
<p>{wakuStatus}</p>
|
||||
</header>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<p>{wakuStatus}</p>
|
||||
</header>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
@ -243,10 +245,10 @@ use the `Waku.waitForConnectedPeer()` async function:
|
|||
React.useEffect(() => {
|
||||
if (!waku) return;
|
||||
|
||||
if (wakuStatus === 'Connected') return;
|
||||
if (wakuStatus === "Connected") return;
|
||||
|
||||
waku.waitForConnectedPeer().then(() => {
|
||||
setWakuStatus('Connected');
|
||||
setWakuStatus("Connected");
|
||||
});
|
||||
}, [waku, wakuStatus]);
|
||||
```
|
||||
|
@ -281,7 +283,7 @@ npm install protons
|
|||
Define the data structure with protons:
|
||||
|
||||
```js
|
||||
import protons from 'protons';
|
||||
import protons from "protons";
|
||||
|
||||
const proto = protons(`
|
||||
message ChatMessage {
|
||||
|
@ -314,11 +316,10 @@ function decodeMessage(wakuMessage) {
|
|||
const time = new Date();
|
||||
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 };
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Retrieve messages
|
||||
|
@ -355,32 +356,31 @@ const processMessages = (retrievedMessages) => {
|
|||
Pass `processMessage` in `WakuStore.queryHistory` as the `callback` value:
|
||||
|
||||
```js
|
||||
waku.store
|
||||
.queryHistory([ContentTopic], { callback: processMessages });
|
||||
waku.store.queryHistory([ContentTopic], { callback: processMessages });
|
||||
```
|
||||
|
||||
Finally, create a `Messages` component to render the messages:
|
||||
|
||||
```tsx
|
||||
function Messages(props) {
|
||||
return props.messages.map(({ text, timestamp, nick }) => {
|
||||
return (
|
||||
<li>
|
||||
({formatDate(timestamp)}) {nick}: {text}
|
||||
</li>
|
||||
);
|
||||
});
|
||||
return props.messages.map(({ text, timestamp, nick }) => {
|
||||
return (
|
||||
<li>
|
||||
({formatDate(timestamp)}) {nick}: {text}
|
||||
</li>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function formatDate(timestamp) {
|
||||
return timestamp.toLocaleString([], {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
hour12: false,
|
||||
});
|
||||
return timestamp.toLocaleString([], {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
hour12: false,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -391,8 +391,8 @@ function App() {
|
|||
// [..]
|
||||
|
||||
return (
|
||||
<div className='App'>
|
||||
<header className='App-header'>
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<h2>{wakuStatus}</h2>
|
||||
<h3>Messages</h3>
|
||||
<ul>
|
||||
|
@ -407,11 +407,11 @@ function App() {
|
|||
All together, you should now have:
|
||||
|
||||
```js
|
||||
import {Waku} from 'js-waku';
|
||||
import * as React from 'react';
|
||||
import protons from 'protons';
|
||||
import { Waku } from "js-waku";
|
||||
import * as React from "react";
|
||||
import protons from "protons";
|
||||
|
||||
const ContentTopic = '/toy-chat/2/huilong/proto';
|
||||
const ContentTopic = "/toy-chat/2/huilong/proto";
|
||||
|
||||
const proto = protons(`
|
||||
message ChatMessage {
|
||||
|
@ -422,107 +422,106 @@ message ChatMessage {
|
|||
`);
|
||||
|
||||
function App() {
|
||||
const [waku, setWaku] = React.useState(undefined);
|
||||
const [wakuStatus, setWakuStatus] = React.useState('None');
|
||||
const [messages, setMessages] = React.useState([]);
|
||||
const [waku, setWaku] = React.useState(undefined);
|
||||
const [wakuStatus, setWakuStatus] = React.useState("None");
|
||||
const [messages, setMessages] = React.useState([]);
|
||||
|
||||
// Start Waku
|
||||
React.useEffect(() => {
|
||||
// If Waku status not None, it means we are already starting Waku
|
||||
if (wakuStatus !== 'None') return;
|
||||
// Start Waku
|
||||
React.useEffect(() => {
|
||||
// If Waku status not None, it means we are already starting Waku
|
||||
if (wakuStatus !== "None") return;
|
||||
|
||||
setWakuStatus('Starting');
|
||||
setWakuStatus("Starting");
|
||||
|
||||
// Create Waku
|
||||
Waku.create({bootstrap: {default: true}}).then((waku) => {
|
||||
// Once done, put it in the state
|
||||
setWaku(waku);
|
||||
// And update the status
|
||||
setWakuStatus('Connecting');
|
||||
});
|
||||
}, [waku, wakuStatus]);
|
||||
// Create Waku
|
||||
Waku.create({ bootstrap: { default: true } }).then((waku) => {
|
||||
// Once done, put it in the state
|
||||
setWaku(waku);
|
||||
// And update the status
|
||||
setWakuStatus("Connecting");
|
||||
});
|
||||
}, [waku, wakuStatus]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!waku) return;
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!waku) return;
|
||||
if (wakuStatus === "Connected") return;
|
||||
|
||||
if (wakuStatus === 'Connected') return;
|
||||
waku.waitForConnectedPeer().then(() => {
|
||||
setWakuStatus("Connected");
|
||||
});
|
||||
}, [waku, wakuStatus]);
|
||||
|
||||
waku.waitForConnectedPeer().then(() => {
|
||||
setWakuStatus('Connected');
|
||||
});
|
||||
}, [waku, wakuStatus]);
|
||||
React.useEffect(() => {
|
||||
if (wakuStatus !== "Connected") return;
|
||||
|
||||
React.useEffect(() => {
|
||||
if (wakuStatus !== 'Connected') return;
|
||||
const processMessages = (retrievedMessages) => {
|
||||
const messages = retrievedMessages.map(decodeMessage).filter(Boolean);
|
||||
|
||||
const processMessages = (retrievedMessages) => {
|
||||
const messages = retrievedMessages.map(decodeMessage).filter(Boolean);
|
||||
setMessages((currentMessages) => {
|
||||
return currentMessages.concat(messages.reverse());
|
||||
});
|
||||
};
|
||||
|
||||
setMessages((currentMessages) => {
|
||||
return currentMessages.concat(messages.reverse());
|
||||
});
|
||||
};
|
||||
waku.store
|
||||
.queryHistory([ContentTopic], { callback: processMessages })
|
||||
.catch((e) => {
|
||||
console.log("Failed to retrieve messages", e);
|
||||
});
|
||||
}, [waku, wakuStatus]);
|
||||
|
||||
waku.store
|
||||
.queryHistory([ContentTopic], {callback: processMessages})
|
||||
.catch((e) => {
|
||||
console.log('Failed to retrieve messages', e);
|
||||
});
|
||||
}, [waku, wakuStatus]);
|
||||
|
||||
return (
|
||||
<div className='App'>
|
||||
<header className='App-header'>
|
||||
<h2>{wakuStatus}</h2>
|
||||
<h3>Messages</h3>
|
||||
<ul>
|
||||
<Messages messages={messages}/>
|
||||
</ul>
|
||||
</header>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<h2>{wakuStatus}</h2>
|
||||
<h3>Messages</h3>
|
||||
<ul>
|
||||
<Messages messages={messages} />
|
||||
</ul>
|
||||
</header>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
||||
function decodeMessage(wakuMessage) {
|
||||
if (!wakuMessage.payload) return;
|
||||
if (!wakuMessage.payload) return;
|
||||
|
||||
const {timestamp, nick, text} = proto.ChatMessage.decode(
|
||||
wakuMessage.payload
|
||||
);
|
||||
const { timestamp, nick, text } = proto.ChatMessage.decode(
|
||||
wakuMessage.payload
|
||||
);
|
||||
|
||||
// All fields in protobuf are optional so be sure to check
|
||||
if (!timestamp || !text || !nick) return;
|
||||
// All fields in protobuf are optional so be sure to check
|
||||
if (!timestamp || !text || !nick) return;
|
||||
|
||||
const time = new Date();
|
||||
time.setTime(timestamp);
|
||||
const time = new Date();
|
||||
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) {
|
||||
return props.messages.map(({text, timestamp, nick}) => {
|
||||
return (
|
||||
<li>
|
||||
({formatDate(timestamp)}) {nick}: {text}
|
||||
</li>
|
||||
);
|
||||
});
|
||||
return props.messages.map(({ text, timestamp, nick }) => {
|
||||
return (
|
||||
<li>
|
||||
({formatDate(timestamp)}) {nick}: {text}
|
||||
</li>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function formatDate(timestamp) {
|
||||
return timestamp.toLocaleString([], {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
hour12: false,
|
||||
});
|
||||
return timestamp.toLocaleString([], {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
hour12: false,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -552,11 +551,10 @@ const startTime = new Date();
|
|||
// 7 days/week, 24 hours/day, 60min/hour, 60secs/min, 100ms/sec
|
||||
startTime.setTime(startTime.getTime() - 7 * 24 * 60 * 60 * 1000);
|
||||
|
||||
waku.store
|
||||
.queryHistory([ContentTopic], {
|
||||
callback: processMessages,
|
||||
timeFilter: { startTime, endTime: new Date() }
|
||||
});
|
||||
waku.store.queryHistory([ContentTopic], {
|
||||
callback: processMessages,
|
||||
timeFilter: { startTime, endTime: new Date() },
|
||||
});
|
||||
```
|
||||
|
||||
## End result
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
weight: 30
|
||||
---
|
||||
|
||||
# Guides
|
||||
|
||||
## Waku Concepts
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
weight: 100
|
||||
---
|
||||
|
||||
# WakuConnect Vote & Poll SDK
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
### Documentation
|
||||
|
|
|
@ -13,7 +13,6 @@ 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
|
||||
|
@ -64,29 +63,28 @@ yarn add -D react-app-rewired
|
|||
Create a `config-overrides.js` file at the root of your app:
|
||||
|
||||
```js
|
||||
const webpack = require('webpack');
|
||||
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"),
|
||||
});
|
||||
|
||||
// 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"],
|
||||
})
|
||||
);
|
||||
|
||||
if (!config.plugins) config.plugins = []
|
||||
config.plugins.push(
|
||||
new webpack.ProvidePlugin({
|
||||
Buffer: ['buffer', 'Buffer'],
|
||||
}));
|
||||
|
||||
return config;
|
||||
}
|
||||
return config;
|
||||
};
|
||||
```
|
||||
|
||||
Use `react-app-rewired` in the `package.json`, instead of `react-scripts`:
|
||||
|
|
|
@ -25,31 +25,31 @@ 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)
|
||||
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])
|
||||
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>
|
||||
)
|
||||
return (
|
||||
<div>
|
||||
<TopBar
|
||||
logo={""}
|
||||
logoWidth={84}
|
||||
title={"Poll dApp"}
|
||||
theme={orangeTheme}
|
||||
activate={activateBrowserWallet}
|
||||
account={account}
|
||||
deactivate={deactivate}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -60,25 +60,27 @@ export function PollPage() {
|
|||
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";
|
||||
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,
|
||||
},
|
||||
}
|
||||
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).
|
||||
|
@ -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:
|
||||
|
||||
```tsx
|
||||
import styled from 'styled-components'
|
||||
import styled from "styled-components";
|
||||
|
||||
const Wrapper = styled.div`
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
`
|
||||
`;
|
||||
```
|
||||
|
||||
### Render
|
||||
|
@ -103,97 +105,99 @@ Finally, create the `App` component:
|
|||
|
||||
```tsx
|
||||
export function App() {
|
||||
return (
|
||||
<Wrapper>
|
||||
<GlobalStyle/>
|
||||
<DAppProvider config={config}>
|
||||
<PollPage/>
|
||||
</DAppProvider>
|
||||
</Wrapper>
|
||||
)
|
||||
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'
|
||||
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,
|
||||
},
|
||||
}
|
||||
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)
|
||||
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])
|
||||
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>
|
||||
)
|
||||
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>
|
||||
)
|
||||
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')
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById("root")
|
||||
);
|
||||
```
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ touch components/Poll.tsx
|
|||
Again, create a `Wrapper` for styling:
|
||||
|
||||
```tsx
|
||||
import styled from 'styled-components'
|
||||
import styled from "styled-components";
|
||||
|
||||
const Wrapper = styled.div`
|
||||
display: flex;
|
||||
|
@ -40,7 +40,7 @@ const Wrapper = styled.div`
|
|||
@media (max-width: 425px) {
|
||||
padding: 96px 16px 84px;
|
||||
}
|
||||
`
|
||||
`;
|
||||
```
|
||||
|
||||
## Button
|
||||
|
@ -56,67 +56,74 @@ 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'
|
||||
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
|
||||
}
|
||||
signer: JsonRpcSigner | undefined;
|
||||
theme: Theme;
|
||||
};
|
||||
|
||||
export function Poll({signer, theme}: PollProps) {
|
||||
const [showPollCreation, setShowPollCreation] = useState(false)
|
||||
export function Poll({ signer, theme }: PollProps) {
|
||||
const [showPollCreation, setShowPollCreation] = useState(false);
|
||||
|
||||
const disabled = !signer;
|
||||
const disabled = !signer;
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
{
|
||||
<CreateButton style={{backgroundColor: disabled ? "lightgrey" : theme.primaryColor}} theme={theme}
|
||||
disabled={disabled}
|
||||
onClick={() => setShowPollCreation(true)}>
|
||||
Create a poll
|
||||
</CreateButton>
|
||||
}
|
||||
</Wrapper>
|
||||
)
|
||||
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)
|
||||
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])
|
||||
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>
|
||||
)
|
||||
return (
|
||||
<div>
|
||||
<TopBar
|
||||
logo={""}
|
||||
logoWidth={84}
|
||||
title={"Poll dApp"}
|
||||
theme={orangeTheme}
|
||||
activate={activateBrowserWallet}
|
||||
account={account}
|
||||
deactivate={deactivate}
|
||||
/>
|
||||
<Poll theme={orangeTheme} signer={signer} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -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`.
|
||||
|
||||
`useWakuPolling` takes:
|
||||
|
||||
- `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.
|
||||
- `tokenAddress`: The address of your ERC-20 token.
|
||||
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`.
|
||||
|
||||
`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";
|
||||
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
|
||||
}
|
||||
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])
|
||||
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;
|
||||
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>
|
||||
)
|
||||
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>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -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.
|
||||
|
||||
`index.tsx`
|
||||
|
||||
```tsx
|
||||
export function PollPage() {
|
||||
const {account, library, activateBrowserWallet, deactivate, chainId} = useEthers()
|
||||
const [signer, setSigner] = useState<undefined | JsonRpcSigner>(undefined)
|
||||
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])
|
||||
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>
|
||||
)
|
||||
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>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -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`:
|
||||
|
||||
`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";
|
||||
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
|
||||
}
|
||||
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])
|
||||
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;
|
||||
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>
|
||||
)
|
||||
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'}/>
|
||||
<Poll
|
||||
theme={orangeTheme}
|
||||
appName={"demo-poll-dapp"}
|
||||
library={library}
|
||||
signer={signer}
|
||||
chainId={chainId}
|
||||
account={account}
|
||||
tokenAddress={"0x744d70FDBE2Ba4CF95131626614a1763DF805B9E"}
|
||||
/>
|
||||
```
|
||||
|
||||
Et voila!
|
||||
|
@ -77,12 +107,11 @@ You can find the resulting code in the [examples folder](https://github.com/stat
|
|||
|
||||
{{< 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).
|
||||
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:
|
||||
|
||||
![Poll demo](/assets/poll_sdk/wakuconnect-poll-demo.gif)
|
||||
|
||||
|
||||
{{< button relref="./04_poll_creation" >}}Back{{< /button >}}
|
||||
|
|
|
@ -3,6 +3,7 @@ title: Introduction
|
|||
date: 2021-12-09T14:00:00+01:00
|
||||
weight: 10
|
||||
---
|
||||
|
||||
# WakuConnect Docs
|
||||
|
||||
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 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/).
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ title: Presentations & Videos
|
|||
date: 2022-01-12T01:00:00+01:00
|
||||
weight: 22
|
||||
---
|
||||
|
||||
# Presentations & Videos
|
||||
|
||||
## 17 Sep 2021 - EthOnline
|
||||
|
|
|
@ -3,6 +3,7 @@ title: Quick Start
|
|||
date: 2021-12-09T14:00:00+01:00
|
||||
weight: 20
|
||||
---
|
||||
|
||||
# Quick Start
|
||||
|
||||
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
|
||||
|
||||
```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
|
||||
|
@ -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/):
|
||||
|
||||
```ts
|
||||
waku.relay.addObserver((msg) => {
|
||||
console.log("Message received:", msg.payloadAsUtf8)
|
||||
}, ["/my-cool-app/1/my-use-case/proto"]);
|
||||
waku.relay.addObserver(
|
||||
(msg) => {
|
||||
console.log("Message received:", msg.payloadAsUtf8);
|
||||
},
|
||||
["/my-cool-app/1/my-use-case/proto"]
|
||||
);
|
||||
```
|
||||
|
||||
### Send messages
|
||||
|
@ -48,12 +52,15 @@ waku.relay.addObserver((msg) => {
|
|||
Messages are wrapped in a `WakuMessage` envelop.
|
||||
|
||||
```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);
|
||||
```
|
||||
|
||||
### 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.
|
||||
|
|
|
@ -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).
|
||||
|
||||
Legend:
|
||||
|
||||
- _Live_: We are aware of projects who have implemented 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.
|
||||
- _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.
|
||||
|
||||
---
|
||||
|
||||
{{< columns >}}
|
||||
|
@ -27,7 +29,7 @@ Legend:
|
|||
## Chat Messenger
|
||||
|
||||
| _Work In Progress_ |
|
||||
|--------------------|
|
||||
| ------------------ |
|
||||
|
||||
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
|
||||
|
||||
| _SDK Available_ |
|
||||
|-----------------|
|
||||
| --------------- |
|
||||
|
||||
Create, answer and view polls which are censorship-resistant.
|
||||
|
||||
|
@ -51,7 +53,7 @@ Create, answer and view polls which are censorship-resistant.
|
|||
## NFT Marketplace
|
||||
|
||||
| _Live_ |
|
||||
|--------|
|
||||
| ------ |
|
||||
|
||||
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.
|
||||
|
@ -67,7 +69,7 @@ Add a social media layer, allowing NFT owners to like, comments, etc.
|
|||
## State Channels
|
||||
|
||||
| _Idea_ |
|
||||
|--------|
|
||||
| ------ |
|
||||
|
||||
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
|
||||
|
||||
| _SDK Available_ |
|
||||
|-----------------|
|
||||
| --------------- |
|
||||
|
||||
For proposals submitted on the blockchain,
|
||||
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
|
||||
|
||||
| _Idea_ |
|
||||
|--------|
|
||||
| ------ |
|
||||
|
||||
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.
|
||||
|
@ -109,7 +111,7 @@ private & censorship-resistant manner to approve transactions.
|
|||
## Gameplay Communication
|
||||
|
||||
| _Proof of Concept_ |
|
||||
|--------------------|
|
||||
| ------------------ |
|
||||
|
||||
Use Waku as the communication layer for a peer-to-peer, decentralize game.
|
||||
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
|
||||
|
||||
| _Live_ |
|
||||
|--------|
|
||||
| ------ |
|
||||
|
||||
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),
|
||||
|
@ -135,7 +137,7 @@ or for a dApp to request transaction signature to the wallet.
|
|||
## Layer 2 Communication
|
||||
|
||||
| _Idea_ |
|
||||
|--------|
|
||||
| ------ |
|
||||
|
||||
Use Waku as an existing communication network to broadcast and aggregate layer 2 transactions.
|
||||
Possibly increasing privacy, anonymity and resilience.
|
||||
|
@ -149,7 +151,7 @@ Possibly increasing privacy, anonymity and resilience.
|
|||
## Generalized Marketplace
|
||||
|
||||
| _Proof of Concept_ |
|
||||
|--------------------|
|
||||
| ------------------ |
|
||||
|
||||
Use Waku to enable users to offer, bid, accept and trade goods and services
|
||||
to create a ride-sharing or tradings apps.
|
||||
|
@ -163,7 +165,7 @@ to create a ride-sharing or tradings apps.
|
|||
## Social Media Platform
|
||||
|
||||
| _Idea_ |
|
||||
|--------|
|
||||
| ------ |
|
||||
|
||||
[Chat Messenger](#chat-messenger) is one form of social media that can be empowered by Waku to be decentralized
|
||||
and censorship-resistant.
|
||||
|
|
|
@ -3,6 +3,7 @@ title: Implemented Waku Protocols
|
|||
date: 2021-12-09T14:00:00+01:00
|
||||
weight: 60
|
||||
---
|
||||
|
||||
## Waku Protocol Support
|
||||
|
||||
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
|
||||
- ⛔: Support is not planned
|
||||
|
||||
| Spec | Implementation Status |
|
||||
| ---- | -------------- |
|
||||
|[6/WAKU1](https://rfc.vac.dev/spec/6)|⛔|
|
||||
|[7/WAKU-DATA](https://rfc.vac.dev/spec/7)|⛔|
|
||||
|[8/WAKU-MAIL](https://rfc.vac.dev/spec/8)|⛔|
|
||||
|[9/WAKU-RPC](https://rfc.vac.dev/spec/9)|⛔|
|
||||
|[10/WAKU2](https://rfc.vac.dev/spec/10)|🚧|
|
||||
|[11/WAKU2-RELAY](https://rfc.vac.dev/spec/11)|✔|
|
||||
|[12/WAKU2-FILTER](https://rfc.vac.dev/spec/12)||
|
||||
|[13/WAKU2-STORE](https://rfc.vac.dev/spec/13)|✔ (querying node only)|
|
||||
|[14/WAKU2-MESSAGE](https://rfc.vac.dev/spec/14)|✔|
|
||||
|[15/WAKU2-BRIDGE](https://rfc.vac.dev/spec/15)||
|
||||
|[16/WAKU2-RPC](https://rfc.vac.dev/spec/16)|⛔|
|
||||
|[17/WAKU2-RLNRELAY](https://rfc.vac.dev/spec/17)||
|
||||
|[18/WAKU2-SWAP](https://rfc.vac.dev/spec/18)||
|
||||
|[19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/)|✔|
|
||||
|[20/TOY-ETH-PM](https://rfc.vac.dev/spec/20/)|✔ (as example)|
|
||||
|[21/WAKU2-FTSTORE](https://rfc.vac.dev/spec/21/)|✔|
|
||||
|[22/TOY-CHAT](https://rfc.vac.dev/spec/22/)|✔ (as example)|
|
||||
|[25/LIBP2P-DNS-DISCOVERY](https://rfc.vac.dev/spec/25/)|🚧|
|
||||
|[26/WAKU2-PAYLOAD](https://rfc.vac.dev/spec/26/)|✔|
|
||||
| Spec | Implementation Status |
|
||||
| ------------------------------------------------------- | ---------------------- |
|
||||
| [6/WAKU1](https://rfc.vac.dev/spec/6) | ⛔ |
|
||||
| [7/WAKU-DATA](https://rfc.vac.dev/spec/7) | ⛔ |
|
||||
| [8/WAKU-MAIL](https://rfc.vac.dev/spec/8) | ⛔ |
|
||||
| [9/WAKU-RPC](https://rfc.vac.dev/spec/9) | ⛔ |
|
||||
| [10/WAKU2](https://rfc.vac.dev/spec/10) | 🚧 |
|
||||
| [11/WAKU2-RELAY](https://rfc.vac.dev/spec/11) | ✔ |
|
||||
| [12/WAKU2-FILTER](https://rfc.vac.dev/spec/12) | |
|
||||
| [13/WAKU2-STORE](https://rfc.vac.dev/spec/13) | ✔ (querying node only) |
|
||||
| [14/WAKU2-MESSAGE](https://rfc.vac.dev/spec/14) | ✔ |
|
||||
| [15/WAKU2-BRIDGE](https://rfc.vac.dev/spec/15) | |
|
||||
| [16/WAKU2-RPC](https://rfc.vac.dev/spec/16) | ⛔ |
|
||||
| [17/WAKU2-RLNRELAY](https://rfc.vac.dev/spec/17) | |
|
||||
| [18/WAKU2-SWAP](https://rfc.vac.dev/spec/18) | |
|
||||
| [19/WAKU2-LIGHTPUSH](https://rfc.vac.dev/spec/19/) | ✔ |
|
||||
| [20/TOY-ETH-PM](https://rfc.vac.dev/spec/20/) | ✔ (as example) |
|
||||
| [21/WAKU2-FTSTORE](https://rfc.vac.dev/spec/21/) | ✔ |
|
||||
| [22/TOY-CHAT](https://rfc.vac.dev/spec/22/) | ✔ (as example) |
|
||||
| [25/LIBP2P-DNS-DISCOVERY](https://rfc.vac.dev/spec/25/) | 🚧 |
|
||||
| [26/WAKU2-PAYLOAD](https://rfc.vac.dev/spec/26/) | ✔ |
|
||||
|
|
Loading…
Reference in New Issue