Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/simple store dapp #20

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,7 @@
yarn install
```

## Usage

```sh
yarn dev
```

## Run tests

```sh
yarn test
```
Remember to create `.env` file from `.env.example` then deploy smart contract and open web app.

## Hardhat guideline

Expand Down Expand Up @@ -74,6 +64,18 @@ npx solhint 'contracts/**/*.sol'
npx solhint 'contracts/**/*.sol' --fix
```

## Usage

```sh
yarn dev
```

## Run tests

```sh
yarn test
```

## Etherscan verification

To try out Etherscan verification, you first need to deploy a contract to an Ethereum network that's supported by Etherscan, such as Ropsten.
Expand Down
7 changes: 6 additions & 1 deletion contracts/Box.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

contract Box {
contract Box is Initializable{
uint256 private _value;

function initialize(uint256 value) public initializer {
_value = value;
}

// Emitted when the stored value changes
event ValueChanged(uint256 value);

Expand Down
7 changes: 6 additions & 1 deletion contracts/BoxV2.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

contract BoxV2 {
contract BoxV2 is Initializable {
uint256 private _value;

function initialize(uint256 value) public initializer {
_value = value;
}

// Emitted when the stored value changes
event ValueChanged(uint256 value);

Expand Down
5 changes: 5 additions & 0 deletions hardhat.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ module.exports = {
url: process.env.BSC_PROVIDER_URL || "https://speedy-nodes-nyc.moralis.io/036063875a28828fa0c00596/bsc/testnet",
accounts: process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [],
},
tomotestnet: {
chainId: 89,
url: "https://rpc.testnet.tomochain.com",
accounts: process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [],
},
},
gasReporter: {
enabled: process.env.REPORT_GAS !== undefined,
Expand Down
98 changes: 49 additions & 49 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,63 +10,63 @@
"test": "mocha --exit --recursive"
},
"dependencies": {
"@tailwindcss/typography": "0.4.1",
"@tailwindcss/typography": "0.5.7",
"@web3-react/core": "6.1.9",
"@web3-react/injected-connector": "6.0.7",
"@web3-react/network-connector": "6.1.9",
"@web3-react/walletconnect-connector": "6.2.4",
"daisyui": "1.14.0",
"loglevel": "1.7.1",
"react": "17.0.2",
"react-dom": "17.0.2",
"@web3-react/network-connector": "6.2.9",
"@web3-react/walletconnect-connector": "6.2.13",
"daisyui": "2.38.0",
"loglevel": "1.8.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"web3-react": "5.0.5"
},
"devDependencies": {
"@nomiclabs/hardhat-ethers": "2.0.2",
"@nomiclabs/hardhat-etherscan": "2.1.5",
"@nomiclabs/hardhat-waffle": "2.0.1",
"@openzeppelin/contracts": "4.3.1",
"@openzeppelin/contracts-upgradeable": "4.3.1",
"@openzeppelin/hardhat-upgrades": "1.10.0",
"@trivago/prettier-plugin-sort-imports": "2.0.4",
"@typechain/ethers-v5": "7.0.1",
"@typechain/hardhat": "2.3.0",
"@types/react": "17.0.19",
"@types/react-dom": "17.0.9",
"@typescript-eslint/eslint-plugin": "4.29.3",
"@typescript-eslint/parser": "4.29.3",
"@vitejs/plugin-react-refresh": "1.3.6",
"autoprefixer": "10.3.3",
"chai": "4.3.4",
"dotenv": "10.0.0",
"eslint": "7.32.0",
"eslint-config-airbnb": "18.2.1",
"eslint-config-prettier": "8.3.0",
"eslint-plugin-import": "2.24.2",
"eslint-plugin-jsx-a11y": "6.4.1",
"@nomiclabs/hardhat-ethers": "2.2.1",
"@nomiclabs/hardhat-etherscan": "3.1.2",
"@nomiclabs/hardhat-waffle": "2.0.3",
"@openzeppelin/contracts": "4.7.3",
"@openzeppelin/contracts-upgradeable": "4.7.3",
"@openzeppelin/hardhat-upgrades": "1.21.0",
"@trivago/prettier-plugin-sort-imports": "3.4.0",
"@typechain/ethers-v5": "10.1.1",
"@typechain/hardhat": "6.1.4",
"@types/mocha": "^10.0.0",
"@types/react": "18.0.24",
"@types/react-dom": "18.0.8",
"@typescript-eslint/eslint-plugin": "5.42.0",
"@typescript-eslint/parser": "5.42.0",
"@vitejs/plugin-react": "^2.2.0",
"autoprefixer": "10.4.13",
"chai": "4.3.6",
"dotenv": "16.0.3",
"eslint": "8.26.0",
"eslint-config-airbnb": "19.0.4",
"eslint-config-prettier": "8.5.0",
"eslint-plugin-import": "2.26.0",
"eslint-plugin-jsx-a11y": "6.6.1",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "5.1.0",
"eslint-plugin-react": "7.25.1",
"eslint-plugin-react-hooks": "4.2.0",
"ethereum-waffle": "3.4.0",
"ethers": "5.4.6",
"hardhat": "2.6.1",
"hardhat-gas-reporter": "1.0.4",
"husky": "7.0.2",
"lint-staged": "11.1.2",
"postcss": "8.3.6",
"prettier": "2.3.2",
"prettier-plugin-solidity": "1.0.0-beta.17",
"solhint": "3.3.6",
"solidity-coverage": "0.7.17",
"tailwindcss": "2.2.9",
"typechain": "5.1.2",
"typescript": "4.4.2",
"vite": "2.5.1",
"vite-plugin-checker": "0.3.4"
"eslint-plugin-promise": "6.1.1",
"eslint-plugin-react": "7.31.10",
"eslint-plugin-react-hooks": "4.6.0",
"ethereum-waffle": "3.4.4",
"ethers": "5.7.2",
"hardhat": "2.12.2",
"hardhat-gas-reporter": "1.0.9",
"husky": "8.0.1",
"lint-staged": "13.0.3",
"postcss": "8.4.18",
"prettier": "2.7.1",
"prettier-plugin-solidity": "1.0.0-rc.1",
"solhint": "3.3.7",
"solidity-coverage": "0.8.2",
"tailwindcss": "3.2.1",
"typechain": "8.1.1",
"typescript": "4.8.4",
"vite": "3.2.2"
},
"lint-staged": {
"*.js": "eslint --cache --fix",
"*.{js,css,md}": "prettier --write"
}
}
}
3 changes: 3 additions & 0 deletions scripts/deploy_upgradeable_box.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ async function main() {
const box = await upgrades.deployProxy(Box, [42], { initializer: "store" });
await box.deployed();
console.log("Box deployed to:", box.address);

const value = await box.retrieve();
console.log("Box value:", value);
}

// We recommend this pattern to be able to use async/await everywhere
Expand Down
5 changes: 3 additions & 2 deletions scripts/upgrade_box.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
/* eslint-disable import/no-extraneous-dependencies */
// We require the Hardhat Runtime Environment explicitly here. This is optional
// but useful for running the script in a standalone fashion through `node <script>`.
//
// When running the script with `npx hardhat run <script>` you'll find the Hardhat
// Runtime Environment's members available in the global scope.
// eslint-disable-next-line import/no-extraneous-dependencies
require("dotenv").config();
const { ethers, upgrades } = require("hardhat");

async function main() {
Expand All @@ -17,7 +18,7 @@ async function main() {
// We get the contract to deploy
const BoxV2 = await ethers.getContractFactory("BoxV2");
console.log("Upgrading Box...");
await upgrades.upgradeProxy("0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0", BoxV2);
await upgrades.upgradeProxy(process.env.VITE_BOX_ADDRESS || "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0", BoxV2);
console.log("Box upgraded");
}

Expand Down
10 changes: 4 additions & 6 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,19 @@ import { Web3ReactProvider } from "@web3-react/core";
import React from "react";

import "./App.css";
import SimpleStoreApp from "./SimpleStoreApp";
import Demo from "./components/Demo";
import { getLibrary } from "./components/Demo";
import logo from "./logo.svg";

const VITE_BOX_ADDRESS = import.meta.env.VITE_BOX_ADDRESS;

function App() {
return (
<Web3ReactProvider getLibrary={getLibrary}>
<div className="App">
<Demo />
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>Hello Dapp Starter!</p>
<p>
Edit <code>App.tsx</code> and save to test HMR updates.
</p>
<SimpleStoreApp contractAddress={VITE_BOX_ADDRESS} />
</header>
<footer className="p-10 footer bg-base-200 text-base-content">
<div>
Expand Down
96 changes: 96 additions & 0 deletions src/SimpleStoreApp.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { useWeb3React } from "@web3-react/core";
import { BigNumber, ethers } from "ethers";
import React from "react";

import BoxArtifacts from "./artifacts/contracts/Box.sol/Box.json";
import BoxV2Artifacts from "./artifacts/contracts/BoxV2.sol/BoxV2.json";
import logger from "./logger";
import { Box, BoxV2 } from "./types";

interface Props {
contractAddress: string;
}

declare global {
interface Window {
ethereum: ethers.providers.ExternalProvider;
}
}

const SimpleStoreApp = ({ contractAddress }: Props) => {
const { library, account } = useWeb3React();

// get store value form smart contract
const fetchValue = () => {
logger.warn("fetchValue");
const provider = library || new ethers.providers.Web3Provider(window.ethereum);
const contract = new ethers.Contract(contractAddress, BoxArtifacts.abi, provider) as Box;
contract.retrieve().then(logger.warn).catch(logger.error);
};

// set random number for store
const setValue = async (val: number) => {
logger.warn("setValue", val);
const provider = library || new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const contract = new ethers.Contract(contractAddress, BoxArtifacts.abi, signer) as Box;

try {
const transaction = await contract.store(val);
await transaction.wait();
} catch (error) {
logger.error(error);
}
};

// increase store + 1
const increase = async () => {
logger.warn("increase");
const provider = library || new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const contract = new ethers.Contract(contractAddress, BoxV2Artifacts.abi, signer) as BoxV2;

try {
const transaction = await contract.increment();
await transaction.wait();
} catch (error) {
logger.error(error);
}
};

React.useEffect(() => {
const provider = library || new ethers.providers.Web3Provider(window.ethereum);
if (account) {
const signer = provider.getSigner();
const contract = new ethers.Contract(contractAddress, BoxArtifacts.abi, signer) as Box;
const listener = (newValue: BigNumber) => {
logger.warn("ValueChanged", newValue);
};

contract.on("ValueChanged", listener);
return () => {
contract.removeListener("ValueChanged", listener);
};
}
}, [library, account]);

return (
<div>
SimpleStoreApp
<h3>Contract Address: {contractAddress}</h3>
<div>
<button type="button" className="btn" onClick={fetchValue}>
Fetch value
</button>
<button disabled={!account} type="button" className="btn" onClick={() => setValue(Date.now())}>
Set value
</button>
<button disabled={!account} type="button" className="btn" onClick={increase}>
Increase +1
</button>
</div>
</div>
);
};

export default SimpleStoreApp;
8 changes: 8 additions & 0 deletions src/types/@openzeppelin/contracts-upgradeable/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/* Autogenerated file. Do not edit manually. */

/* tslint:disable */

/* eslint-disable */
import type * as proxy from "./proxy";

export type { proxy };
8 changes: 8 additions & 0 deletions src/types/@openzeppelin/contracts-upgradeable/proxy/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/* Autogenerated file. Do not edit manually. */

/* tslint:disable */

/* eslint-disable */
import type * as utils from "./utils";

export type { utils };
Loading