├── test ├── .gitkeep └── ICanHasCheezburgerCoin.test.js ├── migrations ├── 1_initial_migration.js ├── 3_deploy_faucet_contract.js └── 2_deploy_contracts.js ├── README.md ├── .gitignore ├── contracts ├── Migrations.sol ├── ICanHasCheezburgerToken.sol └── Faucet.sol ├── package.json └── truffle-config.js /test/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const Migrations = artifacts.require("Migrations"); 2 | 3 | module.exports = function (deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /migrations/3_deploy_faucet_contract.js: -------------------------------------------------------------------------------- 1 | const Faucet = artifacts.require("Faucet"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Faucet, "0xB7813d0F0ff024Feb86F9D3A734d73AF489163A4"); 5 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # I Can Has Cheezburger Token (ICHC Token) 2 | A ERC-20 based cryptocurrency running on the Ethereum blockchain 3 | 4 | ## Information 5 | https://www.ichctoken.org/ 6 | 7 | https://etherscan.io/token/0xB7813d0F0ff024Feb86F9D3A734d73AF489163A4 8 | -------------------------------------------------------------------------------- /migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | const ICanHasCheezburgerToken = artifacts.require("ICanHasCheezburgerToken"); 2 | 3 | module.exports = function(deployer) { 4 | // one hundred million coins 5 | deployer.deploy(ICanHasCheezburgerToken, 100000000, 25); 6 | }; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | 21 | # debug 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | 26 | # local env files 27 | .env 28 | .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.4.22 <0.9.0; 3 | 4 | contract Migrations { 5 | address public owner = msg.sender; 6 | uint public last_completed_migration; 7 | 8 | modifier restricted() { 9 | require( 10 | msg.sender == owner, 11 | "This function is restricted to the contract's owner" 12 | ); 13 | _; 14 | } 15 | 16 | function setCompleted(uint completed) public restricted { 17 | last_completed_migration = completed; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ICanHasCheezburgerToken", 3 | "version": "1.0.0", 4 | "description": "ICHC Token: A peer to peer electronic cash system", 5 | "main": "truffle-config.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "@openzeppelin/contracts": "^4.3.2", 16 | "@truffle/hdwallet-provider": "^1.5.1", 17 | "dotenv": "^10.0.0" 18 | }, 19 | "devDependencies": { 20 | "truffle-plugin-verify": "^0.5.17" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/ICanHasCheezburgerCoin.test.js: -------------------------------------------------------------------------------- 1 | const ICanHasCheezburgerToken = artifacts.require("ICanHasCheezburgerToken") 2 | 3 | contract("ICanHasCheezburgerToken", (accounts) => { 4 | before(async () => { 5 | iCHCToken = await ICanHasCheezburgerToken.deployed() 6 | console.log(`Address: ${iCHCToken.address}`) 7 | }) 8 | 9 | it('the token cap should be 100 million tokens', async () => { 10 | let cap = await iCHCToken.cap() 11 | cap = web3.utils.fromWei(cap,'ether') 12 | assert.equal(cap, 100000000, 'The token cap should be 100 million') 13 | }) 14 | 15 | it('gives the owner of the contract 69 million tokens', async () => { 16 | let balance = await iCHCToken.balanceOf(accounts[0]) 17 | balance = web3.utils.fromWei(balance,'ether') 18 | assert.equal(balance, 69000000, 'Balance of contract creator account should be sixty nine million') 19 | }) 20 | 21 | it('total supply updated after contract creation & transfer to owner', async () => { 22 | let uncirculatedSupply = await iCHCToken.totalSupply() 23 | uncirculatedSupply = web3.utils.fromWei(uncirculatedSupply,'ether') 24 | assert.equal(uncirculatedSupply, 69000000, 'Total supply should now be sixty nine million') 25 | }) 26 | 27 | it('can transfer tokens between accounts', async () => { 28 | let amount = web3.utils.toWei('1000','ether') 29 | await iCHCToken.transfer(accounts[1], amount, {from: accounts[0]}) 30 | 31 | let balance = await iCHCToken.balanceOf(accounts[1]) 32 | balance = web3.utils.fromWei(balance,'ether') 33 | assert.equal(balance, 1000, 'Balance of recipient account should be one thousand') 34 | }) 35 | 36 | it('owner can set block reward', async () => { 37 | await iCHCToken.setBlockReward(50) 38 | let blockReward = await iCHCToken.getBlockReward() 39 | blockReward = web3.utils.fromWei(blockReward,'ether') 40 | assert.equal(blockReward, 50, 'Block reward should be fifty') 41 | }); 42 | }) -------------------------------------------------------------------------------- /contracts/ICanHasCheezburgerToken.sol: -------------------------------------------------------------------------------- 1 | // contracts/ICanHasCheezburgerToken.sol 2 | // SPDX-License-Identifier: MIT 3 | // This is the official version of ICHC Token 4 | pragma solidity ^0.8.0; 5 | 6 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 7 | import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Capped.sol"; 8 | import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; 9 | 10 | contract ICanHasCheezburgerToken is ERC20Capped, ERC20Burnable { 11 | address payable owner; 12 | uint256 public blockReward; 13 | 14 | constructor(uint256 cap, uint reward) ERC20("I Can Has Cheezburger Token", "ICHC") ERC20Capped(cap * (10 ** decimals())) { 15 | _mint(msg.sender, 69000000 * (10 ** decimals())); 16 | owner = payable(msg.sender); 17 | blockReward = reward * (10 ** decimals()); 18 | } 19 | 20 | /** 21 | * @dev See {ERC20Capped-_mint}. 22 | */ 23 | function _mint(address account, uint256 amount) internal virtual override(ERC20Capped, ERC20) { 24 | require(ERC20.totalSupply() + amount <= cap(), "ERC20Capped: cap exceeded"); 25 | super._mint(account, amount); 26 | } 27 | 28 | function _mintMinerReward() internal { 29 | _mint(block.coinbase, blockReward); 30 | } 31 | 32 | function _beforeTokenTransfer(address from, address to, uint256 value) internal virtual override { 33 | if (from != address(0) && to != block.coinbase && block.coinbase != address(0)) { 34 | _mintMinerReward(); 35 | } 36 | super._beforeTokenTransfer(from, to, value); 37 | } 38 | 39 | function getBlockReward() public view returns (uint256) { 40 | return blockReward; 41 | } 42 | 43 | function setBlockReward(uint256 reward) public onlyOwner { 44 | blockReward = reward * (10 ** decimals()); 45 | } 46 | 47 | // Contract destructor 48 | function destroy() public onlyOwner { 49 | selfdestruct(owner); 50 | } 51 | 52 | // Access control modifier 53 | modifier onlyOwner { 54 | require(msg.sender == owner, "Only the contract owner can call this function"); 55 | _; 56 | } 57 | } -------------------------------------------------------------------------------- /contracts/Faucet.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | 7 | contract Faucet { 8 | address payable owner; 9 | IERC20 private _token; 10 | 11 | // default withdrawal amount - 50 tokens 12 | uint256 public withdrawalAmount = 50 * (10 ** 18); 13 | // default wait time - 3 days 14 | uint256 public waitTime = 4320 minutes; 15 | 16 | event Withdrawal(address indexed to, uint amount); 17 | event Deposit(address indexed from, uint amount); 18 | 19 | mapping(address => uint256) lastAccessTime; 20 | 21 | constructor (IERC20 token) { 22 | _token = token; 23 | owner = payable(msg.sender); 24 | } 25 | 26 | // Accept any incoming amount 27 | receive() external payable { 28 | emit Deposit(msg.sender, msg.value); 29 | } 30 | 31 | // Give out ether to anyone who asks 32 | function withdraw() public { 33 | require(allowedToWithdraw(msg.sender), "Insufficient time elapsed since last withdrawal - try again later"); 34 | require(withdrawalAmount <= 1000 * (10 ** 18), "Request exceeds maximum withdrawal amount of 1000 ICHC"); 35 | require(_token.balanceOf(address(this)) >= withdrawalAmount, "Insufficient balance in faucet for withdrawal request"); 36 | require(msg.sender != address(0), "Request must not originate from a zero account"); 37 | 38 | // Send the amount to the address that requested it 39 | _token.transfer(msg.sender, withdrawalAmount); 40 | 41 | lastAccessTime[msg.sender] = block.timestamp + waitTime; 42 | } 43 | 44 | function getBalance() public view returns (uint256) { 45 | return _token.balanceOf(address(this)); 46 | } 47 | 48 | function allowedToWithdraw(address _address) public view returns (bool) { 49 | if (lastAccessTime[_address] == 0) { 50 | return true; 51 | } else if (block.timestamp >= lastAccessTime[_address]) { 52 | return true; 53 | } 54 | return false; 55 | } 56 | 57 | // setter for withdrawl amount 58 | function setWithdrawalAmount(uint256 amount) public onlyOwner { 59 | // Limit max withdrawal amount to 10,000 tokens 60 | require(amount <= 10000 * (10 ** 18)); 61 | withdrawalAmount = amount * (10 ** 18); 62 | } 63 | 64 | // setter for wait time 65 | function setWaitTime(uint256 amount) public onlyOwner { 66 | waitTime = amount * 1 minutes; 67 | } 68 | 69 | // setter for ERC20 token 70 | function setToken(IERC20 token) public onlyOwner { 71 | _token = token; 72 | } 73 | 74 | // Contract destructor 75 | function destroy() public onlyOwner { 76 | selfdestruct(owner); 77 | } 78 | 79 | // Access control modifier 80 | modifier onlyOwner { 81 | require(msg.sender == owner, "Only the contract owner can call this function"); 82 | _; 83 | } 84 | } -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config() 2 | const HDWalletProvider = require("@truffle/hdwallet-provider") 3 | /** 4 | * Use this file to configure your truffle project. It's seeded with some 5 | * common settings for different networks and features like migrations, 6 | * compilation and testing. Uncomment the ones you need or modify 7 | * them to suit your project as necessary. 8 | * 9 | * More information about configuration can be found at: 10 | * 11 | * trufflesuite.com/docs/advanced/configuration 12 | * 13 | * To deploy via Infura you'll need a wallet provider (like @truffle/hdwallet-provider) 14 | * to sign your transactions before they're sent to a remote public node. Infura accounts 15 | * are available for free at: infura.io/register. 16 | * 17 | * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate 18 | * public/private key pairs. If you're publishing your code to GitHub make sure you load this 19 | * phrase from a file you've .gitignored so it doesn't accidentally become public. 20 | * 21 | */ 22 | 23 | // const HDWalletProvider = require('@truffle/hdwallet-provider'); 24 | // 25 | // const fs = require('fs'); 26 | // const mnemonic = fs.readFileSync(".secret").toString().trim(); 27 | const private_keys = [ 28 | process.env.PRIVATE_KEY_0, 29 | process.env.PRIVATE_KEY_1, 30 | ] 31 | 32 | module.exports = { 33 | /** 34 | * Networks define how you connect to your ethereum client and let you set the 35 | * defaults web3 uses to send transactions. If you don't specify one truffle 36 | * will spin up a development blockchain for you on port 9545 when you 37 | * run `develop` or `test`. You can ask a truffle command to use a specific 38 | * network from the command line, e.g 39 | * 40 | * $ truffle test --network 41 | */ 42 | 43 | networks: { 44 | // Useful for testing. The `development` name is special - truffle uses it by default 45 | // if it's defined here and no other network is specified at the command line. 46 | // You should run a client (like ganache-cli, geth or parity) in a separate terminal 47 | // tab if you use this network and you must also set the `host`, `port` and `network_id` 48 | // options below to some value. 49 | // 50 | development: { 51 | host: "127.0.0.1", // Localhost (default: none) 52 | port: 8545, // Standard Ethereum port (default: none) 53 | network_id: "*", // Any network (default: none) 54 | }, 55 | // Another network with more advanced options... 56 | // advanced: { 57 | // port: 8777, // Custom port 58 | // network_id: 1342, // Custom network 59 | // gas: 8500000, // Gas sent with each transaction (default: ~6700000) 60 | // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) 61 | // from:
, // Account to send txs from (default: accounts[0]) 62 | // websocket: true // Enable EventEmitter interface for web3 (default: false) 63 | // }, 64 | // Useful for deploying to a public network. 65 | // NB: It's important to wrap the provider as a function. 66 | // ropsten: { 67 | // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), 68 | // network_id: 3, // Ropsten's id 69 | // gas: 5500000, // Ropsten has a lower block limit than mainnet 70 | // confirmations: 2, // # of confs to wait between deployments. (default: 0) 71 | // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) 72 | // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) 73 | // }, 74 | kovan: { 75 | provider: () => new HDWalletProvider({ 76 | privateKeys: private_keys, 77 | providerOrUrl: `https://kovan.infura.io/v3/${process.env.INFURIA_API_KEY}`, 78 | numberOfAddresses: 2 79 | }), 80 | network_id: 42, // Kovan's id 81 | gas: 5500000, // Kovan has a lower block limit than mainnet 82 | confirmations: 2, // # of confs to wait between deployments. (default: 0) 83 | timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) 84 | skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) 85 | }, 86 | ropsten: { 87 | provider: () => new HDWalletProvider({ 88 | privateKeys: private_keys, 89 | providerOrUrl: `https://ropsten.infura.io/v3/${process.env.INFURIA_API_KEY}`, 90 | numberOfAddresses: 2 91 | }), 92 | network_id: 3, // Ropsten's id 93 | gas: 5500000, // Ropsten has a lower block limit than mainnet 94 | confirmations: 2, // # of confs to wait between deployments. (default: 0) 95 | timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) 96 | skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) 97 | }, 98 | rinkeby: { 99 | provider: () => new HDWalletProvider({ 100 | privateKeys: private_keys, 101 | providerOrUrl: `https://rinkeby.infura.io/v3/${process.env.INFURIA_API_KEY}`, 102 | numberOfAddresses: 2 103 | }), 104 | network_id: 4, // Rinkeby's id 105 | gas: 5500000, // Rinkeby has a lower block limit than mainnet 106 | confirmations: 2, // # of confs to wait between deployments. (default: 0) 107 | timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) 108 | skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) 109 | }, 110 | mainnet: { 111 | provider: () => new HDWalletProvider( 112 | process.env.STOCKHOLM, 113 | `wss://mainnet.infura.io/ws/v3/${process.env.INFURIA_API_KEY}`, 114 | ), 115 | gas: 2000000, 116 | gasPrice: 100000000000, 117 | confirmations: 2, 118 | network_id: 1 119 | } 120 | // Useful for private networks 121 | // private: { 122 | // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), 123 | // network_id: 2111, // This network is yours, in the cloud. 124 | // production: true // Treats this network as if it was a public net. (default: false) 125 | // } 126 | }, 127 | 128 | // Set default mocha options here, use special reporters etc. 129 | mocha: { 130 | // timeout: 100000 131 | }, 132 | 133 | // Configure your compilers 134 | compilers: { 135 | solc: { 136 | version: "0.8.9", // Fetch exact version from solc-bin (default: truffle's version) 137 | // docker: true, // Use "0.5.1" you've installed locally with docker (default: false) 138 | // settings: { // See the solidity docs for advice about optimization and evmVersion 139 | // optimizer: { 140 | // enabled: false, 141 | // runs: 200 142 | // }, 143 | // evmVersion: "byzantium" 144 | // } 145 | } 146 | }, 147 | 148 | plugins: [ 149 | 'truffle-plugin-verify' 150 | ], 151 | 152 | api_keys: { 153 | etherscan: process.env.ETHERSCAN_API_KEY 154 | } 155 | 156 | // Truffle DB is currently disabled by default; to enable it, change enabled: 157 | // false to enabled: true. The default storage location can also be 158 | // overridden by specifying the adapter settings, as shown in the commented code below. 159 | // 160 | // NOTE: It is not possible to migrate your contracts to truffle DB and you should 161 | // make a backup of your artifacts to a safe location before enabling this feature. 162 | // 163 | // After you backed up your artifacts you can utilize db by running migrate as follows: 164 | // $ truffle migrate --reset --compile-all 165 | // 166 | // db: { 167 | // enabled: false, 168 | // host: "127.0.0.1", 169 | // adapter: { 170 | // name: "sqlite", 171 | // settings: { 172 | // directory: ".db" 173 | // } 174 | // } 175 | // } 176 | }; 177 | --------------------------------------------------------------------------------