黎海 2 yıl önce
ebeveyn
işleme
b90909b8bd
37 değiştirilmiş dosya ile 52042 ekleme ve 0 silme
  1. 2 0
      .gitignore
  2. 21 0
      LICENSE
  3. 1 0
      artifacts/build-info/6cf5fc7f8f3a5c23028a1838520c3187.json
  4. 1 0
      artifacts/build-info/a94026f84ea9eac73eedff0349d4d183.json
  5. 4 0
      artifacts/contracts/Token.sol/Token.dbg.json
  6. 44 0
      artifacts/contracts/Token.sol/Token.json
  7. 4 0
      artifacts/hardhat/console.sol/console.dbg.json
  8. 10 0
      artifacts/hardhat/console.sol/console.json
  9. 75 0
      cache/solidity-files-cache.json
  10. 99 0
      contracts/Token.sol
  11. 25 0
      frontend/.gitignore
  12. 38 0
      frontend/README.md
  13. 31500 0
      frontend/package-lock.json
  14. 34 0
      frontend/package.json
  15. BIN
      frontend/public/favicon.ico
  16. 43 0
      frontend/public/index.html
  17. BIN
      frontend/public/logo192.png
  18. BIN
      frontend/public/logo310.png
  19. 25 0
      frontend/public/manifest.json
  20. 3 0
      frontend/public/robots.txt
  21. 31 0
      frontend/src/components/ConnectWallet.js
  22. 370 0
      frontend/src/components/Dapp.js
  23. 35 0
      frontend/src/components/Loading.js
  24. 18 0
      frontend/src/components/NetworkErrorMessage.js
  25. 15 0
      frontend/src/components/NoTokensMessage.js
  26. 24 0
      frontend/src/components/NoWalletDetected.js
  27. 18 0
      frontend/src/components/TransactionErrorMessage.js
  28. 43 0
      frontend/src/components/Transfer.js
  29. 9 0
      frontend/src/components/WaitingForTransactionMessage.js
  30. 16 0
      frontend/src/index.js
  31. 92 0
      frontend/src/translate.py
  32. 28 0
      hardhat.config.js
  33. 19164 0
      package-lock.json
  34. 32 0
      package.json
  35. 61 0
      scripts/deploy.js
  36. 46 0
      tasks/faucet.js
  37. 111 0
      test/Token.js

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
1
+.DS_Store
2
+/node_modules

+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
1
+MIT License
2
+
3
+Copyright (c) 2020 Nomic Labs
4
+
5
+Permission is hereby granted, free of charge, to any person obtaining a copy
6
+of this software and associated documentation files (the "Software"), to deal
7
+in the Software without restriction, including without limitation the rights
8
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+copies of the Software, and to permit persons to whom the Software is
10
+furnished to do so, subject to the following conditions:
11
+
12
+The above copyright notice and this permission notice shall be included in all
13
+copies or substantial portions of the Software.
14
+
15
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+SOFTWARE.

Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 0
artifacts/build-info/6cf5fc7f8f3a5c23028a1838520c3187.json


Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 0
artifacts/build-info/a94026f84ea9eac73eedff0349d4d183.json


+ 4 - 0
artifacts/contracts/Token.sol/Token.dbg.json

@@ -0,0 +1,4 @@
1
+{
2
+  "_format": "hh-sol-dbg-1",
3
+  "buildInfo": "../../build-info/6cf5fc7f8f3a5c23028a1838520c3187.json"
4
+}

Dosya farkı çok büyük olduğundan ihmal edildi
+ 44 - 0
artifacts/contracts/Token.sol/Token.json


+ 4 - 0
artifacts/hardhat/console.sol/console.dbg.json

@@ -0,0 +1,4 @@
1
+{
2
+  "_format": "hh-sol-dbg-1",
3
+  "buildInfo": "../../build-info/a94026f84ea9eac73eedff0349d4d183.json"
4
+}

+ 10 - 0
artifacts/hardhat/console.sol/console.json

@@ -0,0 +1,10 @@
1
+{
2
+  "_format": "hh-sol-artifact-1",
3
+  "contractName": "console",
4
+  "sourceName": "hardhat/console.sol",
5
+  "abi": [],
6
+  "bytecode": "0x60566050600b82828239805160001a6073146043577f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122023ed7727ab4a3926687af4d4c2d34d1104da736a65dadf10a6bb9551cb1c779564736f6c63430008090033",
7
+  "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122023ed7727ab4a3926687af4d4c2d34d1104da736a65dadf10a6bb9551cb1c779564736f6c63430008090033",
8
+  "linkReferences": {},
9
+  "deployedLinkReferences": {}
10
+}

+ 75 - 0
cache/solidity-files-cache.json

@@ -0,0 +1,75 @@
1
+{
2
+  "_format": "hh-sol-cache-2",
3
+  "files": {
4
+    "/Users/lihai/Remix/hardhat-boilerplate/contracts/Token.sol": {
5
+      "lastModificationDate": 1671500749681,
6
+      "contentHash": "8db5419daad0c435bdc5276ce4eb8b7e",
7
+      "sourceName": "contracts/Token.sol",
8
+      "solcConfig": {
9
+        "version": "0.8.9",
10
+        "settings": {
11
+          "optimizer": {
12
+            "enabled": false,
13
+            "runs": 200
14
+          },
15
+          "outputSelection": {
16
+            "*": {
17
+              "*": [
18
+                "abi",
19
+                "evm.bytecode",
20
+                "evm.deployedBytecode",
21
+                "evm.methodIdentifiers",
22
+                "metadata"
23
+              ],
24
+              "": [
25
+                "ast"
26
+              ]
27
+            }
28
+          }
29
+        }
30
+      },
31
+      "imports": [],
32
+      "versionPragmas": [
33
+        "^0.8.9"
34
+      ],
35
+      "artifacts": [
36
+        "Token"
37
+      ]
38
+    },
39
+    "/Users/lihai/Remix/hardhat-boilerplate/node_modules/hardhat/console.sol": {
40
+      "lastModificationDate": 1671092320072,
41
+      "contentHash": "4ff3cd2f6272c9a6516e9ee4f2b967d3",
42
+      "sourceName": "hardhat/console.sol",
43
+      "solcConfig": {
44
+        "version": "0.8.9",
45
+        "settings": {
46
+          "optimizer": {
47
+            "enabled": false,
48
+            "runs": 200
49
+          },
50
+          "outputSelection": {
51
+            "*": {
52
+              "*": [
53
+                "abi",
54
+                "evm.bytecode",
55
+                "evm.deployedBytecode",
56
+                "evm.methodIdentifiers",
57
+                "metadata"
58
+              ],
59
+              "": [
60
+                "ast"
61
+              ]
62
+            }
63
+          }
64
+        }
65
+      },
66
+      "imports": [],
67
+      "versionPragmas": [
68
+        ">= 0.4.22 <0.9.0"
69
+      ],
70
+      "artifacts": [
71
+        "console"
72
+      ]
73
+    }
74
+  }
75
+}

