{"id":28040,"date":"2022-03-23T22:59:34","date_gmt":"2022-03-23T22:59:34","guid":{"rendered":"http:\/\/Working-with-User-Profiles-on-a-Blockchain"},"modified":"2022-03-23T22:59:34","modified_gmt":"2022-03-23T22:59:34","slug":"working-with-user-profiles-on-a-blockchain","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/","title":{"rendered":"Working with User Profiles on a Blockchain"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>There might be a situation where you want to be able to store user profiles on an Ethereum blockchain so that you can make sure to track every update that\u2019s made. This might be to ensure that NFTs are always associated with the proper creator. It could also be to make sure that sensitive data is stored more securely than in a regular database.<\/p>\n<p>That\u2019s why we\u2019ll be making a Dapp (distributed app) that\u2019s hosted on an Ethereum network. We\u2019ll get the most sensitive information from the blockchain and we\u2019ll also have data in a regular database. All of this will be nicely bundled into a Redwood app.<\/p>\n<h2>Setting things up for the project<\/h2>\n<p>Working with blockchain can seem a little tricky at first. That\u2019s why we\u2019ll get a few things in place first. If you don\u2019t have Ganache installed, go ahead and <a href=\"https:\/\/www.trufflesuite.com\/ganache\">download that here<\/a>. This will give you access to a local Ethereum network you can use to deploy smart contracts.<\/p>\n<p>You\u2019ll also need a local Postgres instance since that\u2019s the regular database we\u2019ll work with. You can <a href=\"https:\/\/www.postgresql.org\/download\">download that for free<\/a> if you don\u2019t already have it.<\/p>\n<p>The last thing we need to set up is the project itself. Since we\u2019ll be working with Redwood, we can generate the files and folders we need for both the front-end and back-end with the following command.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ yarn create redwood-app --typescript user-profile-dapp\n<\/code><\/span><\/pre>\n<p>This bootstraps a fully functional full-stack app that we can modify to fit our Dapp. The two main directories we\u2019ll be working with are <code>api<\/code> and <code>web<\/code> which contain the code and folder structure for the back-end and front-end, respectively. With all of the setup finished, let\u2019s start writing our back-end code.<\/p>\n<h2>Working on the back-end<\/h2>\n<p>The first thing we\u2019ll do is define the models for our regular database. In <code>api &gt; db<\/code>, open the <code>schema.prisma<\/code> file. This is where we handle all of the database changes we need to make. Start by updating the <code>provider<\/code> to <code>postgresql<\/code> from <code>sqlite<\/code>.<\/p>\n<p>Then open your <code>.env<\/code> file in the root of the project. You\u2019ll see a commented-out reference to the <code>DATABASE_URL<\/code> variable. Go ahead and uncomment this and update it to match your connection string to Postgres. It might look something like this.<\/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\">DATABASE_URL=postgres:<span class=\"hljs-comment\">\/\/postgres:admin@localhost:5432\/user_profiles<\/span>\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>Now if you go back to the <code>schema.prisma<\/code> file, you\u2019ll see where this value is used to connect to the database. The last thing we need to do in this file is add our profile model. There\u2019s an example user model there and you can delete this and add 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\">model Profile {\n  id                <span class=\"hljs-built_in\">String<\/span>   @id @<span class=\"hljs-keyword\">default<\/span>(uuid())\n  updatedAt         DateTime\n  email             <span class=\"hljs-built_in\">String<\/span>\n  blockchainAddress <span class=\"hljs-built_in\">String<\/span>\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>That\u2019s all we need for the database model. We can run a migration to get this table in the database now. To do that, run this command.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ yarn rw prisma migrate dev\n<\/code><\/span><\/pre>\n<p>This will establish a connection to the database, prompt you for a migration name, then add your changes to the database. That\u2019s all for the database. Now we\u2019re going to show off one of Redwood\u2019s commands to generate the types and resolvers for the GraphQL server we\u2019ll use.<\/p>\n<h3>Working with GraphQL<\/h3>\n<p>In order to create and update user profiles in the regular database, we\u2019ll run this command to generate some code for us.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ yarn rw g sdl --crud profile\n<\/code><\/span><\/pre>\n<p>This will add a new file inside <code>api &gt; src &gt; graphql<\/code> that has all of the types to support our CRUD functionality. It also generates the resolvers to actually make database updates.<\/p>\n<p>You can find the resolvers in <code>api &gt; src &gt; services &gt; profiles<\/code>. There are a couple of files related to testing in that directory, but if you open <code>profiles.ts<\/code>, you\u2019ll see all of the resolvers.<\/p>\n<p>That wraps up everything on the back-end! Now we\u2019re going to shift focus to the front-end, where we\u2019ll write a smart contract and start interacting with a blockchain.<\/p>\n<h2>Writing the smart contract<\/h2>\n<p>Before we start coding the user interface, we do need to get that smart contract in place. To do this, let\u2019s install <a href=\"https:\/\/www.trufflesuite.com\/truffle\">Truffle<\/a> in the <code>web<\/code> directory. This will let us interact with our local blockchain directly in the terminal. You can install it with the following command.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ yarn add truffle web3\n<\/code><\/span><\/pre>\n<p>If that doesn\u2019t work for you, try the following command:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ npm install -g truffle\n<\/code><\/span><\/pre>\n<p>Sometimes there are issues with using Truffle if it\u2019s not installed globally, but that might be dependent on your local setup.<\/p>\n<p>Now that we have Truffle, let\u2019s start making our smart contract by running the following command in the <code>web<\/code> directory.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ truffle init\n<\/code><\/span><\/pre>\n<p>This will create a new directory called <code>contracts<\/code> and you\u2019ll see an initial smart contract file written in Solidity. We\u2019ll add another smart contract in this directory called <code>Profile.sol<\/code>. This is how we\u2019ll handle adding records to the blockchain.<\/p>\n<p>Every Solidity file starts with the version you want to use. We\u2019ll add this line to the top of the code.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">pragma<\/span> <span class=\"hljs-selector-tag\">solidity<\/span> ^0<span class=\"hljs-selector-class\">.5<\/span><span class=\"hljs-selector-class\">.0<\/span>;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><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>Now we want to start writing the contract. Add the following code below the version declaration.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">contract<\/span> <span class=\"hljs-selector-tag\">Profile<\/span> {\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><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>We can start defining some of the values we\u2019ll be working with. Inside of the contract, add the following code.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">uint256 <span class=\"hljs-keyword\">public<\/span> userCount = <span class=\"hljs-number\">0<\/span>;\n\nstruct User {\n  uint256 id;\n  string name;\n  string role;\n  string profileImg;\n  bool isRegistered;\n}\n\nmapping(uint256 =&gt; User) <span class=\"hljs-keyword\">public<\/span> usersById;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><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>Solidity is an interesting mix of JavaScript\/C++ syntax. The first variable we have is an integer that\u2019s publically accessible called <code>userCount<\/code>. This will help us track how many users we have and it\u2019ll act as the index for their profile information.<\/p>\n<p>Next, we have a struct that defines the <code>User<\/code> and their profile info. A struct is similar to an interface or a type in TypeScript.<\/p>\n<p>The next variable we have is a mapping. Mappings are like objects in JavaScript. We have a public mapping(object) called <code>usersById<\/code> and it has a key-value pair of an integer and a <code>User<\/code> object that looks something like this:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">{\n  <span class=\"hljs-number\">1<\/span>: {\n    <span class=\"hljs-attr\">id<\/span>: <span class=\"hljs-number\">1<\/span>,\n    <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'Spencer'<\/span>,\n    <span class=\"hljs-attr\">role<\/span>: <span class=\"hljs-string\">'admin'<\/span>,\n    <span class=\"hljs-attr\">profileImg<\/span>: <span class=\"hljs-string\">'https:\/\/res.cloudinary.com\/milecia\/image\/upload\/v1624811825\/beach-360_p6u08j.jpg'<\/span>,\n    <span class=\"hljs-attr\">isRegistered<\/span>: <span class=\"hljs-literal\">true<\/span>\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><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 the variable definitions in place, we can add our constructor function. This will get executed exactly one time during the life of the smart contract when it\u2019s initially deployed to the blockchain. Add this code below the mapping.<\/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\"><span class=\"hljs-keyword\">constructor<\/span>() public {\n  createUser(\n    <span class=\"hljs-string\">'Spencer'<\/span>,\n    <span class=\"hljs-string\">'admin'<\/span>,\n    <span class=\"hljs-string\">'https:\/\/res.cloudinary.com\/milecia\/image\/upload\/v1624811825\/beach-360_p6u08j.jpg'<\/span>,\n    <span class=\"hljs-literal\">true<\/span>\n  );\n}\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>We\u2019re adding a new user profile to the blockchain as soon as we add this smart contract. That way we have some initial data to interact with. This is also where you can set the owner info for a smart contract to allow access to different functions, but that\u2019s a more advanced topic.<\/p>\n<p>For now we can add the <code>createUser<\/code> function that is being referenced in the constructor. Right below the constructor call, add this:<\/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-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">createUser<\/span>(<span class=\"hljs-params\">\n  string memory _name,\n  string memory _role,\n  string memory _profileImg,\n  bool _isRegistered\n<\/span>) <span class=\"hljs-title\">public<\/span> <\/span>{\n  userCount++;\n\n  usersById&#91;userCount] = User(\n    userCount,\n    _name,\n    _role,\n    _profileImg,\n    _isRegistered\n  );\n}\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>It\u2019s very similar to a TypeScript function with a few differences. We want to be able to call this function from our front-end, so it will be public. Then we define the types for the function inputs. Inside the function, we\u2019re incrementing the <code>userCount<\/code> by 1.<\/p>\n<p>Then we\u2019re using the new <code>userCount<\/code> value as the id for the new user profile. This function is going to let us add new user profiles from the front-end we\u2019re about to build.<\/p>\n<p>That\u2019s all for the smart contract! Now we just need to deploy it.<\/p>\n<h3>Writing the migration<\/h3>\n<p>Let\u2019s write a quick migration script for our new smart contract. In the <code>web &gt; migrations<\/code> folder, add a new file called <code>2_deploy_profile_contracts.js<\/code>. Open that file and add the following code:<\/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\">const<\/span> Profile = artifacts.require(<span class=\"hljs-string\">\".\/Profile.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(Profile);\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>This is how we write migrations to deploy smart contract changes to the EVM. Now we need to actually run the deploy.<\/p>\n<h3>Deploying the smart contract<\/h3>\n<p>In your terminal, go to the <code>web<\/code> directory and run:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ truffle migrate\n<\/code><\/span><\/pre>\n<p>This will connect to the local EVM you have running with Ganache. If you haven\u2019t opened Ganache, go ahead and do that and choose the \u201cQuickStart\u201d option.<\/p>\n<p>You should see a couple of printouts in the terminal and the only thing you need to get is the <code>contract address<\/code> of the deploy we wrote. It\u2019ll look something like this: <code>0xe3173637950221539F40d7F54a431880786142BD<\/code>.<\/p>\n<p>Now we can switch over to the front-end!<\/p>\n<h2>Setting the smart contract configs<\/h2>\n<p>We need to set up a file to hold our configs to connect the smart contract we just deployed. Inside <code>web &gt; src<\/code>, create a new file called <code>config.tsx<\/code>. Then add the following 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\">export<\/span> <span class=\"hljs-keyword\">const<\/span> PROFILE_ADDRESS = <span class=\"hljs-string\">'0xe3173637950221539F40d7F54a431880786142BD'<\/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>This is the contract address you got from the terminal after deploying the smart contract. Now we need to add the ABI (application binary interface) for the smart contract so that we can interact with the public functions and variables. You can find the ABI for the contract in <code>web &gt; build &gt; Profile.json<\/code>. Go ahead and copy that <code>abi<\/code> from that JSON file and paste it in the <code>config.tsx<\/code> below the <code>PROFILE_ADDRESS<\/code>.<\/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> PROFILE_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\">\"userCount\"<\/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\">\"0x07973ccf\"<\/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\">\"usersById\"<\/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\">\"name\"<\/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\">\"role\"<\/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\">\"profileImg\"<\/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\">\"isRegistered\"<\/span>,\n        <span class=\"hljs-string\">\"type\"<\/span>: <span class=\"hljs-string\">\"bool\"<\/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\">\"0x426b5382\"<\/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\">\"_name\"<\/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\">\"_role\"<\/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\">\"_profileImg\"<\/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\">\"_isRegistered\"<\/span>,\n        <span class=\"hljs-string\">\"type\"<\/span>: <span class=\"hljs-string\">\"bool\"<\/span>\n      }\n    ],\n    <span class=\"hljs-string\">\"name\"<\/span>: <span class=\"hljs-string\">\"createUser\"<\/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\">\"0xe4f3ad95\"<\/span>\n  }\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>That\u2019s all for the setup. We can finally create the user interface for this Dapp!<\/p>\n<h2>Making the user interface<\/h2>\n<p>In your terminal, go to the root of your project and run this command:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ yarn rw g page Profile\n<\/code><\/span><\/pre>\n<p>This will generate a few new files for us and update the <code>Routes.tsx<\/code> with a new <code>\/profile<\/code> route. This is the route users can see their profiles on. If you go to <code>web &gt; src &gt; pages &gt; ProfilePage<\/code>, you\u2019ll see all the new files. You can take a look at the test file and the Storybook story, but our focus is on <code>ProfilePage.tsx<\/code>.<\/p>\n<p>Open this file and clear everything out. We\u2019ll start fresh.<\/p>\n<h3>Adding imports and type definitions<\/h3>\n<p>We\u2019ll start by adding the packages we need to import and a type definition for the profile data. At the top of the file, add the following:<\/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\"><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> { useMutation } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@redwoodjs\/web'<\/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> { PROFILE_ABI, PROFILE_ADDRESS } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/..\/config'<\/span>\n\ninterface UserProps {\n  <span class=\"hljs-attr\">name<\/span>: string;\n  role: string;\n  profileImg: string;\n  isRegistered: boolean;\n}\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>Then we\u2019ll add the call definition to our GraphQL server.<\/p>\n<p><em>Note:<\/em> It\u2019s common to see decentralized apps still using some kind of centralization. Right now, there aren\u2019t many apps that are truly decentralized.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> CREATE_PROFILE_MUTATION = gql`\n  mutation CreateProfileMutation($input: CreateProfileInput!) {\n    createProfile(input: $input) {\n      id\n    }\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\">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 gives us a way to access the database from the front-end. All that\u2019s left now is to fill in the component.<\/p>\n<h2>Filling in the ProfilePage component<\/h2>\n<p>We\u2019ll start by declaring and exporting the component. After the GraphQL definition, add this code:<\/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\">const<\/span> ProfilePage = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> ProfilePage\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>Now we\u2019ll add the states we need right inside this component with this code:<\/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\">const<\/span> &#91;createProfile] = useMutation(CREATE_PROFILE_MUTATION)\n\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;profile, setProfile] = useState&lt;any&gt;()\n<span class=\"hljs-keyword\">const<\/span> &#91;user, setUser] = useState&lt;UserProps&gt;()\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>Next, we\u2019re going to connect to the blockchain as soon as the app has loaded in the browser. We\u2019ll do that by calling a function in a <code>useEffect<\/code> hook like this:<\/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\">useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  loadData()\n}, &#91;])\n\n<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  setAccount(accounts&#91;<span class=\"hljs-number\">0<\/span>])\n\n  <span class=\"hljs-keyword\">const<\/span> profile = <span class=\"hljs-keyword\">new<\/span> web3.eth.Contract(PROFILE_ABI, PROFILE_ADDRESS)\n  setProfile(profile)\n\n  <span class=\"hljs-keyword\">const<\/span> user = <span class=\"hljs-keyword\">await<\/span> profile.methods.usersById(<span class=\"hljs-number\">3<\/span>).call()\n  setUser(user)\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>The <code>loadData<\/code> function is how we get all of the information we need to interact with the blockchain. We make a new instance of Web3 that connects to the local EVM running in Ganache. Then we get the account id of the current user. We get access to the smart contract we deployed by using the address and ABI we go from our deploy.<\/p>\n<p>Lastly, we specify an id and get the user profile info directly from the blockchain. Since we\u2019ll be able to add new profiles to the blockchain and the database, we\u2019ll have a form to let users enter their info. That means we\u2019ll need a function to handle the form submission. We\u2019ll add this code now, right below the <code>loadData<\/code> function.<\/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> handleSubmit = <span class=\"hljs-keyword\">async<\/span> (event) =&gt; {\n  event.preventDefault()\n\n  <span class=\"hljs-keyword\">const<\/span> { email, name, role, profileImg, isRegistered } = event.target.elements\n\n  <span class=\"hljs-keyword\">const<\/span> input = { <span class=\"hljs-attr\">email<\/span>: email.value, <span class=\"hljs-attr\">updatedAt<\/span>: <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Date<\/span>().toISOString(), <span class=\"hljs-attr\">blockchainAddress<\/span>: account }\n\n  createProfile({\n    <span class=\"hljs-attr\">variables<\/span>: { input },\n  })\n\n  <span class=\"hljs-keyword\">await<\/span> profile.methods.createUser(name.value, role.value, profileImg.value, isRegistered.value).send({ <span class=\"hljs-attr\">from<\/span>: account, <span class=\"hljs-attr\">gas<\/span>: <span class=\"hljs-number\">4712388<\/span> })\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 keeps the page from reloading while it pulls the data from the form and makes an input for the database and then calls the GraphQL resolver. Then we add the new profile to the blockchain with the <code>createUser<\/code> method from the smart contract.<\/p>\n<p>The last thing we need to do is render the HTML that will show in the browser. We\u2019ll do this in the return statement for the component. So add this final snippet of code below the <code>handleSubmit<\/code> function.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-18\" 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    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span>&gt;<\/span>Profile Page<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n    Profile account id: {account}\n    {user &amp;&amp;\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>{user.name}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"checkbox\"<\/span> <span class=\"hljs-attr\">checked<\/span>=<span class=\"hljs-string\">{user.isRegistered}<\/span> \/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>{user.role}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{user.profileImg}<\/span> <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">\"360\"<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    }\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2<\/span>&gt;<\/span>Add user profile to the chain<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">form<\/span> <span class=\"hljs-attr\">onSubmit<\/span>=<span class=\"hljs-string\">{handleSubmit}<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">'name'<\/span>&gt;<\/span>Name:<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">'name'<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">'text'<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">'email'<\/span>&gt;<\/span>Email:<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">'email'<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">'email'<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">'role'<\/span>&gt;<\/span>Role:<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">'role'<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">'text'<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">'profileImg'<\/span>&gt;<\/span>Profile Pic:<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">'profileImg'<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">'text'<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">'isRegistered'<\/span>&gt;<\/span>Registered:<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">'isRegistered'<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">'checkbox'<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">'submit'<\/span>&gt;<\/span>Submit<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">form<\/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-18\"><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 shows the data we retrieve from the blockchain if we have a <code>user<\/code> defined. It also shows the form that we use to add new profiles to the blockchain and our database.<\/p>\n<p>Here\u2019s what it might look like in your browser.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1635794444\/e-603fc55d218a650069f5228b\/x4nkvmy5jvgdspbuswte.png\" alt=\"image of the data loaded from the blockchain\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1580\" height=\"1386\"\/><\/p>\n<p>We\u2019re finally done with our Dapp!<\/p>\n<h2>Finished code<\/h2>\n<p>If you want to take a look at the fully functioning front-end and back-end, you can clone the repo from the <a href=\"https:\/\/github.com\/flippedcoder\/blog-examples\/tree\/main\/user-dapp\"><code>user-profile-dapp<\/code> folder in this repo<\/a>. Or you can check out the front-end in <a href=\"https:\/\/codesandbox.io\/s\/bitter-hill-fdgqs\">this Code Sandbox<\/a>.<\/p>\n<\/div>\n  \n  <div class=\"wp-block-cloudinary-code-sandbox \">\n    <iframe\n      src=\"https:\/\/codesandbox.io\/embed\/bitter-hill-fdgqs?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=\"bitter-hill-fdgqs\"\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 \"><p><em>Note:<\/em> The Code Sandbox won\u2019t show anything unless you set up your own config file. This one is connecting to a local EVM.<\/p>\n<h2>Conclusion<\/h2>\n<p>This is a great time to start learning how to work with blockchain and Web3 since it\u2019s on the rise. It might be a niche technology, but it solves an interesting problem. Learning how to write smart contracts and build Dapps around them is a useful skill if you\u2019re looking at where you might like to go with your career!<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":28041,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[134,370,177,246,371],"class_list":["post-28040","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-guest-post","tag-image","tag-javascript","tag-react","tag-under-review"],"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>Working with User Profiles on a Blockchain<\/title>\n<meta name=\"description\" content=\"Getting started with blockchain and smart contract development can seem like a lot of new things to learn. When you start by building simple apps, it makes it easier to learn the core concepts. In this tutorial, we&#039;ll learn how to write smart contracts and a Dapp to handle user profiles using a few different tools.\" \/>\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\/working-with-user-profiles-on-a-blockchain\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Working with User Profiles on a Blockchain\" \/>\n<meta property=\"og:description\" content=\"Getting started with blockchain and smart contract development can seem like a lot of new things to learn. When you start by building simple apps, it makes it easier to learn the core concepts. In this tutorial, we&#039;ll learn how to write smart contracts and a Dapp to handle user profiles using a few different tools.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-03-23T22:59:34+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925586\/Web_Assets\/blog\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4.jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"3840\" \/>\n\t<meta property=\"og:image:height\" content=\"2160\" \/>\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\/working-with-user-profiles-on-a-blockchain\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Working with User Profiles on a Blockchain\",\"datePublished\":\"2022-03-23T22:59:34+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/\"},\"wordCount\":7,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925586\/Web_Assets\/blog\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4.jpg?_i=AA\",\"keywords\":[\"Guest Post\",\"Image\",\"Javascript\",\"React\",\"Under Review\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/\",\"name\":\"Working with User Profiles on a Blockchain\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925586\/Web_Assets\/blog\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4.jpg?_i=AA\",\"datePublished\":\"2022-03-23T22:59:34+00:00\",\"description\":\"Getting started with blockchain and smart contract development can seem like a lot of new things to learn. When you start by building simple apps, it makes it easier to learn the core concepts. In this tutorial, we'll learn how to write smart contracts and a Dapp to handle user profiles using a few different tools.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925586\/Web_Assets\/blog\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925586\/Web_Assets\/blog\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4.jpg?_i=AA\",\"width\":3840,\"height\":2160},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Working with User Profiles on a Blockchain\"}]},{\"@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":"Working with User Profiles on a Blockchain","description":"Getting started with blockchain and smart contract development can seem like a lot of new things to learn. When you start by building simple apps, it makes it easier to learn the core concepts. In this tutorial, we'll learn how to write smart contracts and a Dapp to handle user profiles using a few different tools.","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\/working-with-user-profiles-on-a-blockchain\/","og_locale":"en_US","og_type":"article","og_title":"Working with User Profiles on a Blockchain","og_description":"Getting started with blockchain and smart contract development can seem like a lot of new things to learn. When you start by building simple apps, it makes it easier to learn the core concepts. In this tutorial, we'll learn how to write smart contracts and a Dapp to handle user profiles using a few different tools.","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/","og_site_name":"Cloudinary Blog","article_published_time":"2022-03-23T22:59:34+00:00","og_image":[{"width":3840,"height":2160,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925586\/Web_Assets\/blog\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4.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\/working-with-user-profiles-on-a-blockchain\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/"},"author":{"name":"","@id":""},"headline":"Working with User Profiles on a Blockchain","datePublished":"2022-03-23T22:59:34+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/"},"wordCount":7,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925586\/Web_Assets\/blog\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4.jpg?_i=AA","keywords":["Guest Post","Image","Javascript","React","Under Review"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/","name":"Working with User Profiles on a Blockchain","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925586\/Web_Assets\/blog\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4.jpg?_i=AA","datePublished":"2022-03-23T22:59:34+00:00","description":"Getting started with blockchain and smart contract development can seem like a lot of new things to learn. When you start by building simple apps, it makes it easier to learn the core concepts. In this tutorial, we'll learn how to write smart contracts and a Dapp to handle user profiles using a few different tools.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925586\/Web_Assets\/blog\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925586\/Web_Assets\/blog\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4.jpg?_i=AA","width":3840,"height":2160},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/working-with-user-profiles-on-a-blockchain\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Working with User Profiles on a Blockchain"}]},{"@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\/v1681925586\/Web_Assets\/blog\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4\/d1692fcea425d28476ccc2a5e9d3136119b74235-3840x2160-1_2804112ae4.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28040","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=28040"}],"version-history":[{"count":0,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28040\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/28041"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=28040"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=28040"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=28040"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}