docs.wakuconnect.dev/en.search-data.min.dd2c536f...

1 line
85 KiB
JSON

[{"id":0,"href":"/docs/guides/vote_poll_sdk/poll_sdk/","title":"Poll SDK","section":"Vote Poll Sdk","content":"How to Use the WakuConnect Poll SDK # To demonstrate how to use the WakuConnect Poll SDK in your dApp, we will create a TypeScript React app from scratch.\nYou can then adapt the steps depending on your dApp configuration and build setup.\nThe resulting code of this guide can be found at https://github.com/status-im/wakuconnect-vote-poll-sdk/tree/main/examples/mainnet-poll.\nHere is a preview of the end result:\nGet Started "},{"id":1,"href":"/docs/guides/01_choose_content_topic/","title":"How to Choose a Content Topic","section":"Guides","content":"How to Choose a Content Topic # A content topic is used for content based filtering.\nIt allows you to filter out the messages that your dApp processes, both when receiving live messages (Relay) or retrieving historical messages (Store).\nThe format for content topics is as follows:\n/{dapp-name}/{version}/{content-topic-name}/{encoding}\n dapp-name: The name of your dApp, it must be unique to avoid conflict with other dApps. version: We usually start at 1, useful when introducing breaking changes in your messages. content-topic-name: The actual content topic name to use for filtering. If your dApp uses WakuConnect for several features, you should use a content topic per feature. encoding: The encoding format of the message, Protobuf is most often used: proto. For example: Your dApp\u0026rsquo;s name is SuperCrypto, it enables users to receive notifications and send private messages. You may want to use the following content topics:\n /supercrypto/1/notification/proto /supercrypto/1/private-message/proto You can learn more about Waku topics in the 23/WAKU2-TOPICS specs.\n"},{"id":2,"href":"/docs/guides/02_relay_receive_send_messages/","title":"Receive and Send Messages Using Waku Relay","section":"Guides","content":"Receive and Send Messages Using Waku Relay # Waku Relay is a gossip protocol that enables you to send and receive messages. You can find Waku Relay\u0026rsquo;s specifications on Vac RFC.\nBefore starting, you need to choose a Content Topic for your dApp. Check out the how to choose a content topic guide to learn more about content topics.\nFor this guide, we are using a single content topic: /relay-guide/1/chat/proto.\nInstallation # You can install js-waku using your favorite package manager:\nnpm install js-waku Create Waku Instance # In order to interact with the Waku network, you first need a Waku instance:\nimport {Waku} from \u0026#39;js-waku\u0026#39;; 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:\nimport { Waku } from \u0026#39;js-waku\u0026#39;; const waku = await Waku.create({ bootstrap: [ \u0026#39;/dns4/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm\u0026#39;, \u0026#39;/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ\u0026#39; ] }); Wait to be connected # When using the bootstrap option, it may take some time to connect to other peers. To ensure that you have relay peers available to send and receive messages, use the following function:\nawait waku.waitForConnectedPeer(); The returned Promise will resolve once you are connected to a Waku Relay peer.\nReceive messages # To receive messages for your app, you need to register an observer on relay for your app\u0026rsquo;s content topic:\nconst processIncomingMessage = (wakuMessage) =\u0026gt; { console.log(`Message Received: ${wakuMessage.payloadAsUtf8}`); }; waku.relay.addObserver(processIncomingMessage, [\u0026#39;/relay-guide/1/chat/proto\u0026#39;]); Send Messages # You are now ready to send messages. Let\u0026rsquo;s start by sending simple strings as messages.\nTo 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:\nimport { WakuMessage } from \u0026#39;js-waku\u0026#39;; const wakuMessage = await WakuMessage.fromUtf8String(\u0026#39;Here is a message\u0026#39;, `/relay-guide/1/chat/proto`); Then, use the relay module to send the message to our peers, the message will then be relayed to the rest of the network thanks to Waku Relay:\nawait waku.relay.send(wakuMessage); Use Protobuf # Sending strings as messages in unlikely to cover your dApps needs.\nWaku v2 protocols use protobuf by default.\nLet\u0026rsquo;s review how you can use protobuf to include structured objects in Waku Messages.\nFirst, define a data structure. For this guide, we will use a simple chat message that contains a timestamp and text:\n{ timestamp: Date; text: string; } To encode and decode protobuf payloads, you can use the protons package.\nInstall Protobuf Library # First, install protons:\nnpm install protons Protobuf Definition # Then define the simple chat message:\nimport protons from \u0026#39;protons\u0026#39;; const proto = protons(` message SimpleChatMessage { uint64 timestamp = 1; string text = 2; } `); You can learn about protobuf message definitions here: Protocol Buffers Language Guide.\nEncode Messages # Instead of wrapping an utf-8 string in a Waku Message, you are going to wrap a protobuf payload.\nFirst, encode the object:\nconst payload = proto.SimpleChatMessage.encode({ timestamp: Date.now(), text: \u0026#39;Here is a message\u0026#39; }); Then, wrap it in a Waku Message:\nconst wakuMessage = await WakuMessage.fromBytes(payload, ContentTopic); Now, you can send the message over Waku Relay the same way than before:\nawait waku.relay.send(wakuMessage); Decode Messages # To decode the messages received over Waku Relay, you need to extract the protobuf payload and decode it using protons.\nconst processIncomingMessage = (wakuMessage) =\u0026gt; { // No need to attempt to decode a message if the payload is absent if (!wakuMessage.payload) return; const { timestamp, text } = proto.SimpleChatMessage.decode( wakuMessage.payload ); console.log(`Message Received: ${text}, sent at ${timestamp.toString()}`); }; Like before, add this callback as an observer to Waku Relay:\nwaku.relay.addObserver(processIncomingMessage, [\u0026#39;/relay-guide/1/chat/proto\u0026#39;]); Conclusion # That is it! Now, you know how to send and receive messages over Waku using the Waku Relay protocol.\nHere is the final code:\nimport { getBootstrapNodes, Waku, WakuMessage } from \u0026#39;js-waku\u0026#39;; import protons from \u0026#39;protons\u0026#39;; const proto = protons(` message SimpleChatMessage { uint64 timestamp = 1; string text = 2; } `); const wakuNode = await Waku.create(); const nodes = await getBootstrapNodes(); await Promise.all(nodes.map((addr) =\u0026gt; waku.dial(addr))); const processIncomingMessage = (wakuMessage) =\u0026gt; { // No need to attempt to decode a message if the payload is absent if (!wakuMessage.payload) return; const { timestamp, text } = proto.SimpleChatMessage.decode( wakuMessage.payload ); console.log(`Message Received: ${text}, sent at ${timestamp.toString()}`); }; waku.relay.addObserver(processIncomingMessage, [\u0026#39;/relay-guide/1/chat/proto\u0026#39;]); const payload = proto.SimpleChatMessage.encode({ timestamp: Date.now(), text: \u0026#39;Here is a message\u0026#39; }); const wakuMessage = await WakuMessage.fromBytes(payload, ContentTopic); await waku.relay.send(wakuMessage); "},{"id":3,"href":"/docs/guides/03_store_retrieve_messages/","title":"Retrieve Messages Using Waku Store","section":"Guides","content":"Retrieve Messages Using Waku Store # DApps running on a phone or in a browser are often offline: The browser could be closed or mobile app in the background.\nWaku Relay is a gossip protocol. As a user, it means that your peers forward you messages they just received. If you cannot be reached by your peers, then messages are not relayed; relay peers do not save messages for later.\nHowever, Waku Store peers do save messages they relay, allowing you to retrieve them at a later time. The Waku Store protocol is best-effort and does not guarantee data availability. Waku Relay should still be preferred when online; Waku Store can be used after resuming connectivity: For example, when the dApp starts.\nIn this guide, we\u0026rsquo;ll review how you can use Waku Store to retrieve messages.\nBefore starting, you need to choose a Content Topic for your dApp. Check out the how to choose a content topic guide to learn more about content topics.\nFor this guide, we are using a single content topic: /store-guide/1/news/proto.\nInstallation # You can install js-waku using your favorite package manager:\nnpm install js-waku Create Waku Instance # In order to interact with the Waku network, you first need a Waku instance:\nimport {Waku} from \u0026#39;js-waku\u0026#39;; 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:\nimport { Waku } from \u0026#39;js-waku\u0026#39;; const wakuNode = await Waku.create({ bootstrap: [ \u0026#39;/dns4/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm\u0026#39;, \u0026#39;/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ\u0026#39; ] }); Wait to be connected # When using the bootstrap option, it may take some times to connect to other peers. To ensure that you have store peers available to retrieve historical messages from, use the following function:\nawait waku.waitForConnectedPeer(); The returned Promise will resolve once you are connected to a Waku Store peer.\nUse Protobuf # Waku v2 protocols use protobuf by default.\nLet\u0026rsquo;s review how you can use protobuf to send structured data.\nFirst, define a data structure. For this guide, we will use a simple news article that contains a date of publication, title and body:\n{ date: Date; title: string; body: string; } To encode and decode protobuf payloads, you can use the protons package.\nInstall Protobuf Library # First, install protons:\nnpm install protons Protobuf Definition # Then specify the data structure:\nimport protons from \u0026#39;protons\u0026#39;; const proto = protons(` message ArticleMessage { uint64 date = 1; string title = 2; string body = 3; } `); You can learn about protobuf message definitions here: Protocol Buffers Language Guide.\nDecode Messages # To decode the messages retrieved from a Waku Store node, you need to extract the protobuf payload and decode it using protons.\nconst decodeWakuMessage = (wakuMessage) =\u0026gt; { // No need to attempt to decode a message if the payload is absent if (!wakuMessage.payload) return; const { date, title, body } = proto.SimpleChatMessage.decode( wakuMessage.payload ); // In protobuf, fields are optional so best to check if (!date || !title || !body) return; const publishDate = new Date(); publishDate.setTime(date); return { publishDate, title, body }; }; Retrieve messages # You now have all the building blocks to retrieve and decode messages for a store node.\nStore node responses are paginated. The WakuStore.queryHistory API automatically query all the pages in a sequential manner. To process messages as soon as they received (page by page), use the callback option:\nconst ContentTopic = \u0026#39;/store-guide/1/news/proto\u0026#39;; const callback = (retrievedMessages) =\u0026gt; { const articles = retrievedMessages .map(decodeWakuMessage) // Decode messages .filter(Boolean); // Filter out undefined values console.log(`${articles.length}articles have been retrieved`); }; waku.store .queryHistory([ContentTopic], { callback }) .catch((e) =\u0026gt; { // Catch any potential error console.log(\u0026#39;Failed to retrieve messages from store\u0026#39;, e); }); Note that WakuStore.queryHistory select an available store node for you. However, it can only select a connected node, which is why the bootstrapping is necessary. It will throw an error if no store node is available.\nFilter messages by send time # By default, Waku Store nodes store messages for 30 days. Depending on your use case, you may not need to retrieve 30 days worth of messages.\nWaku Message defines an optional unencrypted timestamp field. The timestamp is set by the sender. By default, js-waku sets the timestamp of outgoing message to the current time.\nYou can filter messages that include a timestamp within given bounds with the timeFilter option.\nRetrieve messages up to a week old:\n// [..] `ContentTopic` and `callback` definitions 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, timeFilter: { startTime, endTime: new Date() } }) .catch((e) =\u0026gt; { console.log(\u0026#39;Failed to retrieve messages from store\u0026#39;, e); }); End result # You can see a similar example implemented in ReactJS in the Minimal ReactJS Waku Store App.\n"},{"id":4,"href":"/docs/guides/04_encrypt_messages_version_1/","title":"Encrypt Messages Using Waku Message Version 1","section":"Guides","content":"Encrypt Messages Using Waku Message Version 1 # The Waku Message format provides an easy way to encrypt messages using symmetric or asymmetric encryption. The encryption comes with several handy design requirements: confidentiality, authenticity and integrity. It also allows the sender to sign messages, see Sign Messages Using Waku Message Version 1 to learn how.\nYou can find more details about Waku Message Payload Encryption in 26/WAKU-PAYLOAD.\nSee Cryptographic Libraries for more details on the cryptographic libraries used by js-waku.\nWhat data is encrypted # With Waku Message Version 1, the entire payload is encrypted.\nWhich means that the only discriminating data available in clear text is the content topic and timestamp (if present). Hence, if Alice expects to receive messages under a given content topic, she needs to try to decrypt all messages received on said content topic.\nThis needs to be kept in mind for scalability and forward secrecy concerns:\n If there is high traffic on a given content topic then all clients need to process and attempt decryption of all messages with said content topic; If a content topic is only used by a given (group of) user(s) then it is possible to deduce some information about said user(s) communications such as sent time and frequency of messages. Key management # By using Waku Message Version 1, you will need to provide a way to your users to generate and store keys in a secure manner. Storing, backing up and recovering key is out of the scope of this guide.\nIf key recovery is important for your dApp, then check out SubtleCrypto.wrapKey() which can be used to securely store or export private keys.\nAn example to save and load a key pair in local storage, protected with a password, can be found in Eth-PM.\nWhich encryption method should I use? # Whether you should use symmetric or asymmetric encryption depends on your use case.\nSymmetric encryption is done using a single key to encrypt and decrypt.\nWhich means that if Alice knows the symmetric key K and uses it to encrypt a message, she can also use K to decrypt any message encrypted with K, even if she is not the sender.\nGroup chats is a possible use case for symmetric encryption: All participants can use an out-of-band method to agree on a K. Participants can then use K to encrypt and decrypt messages within the group chat. Participants MUST keep K secret to ensure that no external party can decrypt the group chat messages.\nAsymmetric encryption is done using a key pair: the public key is used to encrypt messages, the matching private key is used to decrypt messages.\nFor Alice to encrypt a message for Bob, she needs to know Bob\u0026rsquo;s Public Key K. Bob can then use his private key k to decrypt the message. As long as Bob keep his private key k secret, then he, and only he, can decrypt messages encrypted with K.\nPrivate 1:1 messaging is a possible use case for asymmetric encryption: When Alice sends an encrypted message for Bob, only Bob can decrypt it.\nSymmetric Encryption # Generate Key # To use symmetric encryption, you first need to generate a key. Use generateSymmetricKey for secure key generation:\nimport { generateSymmetricKey } from \u0026#39;js-waku\u0026#39;; const symmetricKey = generateSymmetricKey(); Encrypt Message # To encrypt a message with the previously generated key, pass the key in the symKey property to WakuMessage.fromBytes.\nSame as Waku Messages version 0 (unencrypted), payload is your message payload and contentTopic is the content topic for your dApp. See Receive and Send Messages Using Waku Relay for details.\nimport { WakuMessage } from \u0026#39;js-waku\u0026#39;; const message = await WakuMessage.fromBytes(payload, contentTopic, { symKey: symmetricKey }); The Waku Message can then be sent to the Waku network using Waku Relay or Waku Light Push:\nawait waku.lightPush.push(message); Decrypt Messages # To decrypt messages, whether they are received over Waku Relay or using Waku Store, add the symmetric key as a decryption key to your Waku instance.\nwaku.addDecryptionKey(symmetricKey); Alternatively, you can pass the key when creating the instance:\nimport { Waku } from \u0026#39;js-waku\u0026#39;; const waku = Waku.create({ decryptionKeys: [symmetricKey] }); It will attempt to decrypt any message it receives using the key, for both symmetric and asymmetric encryption.\nYou can call addDecryptionKey several times if you are using multiple keys, symmetric key and asymmetric private keys can be used together.\nMessages that are not successfully decrypted are dropped.\nAsymmetric Encryption # Generate Key Pair # To use asymmetric encryption, you first need to generate a private key and calculate the corresponding public key. Use generatePrivateKey for secure key generation:\nimport { generatePrivateKey, getPublicKey } from \u0026#39;js-waku\u0026#39;; const privateKey = generatePrivateKey(); const publicKey = getPublicKey(privateKey); The private key must be securely stored and remain private. If leaked then other parties may be able to decrypt the user\u0026rsquo;s messages.\nThe public key is unique for a given private key and can always be recovered given the private key, hence it is not needed to save it as long as as the private key can be recovered.\nEncrypt Message # The public key is used to encrypt messages; to do so, pass it in the encPublicKey property to WakuMessage.fromBytes.\nSame as clear Waku Messages, payload is your message payload and contentTopic is the content topic for your dApp. See Receive and Send Messages Using Waku Relay for details.\nimport { WakuMessage } from \u0026#39;js-waku\u0026#39;; const message = await WakuMessage.fromBytes(payload, contentTopic, { encPublicKey: publicKey }); The Waku Message can then be sent to the Waku network using Waku Relay or Waku Light Push:\nawait waku.lightPush.push(message); Decrypt Messages # The private key is needed to decrypt messages.\nTo decrypt messages, whether they are received over Waku Relay or using Waku Store, add the private key as a decryption key to your Waku instance.\nwaku.addDecryptionKey(privateKey); Alternatively, you can pass the key when creating the instance:\nimport { Waku } from \u0026#39;js-waku\u0026#39;; const waku = Waku.create({ decryptionKeys: [privateKey] }); It will attempt to decrypt any message it receives using the key, for both symmetric and asymmetric encryption.\nYou can call addDecryptionKey several times if you are using multiple keys, symmetric key and asymmetric private keys can be used together.\nMessages that are not successfully decrypted are dropped.\nHandling WakuMessage instances # When creating a Waku Message using WakuMessage.fromBytes with an encryption key (symmetric or asymmetric), the payload gets encrypted. Which means that wakuMessage.payload returns an encrypted payload:\nimport { WakuMessage } from \u0026#39;js-waku\u0026#39;; const message = await WakuMessage.fromBytes(payload, contentTopic, { encPublicKey: publicKey }); console.log(message.payload); // This is encrypted However, WakuMessage instances returned by WakuRelay or WakuStore are always decrypted.\nWakuRelay and WakuStore never return messages that are encrypted. If a message was not successfully decrypted, then it will be dropped from the results.\nWhich means that WakuMessage instances returned by WakuRelay and WakuStore always have a clear payload (in regard to Waku Message version 1):\nimport { Waku } from \u0026#39;js-waku\u0026#39;; const waku = Waku.create({ decryptionKeys: [privateKey] }); const messages = await waku.store.queryHistory([contentTopic]); if (messages \u0026amp;\u0026amp; messages[0]) { console.log(messages[0].payload); // This payload is decrypted } waku.relay.addObserver((message) =\u0026gt; { console.log(message.payload); // This payload is decrypted }, [contentTopic]); Code Example # The Eth-PM Web App example demonstrates both the use of symmetric and asymmetric encryption.\nAsymmetric encryption is used for private messages so that only the intended recipient can read said messages.\nSymmetric encryption is used for the public key messages. In this instance, the same key is used for all users: the Keccak-256 hash of the content topic (which results in 32 bytes array). While this does not add functional value, it does demonstrate the usage of symmetric encryption in a web app.\nA live version of Eth-PM can be found at https://status-im.github.io/js-waku/eth-pm/.\nThe specifications of the protocol it implements can be found at 20/TOY-ETH-PM.\n"},{"id":5,"href":"/docs/guides/05_sign_messages_version_1/","title":"Sign Messages Using Waku Message Version 1","section":"Guides","content":"Sign Messages Using Waku Message Version 1 # The Waku Message format provides an easy way to sign messages using elliptic curve cryptography.\nIt also allows the sender to encrypt messages, see Encrypt Messages Using Waku Message Version 1 to learn how.\nYou can find more details about Waku Message Payload Signature in 26/WAKU-PAYLOAD.\nSee Cryptographic Libraries for more details on the cryptographic libraries used by js-waku.\nCreate new keypair # Generate a new keypair to sign your messages:\nimport { generatePrivateKey, getPublicKey } from \u0026#39;js-waku\u0026#39;; const privateKey = generatePrivateKey(); const publicKey = getPublicKey(privateKey); Sign Waku Messages # As per version 1\u0026rsquo;s specs, signatures are only included in encrypted messages. In the case where your app does not need encryption then you could use symmetric encryption with a trivial key.\nYou can learn more about encryption at Encrypt Messages Using Waku Message Version 1.\nUsing symmetric encryption # Given symKey the symmetric key used for encryption:\nimport { WakuMessage } from \u0026#39;js-waku\u0026#39;; const message = await WakuMessage.fromBytes(payload, myAppContentTopic, { encPublicKey: symKey, sigPrivKey: privateKey }); If encryption is not needed for your use case, then you can create a symmetric key from the content topic:\nimport { hexToBuf } from \u0026#39;js-waku/lib/utils\u0026#39;; import { keccak256 } from \u0026#39;ethers/lib/utils\u0026#39;; const symKey = hexToBuf( keccak256(Buffer.from(myAppContentTopic, \u0026#39;utf-8\u0026#39;)) ); symKey can then be used to encrypt and decrypt messages on myAppContentTopic content topic. Read How to Choose a Content Topic to learn more about content topics.\nUsing asymmetric encryption # Given recipientPublicKey the public key of the message\u0026rsquo;s recipient:\nimport { WakuMessage } from \u0026#39;js-waku\u0026#39;; const message = await WakuMessage.fromBytes(payload, myAppContentTopic, { encPublicKey: recipientPublicKey, sigPrivKey: privateKey }); Verify Waku Message signatures # Two fields are available on signed WakuMessages:\n signaturePublicKey: Holds the public key of the signer, signature: Holds the actual signature. Thus, if you expect messages to be signed by Alice, you can simply compare WakuMessage.signaturePublicKey with Alice\u0026rsquo;s public key. As comparing hex string can lead to issues (is the 0x prefix present?), simply use helper function equalByteArrays.\nimport { equalByteArrays } from \u0026#39;js-waku/lib/utils\u0026#39;; const sigPubKey = wakuMessage.signaturePublicKey; const isSignedByAlice = sigPubKey \u0026amp;\u0026amp; equalByteArrays(sigPubKey, alicePublicKey); if (!isSignedByAlice) { // Message is not signed by Alice } "},{"id":6,"href":"/docs/guides/06_light_push_send_messages/","title":"Send Messages Using Waku Light Push","section":"Guides","content":"Send Messages Using Waku Light Push # Waku Light Push enables a client to receive a confirmation when sending a message.\nThe Waku Relay protocol sends messages to connected peers but does not provide any information on whether said peers have received messages. This can be an issue when facing potential connectivity issues. For example, when the connection drops easily, or it is connected to a small number of relay peers.\nWaku Light Push allows a client to get a response from a remote peer when sending a message. Note this only guarantees that the remote peer has received the message, it cannot guarantee propagation to the network.\nIt also means weaker privacy properties as the remote peer knows the client is the originator of the message. Whereas with Waku Relay, a remote peer would not know whether the client created or forwarded the message.\nYou can find Waku Light Push\u0026rsquo;s specifications on Vac RFC.\nContent Topic # Before starting, you need to choose a Content Topic for your dApp. Check out the how to choose a content topic guide to learn more about content topics.\nFor this guide, we are using a single content topic: /light-push-guide/1/guide/proto.\nInstallation # You can install js-waku using your favorite package manager:\nnpm install js-waku Create Waku Instance # In order to interact with the Waku network, you first need a Waku instance:\nimport {Waku} from \u0026#39;js-waku\u0026#39;; 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:\nimport { Waku } from \u0026#39;js-waku\u0026#39;; const waku = await Waku.create({ bootstrap: [ \u0026#39;/dns4/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm\u0026#39;, \u0026#39;/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ\u0026#39; ] }); Wait to be connected # When using the bootstrap option, it may take some time to connect to other peers. To ensure that you have a light push peer available to send messages to, use the following function:\nawait waku.waitForConnectedPeer(); The returned Promise will resolve once you are connected to a Waku peer.\nSend messages # You can now send a message using Waku Light Push. By default, it sends the messages to a single randomly selected light push peer. The peer is selected among the dApp\u0026rsquo;s connected peers.\nIf the dApp is not connected to any light push peer, an error is thrown.\nimport {WakuMessage} from \u0026#39;js-waku\u0026#39;; const wakuMessage = await WakuMessage.fromUtf8String(\u0026#39;Here is a message\u0026#39;, `/light-push-guide/1/guide/proto`); const ack = await waku.lightPush.push(wakuMessage); if (!ack?.isSuccess) { // Message was not sent } "},{"id":7,"href":"/docs/guides/07_reactjs_relay/","title":"Receive and Send Messages Using Waku Relay With ReactJS","section":"Guides","content":"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.\nBefore starting, you need to choose a Content Topic for your dApp. Check out the how to choose a content topic guide to learn more about content topics. For this guide, we are using a single content topic: /min-react-js-chat/1/chat/proto.\nSetup # Create a new React app:\nnpx create-react-app relay-reactjs-chat cd relay-reactjs-chat BigInt # Some of js-waku\u0026rsquo;s dependencies use BigInt that is only supported by modern browsers.\nTo ensure that react-scripts properly transpile your webapp code, update the package.json file:\n{ \u0026#34;browserslist\u0026#34;: { \u0026#34;production\u0026#34;: [ \u0026#34;\u0026gt;0.2%\u0026#34;, \u0026#34;not ie \u0026lt;= 99\u0026#34;, \u0026#34;not android \u0026lt;= 4.4.4\u0026#34;, \u0026#34;not dead\u0026#34;, \u0026#34;not op_mini all\u0026#34; ] } } Setup polyfills # A number of Web3 dependencies need polyfills. Said polyfills must be explicitly declared when using webpack 5.\nThe latest react-scripts version uses webpack 5.\nWe will describe below a method to configure polyfills when using create-react-app/react-scripts or webpack 5. This may not be necessary if you do not use react-scripts or if you use webpack 4.\nStart by installing the polyfill libraries:\nnpm install assert buffer crypto-browserify stream-browserify Webpack 5 # If you directly use webpack 5, then you can inspire yourself from this webpack.config.js.\ncra-webpack-rewired # An alternative is to let react-scripts control the webpack 5 config and only override some elements using cra-webpack-rewired.\nInstall cra-webpack-rewired:\nnpm install -D cra-webpack-rewired Create a config/webpack.extend.js file at the root of your app:\nconst webpack = require(\u0026#39;webpack\u0026#39;); module.exports = { dev: (config) =\u0026gt; { // 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(\u0026#39;buffer\u0026#39;), crypto: require.resolve(\u0026#39;crypto-browserify\u0026#39;), stream: require.resolve(\u0026#39;stream-browserify\u0026#39;), }); if (!config.plugins) config.plugins = []; config.plugins.push( new webpack.DefinePlugin({ \u0026#39;process.env.ENV\u0026#39;: JSON.stringify(\u0026#39;dev\u0026#39;), }) ); config.plugins.push( new webpack.ProvidePlugin({ process: \u0026#39;process/browser.js\u0026#39;, Buffer: [\u0026#39;buffer\u0026#39;, \u0026#39;Buffer\u0026#39;], }) ); if (!config.ignoreWarnings) config.ignoreWarnings = []; config.ignoreWarnings.push(/Failed to parse source map/); return config; }, prod: (config) =\u0026gt; { // 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(\u0026#39;buffer\u0026#39;), crypto: require.resolve(\u0026#39;crypto-browserify\u0026#39;), stream: require.resolve(\u0026#39;stream-browserify\u0026#39;), }); if (!config.plugins) config.plugins = []; config.plugins.push( new webpack.DefinePlugin({ \u0026#39;process.env.ENV\u0026#39;: JSON.stringify(\u0026#39;prod\u0026#39;), }) ); config.plugins.push( new webpack.ProvidePlugin({ process: \u0026#39;process/browser.js\u0026#39;, Buffer: [\u0026#39;buffer\u0026#39;, \u0026#39;Buffer\u0026#39;], }) ); if (!config.ignoreWarnings) config.ignoreWarnings = []; config.ignoreWarnings.push(/Failed to parse source map/); return config; }, }; Use cra-webpack-rewired in the package.json, instead of react-scripts:\n \u0026quot;scripts\u0026quot;: { - \u0026quot;start\u0026quot;: \u0026quot;react-scripts start\u0026quot;, - \u0026quot;build\u0026quot;: \u0026quot;react-scripts build\u0026quot;, - \u0026quot;test\u0026quot;: \u0026quot;react-scripts test\u0026quot;, - \u0026quot;eject\u0026quot;: \u0026quot;react-scripts eject\u0026quot; + \u0026quot;start\u0026quot;: \u0026quot;cra-webpack-rewired start\u0026quot;, + \u0026quot;build\u0026quot;: \u0026quot;cra-webpack-rewired build\u0026quot;, + \u0026quot;test\u0026quot;: \u0026quot;cra-webpack-rewired test\u0026quot;, + \u0026quot;eject\u0026quot;: \u0026quot;cra-webpack-rewired eject\u0026quot; }, Then, install js-waku:\nnpm install js-waku Start the dev server and open the dApp in your browser:\nnpm run start Create Waku Instance # In order to interact with the Waku network, you first need a Waku instance. Go to App.js and modify the App function:\nimport {Waku} from \u0026#39;js-waku\u0026#39;; import * as React from \u0026#39;react\u0026#39;; function App() { const [waku, setWaku] = React.useState(undefined); const [wakuStatus, setWakuStatus] = React.useState(\u0026#39;None\u0026#39;); // Start Waku React.useEffect(() =\u0026gt; { // 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 !== \u0026#39;None\u0026#39;) return; setWakuStatus(\u0026#39;Starting\u0026#39;); // Create Waku Waku.create({bootstrap: {default: true}}).then((waku) =\u0026gt; { // Once done, put it in the state setWaku(waku); // And update the status setWakuStatus(\u0026#39;Started\u0026#39;); }); }, [waku, wakuStatus]); return ( \u0026lt;div className=\u0026#39;App\u0026#39;\u0026gt; \u0026lt;header className=\u0026#39;App-header\u0026#39;\u0026gt; \u0026lt;p\u0026gt;Waku node\u0026#39;s status: {wakuStatus}\u0026lt;/p\u0026gt; \u0026lt;/header\u0026gt; \u0026lt;/div\u0026gt; ); } export default App; Wait to be connected # When using the bootstrap option, it may take some time to connect to other peers. To ensure that you have relay peers available to send and receive messages, use the Waku.waitForConnectedPeer() async function:\nReact.useEffect(() =\u0026gt; { if (!!waku) return; if (wakuStatus !== \u0026#39;None\u0026#39;) return; setWakuStatus(\u0026#39;Starting\u0026#39;); Waku.create({bootstrap: {default: true}}).then((waku) =\u0026gt; { setWaku(waku); setWakuStatus(\u0026#39;Connecting\u0026#39;); waku.waitForConnectedPeer().then(() =\u0026gt; { setWakuStatus(\u0026#39;Ready\u0026#39;); }); }); }, [waku, wakuStatus]); Define Message Format # To define the Protobuf message format, use protons\nnpm install protons Define SimpleChatMessage with two fields: timestamp and text.\nimport protons from \u0026#39;protons\u0026#39;; const proto = protons(` message SimpleChatMessage { uint64 timestamp = 1; string text = 2; } `); Send Messages # Create a function that takes the Waku instance and a message to send:\nimport { WakuMessage } from \u0026#39;js-waku\u0026#39;; const ContentTopic = `/relay-reactjs-chat/1/chat/proto`; function sendMessage(message, waku, timestamp) { const time = timestamp.getTime(); // Encode to protobuf const payload = proto.SimpleChatMessage.encode({ timestamp: time, text: message }); // Wrap in a Waku Message return WakuMessage.fromBytes(payload, ContentTopic).then((wakuMessage) =\u0026gt; // Send over Waku Relay waku.relay.send(wakuMessage) ); } Then, add a button to the App function:\nfunction App() { const [waku, setWaku] = React.useState(undefined); const [wakuStatus, setWakuStatus] = React.useState(\u0026#39;None\u0026#39;); // Using a counter just for the messages to be different const [sendCounter, setSendCounter] = React.useState(0); React.useEffect(() =\u0026gt; { // ... creates Waku }, [waku, wakuStatus]); const sendMessageOnClick = () =\u0026gt; { // Check Waku is started and connected first. if (wakuStatus !== \u0026#39;Ready\u0026#39;) return; sendMessage(`Here is message #${sendCounter}`, waku, new Date()).then(() =\u0026gt; console.log(\u0026#39;Message sent\u0026#39;) ); // For demonstration purposes. setSendCounter(sendCounter + 1); }; return ( \u0026lt;div className=\u0026#34;App\u0026#34;\u0026gt; \u0026lt;header className=\u0026#34;App-header\u0026#34;\u0026gt; \u0026lt;p\u0026gt;{wakuStatus}\u0026lt;/p\u0026gt; \u0026lt;button onClick={sendMessageOnClick} disabled={wakuStatus !== \u0026#39;Ready\u0026#39;}\u0026gt; Send Message \u0026lt;/button\u0026gt; \u0026lt;/header\u0026gt; \u0026lt;/div\u0026gt; ); } Receive Messages # To process incoming messages, you need to register an observer on Waku Relay. First, you need to define the observer function.\nYou will need to remove the observer when the component unmount. Hence, you need the reference to the function to remain the same. For that, use React.useCallback:\nconst processIncomingMessage = React.useCallback((wakuMessage) =\u0026gt; { // Empty message? if (!wakuMessage.payload) return; // Decode the protobuf payload const { timestamp, text } = proto.SimpleChatMessage.decode( wakuMessage.payload ); const time = new Date(); time.setTime(timestamp); // For now, just log new messages on the console console.log(`message received at ${time.toString()}: ${text}`); }, []); Then, add this observer to Waku Relay. Do not forget to delete the observer is the component is being unmounted:\nReact.useEffect(() =\u0026gt; { if (!waku) return; // Pass the content topic to only process messages related to your dApp waku.relay.addObserver(processIncomingMessage, [ContentTopic]); // `cleanUp` is called when the component is unmounted, see ReactJS doc. return function cleanUp() { waku.relay.deleteObserver(processIncomingMessage, [ContentTopic]); }; }, [waku, wakuStatus, processIncomingMessage]); Display Messages # The Waku work is now done. Your dApp is able to send and receive messages using Waku. For the sake of completeness, let\u0026rsquo;s display received messages on the page.\nFirst, add incoming messages to the state of the App component:\nfunction App() { //... const [messages, setMessages] = React.useState([]); const processIncomingMessage = React.useCallback((wakuMessage) =\u0026gt; { if (!wakuMessage.payload) return; const { text, timestamp } = proto.SimpleChatMessage.decode( wakuMessage.payload ); const time = new Date(); time.setTime(timestamp); const message = { text, timestamp: time }; setMessages((messages) =\u0026gt; { return [message].concat(messages); }); }, []); // ... } Then, render the messages:\nfunction App() { // ... return ( \u0026lt;div className=\u0026#34;App\u0026#34;\u0026gt; \u0026lt;header className=\u0026#34;App-header\u0026#34;\u0026gt; \u0026lt;p\u0026gt;{wakuStatus}\u0026lt;/p\u0026gt; \u0026lt;button onClick={sendMessageOnClick} disabled={wakuStatus !== \u0026#39;Ready\u0026#39;}\u0026gt; Send Message \u0026lt;/button\u0026gt; \u0026lt;ul\u0026gt; {messages.map((msg) =\u0026gt; { return ( \u0026lt;li\u0026gt; \u0026lt;p\u0026gt; {msg.timestamp.toString()}: {msg.text} \u0026lt;/p\u0026gt; \u0026lt;/li\u0026gt; ); })} \u0026lt;/ul\u0026gt; \u0026lt;/header\u0026gt; \u0026lt;/div\u0026gt; ); } And Voilà! You should now be able to send and receive messages. Try out by opening the app from different browsers.\nYou can see the complete code in the Relay ReactJS Chat Example App.\n"},{"id":8,"href":"/docs/guides/08_reactjs_store/","title":"Retrieve Messages Using Waku Store With ReactJS","section":"Guides","content":"Retrieve Messages Using Waku Store With ReactJS # It is easy to use WakuConnect with ReactJS. In this guide, we will demonstrate how your ReactJS dApp can use Waku Store to retrieve messages.\nDApps running on a phone or in a browser are often offline: The browser could be closed or mobile app in the background.\nWaku Relay is a gossip protocol. As a user, it means that your peers forward you messages they just received. If you cannot be reached by your peers, then messages are not relayed; relay peers do not save messages for later.\nHowever, Waku Store peers do save messages they relay, allowing you to retrieve them at a later time. The Waku Store protocol is best-effort and does not guarantee data availability. Waku Relay should still be preferred when online; Waku Store can be used after resuming connectivity: For example, when the dApp starts.\nIn this guide, we\u0026rsquo;ll review how you can use Waku Store to retrieve messages.\nBefore starting, you need to choose a Content Topic for your dApp. Check out the how to choose a content topic guide to learn more about content topics.\nSetup # Create a new React app:\nnpx create-react-app store-reactjs-chat cd store-reactjs-chat BigInt # Some of js-waku\u0026rsquo;s dependencies use BigInt that is only supported by modern browsers.\nTo ensure that react-scripts properly transpile your webapp code, update the package.json file:\n{ \u0026#34;browserslist\u0026#34;: { \u0026#34;production\u0026#34;: [ \u0026#34;\u0026gt;0.2%\u0026#34;, \u0026#34;not ie \u0026lt;= 99\u0026#34;, \u0026#34;not android \u0026lt;= 4.4.4\u0026#34;, \u0026#34;not dead\u0026#34;, \u0026#34;not op_mini all\u0026#34; ] } } Setup polyfills # A number of Web3 dependencies need polyfills. Said polyfills must be explicitly declared when using webpack 5.\nThe latest react-scripts version uses webpack 5.\nWe will describe below a method to configure polyfills when using create-react-app/react-scripts or webpack 5. This may not be necessary if you do not use react-scripts or if you use webpack 4.\nStart by installing the polyfill libraries:\nnpm install assert buffer crypto-browserify stream-browserify Webpack 5 # If you directly use webpack 5, then you can inspire yourself from this webpack.config.js.\ncra-webpack-rewired # An alternative is to let react-scripts control the webpack 5 config and only override some elements using cra-webpack-rewired.\nInstall cra-webpack-rewired:\nnpm install -D cra-webpack-rewired Create a config/webpack.extend.js file at the root of your app:\nconst webpack = require(\u0026#39;webpack\u0026#39;); module.exports = { dev: (config) =\u0026gt; { // 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(\u0026#39;buffer\u0026#39;), crypto: require.resolve(\u0026#39;crypto-browserify\u0026#39;), stream: require.resolve(\u0026#39;stream-browserify\u0026#39;), }); if (!config.plugins) config.plugins = []; config.plugins.push( new webpack.DefinePlugin({ \u0026#39;process.env.ENV\u0026#39;: JSON.stringify(\u0026#39;dev\u0026#39;), }) ); config.plugins.push( new webpack.ProvidePlugin({ process: \u0026#39;process/browser.js\u0026#39;, Buffer: [\u0026#39;buffer\u0026#39;, \u0026#39;Buffer\u0026#39;], }) ); if (!config.ignoreWarnings) config.ignoreWarnings = []; config.ignoreWarnings.push(/Failed to parse source map/); return config; }, prod: (config) =\u0026gt; { // 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(\u0026#39;buffer\u0026#39;), crypto: require.resolve(\u0026#39;crypto-browserify\u0026#39;), stream: require.resolve(\u0026#39;stream-browserify\u0026#39;), }); if (!config.plugins) config.plugins = []; config.plugins.push( new webpack.DefinePlugin({ \u0026#39;process.env.ENV\u0026#39;: JSON.stringify(\u0026#39;prod\u0026#39;), }) ); config.plugins.push( new webpack.ProvidePlugin({ process: \u0026#39;process/browser.js\u0026#39;, Buffer: [\u0026#39;buffer\u0026#39;, \u0026#39;Buffer\u0026#39;], }) ); if (!config.ignoreWarnings) config.ignoreWarnings = []; config.ignoreWarnings.push(/Failed to parse source map/); return config; }, }; Use cra-webpack-rewired in the package.json, instead of react-scripts:\n \u0026quot;scripts\u0026quot;: { - \u0026quot;start\u0026quot;: \u0026quot;react-scripts start\u0026quot;, - \u0026quot;build\u0026quot;: \u0026quot;react-scripts build\u0026quot;, - \u0026quot;test\u0026quot;: \u0026quot;react-scripts test\u0026quot;, - \u0026quot;eject\u0026quot;: \u0026quot;react-scripts eject\u0026quot; + \u0026quot;start\u0026quot;: \u0026quot;cra-webpack-rewired start\u0026quot;, + \u0026quot;build\u0026quot;: \u0026quot;cra-webpack-rewired build\u0026quot;, + \u0026quot;test\u0026quot;: \u0026quot;cra-webpack-rewired test\u0026quot;, + \u0026quot;eject\u0026quot;: \u0026quot;cra-webpack-rewired eject\u0026quot; }, Then, install js-waku:\nnpm install js-waku Start the dev server and open the dApp in your browser:\nnpm run start We have noticed some issues with React bundling due to npm pulling an old version of babel. If you are getting an error about the optional chaining (?.) character not being valid, try cleaning up and re-installing your dependencies:\nrm -rf node_modules package-lock.json npm install Create Waku Instance # In order to interact with the Waku network, you first need a Waku instance. Go to App.js and modify the App function:\nimport {Waku} from \u0026#39;js-waku\u0026#39;; import * as React from \u0026#39;react\u0026#39;; function App() { const [waku, setWaku] = React.useState(undefined); const [wakuStatus, setWakuStatus] = React.useState(\u0026#39;None\u0026#39;); // Start Waku React.useEffect(() =\u0026gt; { // If Waku status not None, it means we are already starting Waku if (wakuStatus !== \u0026#39;None\u0026#39;) return; setWakuStatus(\u0026#39;Starting\u0026#39;); // Create Waku Waku.create({bootstrap: {default: true}}).then((waku) =\u0026gt; { // Once done, put it in the state setWaku(waku); // And update the status setWakuStatus(\u0026#39;Connecting\u0026#39;); }); }, [waku, wakuStatus]); return ( \u0026lt;div className=\u0026#39;App\u0026#39;\u0026gt; \u0026lt;header className=\u0026#39;App-header\u0026#39;\u0026gt; \u0026lt;p\u0026gt;{wakuStatus}\u0026lt;/p\u0026gt; \u0026lt;/header\u0026gt; \u0026lt;/div\u0026gt; ); } export default App; Wait to be connected # When using the bootstrap option, it may take some time to connect to other peers. To ensure that you have store peers available to retrieve messages from, use the Waku.waitForConnectedPeer() async function:\nReact.useEffect(() =\u0026gt; { if (!waku) return; if (wakuStatus === \u0026#39;Connected\u0026#39;) return; waku.waitForConnectedPeer().then(() =\u0026gt; { setWakuStatus(\u0026#39;Connected\u0026#39;); }); }, [waku, wakuStatus]); Use Protobuf # Waku v2 protocols use protobuf by default.\nLet\u0026rsquo;s review how you can use protobuf to decode structured data.\nFirst, define a data structure. For this guide, we will use a simple chat message that contains a timestamp, nick and text:\n{ timestamp: Date; nick: string; text: string; } To encode and decode protobuf payloads, you can use the protons package.\nInstall Protobuf Library # npm install protons Protobuf Definition # Define the data structure with protons:\nimport protons from \u0026#39;protons\u0026#39;; const proto = protons(` message ChatMessage { uint64 timestamp = 1; string nick = 2; bytes text = 3; } `); You can learn about protobuf message definitions here: Protocol Buffers Language Guide.\nDecode Messages # To decode the messages retrieved from a Waku Store node, you need to extract the protobuf payload and decode it using protons.\nfunction decodeMessage(wakuMessage) { if (!wakuMessage.payload) return; 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; const time = new Date(); time.setTime(timestamp); const utf8Text = Buffer.from(text).toString(\u0026#39;utf-8\u0026#39;); return { text: utf8Text, timestamp: time, nick }; } Retrieve messages # You now have all the building blocks to retrieve and decode messages for a store node.\nNote that Waku Store queries are paginated. The API provided by js-waku automatically traverses all pages of the Waku Store response. By default, the most recent page is retrieved first but this can be changed with the pageDirection option.\nFirst, define a React state to save the messages:\nfunction App() { const [messages, setMessages] = React.useState([]); /// [..] } Then, define processMessages to decode and then store messages in the React state. You will pass processMessages as a callback option to WakuStore.queryHistory. processMessages will be called each time a page is received from the Waku Store.\nconst processMessages = (retrievedMessages) =\u0026gt; { const messages = retrievedMessages.map(decodeMessage).filter(Boolean); setMessages((currentMessages) =\u0026gt; { return currentMessages.concat(messages.reverse()); }); }; Pass processMessage in WakuStore.queryHistory as the callback value:\nwaku.store .queryHistory([ContentTopic], { callback: processMessages }); Finally, create a Messages component to render the messages:\nfunction Messages(props) { return props.messages.map(({ text, timestamp, nick }) =\u0026gt; { return ( \u0026lt;li\u0026gt; ({formatDate(timestamp)}) {nick}: {text} \u0026lt;/li\u0026gt; ); }); } function formatDate(timestamp) { return timestamp.toLocaleString([], { month: \u0026#39;short\u0026#39;, day: \u0026#39;numeric\u0026#39;, hour: \u0026#39;numeric\u0026#39;, minute: \u0026#39;2-digit\u0026#39;, second: \u0026#39;2-digit\u0026#39;, hour12: false, }); } Use Messages in the App function:\nfunction App() { // [..] return ( \u0026lt;div className=\u0026#39;App\u0026#39;\u0026gt; \u0026lt;header className=\u0026#39;App-header\u0026#39;\u0026gt; \u0026lt;h2\u0026gt;{wakuStatus}\u0026lt;/h2\u0026gt; \u0026lt;h3\u0026gt;Messages\u0026lt;/h3\u0026gt; \u0026lt;ul\u0026gt; \u0026lt;Messages messages={messages} /\u0026gt; \u0026lt;/ul\u0026gt; \u0026lt;/header\u0026gt; \u0026lt;/div\u0026gt; ); } All together, you should now have:\nimport {Waku} from \u0026#39;js-waku\u0026#39;; import * as React from \u0026#39;react\u0026#39;; import protons from \u0026#39;protons\u0026#39;; const ContentTopic = \u0026#39;/toy-chat/2/huilong/proto\u0026#39;; const proto = protons(` message ChatMessage { uint64 timestamp = 1; string nick = 2; bytes text = 3; } `); function App() { const [waku, setWaku] = React.useState(undefined); const [wakuStatus, setWakuStatus] = React.useState(\u0026#39;None\u0026#39;); const [messages, setMessages] = React.useState([]); // Start Waku React.useEffect(() =\u0026gt; { // If Waku status not None, it means we are already starting Waku if (wakuStatus !== \u0026#39;None\u0026#39;) return; setWakuStatus(\u0026#39;Starting\u0026#39;); // Create Waku Waku.create({bootstrap: {default: true}}).then((waku) =\u0026gt; { // Once done, put it in the state setWaku(waku); // And update the status setWakuStatus(\u0026#39;Connecting\u0026#39;); }); }, [waku, wakuStatus]); React.useEffect(() =\u0026gt; { if (!waku) return; if (wakuStatus === \u0026#39;Connected\u0026#39;) return; waku.waitForConnectedPeer().then(() =\u0026gt; { setWakuStatus(\u0026#39;Connected\u0026#39;); }); }, [waku, wakuStatus]); React.useEffect(() =\u0026gt; { if (wakuStatus !== \u0026#39;Connected\u0026#39;) return; const processMessages = (retrievedMessages) =\u0026gt; { const messages = retrievedMessages.map(decodeMessage).filter(Boolean); setMessages((currentMessages) =\u0026gt; { return currentMessages.concat(messages.reverse()); }); }; waku.store .queryHistory([ContentTopic], {callback: processMessages}) .catch((e) =\u0026gt; { console.log(\u0026#39;Failed to retrieve messages\u0026#39;, e); }); }, [waku, wakuStatus]); return ( \u0026lt;div className=\u0026#39;App\u0026#39;\u0026gt; \u0026lt;header className=\u0026#39;App-header\u0026#39;\u0026gt; \u0026lt;h2\u0026gt;{wakuStatus}\u0026lt;/h2\u0026gt; \u0026lt;h3\u0026gt;Messages\u0026lt;/h3\u0026gt; \u0026lt;ul\u0026gt; \u0026lt;Messages messages={messages}/\u0026gt; \u0026lt;/ul\u0026gt; \u0026lt;/header\u0026gt; \u0026lt;/div\u0026gt; ); } export default App; function decodeMessage(wakuMessage) { if (!wakuMessage.payload) return; 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; const time = new Date(); time.setTime(timestamp); const utf8Text = Buffer.from(text).toString(\u0026#39;utf-8\u0026#39;); return {text: utf8Text, timestamp: time, nick}; } function Messages(props) { return props.messages.map(({text, timestamp, nick}) =\u0026gt; { return ( \u0026lt;li\u0026gt; ({formatDate(timestamp)}) {nick}: {text} \u0026lt;/li\u0026gt; ); }); } function formatDate(timestamp) { return timestamp.toLocaleString([], { month: \u0026#39;short\u0026#39;, day: \u0026#39;numeric\u0026#39;, hour: \u0026#39;numeric\u0026#39;, minute: \u0026#39;2-digit\u0026#39;, second: \u0026#39;2-digit\u0026#39;, hour12: false, }); } Note that WakuStore.queryHistory select an available store node for you. However, it can only select a connected node, which is why the bootstrapping is necessary. It will throw an error if no store node is available.\nIf no message are returned, then you can use https://status-im.github.io/js-waku/ to send some messages on the toy chat topic and refresh your app.\nFilter messages by send time # By default, Waku Store nodes store messages for 30 days. Depending on your use case, you may not need to retrieve 30 days worth of messages.\nWaku Message defines an optional unencrypted timestamp field. The timestamp is set by the sender. By default, js-waku sets the timestamp of outgoing message to the current time.\nYou can filter messages that include a timestamp within given bounds with the timeFilter option.\nRetrieve messages up to a week old:\nconst 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() } }); End result # You can see the complete code in the Minimal ReactJS Waku Store App.\n"},{"id":9,"href":"/docs/introduction/","title":"Introduction","section":"Introduction","content":"WakuConnect Docs # WakuConnect is a suite of libraries, SDKs and documentations to help you use Waku in your dApp.\nWaku is a decentralized, censorship-resistant, network and protocol family. It enables you to add communication features to your dApp in a decentralized manner, ensuring to your users that they will not be censored or de-platformed.\nWaku can be used for chat purposes and for many machine-to-machine use cases. You can learn more about Waku at wakunetwork.com.\nJS-Waku is the TypeScript implementation of the Waku protocol, built for browser environment.\nThe quick start presents an easy way to send and receive messages using js-waku.\nIf you prefer video content, check out the presentations.\nIf you are looking for inspiration, check out the use cases Waku can enable.\nThe guides explain specific js-waku features and how it can be used with popular web frameworks.\nThe js-waku repository also holds a number of examples. The examples are working Proof-of-Concepts that demonstrate how to use js-waku. Check out the example list to see what usage each example demonstrates.\nFinally, if you want to learn how Waku works under the hoods, check the specs at rfc.vac.dev.\nBugs, Questions \u0026amp; Support # If you encounter any bug or would like to propose new features, feel free to open an issue.\nTo get help, join #dappconnect-support on Vac Discord or Telegram. For more general discussion and latest news, join #dappconnect on Vac Discord or Telegram.\n"},{"id":10,"href":"/docs/","title":"Introduction","section":"Introduction","content":"WakuConnect Docs # WakuConnect is a suite of libraries, SDKs and documentations to help you use Waku in your dApp.\nWaku is a decentralized, censorship-resistant, network and protocol family. It enables you to add communication features to your dApp in a decentralized manner, ensuring to your users that they will not be censored or de-platformed.\nWaku can be used for chat purposes and for many machine-to-machine use cases. You can learn more about Waku at wakunetwork.com.\nJS-Waku is the TypeScript implementation of the Waku protocol, built for browser environment.\nThe quick start presents an easy way to send and receive messages using js-waku.\nIf you prefer video content, check out the presentations.\nIf you are looking for inspiration, check out the use cases Waku can enable.\nThe guides explain specific js-waku features and how it can be used with popular web frameworks.\nThe js-waku repository also holds a number of examples. The examples are working Proof-of-Concepts that demonstrate how to use js-waku. Check out the example list to see what usage each example demonstrates.\nFinally, if you want to learn how Waku works under the hoods, check the specs at rfc.vac.dev.\nBugs, Questions \u0026amp; Support # If you encounter any bug or would like to propose new features, feel free to open an issue.\nTo get help, join #dappconnect-support on Vac Discord or Telegram. For more general discussion and latest news, join #dappconnect on Vac Discord or Telegram.\n"},{"id":11,"href":"/docs/guides/vote_poll_sdk/poll_sdk/01_create_dapp/","title":"Create the DApp and Install Dependencies","section":"Poll SDK","content":"Create the DApp and Install Dependencies # Create React App # Create the new React app using the typescript template. Install the Waku Poll SDK packages.\nIn this guide, we use useDApp to access the blockchain.\nyarn create react-app poll-dapp-ts --template typescript cd poll-dapp-ts yarn add \\ @waku/poll-sdk-react-components @waku/poll-sdk-react-hooks @waku/vote-poll-sdk-react-components \\ @usedapp/core@0.4.7 yarn add -D @types/styled-components @usedapp/core must be frozen to version 0.4.7 due to incompatibility between minor versions of ethers.\nWakuConnect Vote \u0026amp; Poll SDK will be upgraded to the latest version of @usedapp/core and ethers once ethereum-waffle is released with the latest version of ethers.\n Setup polyfills # A number of Web3 dependencies need polyfills. Said polyfills must be explicitly declared when using webpack 5.\nThe latest react-scripts version uses webpack 5.\nWe will describe below a method to configure polyfills when using create-react-app/react-scripts or webpack 5. This may not be necessary if you do not use react-scripts or if you use webpack 4.\nStart by installing the polyfill libraries:\nyarn add assert buffer crypto-browserify stream-browserify Webpack 5 # If you directly use webpack 5, then you can inspire yourself from this webpack.config.js.\nReact-App-Rewired # An alternative is to let react-scripts control the webpack 5 config and only override some elements using react-app-rewired.\nInstall react-app-rewired:\nyarn add -D react-app-rewired Create a config-overrides.js file at the root of your app:\nconst webpack = require(\u0026#39;webpack\u0026#39;); module.exports = (config) =\u0026gt; { // 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, { \u0026#34;buffer\u0026#34;: require.resolve(\u0026#34;buffer\u0026#34;), \u0026#34;crypto\u0026#34;: require.resolve(\u0026#34;crypto-browserify\u0026#34;), \u0026#34;stream\u0026#34;: require.resolve(\u0026#34;stream-browserify\u0026#34;), \u0026#34;assert\u0026#34;: require.resolve(\u0026#34;assert\u0026#34;) } ) if (!config.plugins) config.plugins = [] config.plugins.push( new webpack.ProvidePlugin({ Buffer: [\u0026#39;buffer\u0026#39;, \u0026#39;Buffer\u0026#39;], })); return config; } Use react-app-rewired in the package.json, instead of react-scripts:\n \u0026quot;scripts\u0026quot;: { - \u0026quot;start\u0026quot;: \u0026quot;react-scripts start\u0026quot;, - \u0026quot;build\u0026quot;: \u0026quot;react-scripts build\u0026quot;, - \u0026quot;test\u0026quot;: \u0026quot;react-scripts test\u0026quot;, - \u0026quot;eject\u0026quot;: \u0026quot;react-scripts eject\u0026quot; + \u0026quot;start\u0026quot;: \u0026quot;react-app-rewired start\u0026quot;, + \u0026quot;build\u0026quot;: \u0026quot;react-app-rewired build\u0026quot;, + \u0026quot;test\u0026quot;: \u0026quot;react-app-rewired test\u0026quot;, + \u0026quot;eject\u0026quot;: \u0026quot;react-app-rewired eject\u0026quot; }, Start development server # You can now start the development server to serve your dApp at http://localhost:3000/ while we code:\nyarn start Back Next: Connect to the Ethereum Wallet "},{"id":12,"href":"/docs/guides/vote_poll_sdk/poll_sdk/02_connect_wallet/","title":"Connect to the Ethereum Wallet","section":"Poll SDK","content":"Connect to the Ethereum Wallet # This section may be skipped if you are adding the poll feature to an existing dApp that already connects to the user\u0026rsquo;s wallet. Delete the template App component:\nrm -f App.tsx App.css App.test.tsx Top bar # Use TopBar component to display wallet information. For that, create a PollPage component that includes the top bar and will include the poll elements. The component uses ethers to connect to the user\u0026rsquo;s wallet:\nexport function PollPage() { const {account, library, activateBrowserWallet, deactivate} = useEthers() const [signer, setSigner] = useState\u0026lt;undefined | JsonRpcSigner\u0026gt;(undefined) useEffect(() =\u0026gt; { if (account) { setSigner(library?.getSigner()) } else { // Deactivate signer if signed out setSigner(undefined) } }, [account]) return ( \u0026lt;div\u0026gt; \u0026lt;TopBar logo={\u0026#34;\u0026#34;} logoWidth={84} title={\u0026#39;Poll dApp\u0026#39;} theme={orangeTheme} activate={activateBrowserWallet} account={account} deactivate={deactivate} /\u0026gt; \u0026lt;/div\u0026gt; ) } Page # UseDApp # Create a config variable that contains the Ethereum network parameters:\nimport {ChainId, DAppProvider, useEthers} from \u0026#39;@usedapp/core\u0026#39;; import {DEFAULT_CONFIG} from \u0026#34;@usedapp/core/dist/cjs/src/model/config/default\u0026#34;; const config = { readOnlyChainId: ChainId.Mainnet, readOnlyUrls: { [ChainId.Mainnet]: \u0026#39;https://mainnet.infura.io/v3/your-infura-token\u0026#39;, }, multicallAddresses: { 1: \u0026#39;0xeefba1e63905ef1d7acba5a8513c70307c1ce441\u0026#39;, 3: \u0026#39;0x53c43764255c17bd724f74c4ef150724ac50a3ed\u0026#39;, 1337: process.env.GANACHE_MULTICALL_CONTRACT ?? \u0026#39;0x0000000000000000000000000000000000000000\u0026#39;, }, supportedChains: [...DEFAULT_CONFIG.supportedChains, 1337], notifications: { checkInterval: 500, expirationPeriod: 50000, }, } Replace your-infura-token with your Infura API token.\nStyled-components # styled-components is used for easy styling. Create a Wrapper variable to use in the page component:\nimport styled from \u0026#39;styled-components\u0026#39; const Wrapper = styled.div` height: 100%; width: 100%; ` Render # Finally, create the App component:\nexport function App() { return ( \u0026lt;Wrapper\u0026gt; \u0026lt;GlobalStyle/\u0026gt; \u0026lt;DAppProvider config={config}\u0026gt; \u0026lt;PollPage/\u0026gt; \u0026lt;/DAppProvider\u0026gt; \u0026lt;/Wrapper\u0026gt; ) } Your index.tsx should now be:\nimport {ChainId, DAppProvider, useEthers} from \u0026#39;@usedapp/core\u0026#39;; import {GlobalStyle, TopBar} from \u0026#39;@waku/vote-poll-sdk-react-components\u0026#39;; import React, {useEffect, useState} from \u0026#39;react\u0026#39;; import ReactDOM from \u0026#39;react-dom\u0026#39;; import \u0026#39;./index.css\u0026#39;; import {JsonRpcSigner} from \u0026#34;@ethersproject/providers\u0026#34;; import {orangeTheme} from \u0026#34;@waku/vote-poll-sdk-react-components/dist/cjs/src/style/themes\u0026#34;; import {DEFAULT_CONFIG} from \u0026#34;@usedapp/core/dist/cjs/src/model/config/default\u0026#34;; import styled from \u0026#39;styled-components\u0026#39; const config = { readOnlyChainId: ChainId.Mainnet, readOnlyUrls: { [ChainId.Mainnet]: \u0026#39;https://mainnet.infura.io/v3/b4451d780cc64a078ccf2181e872cfcf\u0026#39;, }, multicallAddresses: { 1: \u0026#39;0xeefba1e63905ef1d7acba5a8513c70307c1ce441\u0026#39;, 3: \u0026#39;0x53c43764255c17bd724f74c4ef150724ac50a3ed\u0026#39;, 1337: process.env.GANACHE_MULTICALL_CONTRACT ?? \u0026#39;0x0000000000000000000000000000000000000000\u0026#39;, }, supportedChains: [...DEFAULT_CONFIG.supportedChains, 1337], notifications: { checkInterval: 500, expirationPeriod: 50000, }, } export function PollPage() { const {account, library, activateBrowserWallet, deactivate} = useEthers() const [signer, setSigner] = useState\u0026lt;undefined | JsonRpcSigner\u0026gt;(undefined) useEffect(() =\u0026gt; { if (account) { setSigner(library?.getSigner()) } else { // Deactivate signer if signed out setSigner(undefined) } }, [account]) return ( \u0026lt;div\u0026gt; \u0026lt;TopBar logo={\u0026#34;\u0026#34;} logoWidth={84} title={\u0026#39;Poll dApp\u0026#39;} theme={orangeTheme} activate={activateBrowserWallet} account={account} deactivate={deactivate} /\u0026gt; \u0026lt;/div\u0026gt; ) } export function App() { return ( \u0026lt;Wrapper\u0026gt; \u0026lt;GlobalStyle/\u0026gt; \u0026lt;DAppProvider config={config}\u0026gt; \u0026lt;PollPage/\u0026gt; \u0026lt;/DAppProvider\u0026gt; \u0026lt;/Wrapper\u0026gt; ) } const Wrapper = styled.div` height: 100%; width: 100%; ` ReactDOM.render( \u0026lt;React.StrictMode\u0026gt; \u0026lt;App/\u0026gt; \u0026lt;/React.StrictMode\u0026gt;, document.getElementById(\u0026#39;root\u0026#39;) ); Back Next: Create-A-Poll Button "},{"id":13,"href":"/docs/guides/vote_poll_sdk/poll_sdk/03_create-a-poll_button/","title":"Create-A-Poll Button","section":"Poll SDK","content":"Create-A-Poll Button # Create the Poll component. It will allow the user to create a new poll, view polls and answer them. We\u0026rsquo;ll start by adding a button to create a poll.\nmkdir components touch components/Poll.tsx Styled-components # Again, create a Wrapper for styling:\nimport styled from \u0026#39;styled-components\u0026#39; const Wrapper = styled.div` display: flex; flex-direction: column; align-items: center; max-width: 1146px; position: relative; margin: 0 auto; padding: 150px 32px 50px; width: 100%; @media (max-width: 1146px) { max-width: 780px; } @media (max-width: 600px) { padding: 132px 16px 32px; } @media (max-width: 425px) { padding: 96px 16px 84px; } ` Button # Create a button that will display the PollCreation component on click. To create a poll, we need access to the wallet, thus the button must be disabled if the wallet is not connected.\nThe button is disabled if signer is undefined. To give a visual clue to the user, also make the button grey when disabled.\nUpon clicking the button, we set showPollCreation to true. showPollCreation will control when to render the poll creation modal.\ncomponents/Poll.tsx:\nimport {useState} from \u0026#39;react\u0026#39; import {JsonRpcSigner, Web3Provider} from \u0026#39;@ethersproject/providers\u0026#39; import {CreateButton} from \u0026#39;@waku/vote-poll-sdk-react-components\u0026#39; import {Theme} from \u0026#39;@waku/vote-poll-sdk-react-components/dist/esm/src/style/themes\u0026#39; type PollProps = { signer: JsonRpcSigner | undefined theme: Theme } export function Poll({signer, theme}: PollProps) { const [showPollCreation, setShowPollCreation] = useState(false) const disabled = !signer; return ( \u0026lt;Wrapper\u0026gt; { \u0026lt;CreateButton style={{backgroundColor: disabled ? \u0026#34;lightgrey\u0026#34; : theme.primaryColor}} theme={theme} disabled={disabled} onClick={() =\u0026gt; setShowPollCreation(true)}\u0026gt; Create a poll \u0026lt;/CreateButton\u0026gt; } \u0026lt;/Wrapper\u0026gt; ) } Now update the PollPage component to render the new Poll component:\nindex.tsx:\nexport function PollPage() { const {account, library, activateBrowserWallet, deactivate} = useEthers() const [signer, setSigner] = useState\u0026lt;undefined | JsonRpcSigner\u0026gt;(undefined) useEffect(() =\u0026gt; { if (account) { setSigner(library?.getSigner()) } else { // Deactivate signer if signed out setSigner(undefined) } }, [account]) return ( \u0026lt;div\u0026gt; \u0026lt;TopBar logo={\u0026#34;\u0026#34;} logoWidth={84} title={\u0026#39;Poll dApp\u0026#39;} theme={orangeTheme} activate={activateBrowserWallet} account={account} deactivate={deactivate} /\u0026gt; \u0026lt;Poll theme={orangeTheme} signer={signer}/\u0026gt; \u0026lt;/div\u0026gt; ) } Now, you have a button:\n Back Next: Poll Creation Component "},{"id":14,"href":"/docs/guides/vote_poll_sdk/poll_sdk/04_poll_creation/","title":"Poll Creation Component","section":"Poll SDK","content":"Poll Creation Component # The Poll SDK provides an off-the-shelf component to create a new poll: PollCreation. It takes in a WakuPolling hook that can created with useWakuPolling.\nuseWakuPolling takes:\n appName: Your app name. It is used to generate a unique content topic for your polls. See How to Choose a Content Topic for more information. tokenAddress: The address of your ERC-20 token. Only token holders can create and answer polls. provider: The Web3 provider to access the blockchain. multicallAddress: Address to this blockchain\u0026rsquo;s multicall contract. Add these parameters to PollProps and call useWakuPolling.\ncomponents/Poll.tsx\nimport {useState} from \u0026#39;react\u0026#39; import {useConfig} from \u0026#39;@usedapp/core\u0026#39; import {PollCreation} from \u0026#39;@waku/poll-sdk-react-components\u0026#39; import {JsonRpcSigner, Web3Provider} from \u0026#39;@ethersproject/providers\u0026#39; import {useWakuPolling} from \u0026#39;@waku/poll-sdk-react-hooks\u0026#39; import {CreateButton} from \u0026#39;@waku/vote-poll-sdk-react-components\u0026#39; import {Theme} from \u0026#39;@waku/vote-poll-sdk-react-components/dist/esm/src/style/themes\u0026#39; import {ChainId} from \u0026#34;@usedapp/core/src/constants\u0026#34;; type PollProps = { appName: string library: Web3Provider | undefined signer: JsonRpcSigner | undefined chainId: ChainId | undefined theme: Theme tokenAddress: string } export function Poll({appName, library, signer, chainId, theme, tokenAddress}: PollProps) { const config = useConfig() const [showPollCreation, setShowPollCreation] = useState(false) const wakuPolling = useWakuPolling(appName, tokenAddress, library, config?.multicallAddresses?.[chainId ?? 1337]) const disabled = !signer; return ( \u0026lt;Wrapper\u0026gt; {showPollCreation \u0026amp;\u0026amp; signer \u0026amp;\u0026amp; ( \u0026lt;PollCreation wakuPolling={wakuPolling} setShowPollCreation={setShowPollCreation} theme={theme}/\u0026gt; )} { \u0026lt;CreateButton style={{backgroundColor: disabled ? \u0026#34;lightgrey\u0026#34; : theme.primaryColor}} theme={theme} disabled={disabled} onClick={() =\u0026gt; setShowPollCreation(true)}\u0026gt; Create a poll \u0026lt;/CreateButton\u0026gt; } \u0026lt;/Wrapper\u0026gt; ) } Then pass them in PollPage.\nIn this example, we use demo-poll-dapp for the app name and the mainnet SNT token contract for the token address. Replace those with your own.\nindex.tsx\nexport function PollPage() { const {account, library, activateBrowserWallet, deactivate, chainId} = useEthers() const [signer, setSigner] = useState\u0026lt;undefined | JsonRpcSigner\u0026gt;(undefined) useEffect(() =\u0026gt; { if (account) { setSigner(library?.getSigner()) } else { // Deactivate signer if signed out setSigner(undefined) } }, [account]) return ( \u0026lt;div\u0026gt; \u0026lt;TopBar logo={\u0026#34;\u0026#34;} logoWidth={84} title={\u0026#39;Poll dApp\u0026#39;} theme={orangeTheme} activate={activateBrowserWallet} account={account} deactivate={deactivate} /\u0026gt; \u0026lt;Poll theme={orangeTheme} appName={\u0026#39;demo-poll-dapp\u0026#39;} library={library} signer={signer} chainId={chainId} tokenAddress={\u0026#39;0x744d70FDBE2Ba4CF95131626614a1763DF805B9E\u0026#39;}/\u0026gt; \u0026lt;/div\u0026gt; ) } You can now see the poll creation modal when clicking on the button:\n Back Next: Poll List Component "},{"id":15,"href":"/docs/guides/vote_poll_sdk/poll_sdk/05_poll_list/","title":"Poll List Component","section":"Poll SDK","content":"Poll List Component # To display existing polls, the PollList component is provided.\nSimply add it to the Poll function to render it. It needs the account variable that can be passed as a property to Poll:\ncomponents/Poll.tsx:\nimport {useState} from \u0026#39;react\u0026#39; import {useConfig} from \u0026#39;@usedapp/core\u0026#39; import {PollCreation, PollList} from \u0026#39;@waku/poll-sdk-react-components\u0026#39; import {JsonRpcSigner, Web3Provider} from \u0026#39;@ethersproject/providers\u0026#39; import {useWakuPolling} from \u0026#39;@waku/poll-sdk-react-hooks\u0026#39; import {CreateButton} from \u0026#39;@waku/vote-poll-sdk-react-components\u0026#39; import {Theme} from \u0026#39;@waku/vote-poll-sdk-react-components/dist/esm/src/style/themes\u0026#39; import {ChainId} from \u0026#34;@usedapp/core/src/constants\u0026#34;; type PollProps = { appName: string library: Web3Provider | undefined signer: JsonRpcSigner | undefined chainId: ChainId | undefined account: string | null | undefined theme: Theme tokenAddress: string } export function Poll({appName, library, signer, chainId, account, theme, tokenAddress}: PollProps) { const config = useConfig() const [showPollCreation, setShowPollCreation] = useState(false) const wakuPolling = useWakuPolling(appName, tokenAddress, library, config?.multicallAddresses?.[chainId ?? 1337]) const disabled = !signer; return ( \u0026lt;Wrapper\u0026gt; {showPollCreation \u0026amp;\u0026amp; signer \u0026amp;\u0026amp; ( \u0026lt;PollCreation wakuPolling={wakuPolling} setShowPollCreation={setShowPollCreation} theme={theme}/\u0026gt; )} { \u0026lt;CreateButton style={{backgroundColor: disabled ? \u0026#34;lightgrey\u0026#34; : theme.primaryColor}} theme={theme} disabled={disabled} onClick={() =\u0026gt; setShowPollCreation(true)}\u0026gt; Create a poll \u0026lt;/CreateButton\u0026gt; } \u0026lt;PollList wakuPolling={wakuPolling} account={account} theme={theme} /\u0026gt; \u0026lt;/Wrapper\u0026gt; ) } Pass the account to Poll in index.tsx:\n\u0026lt;Poll theme={orangeTheme} appName={\u0026#39;demo-poll-dapp\u0026#39;} library={library} signer={signer} chainId={chainId} account={account} tokenAddress={\u0026#39;0x744d70FDBE2Ba4CF95131626614a1763DF805B9E\u0026#39;}/\u0026gt; Et voila! The PollList component handles the display of polls:\nAnd answering them:\nYou can find the resulting code in the examples folder.\nThe 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. The final gif:\nBack "},{"id":16,"href":"/docs/quick_start/","title":"Quick Start","section":"Introduction","content":"Quick Start # In this section you will learn how to receive and send messages using Waku Relay.\nA more in depth guide for Waku Relay can be found here.\nInstall # Install the js-waku package:\nnpm install js-waku # or with yarn yarn add js-waku Start a waku node # import {Waku} from \u0026#39;js-waku\u0026#39;; const waku = await Waku.create({bootstrap: {default: true}}); Listen for messages # The contentTopic is a metadata string that allows categorization of messages on the waku network. Depending on your use case, you can either create one (or several) new contentTopic(s) or look at the RFCs and use an existing contentTopic. See How to Choose a Content Topic for more details.\nFor example, if you were to use a new contentTopic such as /my-cool-app/1/my-use-case/proto, here is how to listen to new messages received via Waku v2 Relay:\nwaku.relay.addObserver((msg) =\u0026gt; { console.log(\u0026#34;Message received:\u0026#34;, msg.payloadAsUtf8) }, [\u0026#34;/my-cool-app/1/my-use-case/proto\u0026#34;]); Send messages # Messages are wrapped in a WakuMessage envelop.\nimport { WakuMessage } from \u0026#39;js-waku\u0026#39;; const msg = await WakuMessage.fromUtf8String(\u0026#34;Here is a message!\u0026#34;, \u0026#34;/my-cool-app/1/my-use-case/proto\u0026#34;) await waku.relay.send(msg); Building an app # Check out the ReactJS Waku Relay guide to learn how you can use the code above in a React app.\n"},{"id":17,"href":"/docs/use_cases/","title":"Use Cases","section":"Introduction","content":"Use Cases # Waku is a generalized communication network. It can enable numerous use cases, both person-to-person (e.g. messenger) and machine-to-machine (e.g. state channels).\nThis is a non-exhaustive list of use cases that we have considered and their current status.\nIf we are aware of other projects using js-waku and other use cases that could be implemented, feel free to open a PR.\nLegend:\n 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. Chat Messenger # Work In Progress Waku can be used as the communication layer to a private, decentralized, censorship-resistant messenger.\n WakuConnect Chat SDK: repo Polls # SDK Available Create, answer and view polls which are censorship-resistant.\n WakuConnect Poll SDK: docs, repo 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.\n https://smolpuddle.io/ repo State Channels # Idea Use Waku to enable two parties to setup and maintain a state channel.\n Discussion: statechannels.org Discourse Voting and Proposals # SDK Available For proposals submitted on the blockchain, exchange votes over Waku to save gas. Votes can then be aggregated and submitted to the blockchain to commit the result.\nCreate, answer and view polls which are censorship-resistant.\n WakuConnect Vote SDK: docs, repo 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 \u0026amp; 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.\n Super Card Game dApp to Wallet Communication # Live Communication between a user\u0026rsquo;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), or for a dApp to request transaction signature to the wallet.\n WalletConnect 2.0 HashPack Layer 2 Communication # Idea Use Waku as an existing communication network to broadcast and aggregate layer 2 transactions. 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.\n Waku-Uber: article, repo Social Media Platform # Idea Chat Messenger is one form of social media that can be empowered by Waku to be decentralized and censorship-resistant. Other form of social media: news feed, blogposts, audio or video sharing, can also benefit of Waku. "},{"id":18,"href":"/docs/presentations/","title":"Presentations \u0026 Videos","section":"Introduction","content":"Presentations \u0026amp; Videos # 17 Sep 2021 - EthOnline # Pre-recorded video for hackathon participants.\n Slides: https://notes.status.im/eth-global-2021\n21 Jul 2021 - EthCC 2021 # Note: DappConnect is now named WakuConnect.\n Slides: https://notes.status.im/dappconnect-pres\n21 Jul 2021 - Ethereum Engineering Group meetup # Note: DappConnect is now named WakuConnect.\n Slides: https://notes.status.im/dappconnect-pres\n"},{"id":19,"href":"/docs/guides/","title":"Guides","section":"Introduction","content":"Guides # Waku Concepts # How to Choose a Content Topic JavaScript # Receive and Send Messages Using Waku Relay Retrieve Messages Using Waku Store Encrypt Messages Using Waku Message Version 1 Sign Messages Using Waku Message Version 1 Send Messages Using Waku Light Push ReactJS # Receive and Send Messages Using Waku Relay With ReactJS Retrieve Messages Using Waku Store With ReactJS "},{"id":20,"href":"/docs/examples/","title":"Examples","section":"Introduction","content":"Examples # Here is the list of the code examples and the features they demonstrate. To run or studies the example, click on the repo links.\nMinimal ReactJS Chat App # Repo: min-react-js-chat.\nDemonstrates:\n Group chat React/JavaScript Waku Relay Protobuf using protons No async/await syntax Minimal ReactJS Waku Store App # Repo: store-reactjs-chat.\nDemonstrates:\n Waku Store React/JavaScript Protobuf using protons Vanilla Javascript Using Minified Library # Repo: unpkg-js-store.\nDemonstrates:\n How to stop retrieving results from Waku Store on condition Use minified bundle from Unpkg.com Vanilla JavaScript application Web Chat App # Repo: web-chat.\nDemonstrates:\n Group chat React/TypeScript Waku Relay Waku Store Protobuf using .proto files + bufbuild + ts-proto Ethereum Private Message Web App # Repo: eth-pm.\nDemonstrates:\n Private messaging React/TypeScript Waku Light Push Signature with Web3 Wallet Asymmetric Encryption Symmetric Encryption Protobuf using protobufjs Ethereum Private Message Using Web3 Wallet Encryption API Web App # Repo: eth-pm-wallet-encryption.\nDemonstrates:\n Private Messaging React/TypeScript Waku Light Push Signature with Web3 using EIP-712: eth_signTypedData_v4 Asymmetric Encryption Usage of eth_decrypt Web3 Wallet API Protobuf using protobufjs Uber-like minimalistic car sharing app suing Vue.js # Repo: TheBojda/waku-uber.\nArticle: Decentralized Uber: Here\u0026rsquo;s How I Built It With Status.im, Waku, and Vue.js.\nDemonstrates:\n Vue.js Waku Relay Protobuf using protons "},{"id":21,"href":"/docs/crypto_libraries/","title":"Cryptographic Libraries","section":"Introduction","content":"Cryptographic Libraries # A note on the cryptographic libraries used as it is a not a straightforward affair.\nAsymmetric encryption # Uses ecies-geth which in turns uses SubtleCrypto Web API (browser), secp256k1 (native binding for node) or elliptic (pure JS if none of the other libraries are available).\nSymmetric encryption # Uses SubtleCrypto Web API (browser) or NodeJS' crypto module.\n"},{"id":22,"href":"/docs/waku_protocols/","title":"Implemented Waku Protocols","section":"Introduction","content":"Waku Protocol Support # You can track progress on the project board.\n ✔: Supported 🚧: Implementation in progress ⛔: Support is not planned Spec Implementation Status 6/WAKU1 ⛔ 7/WAKU-DATA ⛔ 8/WAKU-MAIL ⛔ 9/WAKU-RPC ⛔ 10/WAKU2 🚧 11/WAKU2-RELAY ✔ 12/WAKU2-FILTER 13/WAKU2-STORE ✔ (querying node only) 14/WAKU2-MESSAGE ✔ 15/WAKU2-BRIDGE 16/WAKU2-RPC ⛔ 17/WAKU2-RLNRELAY 18/WAKU2-SWAP 19/WAKU2-LIGHTPUSH ✔ 20/TOY-ETH-PM ✔ (as example) 21/WAKU2-FTSTORE ✔ 22/TOY-CHAT ✔ (as example) 25/LIBP2P-DNS-DISCOVERY 🚧 26/WAKU2-PAYLOAD ✔ "},{"id":23,"href":"/docs/guides/vote_poll_sdk/","title":"Vote Poll Sdk","section":"Guides","content":"WakuConnect Vote \u0026amp; Poll SDK # The WakuConnect Vote \u0026amp; Poll SDK enables developers to add Waku powered polling and voting features to their dApp.\nThe repository can be found on GitHub: https://github.com/status-im/wakuconnect-vote-poll-sdk.\nThe SDK can be used in two different ways: to vote (commitment to the blockchain) or poll (no interaction with the blockchain).\nFor both functionalities, only ERC-20 token holders can create or answer polls/votes. The developer using the SDK can configure which ERC-20 token contract is used.\nPackages # Common # @waku/vote-poll-sdk-core: Common libraries to both vote and poll functionalities. @waku/vote-poll-sdk-react-components: Common React components to both vote and poll functionalities. Vote # @waku/vote-sdk-react-components: React components. @waku/vote-sdk-react-hooks: React hooks. @waku/vote-sdk-contracts: Solidity contracts. Poll # @waku/poll-sdk-react-components: React components. @waku/poll-sdk-react-hooks: React hooks. WakuConnect Vote SDK # The WakuConnect Vote SDK allows you to leverage Waku to save gas fees for most voters. It uses Waku to broadcast and aggregate votes. Most token holders will not need to spend gas to vote.\nOnly the party that starts an election and submit the end results need to interact with the blockchain.\nFor example, it can be used by a DAO to manage proposals where proposal creation and vote results must be committed to the blockchain.\nWith 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.\nDocumentation # The documentation effort is currently in progress. It is tracked with status-im/wakuconnect-vote-poll-sdk#11. Contributions are welcome. You can find more information about the Vote SDK\u0026rsquo;s properties in the README.\nA working example dApp that includes voting feature can be found in the repo.\nAs the example is part of the yarn workspace, there may be issues with undeclared dependencies with this example. Tracked with status-im/wakuconnect-vote-poll-sdk#11. WakuConnect Poll SDK # The WakuConnect Poll SDK allows you to leverage Waku and enable token holders to create, answer and view polls. The polls are not committed to the blockchain and hence do not cost gas.\nAs the polls use Waku, they do maintain properties expected from dApps: decentralized and censorship-resistant.\nThe high-level functionality is as follows:\n To create a poll, a token holder sends a message with the poll questions, possible answers and an end time over Waku, Other users receive the poll creation message and can view the poll, To avoid spam, only polls created by actual token holders are displayed, Any token holder can send their poll answer over Waku, Each user cumulates poll responses from Waku and can view them, To avoid spam, only responses sent by actual token holders are displayed. Documentation # See How to Use the WakuConnect Poll SDK.\n"}]