+ 99 - 0
contracts/Token.sol

@@ -0,0 +1,99 @@
1
+
2
+pragma solidity ^0.8.9;
3
+
4
+contract Token {
5
+
6
+    // Public variable of type unsigned int to keep the number of counts
7
+    uint256 public count = 0;
8
+
9
+    // Function that increments our counter
10
+    function increment() public {
11
+        count += 1;
12
+    }
13
+
14
+    // Not necessary getter to get the count value
15
+    function getCount() public view returns (uint256) {
16
+        return count;
17
+    }
18
+
19
+}
20
+
21
+
22
+//SPDX-License-Identifier: UNLICENSED
23
+
24
+// Solidity files have to start with this pragma.
25
+// It will be used by the Solidity compiler to validate its version.
26
+// pragma solidity ^0.8.9;
27
+
28
+// // We import this library to be able to use console.log
29
+// import "hardhat/console.sol";
30
+
31
+
32
+// // This is the main building block for smart contracts.
33
+// contract Token {
34
+//     // Some string type variables to identify the token.
35
+//     string public name = "My Hardhat Token";
36
+//     string public symbol = "MHT";
37
+
38
+//     // The fixed amount of tokens stored in an unsigned integer type variable.
39
+//     uint256 public totalSupply = 1000000;
40
+
41
+//     // An address type variable is used to store ethereum accounts.
42
+//     address public owner;
43
+
44
+//     // A mapping is a key/value map. Here we store each account balance.
45
+//     mapping(address => uint256) balances;
46
+
47
+//     // The Transfer event helps off-chain aplications understand
48
+//     // what happens within your contract.
49
+//     event Transfer(address indexed _from, address indexed _to, uint256 _value);
50
+
51
+//     /**
52
+//      * Contract initialization.
53
+//      */
54
+//     constructor() {
55
+//         // The totalSupply is assigned to the transaction sender, which is the
56
+//         // account that is deploying the contract.
57
+//         balances[msg.sender] = totalSupply;
58
+//         owner = msg.sender;
59
+//     }
60
+
61
+//     /**
62
+//      * A function to transfer tokens.
63
+//      *
64
+//      * The `external` modifier makes a function *only* callable from outside
65
+//      * the contract.
66
+//      */
67
+//     function transfer(address to, uint256 amount) external {
68
+//         // Check if the transaction sender has enough tokens.
69
+//         // If `require`'s first argument evaluates to `false` then the
70
+//         // transaction will revert.
71
+//         require(balances[msg.sender] >= amount, "Not enough tokens");
72
+
73
+//         // We can print messages and values using console.log, a feature of
74
+//         // Hardhat Network:
75
+//         console.log(
76
+//             "Transferring from %s to %s %s tokens",
77
+//             msg.sender,
78
+//             to,
79
+//             amount
80
+//         );
81
+
82
+//         // Transfer the amount.
83
+//         balances[msg.sender] -= amount;
84
+//         balances[to] += amount;
85
+
86
+//         // Notify off-chain applications of the transfer.
87
+//         emit Transfer(msg.sender, to, amount);
88
+//     }
89
+
90
+//     /**
91
+//      * Read only function to retrieve the token balance of a given account.
92
+//      *
93
+//      * The `view` modifier indicates that it doesn't modify the contract's
94
+//      * state, which allows us to call it without executing a transaction.
95
+//      */
96
+//     function balanceOf(address account) external view returns (uint256) {
97
+//         return balances[account];
98
+//     }
99
+// }

+ 25 - 0
frontend/.gitignore

@@ -0,0 +1,25 @@
1
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2
+
3
+src/contracts
4
+
5
+# dependencies
6
+/node_modules
7
+/.pnp
8
+.pnp.js
9
+
10
+# testing
11
+/coverage
12
+
13
+# production
14
+/build
15
+
16
+# misc
17
+.DS_Store
18
+.env.local
19
+.env.development.local
20
+.env.test.local
21
+.env.production.local
22
+
23
+npm-debug.log*
24
+yarn-debug.log*
25
+yarn-error.log*

+ 38 - 0
frontend/README.md

