Ethereum Faucet
41 |You can withdraw Ether from this Ropsten Faucet. Make sure to connect your wallet and switch to the Ropsten Testnet.
42 |43 | Request Ether 44 | Donate Ether 45 |
46 |├── abi.json ├── Faucet.sol ├── .gitignore ├── README.md └── index.html /abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "from", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": false, 13 | "internalType": "uint256", 14 | "name": "amount", 15 | "type": "uint256" 16 | } 17 | ], 18 | "name": "Deposit", 19 | "type": "event" 20 | }, 21 | { 22 | "anonymous": false, 23 | "inputs": [ 24 | { 25 | "indexed": true, 26 | "internalType": "address", 27 | "name": "to", 28 | "type": "address" 29 | } 30 | ], 31 | "name": "Withdrawal", 32 | "type": "event" 33 | }, 34 | { 35 | "inputs": [], 36 | "name": "destroy", 37 | "outputs": [], 38 | "stateMutability": "nonpayable", 39 | "type": "function" 40 | }, 41 | { 42 | "stateMutability": "payable", 43 | "type": "receive" 44 | }, 45 | { 46 | "inputs": [], 47 | "name": "withdraw", 48 | "outputs": [], 49 | "stateMutability": "nonpayable", 50 | "type": "function" 51 | }, 52 | { 53 | "inputs": [], 54 | "stateMutability": "nonpayable", 55 | "type": "constructor" 56 | } 57 | ] -------------------------------------------------------------------------------- /Faucet.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Author: Jacob Suchorabski 3 | pragma solidity >= 0.7.0 <= 0.7.4; 4 | 5 | contract Faucet{ 6 | 7 | address owner; 8 | mapping (address => uint) timeouts; 9 | 10 | event Withdrawal(address indexed to); 11 | event Deposit(address indexed from, uint amount); 12 | 13 | constructor() { 14 | //Will be called on creation of the smart contract. 15 | owner = msg.sender; 16 | } 17 | 18 | // Sends 0.1 ETH to the sender when the faucet has enough funds 19 | // Only allows one withdrawal every 30 mintues 20 | function withdraw() external{ 21 | 22 | require(address(this).balance >= 0.1 ether, "This faucet is empty. Please check back later."); 23 | require(timeouts[msg.sender] <= block.timestamp - 30 minutes, "You can only withdraw once every 30 minutes. Please check back later."); 24 | 25 | msg.sender.transfer(0.1 ether); 26 | timeouts[msg.sender] = block.timestamp; 27 | 28 | emit Withdrawal(msg.sender); 29 | } 30 | 31 | // Sending Tokens to this faucet fills it up 32 | receive() external payable { 33 | emit Deposit(msg.sender, msg.value); 34 | } 35 | 36 | 37 | // Destroys this smart contract and sends all remaining funds to the owner 38 | function destroy() public{ 39 | require(msg.sender == owner, "Only the owner of this faucet can destroy it."); 40 | selfdestruct(msg.sender); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/solidity,macos 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=solidity,macos 4 | 5 | ### macOS ### 6 | # General 7 | .DS_Store 8 | .AppleDouble 9 | .LSOverride 10 | 11 | # Icon must end with two \r 12 | Icon 13 | 14 | 15 | # Thumbnails 16 | ._* 17 | 18 | # Files that might appear in the root of a volume 19 | .DocumentRevisions-V100 20 | .fseventsd 21 | .Spotlight-V100 22 | .TemporaryItems 23 | .Trashes 24 | .VolumeIcon.icns 25 | .com.apple.timemachine.donotpresent 26 | 27 | # Directories potentially created on remote AFP share 28 | .AppleDB 29 | .AppleDesktop 30 | Network Trash Folder 31 | Temporary Items 32 | .apdisk 33 | 34 | ### Solidity ### 35 | # Logs 36 | logs 37 | *.log 38 | npm-debug.log* 39 | yarn-debug.log* 40 | yarn-error.log* 41 | lerna-debug.log* 42 | 43 | # Diagnostic reports (https://nodejs.org/api/report.html) 44 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 45 | 46 | # Runtime data 47 | pids 48 | *.pid 49 | *.seed 50 | *.pid.lock 51 | 52 | # Directory for instrumented libs generated by jscoverage/JSCover 53 | lib-cov 54 | 55 | # Coverage directory used by tools like istanbul 56 | coverage 57 | *.lcov 58 | 59 | # nyc test coverage 60 | .nyc_output 61 | 62 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 63 | .grunt 64 | 65 | # Bower dependency directory (https://bower.io/) 66 | bower_components 67 | 68 | # node-waf configuration 69 | .lock-wscript 70 | 71 | # Compiled binary addons (https://nodejs.org/api/addons.html) 72 | build/Release 73 | 74 | # Dependency directories 75 | node_modules/ 76 | jspm_packages/ 77 | 78 | # TypeScript v1 declaration files 79 | typings/ 80 | 81 | # TypeScript cache 82 | *.tsbuildinfo 83 | 84 | # Optional npm cache directory 85 | .npm 86 | 87 | # Optional eslint cache 88 | .eslintcache 89 | 90 | # Microbundle cache 91 | .rpt2_cache/ 92 | .rts2_cache_cjs/ 93 | .rts2_cache_es/ 94 | .rts2_cache_umd/ 95 | 96 | # Optional REPL history 97 | .node_repl_history 98 | 99 | # Output of 'npm pack' 100 | *.tgz 101 | 102 | # Yarn Integrity file 103 | .yarn-integrity 104 | 105 | # dotenv environment variables file 106 | .env 107 | .env.test 108 | .env*.local 109 | 110 | # parcel-bundler cache (https://parceljs.org/) 111 | .cache 112 | .parcel-cache 113 | 114 | # Next.js build output 115 | .next 116 | 117 | # Nuxt.js build / generate output 118 | .nuxt 119 | dist 120 | 121 | # Gatsby files 122 | .cache/ 123 | # Comment in the public line in if your project uses Gatsby and not Next.js 124 | # https://nextjs.org/blog/next-9-1#public-directory-support 125 | # public 126 | 127 | # vuepress build output 128 | .vuepress/dist 129 | 130 | # Serverless directories 131 | .serverless/ 132 | 133 | # FuseBox cache 134 | .fusebox/ 135 | 136 | # DynamoDB Local files 137 | .dynamodb/ 138 | 139 | # TernJS port file 140 | .tern-port 141 | 142 | # Stores VSCode versions used for testing VSCode extensions 143 | .vscode-test 144 | 145 | # End of https://www.toptal.com/developers/gitignore/api/solidity,macos 146 | 147 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ethereum Faucet 2 | 3 | ## Description 4 | 5 | This project is a basic Ethereum faucet that enables anyone to send Ether to the smart contract to fill it up with funds and you can interact with it through the withdraw function to request 0.1 ETH from the faucet. 6 | 7 | If the faucet has enough funds you will receive 0.1 ETH to your Ethereum address. There is a simple timeout filter built in to only allow one request per 30 minutes. 8 | 9 | ## Key Facts 10 | 11 | * This code is published under the MIT License 12 | * This code has been deveoped by Jacob Suchorabski 13 | * Solidity (v. 0.7.4) has been used to develop and test the faucet 14 | * You can find the frontend implementation in the `index.html` file which you can use to interface with the smart contract [here](https://svcho.github.io/Ethereum-Faucet/). 15 | 16 | ## Requirements & Demo 17 | 18 | This version of the smart contract is deployed on the [Ropsten Testnetwork](https://ropsten.etherscan.io/) and you can find it with the following address: 19 | 20 | [0x5194d3D2D77585ff89a2823F77C191a93d2F6416](https://ropsten.etherscan.io/address/0x5194d3D2D77585ff89a2823F77C191a93d2F6416) 21 | 22 | If you want to use the smart contract you will need an Ethereum Wallet that can interact with smart contracts and switch to the Ropsten Testnetwork (Example: [MetaMask](https://metamask.io/)). 23 | 24 | ## Features 25 | 26 | ### Variables & Events 27 | 28 | ```Solidity 29 | address owner; 30 | mapping (address => uint) timeouts; 31 | 32 | event Withdrawal(address indexed to); 33 | event Deposit(address indexed from, uint amount); 34 | 35 | constructor() { 36 | owner = msg.sender; 37 | } 38 | 39 | function destroy() public{ 40 | require(msg.sender == owner, "Only the owner of this faucet can destroy it."); 41 | selfdestruct(msg.sender); 42 | } 43 | ``` 44 | 45 | * When creating the smart contract the owner will be saved in order to protect the `selfdestruct` method which destroys this smart contract and sends all remaining funds of the contract to the sender. 46 | * The `timeouts` hash map is used to track which address already used this faucet at which timestamp. 47 | * `Withdrawal` and `Deposit` are events that will be called in the functions described below to make sure that we store our transactions in the transaction log which can be accessed through the blockchain. 48 | 49 | ### Withdrawing Ether 50 | 51 | ```Solidity 52 | function withdraw() external{ 53 | 54 | require(address(this).balance >= 0.1 ether, "This faucet is empty. Please check back later."); 55 | require(timeouts[msg.sender] <= block.timestamp - 30 minutes, "You can only withdraw once every 30 minutes. Please check back later."); 56 | 57 | msg.sender.transfer(0.1 ether); 58 | timeouts[msg.sender] = block.timestamp; 59 | 60 | emit Withdrawal(msg.sender); 61 | 62 | } 63 | ``` 64 | 65 | * We are checking for two simple requirements in this project 66 | * Does this smart contract have enough funds? (This smart contract always sends exactly 0.1 ETH) 67 | * Did the sender already request a withdrawal in the last 30 minutes? (Checked using the timestamp of the current block of the transaction) 68 | * If those conditions are met 0.1 ETH are sent to the `msg.sender` which is the entity calling the smart contract 69 | * Finally the current timestamp is added to our `timeouts` hashmap 70 | 71 | ### Donating Ether 72 | 73 | ```Solidity 74 | receive() external payable { 75 | emit Deposit(msg.sender, msg.value); 76 | } 77 | ``` 78 | 79 | * Ether can be donated by anyone by simply sending Ether to the smart contract 80 | * The `receive()` function is a default function that is payable so it can receive funds. You could also leave this function empty but since we want donations to be visible in the transaction log we are emitting our defined event. 81 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |You can withdraw Ether from this Ropsten Faucet. Make sure to connect your wallet and switch to the Ropsten Testnet.
42 |43 | Request Ether 44 | Donate Ether 45 |
46 |