Skip to main content

Building your first Decentralized Application

A decentralized application (dApp) is one that doesn't rely on any single party to run it. It can be run by anyone, anytime, anywhere, and used for its intended purpose without relying on a central authority or backend servers.

In this tutorial, we will be building a simple, fully decentralized messaging application on the PWR Chain. This messaging application doesn't rely on any company to run it and doesn't use any conventional backend servers or databases. The only infrastructure it uses is the PWR Chain, and the parties who run it are the users themselves.

Prerequisites

Before starting, make sure you have the following:

  • A development environment set up for your preferred programming language.
  • PWR SDK installed and configured in your project.
  • You have finished reading the SDK guides.

Step 1: Set Up the Project

Create a new project in your preferred programming language, and add the necessary dependencies, including the PWR SDK, to your project's configuration file or build tool.

mkdir messageDapp && cd messageDapp
npm init --yes
npm install @pwrjs/core dotenv readline

NOTE: Rust developers will face some issues with file formatting compared to other languages, you can check out this project on Github.

Step 2: ENV setup to load the wallet

Create a .env file in your project folder and add your wallet's SEED_PHRASE in the file.

SEED_PHRASE="ADD_YOUR_SEED_PHRASE_HERE"

Step 3: Fetch Messages

To fetch messages from the PWR Chain, we'll use the method provided by the PWR SDK to retrieve transactions within a range of blocks.

Create a file in your project and add the following code:

const PWRJS = require("@pwrjs/core");

const rpc = new PWRJS("https://pwrrpc.pwrlabs.io/");

function handlerMessages(transaction) {
// Get the address of the transaction sender
const sender = transaction.sender;
// Get the data sent in the transaction (In Hex Format)
let dataHex = transaction.data;

// Decode the hexadecimal data to bytes data
const data = Buffer.from(dataHex, 'hex');
// convert the bytes data to UTF-8 string as json
const object = JSON.parse(data.toString('utf8'));

Object.keys(object).forEach(key => {
if (key.toLowerCase() === "message") {
console.log(`\nMessage from ${sender}: ${object[key]}`);
} else {
// Handle other data fields if needed
}
});
}

async function sync(vidaId) {
let startingBlock = await rpc.getLatestBlockNumber();

rpc.subscribeToVidaTransactions(vidaId, BigInt(startingBlock), handlerMessages);
}
export { sync };

Step 4: Build the DApp

Now that we have the individual components for sending messages, and fetching messages, let's put them all together in a complete application.

The final implementation should look like this:

  1. Run the project to fetch and send messages.
  2. The application keeps fetching messages without stopping.
  3. Write a message and click Enter to send.
  4. Fetch the message to you.

Create a file in your project and add the following code:

const Wallet = require("@pwrjs/core/wallet");
const { sync } = require("./sync_messages.js");
const readline = require("readline");
require('dotenv').config();

const seedPhrase = process.env.SEED_PHRASE;
let wallet = Wallet.fromSeedPhrase(seedPhrase);

const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});

async function main() {
const vidaId = BigInt(1234);
await sync(vidaId);

while (true) {
const message = await new Promise((resolve) => {
rl.question("Enter your message: ", resolve);
});

const object = { message };
const jsonData = Buffer.from(JSON.stringify(object), 'utf8');

const response = await wallet.sendVidaData(vidaId, jsonData);
if (response.success) {
console.log("Transaction Hash:", response.hash);
} else {
console.error("Error:", response.message || "Transaction failed");
}
}
}
main();

Finally, we enter a loop where the user can input messages, and each message is sent as a transaction to the PWR Chain using the sendVmDataTransaction method.

Step 5: Run the Application

To run the messaging application, add the following command:

node dapp.js

And that's it! You have now built a simple, decentralized messaging application on the PWR Chain. Users can run this application on their own machines, and all the messages will be stored and retrieved from the PWR Chain itself.

Conclusion

In this tutorial, we explored the process of building a decentralized messaging application on the PWR Chain using the PWR SDK. We covered creating or loading a wallet, fetching messages from the chain, sending messages as transactions, and putting all the components together in a complete application.

Remember, this is a basic example to demonstrate the concepts. In a production-ready application, you would need to consider additional factors such as security, error handling, performance optimization, and user interface design.

The power of decentralized applications lies in their ability to operate independently, without relying on a central authority or infrastructure. By leveraging the capabilities of the PWR Chain, developers can build innovative and resilient applications that empower users and promote decentralization.