@@ -0,0 +1,38 @@
1
+# Sample React Dapp
2
+
3
+This directory has a sample Dapp to interact with your contracts, built using
4
+React.
5
+
6
+## Running the Dapp
7
+
8
+This project uses [`create-react-app`](https://create-react-app.dev/), so most
9
+configuration files are handled by it.
10
+
11
+To run it, you just need to execute `npm start` in a terminal, and open
12
+[http://localhost:3000](http://localhost:3000).
13
+
14
+To learn more about what `create-react-app` offers, you can read
15
+[its documentation](https://create-react-app.dev/docs/getting-started).
16
+
17
+## Architecture of the Dapp
18
+
19
+This Dapp consists of multiple React Components, which you can find in
20
+`src/components`.
21
+
22
+Most of them are presentational components, have no logic, and just render HTML.
23
+
24
+The core functionality is implemented in `src/components/Dapp.js`, which has
25
+examples of how to connect to the user's wallet, initialize your Ethereum
26
+connection and contracts, read from the contract's state, and send transactions.
27
+
28
+You can use the `Dapp` component as a starting point for your project. It has
29
+comments explaining each part of its code, and indicating what's specific to
30
+this project, and what can be reused.
31
+
32
+## Getting help and news
33
+
34
+If you need help with this project or with Hardhat in general, please read [this guide](https://hardhat.org/hardhat-runner/docs/guides/getting-help) to learn where and how to get it.
35
+
36
+[Follow us on Twitter](https://twitter.com/HardhatHQ) to get the latest news about Hardhat, and don't forget to star [our GitHub repository](https://github.com/NomicFoundation/hardhat)!
37
+
38
+**Happy _building_!**

Dosya farkı çok büyük olduğundan ihmal edildi
+ 31500 - 0
frontend/package-lock.json


+ 34 - 0
frontend/package.json

@@ -0,0 +1,34 @@
1
+{
2
+  "name": "frontend",
3
+  "version": "0.1.0",
4
+  "private": true,
5
+  "dependencies": {
6
+    "bootstrap": "^4.4.1",
7
+    "ethers": "^5.4.7",
8
+    "react": "^18.2.0",
9
+    "react-dom": "^18.2.0"
10
+  },
11
+  "devDependencies": {
12
+    "react-scripts": "5.0.1"
13
+  },
14
+  "scripts": {
15
+    "start": "react-scripts start",
16
+    "build": "react-scripts build",
17
+    "eject": "react-scripts eject"
18
+  },
19
+  "eslintConfig": {
20
+    "extends": "react-app"
21
+  },
22
+  "browserslist": {
23
+    "production": [
24
+      ">0.2%",
25
+      "not dead",
26
+      "not op_mini all"
27
+    ],
28
+    "development": [
29
+      "last 1 chrome version",
30
+      "last 1 firefox version",
31
+      "last 1 safari version"
32
+    ]
33
+  }
34
+}

BIN
frontend/public/favicon.ico


+ 43 - 0
frontend/public/index.html

@@ -0,0 +1,43 @@
1
+<!DOCTYPE html>
2
+<html lang="en">
3
+  <head>
4
+    <meta charset="utf-8" />
5
+    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
6
+    <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+    <meta name="theme-color" content="#000000" />
8
+    <meta
9
+      name="description"
10
+      content="Hardhat React Dapp"
11
+    />
12
+    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
13
+    <!--
14
+      manifest.json provides metadata used when your web app is installed on a
15
+      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
16
+    -->
17
+    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
18
+    <!--
19
+      Notice the use of %PUBLIC_URL% in the tags above.
20
+      It will be replaced with the URL of the `public` folder during the build.
21
+      Only files inside the `public` folder can be referenced from the HTML.
22
+
23
+      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
24
+      work correctly both with client-side routing and a non-root public URL.
25
+      Learn how to configure a non-root public URL by running `npm run build`.
26
+    -->
27
+    <title>Hardhat + React App = Dapp</title>
28
+  </head>
29
+  <body>
30
+    <noscript>You need to enable JavaScript to run this app.</noscript>
31
+    <div id="root"></div>
32
+    <!--
33
+      This HTML file is a template.
34
+      If you open it directly in the browser, you will see an empty page.
35
+
36
+      You can add webfonts, meta tags, or analytics to this file.
37
+      The build step will place the bundled scripts into the <body> tag.
38
+
39
+      To begin the development, run `npm start` or `yarn start`.
40
+      To create a production bundle, use `npm run build` or `yarn build`.
41
+    -->
42
+  </body>
43
+</html>

BIN
frontend/public/logo192.png


BIN
frontend/public/logo310.png


+ 25 - 0
frontend/public/manifest.json

@@ -0,0 +1,25 @@
1
+{
2
+  "short_name": "Hardhat React Dapp",
3
+  "name": "Hardhat Create React Dapp Sample",
4
+  "icons": [
5
+    {
6
+      "src": "favicon.ico",
7
+      "sizes": "64x64 32x32 24x24 16x16",
8
+      "type": "image/x-icon"
9
+    },
10
+    {
11
+      "src": "logo192.png",
12
+      "type": "image/png",
13
+      "sizes": "192x192"
14
+    },
15
+    {
16
+      "src": "logo310.png",
17
+      "type": "image/png",
18
+      "sizes": "310x310"
19
+    }
20
+  ],
21
+  "start_url": ".",
22
+  "display": "standalone",
23
+  "theme_color": "#000000",
24
+  "background_color": "#ffffff"
25
+}

+ 3 - 0
frontend/public/robots.txt

@@ -0,0 +1,3 @@
1
+# https://www.robotstxt.org/robotstxt.html
2
+User-agent: *
3
+Disallow:

+ 31 - 0
frontend/src/components/ConnectWallet.js

@@ -0,0 +1,31 @@
1
+import React from "react";
2
+
3
+import { NetworkErrorMessage } from "./NetworkErrorMessage";
4
+
5
+export function ConnectWallet({ connectWallet, networkError, dismiss }) {
6
+  return (
7
+    <div className="container">
8
+      <div className="row justify-content-md-center">
9
+        <div className="col-12 text-center">
10
+          {/* Metamask network should be set to Localhost:8545. */}
11
+          {networkError && (
12
+            <NetworkErrorMessage 
13
+              message={networkError} 
14
+              dismiss={dismiss} 
15
+            />
16
+          )}
17
+        </div>
18
+        <div className="col-6 p-4 text-center">
19
+          <p>Please connect to your wallet.</p>
20
+          <button
21
+            className="btn btn-warning"
22
+            type="button"
23
+            onClick={connectWallet}
24
+          >
25
+            Connect Wallet
26
+          </button>
27
+        </div>
28
+      </div>
29
+    </div>
30
+  );
31
+}

+ 370 - 0
frontend/src/components/Dapp.js

@@ -0,0 +1,370 @@
1
+import React from "react";
2
+
3
+// We'll use ethers to interact with the Ethereum network and our contract
4
+import { ethers } from "ethers";
5
+
6
+// We import the contract's artifacts and address here, as we are going to be
7
+// using them with ethers
8
+import TokenArtifact from "../contracts/Token.json";
9
+import contractAddress from "../contracts/contract-address.json";
10
+
11
+// All the logic of this dapp is contained in the Dapp component.
12
+// These other components are just presentational ones: they don't have any
13
+// logic. They just render HTML.
14
+import { NoWalletDetected } from "./NoWalletDetected";
15
+import { ConnectWallet } from "./ConnectWallet";
16
+import { Loading } from "./Loading";
17
+import { Transfer } from "./Transfer";
18
+import { TransactionErrorMessage } from "./TransactionErrorMessage";
19
+import { WaitingForTransactionMessage } from "./WaitingForTransactionMessage";
20
+import { NoTokensMessage } from "./NoTokensMessage";
21
+
22
+// This is the Hardhat Network id that we set in our hardhat.config.js.
23
+// Here's a list of network ids https://docs.metamask.io/guide/ethereum-provider.html#properties
24
+// to use when deploying to other networks.
25
+const HARDHAT_NETWORK_ID = '5';
26
+
27
+// This is an error code that indicates that the user canceled a transaction
28
+const ERROR_CODE_TX_REJECTED_BY_USER = 4001;
29
+
30
+// This component is in charge of doing these things:
31
+//   1. It connects to the user's wallet
32
+//   2. Initializes ethers and the Token contract
33
+//   3. Polls the user balance to keep it updated.
34
+//   4. Transfers tokens by sending transactions
35
+//   5. Renders the whole application
36
+//
37
+// Note that (3) and (4) are specific of this sample application, but they show
38
+// you how to keep your Dapp and contract's state in sync,  and how to send a
39
+// transaction.
40
+export class Dapp extends React.Component {
41
+  constructor(props) {
42
+    super(props);
43
+
44
+    // We store multiple things in Dapp's state.
45
+    // You don't need to follow this pattern, but it's an useful example.
46
+    this.initialState = {
47
+      // The info of the token (i.e. It's Name and symbol)
48
+      tokenData: undefined,
49
+      // The user's address and balance
50
+      selectedAddress: undefined,
51
+      balance: undefined,
52
+      // The ID about transactions being sent, and any possible error with them
53
+      txBeingSent: undefined,
54
+      transactionError: undefined,
55
+      networkError: undefined,
56
+    };
57
+
58
+    this.state = this.initialState;
59
+  }
60
+
61
+  render () {
62
+    // Ethereum wallets inject the window.ethereum object. If it hasn't been
63
+    // injected, we instruct the user to install MetaMask.
64
+    if (window.ethereum === undefined) {
65
+      return <NoWalletDetected />;
66
+    }
67
+
68
+    // The next thing we need to do, is to ask the user to connect their wallet.
69
+    // When the wallet gets connected, we are going to save the users's address
70
+    // in the component's state. So, if it hasn't been saved yet, we have
71
+    // to show the ConnectWallet component.
72
+    //
73
+    // Note that we pass it a callback that is going to be called when the user
74
+    // clicks a button. This callback just calls the _connectWallet method.
75
+    if (!this.state.selectedAddress) {
76
+      return (
77
+        <ConnectWallet
78
+          connectWallet={() => this._connectWallet()}
79
+          networkError={this.state.networkError}
80
+          dismiss={() => this._dismissNetworkError()}
81
+        />
82
+      );
83
+    }
84
+
85
+    // If the token data or the user's balance hasn't loaded yet, we show
86
+    // a loading component.
87
+    if (!this.state.tokenData || !this.state.balance) {
88
+      return <Loading />;
89
+    }
90
+
91
+    // If everything is loaded, we render the application.
92
+    return (
93
+      <div className="container p-4">
94
+        <div className="row">
95
+          <div className="col-12">
96
+            <h1>
97
+              {this.state.tokenData.name} ({this.state.tokenData.symbol})
98
+            </h1>
99
+            <p>
100
+              Welcome <b>{this.state.selectedAddress}</b>, you have{" "}
101
+              <b>
102
+                {this.state.balance.toString()} {this.state.tokenData.symbol}
103
+              </b>
104
+              .
105
+            </p>
106
+          </div>
107
+        </div>
108
+
109
+        <hr />
110
+
111
+        <div className="row">
112
+          <div className="col-12">
113
+            {/* 
114
+              Sending a transaction isn't an immediate action. You have to wait
115
+              for it to be mined.
116
+              If we are waiting for one, we show a message here.
117
+            */}
118
+            {this.state.txBeingSent && (
119
+              <WaitingForTransactionMessage txHash={this.state.txBeingSent} />
120
+            )}
121
+
122
+            {/* 
123
+              Sending a transaction can fail in multiple ways. 
124
+              If that happened, we show a message here.
125
+            */}
126
+            {this.state.transactionError && (
127
+              <TransactionErrorMessage
128
+                message={this._getRpcErrorMessage(this.state.transactionError)}
129
+                dismiss={() => this._dismissTransactionError()}
130
+              />
131
+            )}
132
+          </div>
133
+        </div>
134
+
135
+        <div className="row">
136
+          <div className="col-12">
137
+            {/*
138
+              If the user has no tokens, we don't show the Transfer form
139
+            */}
140
+            {this.state.balance.eq(0) && (
141
+              <NoTokensMessage selectedAddress={this.state.selectedAddress} />
142
+            )}
143
+
144
+            {/*
145
+              This component displays a form that the user can use to send a 
146
+              transaction and transfer some tokens.
147
+              The component doesn't have logic, it just calls the transferTokens
148
+              callback.
149
+            */}
150
+            {this.state.balance.gt(0) && (
151
+              <Transfer
152
+                transferTokens={(to, amount) =>
153
+                  this._transferTokens(to, amount)
154
+                }
155
+                tokenSymbol={this.state.tokenData.symbol}
156
+              />
157
+            )}
158
+          </div>
159
+        </div>
160
+      </div>
161
+    );
162
+  }
163
+
164
+  componentWillUnmount () {
165
+    // We poll the user's balance, so we have to stop doing that when Dapp
166
+    // gets unmounted
167
+    this._stopPollingData();
168
+  }
169
+
170
+  async _connectWallet () {
171
+    console.log('_connectWallet');
172
+    // This method is run when the user clicks the Connect. It connects the
173
+    // dapp to the user's wallet, and initializes it.
174
+
175
+    // To connect to the user's wallet, we have to run this method.
176
+    // It returns a promise that will resolve to the user's address.
177
+    const [selectedAddress] = await window.ethereum.request({ method: 'eth_requestAccounts' });
178
+
179
+    // Once we have the address, we can initialize the application.
180
+
181
+    // First we check the network
182
+    if (!this._checkNetwork()) {
183
+      return;
184
+    }
185
+
186
+    this._initialize(selectedAddress);
187
+
188
+    // We reinitialize it whenever the user changes their account.
189
+    window.ethereum.on("accountsChanged", ([newAddress]) => {
190
+      this._stopPollingData();
191
+      // `accountsChanged` event can be triggered with an undefined newAddress.
192
+      // This happens when the user removes the Dapp from the "Connected
193
+      // list of sites allowed access to your addresses" (Metamask > Settings > Connections)
194
+      // To avoid errors, we reset the dapp state 
195
+      if (newAddress === undefined) {
196
+        return this._resetState();
197
+      }
198
+
199
+      this._initialize(newAddress);
200
+    });
201
+
202
+    // We reset the dapp state if the network is changed
203
+    window.ethereum.on("chainChanged", ([networkId]) => {
204
+      this._stopPollingData();
205
+      this._resetState();
206
+    });
207
+  }
208
+
209
+  _initialize (userAddress) {
210
+    // This method initializes the dapp
211
+
212
+    // We first store the user's address in the component's state
213
+    this.setState({
214
+      selectedAddress: userAddress,
215
+    });
216
+
217
+    //然后,我们初始化ethers,获取令牌的数据,并开始轮询
218
+    //用于用户的平衡。
219
+    //获取令牌数据和用户余额是特定于此的
220
+    //示例项目,但您可以重用相同的初始化模式。
221
+    this._initializeEthers();
222
+    this._getTokenData();
223
+    this._startPollingData();
224
+  }
225
+
226
+  async _initializeEthers () {
227
+    // 我们首先通过使用window.ethereum创建提供程序来初始化ethers
228
+    this._provider = new ethers.providers.Web3Provider(window.ethereum);
229
+
230
+    //然后,我们使用该提供程序和令牌的
231
+    //人工制品。你可以对你的合同做同样的事情。
232
+    console.log(contractAddress.Token,
233
+      TokenArtifact.abi,
234
+      this._provider.getSigner(0), '===');
235
+    this._token = new ethers.Contract(
236
+      contractAddress.Token,
237
+      TokenArtifact.abi,
238
+      this._provider.getSigner(0)
239
+    );
240
+  }
241
+
242
+  //接下来需要两种方法来启动和停止轮询数据。虽然
243
+  //此处轮询的数据特定于此示例,您可以使用
244
+  //模式读取合同中的任何数据。
245
+  //请注意,如果您不需要它近实时更新,您可能会
246
+  //不需要轮询。如果是这样的话,您可以在
247
+  //初始化应用程序,就像我们处理令牌数据一样。
248
+  _startPollingData () {
249
+    this._pollDataInterval = setInterval(() => this._updateBalance(), 1000);
250
+
251
+    //我们立即运行一次,这样就不必等待
252
+    this._updateBalance();
253
+  }
254
+
255
+  _stopPollingData () {
256
+    clearInterval(this._pollDataInterval);
257
+    this._pollDataInterval = undefined;
258
+  }
259
+
260
+  //接下来的两个方法只是读取合同并存储结果
261
+  //处于组件状态。
262
+  async _getTokenData () {
263
+    const name = await this._token.name();
264
+    const symbol = await this._token.symbol();
265
+
266
+    this.setState({ tokenData: { name, symbol } });
267
+  }
268
+
269
+  async _updateBalance () {
270
+    const balance = await this._token.balanceOf(this.state.selectedAddress);
271
+    this.setState({ balance });
272
+  }
273
+
274
+  //此方法发送一个ethereum事务以传输令牌。
275
+  //虽然此操作特定于此应用程序,但它说明了如何
276
+  //发送交易。
277
+  async _transferTokens (to, amount) {
278
+    //发送事务是一项复杂的操作:
279
+    //-用户可以拒绝
280
+    //-它可能在到达ethereum网络之前失败(即,如果用户
281
+    //没有用于支付tx汽油的ETH)
282
+    //-必须开采,因此无法立即确认。
283
+    //请注意,一些测试网络,如Hardhat网络,是我的
284
+    //立即进行交易,但您的dapp应该做好准备
285
+    //其他网络。
286
+    //-一旦开采,可能会失败。
287
+    //这种方法可以处理所有这些事情,所以请继续阅读以了解如何
288
+    //做到这一点。
289
+
290
+    try {
291
+      //如果事务失败,我们会将该错误保存在组件的状态中。
292
+      //我们只保存一个这样的错误,因此在发送第二个事务之前,我们
293
+      //清除它。
294
+      this._dismissTransactionError();
295
+
296
+      //我们发送事务,并将其哈希保存在Dapp的状态中。这
297
+      //我们可以表示我们正在等待它被开采。
298
+      const tx = await this._token.transfer(to, amount);
299
+      this.setState({ txBeingSent: tx.hash });
300
+
301
+      //我们使用.wait()等待事务被挖掘。此方法
302
+      //返回交易的收据。
303
+      const receipt = await tx.wait();
304
+
305
+      //收据包含一个状态标志,0表示错误。
306
+      if (receipt.status === 0) {
307
+        // We can't know the exact error that made the transaction fail when it
308
+        // was mined, so we throw this generic one.
309
+        throw new Error("Transaction failed");
310
+      }
311
+
312
+      // If we got here, the transaction was successful, so you may want to
313
+      // update your state. Here, we update the user's balance.
314
+      await this._updateBalance();
315
+    } catch (error) {
316
+      // We check the error code to see if this error was produced because the
317
+      // user rejected a tx. If that's the case, we do nothing.
318
+      if (error.code === ERROR_CODE_TX_REJECTED_BY_USER) {
319
+        return;
320
+      }
321
+
322
+      // Other errors are logged and stored in the Dapp's state. This is used to
323
+      // show them to the user, and for debugging.
324
+      console.error(error);
325
+      this.setState({ transactionError: error });
326
+    } finally {
327
+      // If we leave the try/catch, we aren't sending a tx anymore, so we clear
328
+      // this part of the state.
329
+      this.setState({ txBeingSent: undefined });
330
+    }
331
+  }
332
+
333
+  // This method just clears part of the state.
334
+  _dismissTransactionError () {
335
+    this.setState({ transactionError: undefined });
336
+  }
337
+
338
+  // This method just clears part of the state.
339
+  _dismissNetworkError () {
340
+    this.setState({ networkError: undefined });
341
+  }
342
+
343
+  // This is an utility method that turns an RPC error into a human readable
344
+  // message.
345
+  _getRpcErrorMessage (error) {
346
+    if (error.data) {
347
+      return error.data.message;
348
+    }
349
+
350
+    return error.message;
351
+  }
352
+
353
+  // This method resets the state
354
+  _resetState () {
355
+    this.setState(this.initialState);
356
+  }
357
+
358
+  // This method checks if Metamask selected network is Localhost:8545 
359
+  _checkNetwork () {
360
+    if (window.ethereum.networkVersion === HARDHAT_NETWORK_ID) {
361
+      return true;
362
+    }
363
+
364
+    this.setState({
365
+      networkError: 'Please connect Metamask to Localhost:8545'
366
+    });
367
+
368
+    return false;
369
+  }
370
+}

+ 35 - 0
frontend/src/components/Loading.js

@@ -0,0 +1,35 @@
1
+import React from "react";
2
+
3
+export function Loading() {
4
+  return (
5
+    <div
6
+      style={{
7
+        position: "fixed",
8
+        zIndex: 2,
9
+        top: 0,
10
+        left: 0,
11
+        width: "100%",
12
+        height: "100%",
13
+        background: "rgba(255, 255, 255, 0.5)",
14
+      }}
15
+    >
16
+      <div
17
+        style={{
18
+          position: "absolute",
19
+          zIndex: 3,
20
+          top: "50%",
21
+          left: "50%",
22
+          width: "100px",
23
+          height: "50px",
24
+          marginLeft: "-50px",
25
+          marginTop: " -25px",
26
+          textAlign: "center",
27
+        }}
28
+      >
29
+        <div className="spinner-border" role="status">
30
+          <span className="sr-only">Loading...</span>
31
+        </div>
32
+      </div>
33
+    </div>
34
+  );
35
+}

+ 18 - 0
frontend/src/components/NetworkErrorMessage.js

@@ -0,0 +1,18 @@
1
+import React from "react";
2
+
3
+export function NetworkErrorMessage({ message, dismiss }) {
4
+  return (
5
+    <div className="alert alert-danger" role="alert">
6
+      {message}
7
+      <button
8
+        type="button"
9
+        className="close"
10
+        data-dismiss="alert"
11
+        aria-label="Close"
12
+        onClick={dismiss}
13
+      >
14
+        <span aria-hidden="true">&times;</span>
15
+      </button>
16
+    </div>
17
+  );
18
+}

+ 15 - 0
frontend/src/components/NoTokensMessage.js

@@ -0,0 +1,15 @@
1
+import React from "react";
2
+
3
+export function NoTokensMessage({ selectedAddress }) {
4
+  return (
5
+    <>
6
+      <p>You don't have tokens to transfer</p>
7
+      <p>
8
+        To get some tokens, open a terminal in the root of the repository and run: 
9
+        <br />
10
+        <br />
11
+        <code>npx hardhat --network localhost faucet {selectedAddress}</code>
12
+      </p>
13
+    </>
14
+  );
15
+}

+ 24 - 0
frontend/src/components/NoWalletDetected.js

@@ -0,0 +1,24 @@
1
+import React from "react";
2
+
3
+export function NoWalletDetected() {
4
+  return (
5
+    <div className="container">
6
+      <div className="row justify-content-md-center">
7
+        <div className="col-6 p-4 text-center">
8
+          <p>
9
+            No Ethereum wallet was detected. <br />
10
+            Please install{" "}
11
+            <a
12
+              href="http://metamask.io"
13
+              target="_blank"
14
+              rel="noopener noreferrer"
15
+            >
16
+              MetaMask
17
+            </a>
18
+            .
19
+          </p>
20
+        </div>
21
+      </div>
22
+    </div>
23
+  );
24
+}

+ 18 - 0
frontend/src/components/TransactionErrorMessage.js

@@ -0,0 +1,18 @@
1
+import React from "react";
2
+
3
+export function TransactionErrorMessage({ message, dismiss }) {
4
+  return (
5
+    <div className="alert alert-danger" role="alert">
6
+      Error sending transaction: {message.substring(0, 100)}
7
+      <button
8
+        type="button"
9
+        className="close"
10
+        data-dismiss="alert"
11
+        aria-label="Close"
12
+        onClick={dismiss}
13
+      >
14
+        <span aria-hidden="true">&times;</span>
15
+      </button>
16
+    </div>
17
+  );
18
+}

+ 43 - 0
frontend/src/components/Transfer.js

@@ -0,0 +1,43 @@
1
+import React from "react";
2
+
3
+export function Transfer({ transferTokens, tokenSymbol }) {
4
+  return (
5
+    <div>
6
+      <h4>Transfer</h4>
7
+      <form
8
+        onSubmit={(event) => {
9
+          // This function just calls the transferTokens callback with the
10
+          // form's data.
11
+          event.preventDefault();
12
+
13
+          const formData = new FormData(event.target);
14
+          const to = formData.get("to");
15
+          const amount = formData.get("amount");
16
+
17
+          if (to && amount) {
18
+            transferTokens(to, amount);
19
+          }
20
+        }}
21
+      >
22
+        <div className="form-group">
23
+          <label>Amount of {tokenSymbol}</label>
24
+          <input
25
+            className="form-control"
26
+            type="number"
27
+            step="1"
28
+            name="amount"
29
+            placeholder="1"
30
+            required
31
+          />
32
+        </div>
33
+        <div className="form-group">
34
+          <label>Recipient address</label>
35
+          <input className="form-control" type="text" name="to" required />
36
+        </div>
37
+        <div className="form-group">
38
+          <input className="btn btn-primary" type="submit" value="Transfer" />
39
+        </div>
40
+      </form>
41
+    </div>
42
+  );
43
+}

+ 9 - 0
frontend/src/components/WaitingForTransactionMessage.js

@@ -0,0 +1,9 @@
1
+import React from "react";
2
+
3
+export function WaitingForTransactionMessage({ txHash }) {
4
+  return (
5
+    <div className="alert alert-info" role="alert">
6
+      Waiting for transaction <strong>{txHash}</strong> to be mined
7
+    </div>
8
+  );
9
+}

+ 16 - 0
frontend/src/index.js

@@ -0,0 +1,16 @@
1
+import React from "react";
2
+import ReactDOM from "react-dom";
3
+import { Dapp } from "./components/Dapp";
4
+
5
+// We import bootstrap here, but you can remove if you want
6
+import "bootstrap/dist/css/bootstrap.css";
7
+
8
+// This is the entry point of your application, but it just renders the Dapp
9
+// react component. All of the logic is contained in it.
10
+
11
+ReactDOM.render(
12
+  <React.StrictMode>
13
+    <Dapp />
14
+  </React.StrictMode>,
15
+  document.getElementById("root")
16
+);

+ 92 - 0
frontend/src/translate.py

@@ -0,0 +1,92 @@
1
+import hashlib
2
+import random
3
+import re
4
+import time
5
+import requests
6
+import os
7
+
8
+# 百度api
9
+apiurl = 'https://fanyi-api.baidu.com/api/trans/vip/translate'
10
+appid = '20221216001499032'  # 百度翻译api的appid
11
+secretKey = 'pwKjgqPgaAWIP9d31fTr'  # 百度翻译api的secretKey
12
+
13
+# 查找文本中的中文字符,并将连续的中文字符以列表返回
14
+
15
+
16
+def find_chinese(text):
17
+    regStr = '[a-zA-Z0-9]+'
18
+    aa = re.findall(regStr, text)
19
+    return aa
20
+
21
+# 翻译内容 源语言 翻译后的语言
22
+
23
+def translateBaidu(content, fromLang='en', toLang='zh'):
24
+    salt = str(random.randint(32768, 65536))
25
+    sign = appid + content + salt + secretKey  # appid+q+salt+密钥 的MD5值
26
+    # 对sign做md5,得到32位小写的sign
27
+    sign = hashlib.md5(sign.encode("utf-8")).hexdigest()
28
+    try:
29
+        # 根据技术手册中的接入方式进行设定
30
+        paramas = {
31
+            'appid': appid,
32
+            'q': content,
33
+            'from': fromLang,
34
+            'to': toLang,
35
+            'salt': salt,
36
+            'sign': sign
37
+        }
38
+        response = requests.get(apiurl, paramas)
39
+        jsonResponse = response.json()  # 获得返回的结果,结果为json格式
40
+        dst = str(jsonResponse["trans_result"][0]["dst"])  # 取得翻译后的文本结果
41
+        return dst
42
+    except Exception as e:
43
+        print(e)
44
+
45
+# 读取文件,翻译成中文,返回一个翻译好的文档的每行的list
46
+
47
+
48
+def text_deal(filename, fromLang='zh', toLang='pt'):
49
+    '''
50
+    读取文件,翻译成中文,返回一个翻译好的文档的每行的list
51
+    :param filename: 翻译的文档路径
52
+    :return: 翻译好的每行的list
53
+    '''
54
+    file = open(filename, encoding="utf-8")
55
+    while 1:
56
+        lines = file.readlines(100000)
57
+        if not lines:
58
+            break
59
+        # 遍历每一行代码
60
+        i = 0
61
+        newline = []
62
+        for line in lines:
63
+            i += 1
64
+            linea = line.lstrip()  # 去除了左方空行
65
+            # 判断是否是注释,是注释则跳过
66
+            if linea[0:2] == "//":
67
+                # 查找英文字符
68
+                chineses = find_chinese(linea)
69
+                print(chineses,'en====')
70
+                print("[" + str(i) + "]: ", linea)
71
+                # 查找到中文字符,并调用翻译api翻译进行字符串替换
72
+                for c in chineses:
73
+                    time.sleep(2)
74
+                    translate_str = translateBaidu(c, fromLang, toLang)
75
+                    print(translate_str,'translate_str')
76
+                    line = line.replace(c, translate_str)
77
+                    print(c + " ----> " + translate_str)
78
+            newline.append(line)
79
+    file.close()
80
+    return newline
81
+
82
+
83
+# 调用函数处理文档
84
+files = os.listdir("./components")
85
+for file in files:
86
+    print("=====================")
87
+    print("正在处理文件:" + file)
88
+    newlines = text_deal("./components/" + file, "en", "zh")
89
+    fw = open("./componentsed/" + file, "a", encoding="utf-8")
90
+    for l in newlines:
91
+        fw.write(l)
92
+    fw.close()

+ 28 - 0
hardhat.config.js

@@ -0,0 +1,28 @@
1
+require("@nomicfoundation/hardhat-toolbox");
2
+
3
+// The next line is part of the sample project, you don't need it in your
4
+// project. It imports a Hardhat task definition, that can be used for
5
+// testing the frontend.
6
+require("./tasks/faucet");
7
+
8
+
9
+//转到https://www.alchemyapi.io,注册,创建
10
+//在仪表板中安装一个新的应用程序,并用其键替换“KEY”
11
+const ALCHEMY_API_KEY = "1DMM5KirKK3HriaDHRxrTFjYNKko9Kwn";
12
+
13
+
14
+//用Goerli帐户私钥替换此私钥
15
+//要从Metamask导出私钥,请打开Metamask并
16
+//转到帐户详细信息>导出私钥
17
+//小心:切勿将真实以太币放入测试账户
18
+const GOERLI_PRIVATE_KEY = "511348790f6c17d7fbafdb7108307698542acef8ca01e7d263d8367cc412015a";
19
+/** @type import('hardhat/config').HardhatUserConfig */
20
+module.exports = {
21
+  solidity: "0.8.9",
22
+  networks: {
23
+    goerli: {
24
+      url: `https://eth-goerli.alchemyapi.io/v2/${ALCHEMY_API_KEY}`,
25
+      accounts: [GOERLI_PRIVATE_KEY]
26
+    }
27
+  }
28
+};

Dosya farkı çok büyük olduğundan ihmal edildi
+ 19164 - 0
package-lock.json


+ 32 - 0
package.json

@@ -0,0 +1,32 @@
1
+{
2
+  "name": "hardhat-boilerplate",
3
+  "version": "1.0.0",
4
+  "description": "A boilerplate repository to get you started with Hardhat and Ethereum development",
5
+  "scripts": {
6
+    "test": "hardhat test"
7
+  },
8
+  "repository": {
9
+    "type": "git",
10
+    "url": "git+https://github.com/NomicFoundation/hardhat-boilerplate.git"
11
+  },
12
+  "author": "Nomic Foundation",
13
+  "license": "MIT",
14
+  "bugs": {
15
+    "url": "https://github.com/NomicFoundation/hardhat-boilerplate/issues"
16
+  },
17
+  "homepage": "https://github.com/NomicFoundation/hardhat-boilerplate#readme",
18
+  "devDependencies": {
19
+    "@ethersproject/abi": "^5.4.7",
20
+    "@ethersproject/providers": "^5.4.7",
21
+    "@nomicfoundation/hardhat-chai-matchers": "^1.0.0",
22
+    "@nomicfoundation/hardhat-network-helpers": "^1.0.0",
23
+    "@nomicfoundation/hardhat-toolbox": "^1.0.1",
24
+    "@nomiclabs/hardhat-ethers": "^2.0.0",
25
+    "@nomiclabs/hardhat-etherscan": "^3.0.0",
26
+    "chai": "^4.2.0",
27
+    "ethers": "^5.4.7",
28
+    "hardhat": "^2.12.4",
29
+    "hardhat-gas-reporter": "^1.0.8",
30
+    "solidity-coverage": "^0.7.21"
31
+  }
32
+}

+ 61 - 0
scripts/deploy.js

@@ -0,0 +1,61 @@
1
+// This is a script for deploying your contracts. You can adapt it to deploy
2
+// yours, or create new ones.
3
+
4
+const path = require("path");
5
+
6
+async function main() {
7
+  // This is just a convenience check
8
+  if (network.name === "hardhat") {
9
+    console.warn(
10
+      "You are trying to deploy a contract to the Hardhat Network, which" +
11
+        "gets automatically created and destroyed every time. Use the Hardhat" +
12
+        " option '--network localhost'"
13
+    );
14
+  }
15
+
16
+  // ethers is available in the global scope
17
+  const [deployer] = await ethers.getSigners();
18
+  console.log(
19
+    "Deploying the contracts with the account:",
20
+    await deployer.getAddress()
21
+  );
22
+
23
+  console.log("Account balance:", (await deployer.getBalance()).toString());
24
+
25
+  const Token = await ethers.getContractFactory("Token");
26
+  const token = await Token.deploy();
27
+  await token.deployed();
28
+
29
+  console.log("Token address:", token.address);
30
+
31
+  // We also save the contract's artifacts and address in the frontend directory
32
+  saveFrontendFiles(token);
33
+}
34
+
35
+function saveFrontendFiles(token) {
36
+  const fs = require("fs");
37
+  const contractsDir = path.join(__dirname, "..", "frontend", "src", "contracts");
38
+
39
+  if (!fs.existsSync(contractsDir)) {
40
+    fs.mkdirSync(contractsDir);
41
+  }
42
+
43
+  fs.writeFileSync(
44
+    path.join(contractsDir, "contract-address.json"),
45
+    JSON.stringify({ Token: token.address }, undefined, 2)
46
+  );
47
+
48
+  const TokenArtifact = artifacts.readArtifactSync("Token");
49
+
50
+  fs.writeFileSync(
51
+    path.join(contractsDir, "Token.json"),
52
+    JSON.stringify(TokenArtifact, null, 2)
53
+  );
54
+}
55
+
56
+main()
57
+  .then(() => process.exit(0))
58
+  .catch((error) => {
59
+    console.error(error);
60
+    process.exit(1);
61
+  });

+ 46 - 0
tasks/faucet.js

@@ -0,0 +1,46 @@
1
+const fs = require("fs");
2
+
3
+// This file is only here to make interacting with the Dapp easier,
4
+// feel free to ignore it if you don't need it.
5
+
6
+task("faucet", "Sends ETH and tokens to an address")
7
+  .addPositionalParam("receiver", "The address that will receive them")
8
+  .setAction(async ({ receiver }, { ethers }) => {
9
+    if (network.name === "hardhat") {
10
+      console.warn(
11
+        "You are running the faucet task with Hardhat network, which" +
12
+          "gets automatically created and destroyed every time. Use the Hardhat" +
13
+          " option '--network localhost'"
14
+      );
15
+    }
16
+
17
+    const addressesFile =
18
+      __dirname + "/../frontend/src/contracts/contract-address.json";
19
+
20
+    if (!fs.existsSync(addressesFile)) {
21
+      console.error("You need to deploy your contract first");
22
+      return;
23
+    }
24
+
25
+    const addressJson = fs.readFileSync(addressesFile);
26
+    const address = JSON.parse(addressJson);
27
+
28
+    if ((await ethers.provider.getCode(address.Token)) === "0x") {
29
+      console.error("You need to deploy your contract first");
30
+      return;
31
+    }
32
+
33
+    const token = await ethers.getContractAt("Token", address.Token);
34
+    const [sender] = await ethers.getSigners();
35
+
36
+    const tx = await token.transfer(receiver, 100);
37
+    await tx.wait();
38
+
39
+    const tx2 = await sender.sendTransaction({
40
+      to: receiver,
41
+      value: ethers.constants.WeiPerEther,
42
+    });
43
+    await tx2.wait();
44
+
45
+    console.log(`Transferred 1 ETH and 100 tokens to ${receiver}`);
46
+  });

+ 111 - 0
test/Token.js

@@ -0,0 +1,111 @@
1
+// This is an example test file. Hardhat will run every *.js file in `test/`,
2
+// so feel free to add new ones.
3
+
4
+// Hardhat tests are normally written with Mocha and Chai.
5
+
6
+// We import Chai to use its asserting functions here.
7
+const { expect } = require("chai");
8
+
9
+// We use `loadFixture` to share common setups (or fixtures) between tests.
10
+// Using this simplifies your tests and makes them run faster, by taking
11
+// advantage or Hardhat Network's snapshot functionality.
12
+const { loadFixture } = require("@nomicfoundation/hardhat-network-helpers");
13
+
14
+// `describe` is a Mocha function that allows you to organize your tests.
15
+// Having your tests organized makes debugging them easier. All Mocha
16
+// functions are available in the global scope.
17
+//
18
+// `describe` receives the name of a section of your test suite, and a
19
+// callback. The callback must define the tests of that section. This callback
20
+// can't be an async function.
21
+describe("Token contract", function () {
22
+  // We define a fixture to reuse the same setup in every test. We use
23
+  // loadFixture to run this setup once, snapshot that state, and reset Hardhat
24
+  // Network to that snapshot in every test.
25
+  async function deployTokenFixture() {
26
+    // Get the ContractFactory and Signers here.
27
+    const Token = await ethers.getContractFactory("Token");
28
+    const [owner, addr1, addr2] = await ethers.getSigners();
29
+
30
+    // To deploy our contract, we just have to call Token.deploy() and await
31
+    // for it to be deployed(), which happens onces its transaction has been
32
+    // mined.
33
+    const hardhatToken = await Token.deploy();
34
+
35
+    await hardhatToken.deployed();
36
+
37
+    // Fixtures can return anything you consider useful for your tests
38
+    return { Token, hardhatToken, owner, addr1, addr2 };
39
+  }
40
+
41
+  // You can nest describe calls to create subsections.
42
+  describe("Deployment", function () {
43
+    // `it` is another Mocha function. This is the one you use to define your
44
+    // tests. It receives the test name, and a callback function.
45
+//
46
+    // If the callback function is async, Mocha will `await` it.
47
+    it("Should set the right owner", async function () {
48
+      // We use loadFixture to setup our environment, and then assert that
49
+      // things went well
50
+      const { hardhatToken, owner } = await loadFixture(deployTokenFixture);
51
+
52
+      // Expect receives a value and wraps it in an assertion object. These
53
+      // objects have a lot of utility methods to assert values.
54
+
55
+      // This test expects the owner variable stored in the contract to be
56
+      // equal to our Signer's owner.
57
+      expect(await hardhatToken.owner()).to.equal(owner.address);
58
+    });
59
+
60
+    it("Should assign the total supply of tokens to the owner", async function () {
61
+      const { hardhatToken, owner } = await loadFixture(deployTokenFixture);
62
+      const ownerBalance = await hardhatToken.balanceOf(owner.address);
63
+      expect(await hardhatToken.totalSupply()).to.equal(ownerBalance);
64
+    });
65
+  });
66
+
67
+  describe("Transactions", function () {
68
+    it("Should transfer tokens between accounts", async function () {
69
+      const { hardhatToken, owner, addr1, addr2 } = await loadFixture(deployTokenFixture);
70
+      // Transfer 50 tokens from owner to addr1
71
+      await expect(hardhatToken.transfer(addr1.address, 50))
72
+        .to.changeTokenBalances(hardhatToken, [owner, addr1], [-50, 50]);
73
+
74
+      // Transfer 50 tokens from addr1 to addr2
75
+      // We use .connect(signer) to send a transaction from another account
76
+      await expect(hardhatToken.connect(addr1).transfer(addr2.address, 50))
77
+        .to.changeTokenBalances(hardhatToken, [addr1, addr2], [-50, 50]);
78
+    });
79
+
80
+    it("should emit Transfer events", async function () {
81
+      const { hardhatToken, owner, addr1, addr2 } = await loadFixture(deployTokenFixture);
82
+
83
+      // Transfer 50 tokens from owner to addr1
84
+      await expect(hardhatToken.transfer(addr1.address, 50))
85
+        .to.emit(hardhatToken, "Transfer").withArgs(owner.address, addr1.address, 50)
86
+
87
+      // Transfer 50 tokens from addr1 to addr2
88
+      // We use .connect(signer) to send a transaction from another account
89
+      await expect(hardhatToken.connect(addr1).transfer(addr2.address, 50))
90
+        .to.emit(hardhatToken, "Transfer").withArgs(addr1.address, addr2.address, 50)
91
+    });
92
+
93
+    it("Should fail if sender doesn't have enough tokens", async function () {
94
+      const { hardhatToken, owner, addr1 } = await loadFixture(deployTokenFixture);
95
+      const initialOwnerBalance = await hardhatToken.balanceOf(
96
+        owner.address
97
+      );
98
+
99
+      // Try to send 1 token from addr1 (0 tokens) to owner (1000 tokens).
100
+      // `require` will evaluate false and revert the transaction.
101
+      await expect(
102
+        hardhatToken.connect(addr1).transfer(owner.address, 1)
103
+      ).to.be.revertedWith("Not enough tokens");
104
+
105
+      // Owner balance shouldn't have changed.
106
+      expect(await hardhatToken.balanceOf(owner.address)).to.equal(
107
+        initialOwnerBalance
108
+      );
109
+    });
110
+  });
111
+});