Blog.

Creating your fist Dapp

Nicolas Bello Camilletti
Nicolas Bello Camilletti
7 min read

Decentralized applications, or DApps, are applications that run on a blockchain network. These applications are decentralized, meaning they do not have a central authority or control, and are transparent and secure. In this post, we'll be using JavaScript and Remix to create a simple DApp.

Creating the Smart contrat

To create a DApp, you'll need to set up your development environment. There are development framework for Ethereum such as Truffle, Hardhat or Foundry which are very powerful and easy to use, but I want to focus on the consuming that DApp, so we will be using Remix to simplify things a bit.

Remix is a Web Ide that supports creating and deploying solidity's smart contracts in Ethereum. The best is that it provides a few simple examples to start with and you can also compile them and get their ABI (Application Binary Interface) which we will need to call the smart contract from our site.

We can create a simple smart contract like the following which stores and retrive a string.

pragma solidity ^0.8.0;

contract SimpleStorage {
  string private data;

  function setData(string memory _data) public {
    data = _data;
  }

  function getData() public view returns (string memory) {
    return data;
  }
}

The ABI for that smart contract will look like the following.

[
  {
    "inputs": [],
    "name": "getData",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "string",
        "name": "_data",
        "type": "string"
      }
    ],
    "name": "setData",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  }
]

Creating the project structure

Now that we have our Smart Contract, let's focus on the rest of the app. First, let's start creating a new empty project with npm init -y.

Next, we need to install the following dependencies:

  • web3.js: A JavaScript library for interacting with the Ethereum blockchain.
  • remixd: A tool for connecting Remix with a local folder.
  • http-server: A simple web server for serving our DApp.

Run the following command to install these dependencies:

npm install web3 remixd http-server --save-dev

Compiling the smart contract

Now, we need to compile the smart contract into bytecode that can be deployed to the Ethereum blockchain. Let's use Remix by starting the remixd daemon by running the following command in your terminal:

remixd -s ~/path/to/your/project

This command will start a daemon that connects Remix with your project directory.

Next, open your web browser and navigate to https://remix.ethereum.org/. Remix should automatically connect to your local folder. If not, click the "Connect to Localhost" button and select the "Shared Folder" option. Then, navigate to your project directory and click "Connect".

Once you've connected to Remix, create a new file called "SimpleStorage.sol" and paste the code from our smart contract. Then, select the "Solidity Compiler" tab in the left-hand menu and click the "Compile SimpleStorage.sol" button. This will compile your smart contract into bytecode that can be deployed to the blockchain.

Now that we've compiled our smart contract, we need to deploy it to the Ethereum blockchain. For this example, we'll be deploying the contract to a local blockchain using Ganache.

To get started, install Ganache from the official website. Once installed, open Ganache and start a new blockchain.

Next, we need to update our JavaScript code to include the address of the deployed smart contract. Open a new file called "app.js" in your project directory and paste the following code:

const Web3 = require("web3");
const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:7545"));

const abi = [
  {
    inputs: [],
    name: "getData",
    outputs: [
      {
        internalType: "string",
        name: "",
        type: "string",
      },
    ],
    stateMutability: "view",
    type: "function",
  },
  {
    inputs: [
      {
        internalType: "string",
        name: "_data",
        type: "string",
      },
    ],
    name: "setData",
    outputs: [],
    stateMutability: "nonpayable",
    type: "function",
  },
];

const contractAddress = "YOUR_CONTRACT_ADDRESS_HERE";

const simpleStorageContract = new web3.eth.Contract(abi, contractAddress);

simpleStorageContract.methods
  .setData("Hello, world!")
  .send({ from: "YOUR_ACCOUNT_ADDRESS_HERE" })
  .then(() => {
    console.log("Data set successfully!");
    return simpleStorageContract.methods.getData().call();
  })
  .then((data) => {
    console.log(`Data retrieved: ${data}`);
  })
  .catch((err) => {
    console.error(err);
  });

This code creates a new instance of the Web3 library and sets the provider to a local Ganache blockchain. It also includes the ABI (Application Binary Interface) for our "SimpleStorage" contract, which defines the functions and data types of our contract.

