Skip to content

Instantly share code, notes, and snippets.

@sephynox
Last active January 24, 2022 17:45
Show Gist options
  • Save sephynox/90f31b7ed9557c017a13d12b492078cc to your computer and use it in GitHub Desktop.
Save sephynox/90f31b7ed9557c017a13d12b492078cc to your computer and use it in GitHub Desktop.
time-to-hello-world:dapp
#!/bin/bash
# # time-to-hello-world:dapp
#
# ## Information
# This script is designed to automate the process to "Hello World" for
# developing a Dapp with Metamask integration.
readonly __usage="
Usage: $(basename $0) [OPTIONS]
Options:
-h, --help Show documentation
--use-npm Use NPM as the package manager
--use-npx Use NPX as the package manager
--use-yarn Use Yarn as the package manager
"
# ## Constants
readonly CONST_YARN="yarn";
readonly CONST_NPX="npx";
readonly CONST_NPM="npm";
readonly CONST_DEFAULT="yarn";
# ## Dependency Check
if [[ ! -x "$(command -v npm)" ]]; then
echo 'Command not found: npm is not installed.' >&2;
exit 1;
fi
# TODO
# [[ -x "$(command -v brew)" ]] && [[ ! -x "$(command -v gawk)" ]] && brew install gawk;
# if [[ ! -x "$(command -v gawk)" ]]; then
# echo 'Command not found: gawk is not installed.' >&2;
# exit 1;
# fi
if [[ ! -x "$(command -v ${CONST_DEFAULT})" ]]; then
echo "This script defaults to ${CONST_DEFAULT}. Install ${CONST_DEFAULT}? Manually specify a package manager using: -n --use-npm, -y --use-yarn -x, --use-npx";
select yn in "Yes" "No"; do
case $yn in
Yes ) npm install --global ${CONST_DEFAULT}; break;;
No ) echo "Canceled operation."; exit;;
esac
done
fi
# ## Check optional flags
ARGUMENT_LIST=(
"use-npm"
"use-npx"
"use-yarn"
"help"
);
OPTS=$(getopt \
--longoptions "$(printf "%s," "${ARGUMENT_LIST[@]}")" \
--name "$(basename "$0")" \
--options "" \
-- "$@"
);
eval set --$OPTS;
while [[ $# -gt 0 ]]; do
case "$1" in
--use-npm ) PKG_MNGR="npm"; shift ;;
--use-npx ) PKG_MNGR="npx"; shift ;;
--use-yarn ) PKG_MNGR="yarn"; shift ;;
--help ) echo "$__usage"; exit ;;
* ) break ;;
esac
done
shift $(($OPTIND - 1));
DIRECTORY=$(echo "$@" | sed 's/-- //');
PKG_MNGR="$CONST_DEFAULT";
# ## Directory Check
if [[ -z "${DIRECTORY}" ]]; then
echo 'Directory not specified.' >&2;
exit 1;
fi
if [[ -d "${DIRECTORY}" ]]; then
echo 'Directory already exists.' >&2;
exit 1;
fi
mkdir -p $DIRECTORY;
cd $DIRECTORY;
# ## Install hardhat locally
[[ "yarn" == "$PKG_MNGR" ]] && yarn add -D hardhat;
[[ "npm" == "$PKG_MNGR" ]] && npm install --save-dev hardhat;
[[ "npx" == "$PKG_MNGR" ]] && npm install --save-dev hardhat;
# ### Prompts:
# ```bash
# $ What do you want to do? · Create an advanced sample project that uses TypeScript
# $ Hardhat project root: · /path/project
# $ Do you want to add a .gitignore? (Y/n) · y
# $ Do you want to install this sample project's dependencies with yarn? (Y/n) · y
# ```
[[ ! -x "$(command -v npx)" ]] && npm i -g npx;
npx hardhat;
DEPS=(
'hardhat'
'hardhat-deploy'
'hardhat-deploy-ethers'
'hardhat-typechain'
'hardhat-typechain'
'ts-morph'
'ts-node'
'typescript'
'ts-generator'
'typechain@^7.0.0'
'@symfoni/hardhat-react'
'@typechain/ethers-v5'
'@ethersproject/bytes@^5.0.0'
'@ethersproject/providers@^5.0.0'
'@ethersproject/abi@^5.0.0'
'@ethersproject/hardware-wallets@^5.0.14'
'lodash@^4.17.15'
);
# ## Add the hardhat and hardhat-react peer dependencies
[[ "yarn" == "$PKG_MNGR" ]] && yarn add -D ${DEPS[@]};
[[ "npm" == "$PKG_MNGR" ]] && npm install --save-dev ${DEPS[@]};
[[ "npx" == "$PKG_MNGR" ]] && npm install --save-dev ${DEPS[@]};
# Copy the example .env
cp .env.example .env;
# ## Update hardhat.config.ts
# Add
# ```jsx
# import "@typechain/ethers-v5";
# import "@symfoni/hardhat-react";
#
# ...
#
# // Add the hardhat network
# const config: HardhatUserConfig = {
# solidity: "0.8.4",
# networks: {
# hardhat: { chainId: 1337, },
# ...
# ```
gawk -i inplace 'FNR==NR{ if (/import/) p=NR; next} 1; FNR==p{ print "import \"@typechain/ethers-v5\";\nimport \"@symfoni/hardhat-react\";" }' hardhat.config.ts hardhat.config.ts;
gawk -i inplace 'FNR==NR{ if (/networks: \{/) p=NR; next} 1; FNR==p{ print " hardhat: { chainId: 1337, }," }' hardhat.config.ts hardhat.config.ts;
# ## Create the react app
# (if not exists) create-react-app
# (tar@2.2.2 deprecation warning: `npm install tar -g`)
[[ "yarn" == "$PKG_MNGR" ]] && yarn create react-app frontend --template typescript;
[[ "npm" == "$PKG_MNGR" ]] && npm init react-app frontend --template typescript;
[[ "npx" == "$PKG_MNGR" ]] && npx create-react-app frontend --template typescript;
# ## React app dependencies and peer dependencies
cd frontend;
DEPS=(
'@testing-library/dom@^7.21.4'
'@babel/core@^7.0.0-0'
'@babel/plugin-syntax-flow@^7.14.5'
'@babel/plugin-transform-react-jsx@^7.14.9'
'@types/express@^4.17.13'
'autoprefixer@^10.0.2'
'postcss@^8.1.0'
);
[[ "yarn" == "$PKG_MNGR" ]] && yarn add @usedapp/core && yarn add -D ${DEPS[@]};
[[ "npm" == "$PKG_MNGR" ]] && npm install @usedapp/core && npm install --save-dev ${DEPS[@]};
[[ "npx" == "$PKG_MNGR" ]] && npm install @usedapp/core && npm install --save-dev ${DEPS[@]};
# Copy the example .env
echo "REACT_APP_MULTICALL_ADDRESS=" > .env;
# ## Create a basic configuration file.
echo "
import { Mainnet, Config, ChainId } from \"@usedapp/core\";
const CONFIG: Config = \"production\" !== process.env.NODE_ENV
? {
multicallAddresses: {
[ChainId.Localhost]: process.env.REACT_APP_MULTICALL_ADDRESS ?? \"\",
},
readOnlyUrls: {
[ChainId.Localhost]: \"http://127.0.0.1:8545\",
},
}
: { networks: [Mainnet] };
export default CONFIG;
" > src/Config.tsx;
# ## Add the DAppProvider Wrapper
# ```jsx
# import { DAppProvider } from "@usedapp/core";
# import config from "./Config";
# ...
# <DAppProvider config={config}>
# <App />
# </DAppProvider>
# ...
# ```
gawk -i inplace 'FNR==NR{ if (/import .+;$/) p=NR; next} 1; FNR==p{ print "import { DAppProvider } from \"@usedapp/core\";" }' src/index.tsx src/index.tsx;
gawk -i inplace 'FNR==NR{ if (/import .+;$/) p=NR; next} 1; FNR==p{ print "import config from \"./Config\";" }' src/index.tsx src/index.tsx;
sed -i '/<App \/>/i \ <DAppProvider config={config}>' src/index.tsx;
sed -i '/<App \/>/a \ <\/DAppProvider>' src/index.tsx;
# ## Setup the App.tsx file
# ```jsx
# import { Mainnet, DAppProvider, useEtherBalance, useEthers, Config } from "@usedapp/core";
# import { formatEther } from "@ethersproject/units";
# ...
# const { activateBrowserWallet, account } = useEthers();
# const etherBalance = useEtherBalance(account);
# ...
# ```
gawk -i inplace 'FNR==NR{ if (/import .+;$/) p=NR; next} 1; FNR==p{ print "import { formatEther } from \"@ethersproject/units\";" }' src/App.tsx src/App.tsx;
gawk -i inplace 'FNR==NR{ if (/import .+;$/) p=NR; next} 1; FNR==p{ print "import { useEtherBalance, useEthers } from \"@usedapp/core\";" }' src/App.tsx src/App.tsx;
gawk -i inplace 'FNR==NR{ if (/.*App\(\) \{$/) p=NR; next} 1; FNR==p{ print " const etherBalance = useEtherBalance(account);\n" }' src/App.tsx src/App.tsx;
gawk -i inplace 'FNR==NR{ if (/.*App\(\) \{$/) p=NR; next} 1; FNR==p{ print " const { activateBrowserWallet, account } = useEthers();" }' src/App.tsx src/App.tsx;
gawk -i inplace 'FNR==NR{ if (/.*<div className="App">$/) p=NR; next} 1; FNR==p{ print " {etherBalance && <p>Balance: {formatEther(etherBalance)}</p>}" }' src/App.tsx src/App.tsx;
gawk -i inplace 'FNR==NR{ if (/.*<div className="App">$/) p=NR; next} 1; FNR==p{ print " {account && <p>Account: {account}</p>}" }' src/App.tsx src/App.tsx;
gawk -i inplace 'FNR==NR{ if (/.*<div className="App">$/) p=NR; next} 1; FNR==p{ print " <button onClick={() => activateBrowserWallet()}>Connect</button>" }' src/App.tsx src/App.tsx;
# ## Run
# Start the hardhat node by running the following in the hardhat project root:
# ```bash
# $ npx hardhat node
# ```
#
# Start the local development server from the frontend project root:
# ```bash
# $ yarn start
# ```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment