/scaffold-eth

πŸ— forkable Ethereum dev stack focused on fast product iterations

Primary LanguageJavaScript

πŸ— scaffold-eth

TL;DR: fork this repo for an Ethereum dev stack focused on fast product iteration

Chapter 1: πŸ›  Programming Decentralized Money

Chapter 2: 🏡 The Token

Chapter 3: βš–οΈ Minimum Viable Decentralized Exchange

Chapter 0: 🧫 (research ) Building on Ethereum in 2020

Chapter 7: πŸ—³ Personal Token Voting


⏱ Quickstart:

First, you'll need NodeJS>=10 plus Yarn and Git installed.

πŸ’Ύ Clone/fork repo and then install:

git clone https://github.com/austintgriffith/scaffold-eth.git rad-new-dapp

cd rad-new-dapp

yarn install

⌚️ This will take some time. How about a quick tour of the file structure with your favorite code editor?

πŸ’‘ Sometimes the install throws errors like "node-gyp", try the next step even if you see problems.
(You can also download the Apple command line tools to fix the warning.)


βš›οΈ React frontend powered by πŸ“±create-eth-app using πŸ”§Ethers.js and the πŸ¦„Uniswap template:

yarn start

πŸ“ Edit your frontend App.js in packages/react-app/src and open http://localhost:3000


β›“ Start your local blockchain powered by πŸ‘·β€β™€οΈBuidler:

yarn run chain

Note: You'll need to run this command in a new terminal window

πŸ›  Use this eth.build to double-check your local chain and account balances


βš™οΈ Compile your contracts:

yarn run compile

🚒 Deploy your contracts to the frontend:

yarn run deploy

πŸ” Watch for changes then compile, deploy, and hot reload the frontend:

yarn run watch

πŸ”₯ Your dapp hot reloads as you build your smart contracts and frontend together πŸ”₯


πŸ“ Edit your smart contract SmartContractWallet.sol in packages/buidler/contracts

🀑 There is a spelling error in packages/buidler/contracts/SmartContractWallet.sol!

πŸ€” Can you fix it and deploy the contract locally?

Deployed Contract

☒️ Warning: It is very important that you find SmartContractWallet.sol in packages/buidler/contracts because there are other contract folders and it can get confusing.

πŸ”¬Test your contracts by editing myTest.js in packages/buidler/contracts:

yarn run test

πŸ— List your local accounts:

yarn run accounts

πŸ’° Check account balance:

yarn run balance **YOUR-ADDRESS**

πŸ’Έ Send ETH:

yarn run send --from 0 --amount 0.5 --to **YOUR-ADDRESS**

πŸ”§ Configure πŸ‘·Buidler by editing buidler.config.js in packages/buidler


✨ The BuidlerEVM provides stack traces and console.log debugging for our contracts ✨


πŸƒβ€β™‚οΈ Speedrun (πŸŽ₯ 7 min):

speedrun



follow on Twitter

πŸ” Web3 Providers:

The frontend has three different providers that provide different levels of access to different chains:

mainnetProvider: (read only) Infura connection to main Ethereum network (and contracts already deployed like DAI or Uniswap).

localProvider: local Buidler accounts, used to read from your contracts (.env file points you at testnet or mainnet)

injectedProvider: your personal MetaMask, WalletConnect via Argent, or other injected wallet (generates burner-provider on page load)


🐜 Ant.design is the UI library with components like the grids, menus, dates, times, buttons, etc.


β›‘ Helpers:

Transactor: The transactor returns a tx() function to make running and tracking transactions as simple and standardized as possible. We will bring in BlockNative's Notify library to track our testnet and mainnet transactions.

const tx = Transactor(props.injectedProvider, props.gasPrice);

Then you can use the tx() function to send funds and write to your smart contracts:

tx({
  to: readContracts[contractName].address,
  value: ethers.utils.parseEther("0.001"),
});
tx(writeContracts["SmartContractWallet"].updateOwner(newOwner));

☒️ Warning: You will need to update the configuration for react-app/src/helpers/Transactor.js to use your BlockNative dappId


πŸ–‡ Hooks:

Commonly used Ethereum hooks located in packages/react-app/src/:

usePoller(fn, delay): runs a function on app load and then on a custom interval

usePoller(() => {
  //do something cool at start and then every three seconds
}, 3000);

