├── .gitignore ├── package.json ├── contracts ├── TestToken.sol └── Vault.sol ├── hardhat.config.js ├── test └── vaultTest.js ├── scripts └── sample-script.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | coverage 4 | coverage.json 5 | typechain 6 | 7 | #Hardhat files 8 | cache 9 | artifacts 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "devDependencies": { 4 | "@nomiclabs/hardhat-ethers": "^2.0.3", 5 | "@nomiclabs/hardhat-waffle": "^2.0.1", 6 | "chai": "^4.3.4", 7 | "ethereum-waffle": "^3.4.0", 8 | "ethers": "^5.5.2", 9 | "hardhat": "^2.8.0" 10 | }, 11 | "dependencies": { 12 | "@openzeppelin/contracts": "^4.5.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /contracts/TestToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | 7 | contract TestToken is ERC20, Ownable { 8 | constructor() ERC20("test", "MTK") { 9 | _mint(msg.sender, 4000 * 10 ** decimals()); 10 | } 11 | 12 | function mint(address to, uint256 amount) public onlyOwner { 13 | _mint(to, amount); 14 | } 15 | } -------------------------------------------------------------------------------- /hardhat.config.js: -------------------------------------------------------------------------------- 1 | require("@nomiclabs/hardhat-waffle"); 2 | 3 | // This is a sample Hardhat task. To learn how to create your own go to 4 | // https://hardhat.org/guides/create-task.html 5 | task("accounts", "Prints the list of accounts", async (taskArgs, hre) => { 6 | const accounts = await hre.ethers.getSigners(); 7 | 8 | for (const account of accounts) { 9 | console.log(account.address); 10 | } 11 | }); 12 | 13 | // You need to export an object to set up your config 14 | // Go to https://hardhat.org/config/ to learn more 15 | 16 | /** 17 | * @type import('hardhat/config').HardhatUserConfig 18 | */ 19 | module.exports = { 20 | solidity: "0.8.0", 21 | }; 22 | -------------------------------------------------------------------------------- /test/vaultTest.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | const { ethers } = require("hardhat"); 3 | 4 | describe("Greeter", function () { 5 | it("Should deploy the contract", async function () { 6 | 7 | const TestToken = await ethers.getContractFactory("TestToken"); 8 | const testToken = await TestToken.deploy(); 9 | const testTokenAdress = testToken.address; 10 | const Vault = await ethers.getContractFactory("Vault"); 11 | const vault = await Vault.deploy(testTokenAdress); 12 | const vaultAdress = vault.address; 13 | 14 | await vault.deployed(); 15 | await testToken.deployed(); 16 | 17 | console.log("testToken deployed to:", testTokenAdress); 18 | console.log("vault deployed to:", vaultAdress); 19 | }); 20 | }); -------------------------------------------------------------------------------- /scripts/sample-script.js: -------------------------------------------------------------------------------- 1 | 2 | const hre = require("hardhat"); 3 | 4 | async function main() { 5 | 6 | const TestToken = await ethers.getContractFactory("TestToken"); 7 | const testToken = await TestToken.deploy(); 8 | const testTokenAdress = testToken.address; 9 | const Vault = await ethers.getContractFactory("Vault"); 10 | const vault = await Vault.deploy(testTokenAdress); 11 | const vaultAdress = vault.address; 12 | 13 | await vault.deployed(); 14 | await testToken.deployed(); 15 | 16 | console.log("testToken deployed to:", testTokenAdress); 17 | console.log("vault deployed to:", vaultAdress); 18 | } 19 | 20 | main() 21 | .then(() => process.exit(0)) 22 | .catch((error) => { 23 | console.error(error); 24 | process.exit(1); 25 | }); 26 | -------------------------------------------------------------------------------- /contracts/Vault.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | 7 | contract Vault { 8 | address tokenAddress; 9 | 10 | constructor(address _tokenAddress) { 11 | tokenAddress = _tokenAddress; 12 | } 13 | 14 | // userAddress => tokenAddress => token amount 15 | mapping (address => mapping (address => uint256)) userTokenBalance; 16 | 17 | event tokenDepositComplete(address tokenAddress, uint256 amount); 18 | 19 | function depositToken( uint256 amount) public { 20 | require(IERC20(tokenAddress).balanceOf(msg.sender) >= amount, "Your token amount must be greater then you are trying to deposit"); 21 | require(IERC20(tokenAddress).approve(address(this), amount), "Token approval failed"); 22 | IERC20(tokenAddress).transferFrom(msg.sender, address(this), amount); 23 | 24 | userTokenBalance[msg.sender][tokenAddress] += amount; 25 | emit tokenDepositComplete(tokenAddress, amount); 26 | } 27 | 28 | event tokenWithdrawalComplete(address tokenAddress, uint256 amount); 29 | 30 | function withDrawAll() public { 31 | require(userTokenBalance[msg.sender][tokenAddress] > 0, "User doesnt has funds on this vault"); 32 | uint256 amount = userTokenBalance[msg.sender][tokenAddress]; 33 | IERC20(tokenAddress).transfer(msg.sender, amount); 34 | userTokenBalance[msg.sender][tokenAddress] = 0; 35 | emit tokenWithdrawalComplete(tokenAddress, amount); 36 | } 37 | 38 | function withDrawAmount(uint256 amount) public { 39 | require(userTokenBalance[msg.sender][tokenAddress] >= amount); 40 | IERC20(tokenAddress).transfer(msg.sender, amount); 41 | userTokenBalance[msg.sender][tokenAddress] -= amount; 42 | emit tokenWithdrawalComplete(tokenAddress, amount); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Basic Sample Hardhat Project 2 | 3 | This project demonstrates a basic Hardhat use case. It comes with a sample contract, a test for that contract, a sample script that deploys that contract, and an example of a task implementation, which simply lists the available accounts. 4 | 5 | Try running some of the following tasks: 6 | 7 | ```shell 8 | npx hardhat accounts 9 | npx hardhat compile 10 | npx hardhat clean 11 | npx hardhat test 12 | npx hardhat node 13 | node scripts/sample-script.js 14 | npx hardhat help 15 | ``` 16 | 17 | # TestToken and Vault Smart Contracts Documentation 18 | 19 | This document provides an overview of the TestToken and Vault smart contracts, their features, and their functions. 20 | 21 | ## TestToken 22 | 23 | TestToken is an ERC20 token contract that uses OpenZeppelin's ERC20 and Ownable contracts to create a mintable token. 24 | 25 | ### Features 26 | 27 | - Inherits from OpenZeppelin's ERC20 and Ownable contracts. 28 | - The contract owner can mint new tokens. 29 | 30 | ### Functions 31 | 32 | #### constructor 33 | 34 | The constructor initializes the TestToken with a name, symbol, and initial supply. 35 | 36 | ```solidity 37 | constructor() ERC20("test", "MTK") { 38 | _mint(msg.sender, 4000 * 10 ** decimals()); 39 | } 40 | ``` 41 | 42 | #### mint 43 | 44 | The `mint` function allows the contract owner to mint new tokens and transfer them to a specified address. 45 | 46 | ```solidity 47 | function mint(address to, uint256 amount) public onlyOwner { 48 | _mint(to, amount); 49 | } 50 | ``` 51 | 52 | ## Vault 53 | 54 | The Vault contract is a simple token vault that allows users to deposit and withdraw an ERC20 token. The vault keeps track of each user's token balance. 55 | 56 | ### Features 57 | 58 | - Stores and manages user balances for a specific ERC20 token. 59 | - Allows users to deposit and withdraw tokens. 60 | - Uses OpenZeppelin's IERC20 interface. 61 | 62 | ### Functions 63 | 64 | #### constructor 65 | 66 | The constructor sets the token address for the Vault contract. 67 | 68 | ```solidity 69 | constructor(address _tokenAddress) { 70 | tokenAddress = _tokenAddress; 71 | } 72 | ``` 73 | 74 | #### depositToken 75 | 76 | The `depositToken` function allows users to deposit a specified amount of tokens into the vault. Before calling this function, users must approve the vault to transfer tokens on their behalf. 77 | 78 | ```solidity 79 | function depositToken(uint256 amount) public { 80 | require(IERC20(tokenAddress).balanceOf(msg.sender) >= amount, "Your token amount must be greater then you are trying to deposit"); 81 | IERC20(tokenAddress).transferFrom(msg.sender, address(this), amount); 82 | userTokenBalance[msg.sender][tokenAddress] += amount; 83 | emit tokenDepositComplete(tokenAddress, amount); 84 | } 85 | ``` 86 | 87 | #### withDrawAll 88 | 89 | The `withDrawAll` function allows users to withdraw all their tokens from the vault. 90 | 91 | ```solidity 92 | function withDrawAll() public { 93 | require(userTokenBalance[msg.sender][tokenAddress] > 0, "User doesnt has funds on this vault"); 94 | uint256 amount = userTokenBalance[msg.sender][tokenAddress]; 95 | IERC20(tokenAddress).transfer(msg.sender, amount); 96 | userTokenBalance[msg.sender][tokenAddress] = 0; 97 | emit tokenWithdrawalComplete(tokenAddress, amount); 98 | } 99 | ``` 100 | 101 | #### withDrawAmount 102 | 103 | The `withDrawAmount` function allows users to withdraw a specified amount of tokens from the vault. 104 | 105 | ```solidity 106 | function withDrawAmount(uint256 amount) public { 107 | require(userTokenBalance[msg.sender][tokenAddress] >= amount); 108 | IERC20(tokenAddress).transfer(msg.sender, amount); 109 | userTokenBalance[msg.sender][tokenAddress] -= amount; 110 | emit tokenWithdrawalComplete(tokenAddress, amount); 111 | } 112 | ``` 113 | 114 | ### Events 115 | 116 | - `tokenDepositComplete`: Emitted when a user deposits tokens into the vault. 117 | - `tokenWithdrawalComplete`: Emitted when a user withdraws tokens from the vault. 118 | 119 | Please note that this documentation provides an overview of the TestToken and Vault smart contracts, but a complete security audit should still be performed by a professional auditor before deploying these contracts to the mainnet. --------------------------------------------------------------------------------