Prerequisites:
- npm (recommended: nvm)
- hardhat
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.35.2/install.sh | bash
nvm install 16
nvm use 16
nvm alias default 16
- Create react project:
npx create-react-app gm
- delete yarn.lock since we're using npm instead of yarn
- Create hardhat project:
npx hardhat
- Talk through:
- Greeter contract
- sample script
npx hardhat run scripts/sample-script.js
-
Modify Greeter contract to become gm contract
-
Set up Alchemy app
-
Set up MetaMask app and get test rinkeby
- chainlink faucet
- paradigm faucet
- plug the alchemy faucet
- alchemy discord
- Configure hardhat to deploy to rinkeby
require("@nomiclabs/hardhat-waffle");
require("dotenv").config();
// This is a sample Hardhat task. To learn how to create your own go to
// https://hardhat.org/guides/create-task.html
task("accounts", "Prints the list of accounts", async (taskArgs, hre) => {
const accounts = await hre.ethers.getSigners();
for (const account of accounts) {
console.log(account.address);
}
});
// You need to export an object to set up your config
// Go to https://hardhat.org/config/ to learn more
/**
* @type import('hardhat/config').HardhatUserConfig
*/
module.exports = {
solidity: "0.8.4",
networks: {
rinkeby: {
url: process.env.RINKEBY_URL,
accounts: [process.env.PRIVATE_KEY],
}
}
};
-
Set up dotenv
npm install —save-dev dotenv
-
Finish rinkeby config in hardhat
-
Deploy to rinkeby
npx hardhat run scripts/sample-script.js --network rinkeby
Greeter deployed to: 0x6bB76f66e2AC71a5C73A820404aC47D0dd42c1b4
- See the contract deployed on rinkeby.etherscan.io
-
Check out Alchemy dashboard
-
Talk about the compiled contract json file containing abi in
./artifacts
-
Load the react website
npm start
in root directory
- copy over the artifacts folder into
./src
- add imports
import { useState } from 'react';
import { ethers } from 'ethers';
import ContractJSON from './artifacts/contracts/Greeter.sol/Greeter.json';
import './App.css';
require('dotenv').config();
- update the .env file to include react environment variables
REACT_APP_ALCHEMY_API_KEY=
REACT_APP_PRIVATE_KEY=
REACT_APP_CONTRACT_ADDRESS=
- Add
useState()
and three functions
function App() {
// MetaMask injects the ethereum object into the webpage.
const ethereum = window.ethereum;
const [gm, setGm] = useState();
async function requestAccount() {
await ethereum.request({ method: 'eth_requestAccounts' });
}
async function fetchGm() {
if (typeof ethereum !== 'undefined') {
const provider = new ethers.providers.AlchemyProvider("rinkeby", process.env.REACT_APP_ALCHEMY_API_KEY);
const contract = new ethers.Contract(contractAddress, ContractJSON.abi, provider);
try {
const isGm = await contract.isGm();
setGm(isGm);
console.log('isGm: ', isGm);
} catch (err) {
console.log("Error: ", err);
}
}
}
async function setGmButton() {
if (typeof ethereum !== 'undefined') {
const provider = new ethers.providers.AlchemyProvider("rinkeby", process.env.REACT_APP_ALCHEMY_API_KEY);
const wallet = new ethers.Wallet(process.env.REACT_APP_PRIVATE_KEY, provider);
const signer = wallet.connect(provider);
const contract = new ethers.Contract(contractAddress, ContractJSON.abi, signer);
const transaction = await contract.toggleGm();
await transaction.wait();
fetchGm();
}
}
return (
<div className="App">
<header className="App-header">
</header>
</div>
);
}
- Update App.css to include styling for gm
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-header-gm {
background-color: #ffffff;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: black;
}
- Update App.js
import { useState } from 'react';
import { ethers } from 'ethers';
import ContractJSON from './artifacts/contracts/Greeter.sol/Greeter.json';
import './App.css';
require('dotenv').config();
const contractAddress = process.env.REACT_APP_CONTRACT_ADDRESS;
function App() {
// MetaMask injects the ethereum object into the webpage.
const ethereum = window.ethereum;
const [gm, setGm] = useState();
async function requestAccount() {
await ethereum.request({ method: 'eth_requestAccounts' });
}
async function fetchGm() {
if (typeof ethereum !== 'undefined') {
const provider = new ethers.providers.AlchemyProvider("rinkeby", process.env.REACT_APP_ALCHEMY_API_KEY);
const contract = new ethers.Contract(contractAddress, ContractJSON.abi, provider);
try {
const isGm = await contract.isGm();
setGm(isGm);
console.log('isGm: ', isGm);
} catch (err) {
console.log("Error: ", err);
}
}
}
async function setGmButton() {
if (typeof ethereum !== 'undefined') {
const provider = new ethers.providers.AlchemyProvider("rinkeby", process.env.REACT_APP_ALCHEMY_API_KEY);
const wallet = new ethers.Wallet(process.env.REACT_APP_PRIVATE_KEY, provider);
const signer = wallet.connect(provider);
const contract = new ethers.Contract(contractAddress, ContractJSON.abi, signer);
const transaction = await contract.toggleGm();
await transaction.wait();
fetchGm();
}
}
requestAccount();
console.log("gm", gm);
const headerClass = gm ? "App-header-gm" : "App-header";
return (
<div className="App">
<header className={headerClass}>
<button onClick={fetchGm}>GM?</button>
<button onClick={setGmButton}>GM</button>
</header>
</div>
);
}
export default App;
- Look at the dashboard and see all your requests!!