Replace YOUR_CONTRACT_ADDRESS_HERE with the address of your deployed smart contract, and replace YOUR_ACCOUNT_ADDRESS_HERE with the address of your Ganache account.

This code also includes two functions: setData and getData. The setData function sets a string value on our smart contract using the send method, which requires a from address. The getData function retrieves the current value of the data variable using the call method.

Serving the DApp

Finally, we need to serve our DApp to users. We'll be using the http-server package to serve our DApp. Open a new file called server.js in your project directory and paste the following code:

const http = require("http");
const { URL } = require("url");
const httpServer = require("http-server");
const WebSocket = require("ws");
const remixd = require("remixd");

// Start Remixd daemon
remixd.start("http://localhost:65520", "/", process.cwd());

// Start HTTP server
const server = httpServer.createServer({ root: __dirname });
server.listen(8080, () => {
  console.log("Server running on port 8080!");
});

// Start WebSocket server
const wss = new WebSocket.Server({ port: 8081 });
wss.on("connection", (ws) => {
  const url = new URL(
    ws.upgradeReq.url,
    `http://${ws.upgradeReq.headers.host}`
  );
  const path = url.pathname;
  const fileManager = remixd.getFileManager();

  fileManager.setWebSocket(ws, path);
});

This code starts a Remixd daemon that connects to your project directory, starts an HTTP server on port 8080, and starts a WebSocket server on port 8081. The WebSocket server is used to communicate between Remix and our DApp.

To serve our DApp, open your terminal and run the following command:

node server.js

Once the server is running, open your web browser and navigate to http://localhost:8080. You should see a blank web page.

Now that we have a server running, let's add some HTML and JavaScript to our DApp. Create a new file called "index.html" in your project directory and paste the following code:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Simple Storage DApp</title>
  </head>
  <body>
    <h1>Simple Storage DApp</h1>
    <form>
      <label for="data">Data:</label>
      <input type="text" id="data" name="data" />
      <button type="button" id="setDataButton">Set Data</button>
    </form>
    <p id="dataOutput"></p>
    <script src="./index.js"></script>
  </body>
</html>

This code creates a simple HTML form with a text input and a button. It also includes a script tag that references a new JavaScript file called index.js.

Create a new file called index.js in your project directory and paste the following code:

const setDataButton = document.getElementById("setDataButton");
const dataInput = document.getElementById("data");
const dataOutput = document.getElementById("dataOutput");

setDataButton.addEventListener("click", async () => {
  const data = dataInput.value;
  await simpleStorageContract.methods
    .setData(data)
    .send({ from: "YOUR_ACCOUNT_ADDRESS_HERE" });
  const retrievedData = await simpleStorageContract.methods.getData().call();
  dataOutput.innerHTML = `Data retrieved: ${retrievedData}`;
});

This code adds an event listener to the "Set Data" button that retrieves the value of the text input, sets the value on the smart contract, retrieves the updated value, and displays it on the page.

Replace YOUR_ACCOUNT_ADDRESS_HERE with the address of your Ganache account.

Time to test your Dapp

Now that we have a server running and our HTML and JavaScript files are in place, let's test our DApp!

Open your terminal and navigate to your project directory. Run the following command to start the http-server.

http-server

Open a new terminal window and navigate to your project directory. Run the following command to start the WebSocket server:

node server.js

Open your web browser and navigate to http://localhost:8080. You should see the "Simple Storage DApp" title, a text input, and a Set Data button.

Enter a string value in the text input and click the Set Data button. You should see the message Data retrieved: [YOUR STRING VALUE] displayed on the page.

Congratulations, you've created your first DApp with JavaScript and Remix! This is just the beginning of what's possible with decentralized applications. Keep exploring and experimenting to unlock the full potential of blockchain technology.


More Stories

Creating a next.js middleware to better handling localization

4 min read

Localization can be hard to handle in your web sites. Luckily for us there are more tools everyday. While working with next.js I ended up…

Nicolas Bello Camilletti
Nicolas Bello Camilletti

ASP.NET Community Standup LATAM

3 min read

Hace algún tiempo venimos hablando con algunos amigos y compañeros sobre la falta de contenido en español y la necesidad de unir esfuerzos…

Nicolas Bello Camilletti
Nicolas Bello Camilletti