{"id":28482,"date":"2022-03-23T22:57:59","date_gmt":"2022-03-23T22:57:59","guid":{"rendered":"http:\/\/Making-a-User-Interface-for-DApps"},"modified":"2022-03-23T22:57:59","modified_gmt":"2022-03-23T22:57:59","slug":"making-a-user-interface-for-dapps","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/","title":{"rendered":"Making a User Interface for DApps"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>As much of a buzz term as blockchain has become, it\u2019s still a great technology. To take some of the magic out of it, blockchain is essentially a distributed database. A blockchain is made of blocks that contain data and those blocks are chained together across multiple machines, which make up the distributed network.<\/p>\n<p>In this article, we\u2019ll build a distributed app in the Redwood framework that handles video data. We\u2019ll make a smart contract to handle our blockchain interactions. Then we\u2019ll set up the Redwood distributed app that will work with the blockchain.<\/p>\n<h2>Background on DApps<\/h2>\n<p>A DApp is very similar to a regular app. The only difference is that the back-end runs on a decentralized network instead of a central server that might host APIs or other services. It uses the <a href=\"https:\/\/ethereum.org\/en\/what-is-ethereum\/\">Ethereum<\/a> blockchain to store data and it has smart contracts to handle the business logic.<\/p>\n<p>By using smart contracts, DApps don\u2019t have an owner. A smart contract is like a set of rules that every part of the network has to follow. Once the smart contract has been deployed to Ethereum, you can\u2019t change it. That means no companies or individuals can change the instructions for that set of rules in any way.<\/p>\n<h3>Ethereum<\/h3>\n<p>For a little context, Ethereum is a decentralized, open-source blockchain that has smart contract functionality. This is used as the network to host smart contracts. Anybody can join an Ethereum network and they will automatically follow the rules in the smart contract.<\/p>\n<h2>Setting up a Redwood app<\/h2>\n<p>Now that we have a little background on what we\u2019ll be making, let\u2019s start by making the Redwood app. To do this, open a terminal and run:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">yarn create redwood-app user-dapp\n<\/code><\/span><\/pre>\n<p>This will generate new directories and files for the project that covers everything from the front-end to the back-end, including a database. Even when you\u2019re working with a DApp, there might be reasons you want to track data in a more common way, like easier data processing.<\/p>\n<p>With the app created, you should see two main directories: <code>api<\/code> and <code>web<\/code>. The <code>api<\/code> folder holds all of the logic for the GraphQL back-end and the code to manage the database transactions. The <code>web<\/code> folder, which is where we\u2019ll be focused, holds all of the front-end logic and user interface.<\/p>\n<h2>Some Installations<\/h2>\n<p>You\u2019ll need to <a href=\"https:\/\/www.trufflesuite.com\/ganache\">download Ganache<\/a> to set up a local Ethereum network that you can develop on. Once you have it installed, you can use the \u201cQuickstart\u201d option.<\/p>\n<p>You\u2019ll also need to install Truffle with the following command in the <code>web<\/code> directory.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">yarn add truffle\n<\/code><\/span><\/pre>\n<p>This is how we\u2019ll deploy the smart contract to the local Ethereum network.<\/p>\n<p>There are a few dependencies that need to be installed too. In the <code>web<\/code> directory run:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">yarn add truffle truffle-contract web3\n<\/code><\/span><\/pre>\n<p>This gives us everything we need for the smart contract.<\/p>\n<h2>Initializing the Truffle project<\/h2>\n<p>Now run the following in the <code>web<\/code> directory:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">yarn truffle init\n<\/code><\/span><\/pre>\n<p>This will create an initial migration and the smart contract for it in the <code>web<\/code> directory. Now we\u2019ll jump straight into some code since we have everything set up.<\/p>\n<h2>Writing the smart contract<\/h2>\n<p>Inside the <code>web &gt; contracts<\/code> directory, add a new file called <code>VideoList.sol<\/code>. This is where we\u2019ll write some <a href=\"https:\/\/docs.soliditylang.org\/en\/v0.8.7\/\">Solidity<\/a> code to define the rules for this contract. It looks very similar to JavaScript, but it\u2019s not the same language. Copy and paste the following code into this new file.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">pragma solidity ^<span class=\"hljs-number\">0.5<\/span><span class=\"hljs-number\">.0<\/span>;\n\ncontract VideoList {\n  uint public videoCount = <span class=\"hljs-number\">0<\/span>;\n\n  struct Video {\n    uint id;\n    string url;\n  }\n\n  mapping(<span class=\"hljs-function\"><span class=\"hljs-params\">uint<\/span> =&gt;<\/span> Video) public videos;\n\n  <span class=\"hljs-keyword\">constructor<\/span>() public {\n    createVideo(<span class=\"hljs-string\">\"https:\/\/res.cloudinary.com\/milecia\/video\/upload\/c_pad,h_360,w_480,q_70,du_10\/elephant_herd.mp4\"<\/span>);\n  }\n\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">createVideo<\/span>(<span class=\"hljs-params\">string memory _content<\/span>) <span class=\"hljs-title\">public<\/span> <\/span>{\n    videoCount ++;\n    videos&#91;videoCount] = Video(videoCount, _content);\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Let\u2019s walk through what happened here. We start by defining the version of Solidity we want to work with. Then we create the definition for the contract. In this example, the contract is called <code>VideoList<\/code>.<\/p>\n<p>In the contract, we have a publically exposed <code>videoCount<\/code> variable that holds how many videos have been added to the blockchain.<\/p>\n<p>Next, there\u2019s a <code>struct<\/code> that defines a <code>Video<\/code> record. It has an integer <code>id<\/code> value and a string <code>url<\/code> value. Then we map all of the videos into a public <code>videos<\/code> array.<\/p>\n<p>Using the <code>constructor<\/code>, we add a default video to the blockchain when the smart contract is deployed. Lastly, we have a function that will let us add new videos to the blockchain.<\/p>\n<p>This is the whole smart contract! All that\u2019s left to do is create a migration for it and deploy it to the local blockchain.<\/p>\n<h3>Migrations and deploys<\/h3>\n<p>Before we actually do the migration and deploy, there\u2019s a little config file we need to add. In the <code>web<\/code> directory, add a new file called <code>truffle-config.js<\/code>. Inside the file, paste the following code.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-built_in\">module<\/span>.exports = {\n  <span class=\"hljs-attr\">networks<\/span>: {\n    <span class=\"hljs-attr\">development<\/span>: {\n      <span class=\"hljs-attr\">host<\/span>: <span class=\"hljs-string\">\"127.0.0.1\"<\/span>,\n      <span class=\"hljs-attr\">port<\/span>: <span class=\"hljs-number\">7545<\/span>,\n      <span class=\"hljs-attr\">network_id<\/span>: <span class=\"hljs-string\">\"*\"<\/span> <span class=\"hljs-comment\">\/\/ so it can match any network id<\/span>\n    }\n  },\n  <span class=\"hljs-attr\">solc<\/span>: {\n    <span class=\"hljs-attr\">optimizer<\/span>: {\n      <span class=\"hljs-attr\">enabled<\/span>: <span class=\"hljs-literal\">true<\/span>,\n      <span class=\"hljs-attr\">runs<\/span>: <span class=\"hljs-number\">200<\/span>\n    }\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This is how we connect to the local Ethereum blockchain that\u2019s running through Ganache. These are the default values in Ganache and you can see them directly in the app.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1629510091\/e-603fc55d218a650069f5228b\/brte8mdkajhzmtcgvzkq.png\" alt=\"Ganache configs\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1333\"\/><\/p>\n<p>Then we\u2019ll need to add a new migration file to the <code>migrations<\/code> folder. Create a new migration file called <code>2_deploy_contracts.js<\/code>. We put the number at the beginning of the migration file so the network knows which order they should be run in.<\/p>\n<p>Open this file and add the following code.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> VideoList = artifacts.require(<span class=\"hljs-string\">\".\/VideoList.sol\"<\/span>);\n\n<span class=\"hljs-built_in\">module<\/span>.exports = <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span>(<span class=\"hljs-params\">deployer<\/span>) <\/span>{\n  deployer.deploy(VideoList);\n};\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This is how we deploy the <code>VideoList<\/code> smart contract we created.<\/p>\n<p>With this in place, we can run the migration for the smart contract. In the <code>web<\/code> directory, run:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">truffle migrate\n<\/code><\/span><\/pre>\n<p>You should see that the migration has run successfully. Now let\u2019s take a look at the smart contract in the Truffle console. We\u2019ll need the address of the smart contract for a later part of this article, so let\u2019s grab it while we\u2019re here.<\/p>\n<p>In the <code>web<\/code> directory, run:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">truffle <span class=\"hljs-built_in\">console<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This should bring you to an instance of the smart contract we deployed with the migration. Let\u2019s run so code in the console to get an instance of the contract with a function.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">videoList = <span class=\"hljs-keyword\">await<\/span> VideoList.deployed()\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We have to interact with the blockchain in an async manner, that\u2019s why we\u2019re using the <code>await<\/code> keyword in the Truffle console. Now let\u2019s get the address for this contract because we\u2019ll need it in the DApp.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">videoList<\/span><span class=\"hljs-selector-class\">.address<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This should return a string similiar to this:<\/p>\n<p><code>0x82293fe0BE6cCbA6Eb9bd6d5824fC6ACeB6d3957<\/code><\/p>\n<p>Since we have the smart contract built and deployed, we can turn our attention to the DApp which uses the data from the blockchain.<\/p>\n<h2>Working on the front-end<\/h2>\n<p>We\u2019ll take advantage of a Redwood command to get started on the front-end. We need a page that lets users interact with the DApp. Leave the <code>web<\/code> directory and go to the project root in the terminal and run the following command.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">yarn rw g page dapp \/\n<\/code><\/span><\/pre>\n<p>This will generate the page component, a Storybook component for the page, and a test for the page. It\u2019ll also add the route for this new page to the <code>Routes.tsx<\/code> file. Since we added the <code>\/<\/code> in the generate command above, it makes this new page the root page for the app.<\/p>\n<p>Back in the <code>web<\/code> directory, take a look inside <code>src &gt; pages &gt; DappPage<\/code>. This has all the files we talked about. Our focus will be on <code>DappPage.tsx<\/code>. Open this file and delete everything out of it.<\/p>\n<h3>Connecting to the Ethereum blockchain with Web3.js<\/h3>\n<p>The first thing we need to do is make a new file called <code>config.tsx<\/code> in the <code>web &gt; src<\/code> directory. This is where we\u2019ll add some config values that let the front-end connect to the blockchain network we have running with Ganache.<\/p>\n<p>Remember that address we got for our smart contract earlier? It\u2019s ok if you don\u2019t. All you have to do is open a terminal in the <code>web<\/code> directory and run the following commands to get that address again.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">truffle <span class=\"hljs-built_in\">console<\/span>\nvideoList = <span class=\"hljs-keyword\">await<\/span> VideoList.deployed()\nvideoList.address\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>In the <code>config.tsx<\/code> file, add the following line with your own smart contract address.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> VIDEO_LIST_ADDRESS = <span class=\"hljs-string\">'0x82293fe0BE6cCbA6Eb9bd6d5824fC6ACeB6d3957'<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Next, you\u2019ll have to get an array of values for the ABI of the smart contract. This describes the smart contract behavior and functionality to the front-end. You\u2019ll find this in <code>web &gt; build &gt; contracts &gt; VideoList.json<\/code>. In the json file, you\u2019ll see a key-value pair named <code>&quot;abi&quot;<\/code>. Copy that whole array and add the following code to <code>config.tsx<\/code> like this.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> VIDEO_LIST_ABI: any = &#91;\n  {\n    <span class=\"hljs-string\">\"constant\"<\/span>: <span class=\"hljs-literal\">true<\/span>,\n    <span class=\"hljs-string\">\"inputs\"<\/span>: &#91;],\n    <span class=\"hljs-string\">\"name\"<\/span>: <span class=\"hljs-string\">\"videoCount\"<\/span>,\n    <span class=\"hljs-string\">\"outputs\"<\/span>: &#91;\n      {\n        <span class=\"hljs-string\">\"name\"<\/span>: <span class=\"hljs-string\">\"\"<\/span>,\n        <span class=\"hljs-string\">\"type\"<\/span>: <span class=\"hljs-string\">\"uint256\"<\/span>\n      }\n    ],\n    <span class=\"hljs-string\">\"payable\"<\/span>: <span class=\"hljs-literal\">false<\/span>,\n    <span class=\"hljs-string\">\"stateMutability\"<\/span>: <span class=\"hljs-string\">\"view\"<\/span>,\n    <span class=\"hljs-string\">\"type\"<\/span>: <span class=\"hljs-string\">\"function\"<\/span>,\n    <span class=\"hljs-string\">\"signature\"<\/span>: <span class=\"hljs-string\">\"0xc61b5f4c\"<\/span>\n  },\n  {\n    <span class=\"hljs-string\">\"constant\"<\/span>: <span class=\"hljs-literal\">true<\/span>,\n    <span class=\"hljs-string\">\"inputs\"<\/span>: &#91;\n      {\n        <span class=\"hljs-string\">\"name\"<\/span>: <span class=\"hljs-string\">\"\"<\/span>,\n        <span class=\"hljs-string\">\"type\"<\/span>: <span class=\"hljs-string\">\"uint256\"<\/span>\n      }\n    ],\n    <span class=\"hljs-string\">\"name\"<\/span>: <span class=\"hljs-string\">\"videos\"<\/span>,\n    <span class=\"hljs-string\">\"outputs\"<\/span>: &#91;\n      {\n        <span class=\"hljs-string\">\"name\"<\/span>: <span class=\"hljs-string\">\"id\"<\/span>,\n        <span class=\"hljs-string\">\"type\"<\/span>: <span class=\"hljs-string\">\"uint256\"<\/span>\n      },\n      {\n        <span class=\"hljs-string\">\"name\"<\/span>: <span class=\"hljs-string\">\"url\"<\/span>,\n        <span class=\"hljs-string\">\"type\"<\/span>: <span class=\"hljs-string\">\"string\"<\/span>\n      }\n    ],\n    <span class=\"hljs-string\">\"payable\"<\/span>: <span class=\"hljs-literal\">false<\/span>,\n    <span class=\"hljs-string\">\"stateMutability\"<\/span>: <span class=\"hljs-string\">\"view\"<\/span>,\n    <span class=\"hljs-string\">\"type\"<\/span>: <span class=\"hljs-string\">\"function\"<\/span>,\n    <span class=\"hljs-string\">\"signature\"<\/span>: <span class=\"hljs-string\">\"0xe6821bf5\"<\/span>\n  },\n  {\n    <span class=\"hljs-string\">\"inputs\"<\/span>: &#91;],\n    <span class=\"hljs-string\">\"payable\"<\/span>: <span class=\"hljs-literal\">false<\/span>,\n    <span class=\"hljs-string\">\"stateMutability\"<\/span>: <span class=\"hljs-string\">\"nonpayable\"<\/span>,\n    <span class=\"hljs-string\">\"type\"<\/span>: <span class=\"hljs-string\">\"constructor\"<\/span>,\n    <span class=\"hljs-string\">\"signature\"<\/span>: <span class=\"hljs-string\">\"constructor\"<\/span>\n  },\n  {\n    <span class=\"hljs-string\">\"constant\"<\/span>: <span class=\"hljs-literal\">false<\/span>,\n    <span class=\"hljs-string\">\"inputs\"<\/span>: &#91;\n      {\n        <span class=\"hljs-string\">\"name\"<\/span>: <span class=\"hljs-string\">\"_content\"<\/span>,\n        <span class=\"hljs-string\">\"type\"<\/span>: <span class=\"hljs-string\">\"string\"<\/span>\n      }\n    ],\n    <span class=\"hljs-string\">\"name\"<\/span>: <span class=\"hljs-string\">\"createVideo\"<\/span>,\n    <span class=\"hljs-string\">\"outputs\"<\/span>: &#91;],\n    <span class=\"hljs-string\">\"payable\"<\/span>: <span class=\"hljs-literal\">false<\/span>,\n    <span class=\"hljs-string\">\"stateMutability\"<\/span>: <span class=\"hljs-string\">\"nonpayable\"<\/span>,\n    <span class=\"hljs-string\">\"type\"<\/span>: <span class=\"hljs-string\">\"function\"<\/span>,\n    <span class=\"hljs-string\">\"signature\"<\/span>: <span class=\"hljs-string\">\"0x8e878969\"<\/span>\n  }\n]\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>With this config file in place, let\u2019s import a few things in <code>DappPage.tsx<\/code>.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { useState, useEffect } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>\n<span class=\"hljs-keyword\">import<\/span> Web3 <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'web3'<\/span>\n<span class=\"hljs-keyword\">import<\/span> { VIDEO_LIST_ABI, VIDEO_LIST_ADDRESS } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/..\/config'<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Now let\u2019s build the <code>DappPage<\/code> component. We\u2019ll start with just the outline of the component and a few states.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> DappPage = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">const<\/span> &#91;account, setAccount] = useState&lt;string&gt;(<span class=\"hljs-string\">''<\/span>)\n  <span class=\"hljs-keyword\">const<\/span> &#91;videoList, setVideoList] = useState&lt;any&gt;()\n  <span class=\"hljs-keyword\">const<\/span> &#91;videos, setVideos] = useState(&#91;])\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Next, we\u2019ll call the function that will connect to the Ethereum network. We\u2019re using the <code>useEffect<\/code> hook here because we only want this to happen when the page initially loads. So right below the states we defined, add this code.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  loadData()\n}, &#91;])\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Let\u2019s jump into writing the <code>loadData<\/code> method. This is where we\u2019ll actually connect to the network and read data from the blockchain.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> loadData = <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n  <span class=\"hljs-keyword\">const<\/span> web3 = <span class=\"hljs-keyword\">new<\/span> Web3(<span class=\"hljs-string\">'http:\/\/localhost:7545'<\/span>)\n\n  <span class=\"hljs-keyword\">const<\/span> accounts = <span class=\"hljs-keyword\">await<\/span> web3.eth?.getAccounts()\n\n  setAccount(accounts&#91;<span class=\"hljs-number\">0<\/span>])\n\n  <span class=\"hljs-keyword\">const<\/span> videoList = <span class=\"hljs-keyword\">new<\/span> web3.eth.Contract(VIDEO_LIST_ABI, VIDEO_LIST_ADDRESS)\n  setVideoList(videoList)\n\n  <span class=\"hljs-keyword\">const<\/span> videoCount = <span class=\"hljs-keyword\">await<\/span> videoList.methods.videoCount().call()\n\n  <span class=\"hljs-keyword\">for<\/span> (<span class=\"hljs-keyword\">var<\/span> i = <span class=\"hljs-number\">1<\/span>; i &lt;= videoCount; i++) {\n    <span class=\"hljs-keyword\">const<\/span> video = <span class=\"hljs-keyword\">await<\/span> videoList.methods.videos(i).call()\n    setVideos(&#91;...videos, video])\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This is an async function because we want to wait for the blockchain to handle the request. We make a new instance of <code>Web3<\/code> that connects to the local Ethereum blockchain we have running. Then we get the accounts associated with this blockchain and grab the first one. We\u2019ll need this a little later.<\/p>\n<p>Next, we pass in the config values we wrote earlier to interact with the smart contract. We\u2019re getting the <code>videoList<\/code> contract and fetching the <code>videoCount<\/code> to see how many videos are available.<\/p>\n<p>Then we loop through all of the videos in the blockchain and save them to the app\u2019s state.<\/p>\n<p>Now we can return a view to the page that displays the smart contract id and the videos we\u2019ve fetched from the blockchain. Right below the <code>loadData<\/code> method, add the following return statement.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">return<\/span> (\n  <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    Dapp account id: {account}\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ul<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"videoList\"<\/span>&gt;<\/span>\n      {videos.map((video, key) =&gt; {\n        return (\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{key}<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">video<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{video.url}<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">video<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        )\n      })}\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n)\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>If you go to the root of the project in a terminal and run <code>yarn rw dev<\/code>, you should see something similar to this in the browser.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1629510132\/e-603fc55d218a650069f5228b\/p3ofurjfeeixmqensrcz.png\" alt=\"Dapp page\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1049\"\/><\/p>\n<p>You\u2019ve officially connected an app to an Ethereum blockchain using a smart contract you wrote! All that\u2019s left is adding a way for users to add new videos to the blockchain.<\/p>\n<h2>Adding the videos to the blockchain<\/h2>\n<p>For the last bit of functionality, we\u2019ll use the Cloudinary upload widget to add videos directly to the blockchain.<\/p>\n<p>We need to add the <code>react-cloudinary-upload-widget<\/code> package in a terminal in the <code>web<\/code> directory.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">yarn add react-cloudinary-upload-widget\n<\/code><\/span><\/pre>\n<p>Then we\u2019ll add another import line to <code>DappPage.tsx<\/code> below the others.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { WidgetLoader, Widget } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react-cloudinary-upload-widget'<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Now we can write the function to add a video to the blockchain. After the <code>loadData<\/code> function, add this code.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> createVideo = <span class=\"hljs-function\">(<span class=\"hljs-params\">content<\/span>) =&gt;<\/span> {\n  videoList.methods.createVideo(content).send({ <span class=\"hljs-attr\">from<\/span>: account, <span class=\"hljs-attr\">gas<\/span>: <span class=\"hljs-number\">4712388<\/span> })\n    .once(<span class=\"hljs-string\">'receipt'<\/span>, (receipt) =&gt; {\n      <span class=\"hljs-built_in\">console<\/span>.log(receipt)\n    })\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This is how we use the <code>createVideo<\/code> method we defined in the smart contract. One thing to note is that we need to send a certain amount of gas with this request. The amount of gas you have is tied to the account you\u2019re connected with. Each transaction in a smart contract has a gas price, but since we didn\u2019t change any default values <code>4712388<\/code> is what the contract expects as a gas payment.<\/p>\n<p>Now we\u2019ll define the callback that will give us a response from Cloudinary when the video has successfully uploaded. Right below the <code>createVideo<\/code> function we just wrote, add this.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> successCallBack = <span class=\"hljs-function\">(<span class=\"hljs-params\">results<\/span>) =&gt;<\/span> {\n  <span class=\"hljs-keyword\">const<\/span> videoInfo = results.info\n  <span class=\"hljs-keyword\">const<\/span> url = videoInfo.url\n\n  createVideo(url)\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This will be called in the <code>Widget<\/code> when we get a success response from Cloudinary. It\u2019ll take the URL from Cloudinary and add it to the blockchain. That means it\u2019s finally time to add that widget to the return statement. Below the line that displays the account id, add the following code.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">&lt;WidgetLoader \/&gt;\n&lt;Widget\n  sources={&#91;<span class=\"hljs-string\">'local'<\/span>, <span class=\"hljs-string\">'camera'<\/span>]}\n  cloudName={<span class=\"hljs-string\">'test_name'<\/span>}\n  uploadPreset={<span class=\"hljs-string\">'fwe9ewffw'<\/span>}\n  buttonText={<span class=\"hljs-string\">'Open'<\/span>}\n  style={{\n    color: <span class=\"hljs-string\">'white'<\/span>,\n    border: <span class=\"hljs-string\">'none'<\/span>,\n    width: <span class=\"hljs-string\">'120px'<\/span>,\n    backgroundColor: <span class=\"hljs-string\">'green'<\/span>,\n    borderRadius: <span class=\"hljs-string\">'4px'<\/span>,\n    height: <span class=\"hljs-string\">'25px'<\/span>,\n  }}\n  folder={<span class=\"hljs-string\">'test0'<\/span>}\n  onSuccess={successCallBack}\n\/&gt;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This is how we connect to Cloudinary and get URLs for videos we upload. You\u2019ll need to log in to your Cloudinary account and get the <code>cloudName<\/code> and <code>uploadPreset<\/code> name from the dashboard. Now you should see a new \u201cOpen\u201d button in the browser.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1629510164\/e-603fc55d218a650069f5228b\/he28v1wwslpygya3uytu.png\" alt=\"video upload button\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1832\" height=\"1036\"\/><\/p>\n<p>If you click that button, you\u2019ll see the upload widget.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1629510177\/e-603fc55d218a650069f5228b\/fvjvv1yc6ayxgvxkghxc.png\" alt=\"upload widget\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1040\"\/><\/p>\n<p>Go ahead and upload a new video and then reload the page. You should see your new video similar to this.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1629510196\/e-603fc55d218a650069f5228b\/y7zpztupp57f2jy3s2yk.png\" alt=\"second video\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"719\"\/><\/p>\n<p>You have a fully functioning DApp now! Feel free to add more functionality to the smart contract!<\/p>\n<h2>Finished code<\/h2>\n<p>You can check out some of the code in <a href=\"https:\/\/codesandbox.io\/s\/quizzical-frog-cw0sh\">this Code Sandbox<\/a> or clone the project from the <code>user-dapp<\/code> folder of <a href=\"https:\/\/github.com\/flippedcoder\/blog-examples\/tree\/main\/user-dapp\">this repo<\/a>.<\/p>\n<\/div>\n  \n  <div class=\"wp-block-cloudinary-code-sandbox \">\n    <iframe\n      src=\"https:\/\/codesandbox.io\/embed\/quizzical-frog-cw0sh?theme=dark&amp;codemirror=1&amp;highlights=&amp;editorsize=50&amp;fontsize=14&amp;expanddevtools=0&amp;hidedevtools=0&amp;eslint=0&amp;forcerefresh=0&amp;hidenavigation=0&amp;initialpath=%2F&amp;module=&amp;moduleview=0&amp;previewwindow=&amp;view=&amp;runonclick=1\"\n      height=\"500\"\n      style=\"width: 100%;\"\n      title=\"quizzical-frog-cw0sh\"\n      loading=\"lazy\"\n      allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n      sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    ><\/iframe>\n  <\/div>\n\n  <div class=\"wp-block-cloudinary-markdown \"><h2>Conclusion<\/h2>\n<p>DApps are a cool way to interact with blockchains. Some good next steps would be learning more about Solidity and smart contracts or just making more DApps with other frameworks!<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":28483,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[134,246,371,303],"class_list":["post-28482","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-guest-post","tag-react","tag-under-review","tag-video"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Making a User Interface for DApps<\/title>\n<meta name=\"description\" content=\"There are a lot of cool uses for blockchain. So let&#039;s take a look at what tracking videos might look like.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Making a User Interface for DApps\" \/>\n<meta property=\"og:description\" content=\"There are a lot of cool uses for blockchain. So let&#039;s take a look at what tracking videos might look like.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-03-23T22:57:59+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924406\/Web_Assets\/blog\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e.jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"5568\" \/>\n\t<meta property=\"og:image:height\" content=\"3712\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Making a User Interface for DApps\",\"datePublished\":\"2022-03-23T22:57:59+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/\"},\"wordCount\":6,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924406\/Web_Assets\/blog\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e.jpg?_i=AA\",\"keywords\":[\"Guest Post\",\"React\",\"Under Review\",\"Video\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/\",\"name\":\"Making a User Interface for DApps\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924406\/Web_Assets\/blog\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e.jpg?_i=AA\",\"datePublished\":\"2022-03-23T22:57:59+00:00\",\"description\":\"There are a lot of cool uses for blockchain. So let's take a look at what tracking videos might look like.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924406\/Web_Assets\/blog\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924406\/Web_Assets\/blog\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e.jpg?_i=AA\",\"width\":5568,\"height\":3712},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Making a User Interface for DApps\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Making a User Interface for DApps","description":"There are a lot of cool uses for blockchain. So let's take a look at what tracking videos might look like.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/","og_locale":"en_US","og_type":"article","og_title":"Making a User Interface for DApps","og_description":"There are a lot of cool uses for blockchain. So let's take a look at what tracking videos might look like.","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/","og_site_name":"Cloudinary Blog","article_published_time":"2022-03-23T22:57:59+00:00","og_image":[{"width":5568,"height":3712,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924406\/Web_Assets\/blog\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e.jpg?_i=AA","type":"image\/jpeg"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/"},"author":{"name":"","@id":""},"headline":"Making a User Interface for DApps","datePublished":"2022-03-23T22:57:59+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/"},"wordCount":6,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924406\/Web_Assets\/blog\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e.jpg?_i=AA","keywords":["Guest Post","React","Under Review","Video"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/","name":"Making a User Interface for DApps","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924406\/Web_Assets\/blog\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e.jpg?_i=AA","datePublished":"2022-03-23T22:57:59+00:00","description":"There are a lot of cool uses for blockchain. So let's take a look at what tracking videos might look like.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924406\/Web_Assets\/blog\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924406\/Web_Assets\/blog\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e.jpg?_i=AA","width":5568,"height":3712},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-a-user-interface-for-dapps\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Making a User Interface for DApps"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924406\/Web_Assets\/blog\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e\/064ea11510012851a05f980b82cf2a89aeb652e5-5568x3712-1_284832354e.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28482","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=28482"}],"version-history":[{"count":0,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28482\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/28483"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=28482"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=28482"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=28482"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}