{"id":16585439,"url":"https://github.com/christianchiarulli/intro-fullstack-ethereum","last_synced_at":"2025-03-16T21:30:26.612Z","repository":{"id":42969674,"uuid":"450377386","full_name":"ChristianChiarulli/intro-fullstack-ethereum","owner":"ChristianChiarulli","description":"⛓️ Introductory fullstack ethereum dapp using: solidity, hardhat, react.js, ethers.js","archived":false,"fork":false,"pushed_at":"2022-11-05T21:50:28.000Z","size":687,"stargazers_count":82,"open_issues_count":0,"forks_count":8,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-27T14:08:04.046Z","etag":null,"topics":["ethereum","ethersjs","hardhat","javascript","react","smart-contracts","solidity"],"latest_commit_sha":null,"homepage":"https://fullstack-ethereum.netlify.app/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ChristianChiarulli.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-01-21T06:21:30.000Z","updated_at":"2024-11-01T04:03:42.000Z","dependencies_parsed_at":"2022-09-19T03:00:44.491Z","dependency_job_id":null,"html_url":"https://github.com/ChristianChiarulli/intro-fullstack-ethereum","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChristianChiarulli%2Fintro-fullstack-ethereum","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChristianChiarulli%2Fintro-fullstack-ethereum/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChristianChiarulli%2Fintro-fullstack-ethereum/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChristianChiarulli%2Fintro-fullstack-ethereum/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ChristianChiarulli","download_url":"https://codeload.github.com/ChristianChiarulli/intro-fullstack-ethereum/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243830915,"owners_count":20354850,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ethereum","ethersjs","hardhat","javascript","react","smart-contracts","solidity"],"created_at":"2024-10-11T22:48:00.759Z","updated_at":"2025-03-16T21:30:26.106Z","avatar_url":"https://github.com/ChristianChiarulli.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Intro to Fullstack Ethereum Development\n\nCheck out deployed dapp [here!](https://fullstack-ethereum.netlify.app/) (Make sure you're connected to the Rinkeby Testnet)\n\nThis article will help you escape writing solidity tutorials in Remix and explain the tools you will need to create a simple full-stack dapp. The smart contract will be very simple itself and that is because we're focusing on all of the other tools you will need.\n\n[Discord Link for help](https://discord.gg/9cNxMQq8t8) \n\n## Our stack\n\n- [Solidity](https://docs.soliditylang.org) (To write our smart contract)\n- [Hardat](https://hardhat.org/) (build, test and deployment framework)\n- [React](https://reactjs.org/) (Create our frontend)\n- [Metamask](https://metamask.io/) (Web Wallet that will allow us to interact with the ethereum blockchain)\n- [Ethers](https://docs.ethers.io) (web3 library for interacting with the blockchain and our smart contract)\n\n## Installing a web wallet\n\nBefore getting started make sure you have a web wallet installed, I recommend [Metamask](https://metamask.io/download/). It is essentially just a browser extension that will allow us to interact with the ethereum blockchain. Just follow the instructions provided in the link to install and make sure not to use the same seed phrase for development for real ethereum/money.\n\n## Environment\n\nFirst head over to the hardhat [website](https://hardhat.org/), we're going to be doing most of what is covered in the tutorial section as well as some of the documentation.\n\nMake sure you have nodejs installed, if you don't then follow the setup [here](https://hardhat.org/tutorial/setting-up-the-environment.html)\n\n## Create a new project\n\nTo get your project started:\n\n```\nmkdir intro-fullstack-ethereum\ncd intro-fullstack-ethereum\nnpm init --yes\nnpm i --save-dev hardhat\n```\n\nIn the same directory where you installed Hardhat run:\n\n```\nnpx hardhat\n```\n\nA menu will appear, for this tutorial we will be selecting `Create an empty hardhat.config.js`\n\nMake sure these packages are installed, you may have been asked to install them when initializing the project.\n\n```\nnpm install --save-dev @nomicfoundation/hardhat-toolbox\n```\n\n## Create our Contract\n\nLet's create our contract, it will be very simple, the contract will only read from and write to the blockchain. I wanted to keep the contract simple since this will be a comprehensive look at all of the tools necessary to create a fullstack dapp.\n\nFirst we will need to create a directory for our contract, hardhat expects them to be in a directory called `contracts/` so:\n\n```\nmkdir contracts\ncd contracts\ntouch SimpleStorage.sol\n```\n\n### Our Smart Contract\n\n```\n// SPDX-License-Identifier: MIT\npragma solidity \u003e=0.5.0 \u003c0.9.0;\n\ncontract SimpleStorage {\n    uint256 storedData;\n\n    constructor(uint256 _storedData) {\n        storedData = _storedData;\n    }\n\n    function set(uint256 x) public {\n        storedData = x;\n    }\n\n    function get() public view returns (uint256) {\n        return storedData;\n    }\n}\n```\n\nThis contract is very simple. When the contract is deployed it is instantiated with a value called `storedData`, after deploying the contract you have the ability to `get` the data or `set` the data.\n\n\n### Compiling our contract\n\nWe can now use `hardhat` to compile our contract with\n\n```\nnpx hardhat compile\n```\n\n## Shorthand commands\n\nInstead of typing out `npx hardhat \u003ccommand\u003e` we can install `hardhat-shorthand` and use the `hh` command\n\n```\nnpm i -g hardhat-shorthand\n```\n\nWe can also get tab completion by running the command:\n\n```\nhardhat-completion install\n```\n\nChoose to install the autocompletion for your shell and you should now get tab completion after typing `hh` as long as you are in a hardhat project directory.\n\nTry compiling your contract now with:\n\n```\nhh compile\n```\n\n## Testing\n\nIt is very import since money is often on the line when it comes to smart contracts. I will show you how to create a simple test for our `SimpleStorage` contract.\n\nIt is also important to note that hardhat comes with it's own network so when we run our tests hardhat will spin up a local network where we can deploy our contract to and test.\n\nFirst create a directory called `test/` and create a file called `simple-storage-test.js`\n\n```\nmkdir test\ntouch simple-storage-test.js\n```\n\nHere are our simple tests:\n\n```\nconst { expect } = require('chai')\n\ndescribe('SimpleStorage contract', function () {\n  it('test deployment', async function () {\n    const SimpleStorage = await ethers.getContractFactory('SimpleStorage')\n\n    const simpleStorage = await SimpleStorage.deploy(123)\n\n    const storedValue = await simpleStorage.get()\n\n    expect(storedValue).to.equal(123)\n  })\n\n  it('test set new value', async function () {\n    const SimpleStorage = await ethers.getContractFactory('SimpleStorage')\n\n    const simpleStorage = await SimpleStorage.deploy(123)\n\n    await simpleStorage.set(456)\n\n    const storedValue = await simpleStorage.get()\n\n    expect(storedValue).to.equal(456)\n  })\n})\n```\n\nYou will always be able to call the `deploy` method on your contract even if you didn't define a method called `deploy` essentially it just calls your constructor.\n\nWe have defined two tests here one just deploys the contract with an initial value and checks that it was deployed properly, the other does the same except we set a new value using the `set` method defined in our smart contract.\n\nBefore we can run our test we will need to `require` `hardhat-waffle` this will make the `ethers` variable available in global scope\n\nSo add the following line to the top of your `hardhat.config.js` file:\n\n```\nrequire(\"@nomicfoundation/hardhat-toolbox\");\n```\n\nOk now we are ready to run our test:\n\n```\n$ hh test # or npx hardhat test\n\n  SimpleStorage contract\n    ✓ test deployment (366ms)\n    ✓ test set new value (52ms)\n\n\n  2 passing (420ms)\n```\n\nYou will notice the text that we added to the test is printed out when the test runs\n\n**NOTE** Another good example test: [link](https://hardhat.org/tutorial/testing-contracts.html)\n\n### console.log in solidity\n\nWhen running contracts inside of the hardhat network we can make use of a special logging function provided by hardhat, here is an example of how to add it to your contract:\n\n```\n// SPDX-License-Identifier: MIT\npragma solidity \u003e=0.5.0 \u003c0.9.0;\n\nimport \"hardhat/console.sol\";\n\ncontract SimpleStorage {\n    uint256 storedData;\n\n    constructor(uint256 _storedData) {\n        console.log(\"Deployed by: \", msg.sender);\n        console.log(\"Deployed with value: %s\", _storedData);\n        storedData = _storedData;\n    }\n\n    function set(uint256 x) public {\n        console.log(\"Set value to: %s\", x);\n        storedData = x;\n    }\n\n    function get() public view returns (uint256) {\n        console.log(\"Retrieved value: %s\", storedData);\n        return storedData;\n    }\n}\n```\n\nNow when we run `hh test` we should see:\n\n```\n  SimpleStorage contract\nDeployed by:  0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\nDeployed with value: 123\nRetrieved value: 123\n    ✓ test deployment (465ms)\nDeployed by:  0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\nDeployed with value: 123\nSet value to: 456\nRetrieved value: 456\n    ✓ test set new value (74ms)\n```\n\nAs you can see the logging function is very useful when trying to figure out what is happening with the internal logic of the smart contract.\n\n## Deploying our contract\n\nNow we are ready to deploy our contract, hardhat provides a local blockchain for testing so that we don't need to setup a node or use a third party provider to deploy to a testnet. We will first deploy to the local network and then optionally I will show you how to deploy to a testnet.\n\n### Deployment script\n\nBefore we can deploy our contract we will need a deployment script so that `hardhat` knows how to instantiate the contract.\n\n- First create a directory called `scripts/` and a file inside called `deploy.js`:\n\n```\nmkdir scripts/\ntouch scripts/deploy.js\n```\n\n- Here is some example code we can use to deploy our contract:\n\n```\nasync function main() {\n  // We get the contract to deploy\n  const SimpleStorage = await ethers.getContractFactory(\"SimpleStorage\");\n  const simpleStorage = await SimpleStorage.deploy(789);\n\n  // NOTE: All Contracts have an associated address\n  console.log(\"SimpleStorage deployed to:\", simpleStorage.address);\n}\n\nmain()\n  .then(() =\u003e process.exit(0))\n  .catch((error) =\u003e {\n    console.error(error);\n    process.exit(1);\n  });\n```\n\n### Local deployment\n\n- Start a local node\n\n```\nhh node # or npx hardhat node\n```\n\nYou should see that 20 accounts are created with 10000 ETH each.\n\n- In another terminal deploy the contract:\n\n```\nnpx hardhat run --network localhost scripts/deploy.js\n```\n\nIn the terminal where you started your local node you should have noticed the following output:\n\n```\n  Contract deployment: SimpleStorage\n  Contract address:    0x5fbdb2315678afecb367f032d93f642f64180aa3\n  Transaction:         0x024bf3c1eb46ed3f405b7b10ea4c5e6b46c9e9deeed38d0743c6a7ae16b4d5b1\n  From:                0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\n  Value:               0 ETH\n  Gas used:            290646 of 290646\n  Block #1:            0x0eabbc7dff1b963c76b5b077d3df3353f201a450d72361b3de3218454cffe105\n\n  console.log:\n    Deployed by:  0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\n    Deployed with value: 789\n```\n\n**NOTE** Notice the `console.log` section, we can utilize the builtin logging functionality whenever our contract is deployed on the `hardhat` network, this is not just available in testing.\n\n**NOTE** The Contract address will be useful later when we want to interact with our contract\n\n## Creating our frontend\n\nWe will be using [React](https://reactjs.org/) since it is by far the most popular framework used to create frontends for dapps.\n\nIf you need to brush up on your React skills I recommend checking out this tutorial: [React Tutorial](https://www.youtube.com/watch?v=j942wKiXFu8\u0026list=PL4cUxeGkcC9gZD-Tvwfod2gaISzfRiP9d)\n\nMake sure you are in the root of our project (in the `intro-fullstack-ethereum` directory) and run:\n\n```\nnpx create-react-app frontend\n```\n\nMake sure you can start your frontend by entering the `frontend` directory and running:\n\n```\nnpm start\n```\n\n### Accessing our contract\n\nBefore we get started writing any code for the frontend we will need to have access to our contracts `ABI` or Application Binary Interface, which is basically just a JSON file containing the functions, permissions and other information about our smart contract. Normally this would be found under the `./artifacts/contracts/SimpleStorage.sol` directory and be called: `SimpleStorage.json`, but we want to move this somewhere that our frontend will be able to access it. so that `ethers.js` will know what functions are available for example.\n\nInstead of moving this file somewhere our frontend can find it. I think it would be better if every time we compile our contract the file is automatically placed in `frontend/src/artifacts`. We can achieve this by adding the `paths` option to our `hardhat.config.js` file:\n\n```\nmodule.exports = {\n  solidity: '0.8.4',\n  paths: {\n    artifacts: './frontend/src/artifacts',\n  },\n}\n```\n\nNow whenever we run `hh compile` the `ABI` is placed in `./frontend/src/artifacts`\n\n## Metamask Hardhat Local Blockchain Fix\n\nBefore we can use metamask with our local blockchain we also need to add the following to `hardhat.config.js`:\n\n```\nmodule.exports = {\n  solidity: '0.8.4',\n  paths: {\n    artifacts: './frontend/src/artifacts',\n  },\n  networks: {\n    hardhat: {\n      chainId: 1337,\n    },\n  },\n}\n```\n\n[Metamask chainId issue](https://hardhat.org/metamask-issue.html)\n\n## Interacting with the Blockchain (using ethers.js)\n\nOk so now that we've created our smart contract, tested it, deployed it, and obtained the ABI, we are now ready to interact with our contract and create our dapp.\n\nTo begin remove all of the code in `src/App.js` and replace it with the code found at the following link: [App.js](https://github.com/ChristianChiarulli/intro-fullstack-ethereum/blob/master/frontend/src/App.js)\n\nInstead of explaining all of the code here, the file is heavily commented and should explain everything you need to know.\n\nAlso get the deployed contract address from earlier and set in `App.js`:\n\n```\nconst simpleStorageAddress = '0x5fbdb2315678afecb367f032d93f642f64180aa3'\n```\n\n### Connect Metamask to Local Blockchain\n\nOpen up your Metamask extension, click on the top where it says `mainnet` and choose `Localhost 8545`.\n\nI also recommend importing one of the accounts into Metamask so that you have 10,000 ether to play with. You can import by private key in metamask so just grab one of the private keys from the terminal where you started your node.\n\n### Interact with the Dapp\n\nYou should now be able to interact with the dapp. Try getting the value and observe that it is the same value passed to the deploy function in out deploy script. After clicking the connect button you will be able to spend some ether and update the value in the smart contract.\n\n**NOTE:** Remember changing values on chain cost ether, reading values from the blockchain is free.\n\n## Styling\n\nIf you want to be a **fullstack** blockchain developer then you cannot escape learning `css` and how to create a solid UI/UX for your users, or investors. There are solutions like [bootstrap](https://getbootstrap.com/) available, but I would recommend at least knowing the basics including `flexbox`, `css-grid` and how to make your site responsive.\n\nHere are some good resources to learn `css`\n\n- [Flexbox](https://www.youtube.com/watch?v=3YW65K6LcIA)\n- [CSS Grid](https://www.youtube.com/watch?v=moBhzSC455o)\n- [Build a Responsive Website](https://www.youtube.com/watch?v=p0bGHP-PXD4)\n- [Complete Guide](https://www.udemy.com/course/css-the-complete-guide-incl-flexbox-grid-sass/learn/lecture/9654188?start=15#content)\n\nRemove all of the code in `src/App.css` and replace it with the code found at the following link: [App.css](https://github.com/ChristianChiarulli/intro-fullstack-ethereum/blob/master/frontend/src/App.css)\n\nA basic understanding of `css` and `flexbox` is all you will need to understand the code found at that link. For frontend styling idea/inspiration I recommend heading over to a site like [coingecko](https://www.coingecko.com/), and click on a token you're interested, for most of them you should see a site associated with the token where you can checkout their dapp for instance here is a link to [uniswap](https://app.uniswap.org/#/swap)\n\n## Testnet deployment (Optional)\n\nIn order to deploy your contract to a testnet you will need to edit the `hardhat.config.js` to include networks other than `localhost`.\n\nYou will need to set up an account with a node provider (you could do this without one but it will be much more complicated) for this tutorial I set one up at [alchemy.io](https://www.alchemy.com/)\n\nWe'll also need to install another package called `dotenv` so we can get secrets like the *private key* and *node url* from environment variables, that way you don't need to worry about committing them to source control.\n\n```\ncd frontend\n\nnpm i dotenv\n```\n\nFor the environment variable: `RINKEBY_PRIVATE_KEY` replace it with your Rinkeby account private key. To export your private key from Metamask, open Metamask and go to **Account Details** \u003e **Export Private Key**.\n\n***WARNING:*** Don't use the private associated with an account you keep any real ether in!\n\nFor the environment variable: `RINKEBY_URL` replace it with the *http* key after setting up a rinkeby app in alchemy.\n\n```\n# Replace with your values\nexport RINKEBY_URL=https://eth-rinkeby.alchemyapi.io/v2/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nexport RINKEBY_PRIVATE_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n```\n\nHere is an example of adding the `Rinkeby` testnet to our list of networks:\n\n```\nrequire('@nomiclabs/hardhat-waffle')\nrequire(\"dotenv\").config();\n\n// Replace this with a URL generated after setting up and account\n// with a node provider e.g. alchemy.io\nconst RINKEBY_URL = process.env.RINKEBY_URL\n\nconst RINKEBY_PRIVATE_KEY = process.env.RINKEBY_PRIVATE_KEY\n\nmodule.exports = {\n  solidity: '0.8.4',\n  paths: {\n    artifacts: './frontend/src/artifacts',\n  },\n  networks: {\n    hardhat: {\n      chainId: 1337,\n    },\n    rinkeby: {\n      url: `${RINKEBY_URL}`,\n      accounts: [`${RINKEBY_PRIVATE_KEY}`],\n    },\n  },\n}\n```\n\nAfter adding the new entry you will need to deploy your contract using the same deployment script and command as before\n\n```\nnpx hardhat run --network rinkeby scripts/deploy.js\n```\n\nAfter running this command copy the address for your deployed contract and head over to [rinkeby.etherscan.io](https://rinkeby.etherscan.io/) and click on the `Contract` tab and `Verify and Publish` your contract. For this tutorial you can select `Solidity (Single file)` for `Compile Type`, `0.8.4` for the `Compiler Version` and `MIT` for `License Type`\n\nYou will also need to update the contract address in `App.js`, example:\n\n```\nconst simpleStorageAddress = '0xde4De608C284709E8980212C7A48B8bcA5b570A2'\n```\n\n### Get Test Ether\n\nMake sure you're connected to the Rinkeby Network in Metamask before you get started. After that all you will need to do is paste your public address into the form, solve a captcha and get your ether.\n\n[Rinkeby Faucet](https://faucets.chain.link/rinkeby) \n\n### Interact with Contract Deployed on Testnet\n\nYou should now be able to interact with the contract deployed to the rinkeby testnet in the same way you did with the local deployment.\n\n### Deploy to Netlify\n\nFinally we can deploy our dapp to a hosting site like Netlify.\n\nTo get started head over to [netlify.com](https://www.netlify.com/) and create an account.\n\nYou will also need to install `netlify-cli` via `npm`\n\n```\nnpm i -g netlify-cli\n```\n\nNow we can build our application and deploy.\n\n```\ncd frontend/\n\nnpm run build\n\nnetlify deploy\n```\n\nFollow the command line prompts and choose yes for a new project and `./build` as your deploy folder.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchristianchiarulli%2Fintro-fullstack-ethereum","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchristianchiarulli%2Fintro-fullstack-ethereum","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchristianchiarulli%2Fintro-fullstack-ethereum/lists"}