useBalance(address, provider, [pollTime]): poll for the balance of an address from a provider

const localBalance = useBalance(address, localProvider);

useBlockNumber(provider,[pollTime]): get current block number from a provider

const blockNumber = useBlockNumber(props.provider);

useGasPrice([speed]): gets current "fast" price from ethgasstation

const gasPrice = useGasPrice();

useExchangePrice(mainnetProvider, [pollTime]): gets current price of Ethereum on the Uniswap exchange

const price = useExchangePrice(mainnetProvider);

useContractLoader(provider): loads your smart contract interface

const readContracts = useContractLoader(localProvider);
const writeContracts = useContractLoader(injectedProvider);

useContractReader(contracts, contractName, variableName, [pollTime]): reads a variable from your contract and keeps it in the state

const title = useContractReader(props.readContracts, contractName, "title");
const owner = useContractReader(props.readContracts, contractName, "owner");

useEventListener(contracts, contractName, eventName, [provider], [startBlock]): listens for events from a smart contract and keeps them in the state

const ownerUpdates = useEventListener(
  readContracts,
  contractName,
  "UpdateOwner",
  props.localProvider,
  1
);

πŸ“¦ Components:

Your commonly used React Ethereum components located in packages/react-app/src/:


πŸ“¬ <Address />: A simple display for an Ethereum address that uses a Blockie, lets you copy, and links to Etherescan.

  <Address value={address} />
  <Address value={address} size="short" />
  <Address value={address} size="long" blockexplorer="https://blockscout.com/poa/xdai/address/"/>
  <Address value={address} ensProvider={mainnetProvider}/>

ensaddress


πŸ–‹ <AddressInput />: An input box you control with useState for an Ethereum address that uses a Blockie and ENS lookup/display.

  const [ address, setAddress ] = useState("")
  <AddressInput
    value={address}
    ensProvider={props.ensProvider}
    onChange={(address)=>{
      setAddress(address)
    }}
  />

TODO GIF


πŸ’΅ <Balance />: Displays the balance of an address in either dollars or decimal.

<Balance
  address={address}
  provider={injectedProvider}
  dollarMultiplier={price}
/>

balance



πŸ‘€ <Account />: Allows your users to start with an Ethereum address on page load but upgrade to a more secure, injected provider, using Web3Modal. It will track your address and localProvider in your app's state:

const [address, setAddress] = useState();
const [injectedProvider, setInjectedProvider] = useState();
const price = useExchangePrice(mainnetProvider);
<Account
  address={address}
  setAddress={setAddress}
  localProvider={localProvider}
  injectedProvider={injectedProvider}
  setInjectedProvider={setInjectedProvider}
  dollarMultiplier={price}
/>

account

πŸ’‘ Notice: the <Account /> component will call setAddress and setInjectedProvider for you.

☒️ Warning: You will need to update the configuration for Web3Modal to use your Infura Id



πŸ“‘ <Provider />: You can choose to display the provider connection status to your users with:

<Provider name={"mainnet"} provider={mainnetProvider} />
<Provider name={"local"} provider={localProvider} />
<Provider name={"injected"} provider={injectedProvider} />

providere

πŸ’‘ Notice: you will need to check the network id of your injectedProvider compared to your localProvider or mainnetProvider and alert your users if they are on the wrong network!


πŸ“„ Smart Contract Wallet:

πŸ“ Edit your smart contract SmartContractWallet.sol in packages/buidler/contracts

πŸ“ Then edit the SmartContractWallet.js React component in packages/react-app/src

▢️ Run yarn run compile and yarn run deploy or just yarn run watch

smortcontractwallet

πŸ›  Run this eth.build with your contract address to ask it who its owner is.


πŸ“š OpenZeppelin Contracts -- TODO

You can import any of the OpenZeppelin contracts:

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

πŸ›° The Graph -- TODO

⛽️ GSN -- TODO


πŸ“€ Save to your Git

Create a new repo with the same name as this project and then:

git remote add origin https://github.com/**YOUR_GITHUB_USERNAME**/**YOUR_COOL_PROJECT_NAME**.git
git push -u origin master

πŸ›³ Ship it!

You can deploy your static site and your dapp can go live:

yarn run build

yarn run ship

TODO: GITHUB PAGES OR SURGE TUTORIAL?