├── DepositContract.sol ├── HungerGames.sol ├── Inheritance.sol ├── LemonICO.sol ├── PetSanctuary.sol ├── README.md ├── SimpleBank.sol ├── TokenAuction1.sol └── TokenAuction2.sol /DepositContract.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.8; 2 | 3 | contract DepositContract { 4 | 5 | address owner; 6 | 7 | uint balances; 8 | 9 | event MoneySent(address contractAdd, uint amount); 10 | 11 | constructor() public payable { 12 | owner = msg.sender; 13 | } 14 | 15 | modifier onlyOwner() { 16 | require(owner == msg.sender, "Only Contract Owner is authorized"); 17 | _; 18 | } 19 | 20 | function deposit() public payable { 21 | balances += msg.value; 22 | emit MoneySent(address(this), address(this).balance); 23 | } 24 | 25 | function getContractBalance() public view returns (uint) { 26 | return address(this).balance; 27 | } 28 | 29 | function killContract() public onlyOwner { 30 | selfdestruct(msg.sender); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /HungerGames.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "github.com/provable-things/ethereum-api/provableAPI.sol"; // Must use Injected Web3 4 | 5 | 6 | contract HungerGames is usingProvable { 7 | 8 | uint startTime; 9 | uint durationTime; 10 | uint public randomNumber; 11 | bool hasStarted = false; 12 | string[] private nameIndex; 13 | mapping (string => Tribute) private Tributes; 14 | 15 | event generatedRandomNumber(uint256 randomNumber); 16 | event selectedTributes(string maleTribute, string femTribute); 17 | event allTributes(string gender, uint age, bool isAlive); 18 | uint public modulus; 19 | 20 | string[] private boyList; 21 | string[] private girlList; 22 | 23 | struct Tribute { 24 | string name; 25 | string gender; 26 | uint age; 27 | bool isAlive; 28 | uint index; 29 | uint genderIndex; 30 | } 31 | 32 | 33 | constructor() public payable { 34 | provable_setProof(proofType_Ledger); 35 | } 36 | 37 | modifier gameTime() { 38 | hasStarted = true; 39 | startTime = block.timestamp; 40 | durationTime = startTime + 5 minutes; 41 | _; 42 | } 43 | 44 | modifier beforeGame() { 45 | require(!hasStarted, "The Hunger Games has already begun"); 46 | _; 47 | } 48 | 49 | modifier afterGame() { 50 | require(hasStarted && durationTime <= block.timestamp, "The Hunger Games is not Over yet"); 51 | _; 52 | } 53 | 54 | function isTribute(string memory name) 55 | internal 56 | returns(bool) 57 | { 58 | if(nameIndex.length == 0) return false; 59 | 60 | return keccak256(bytes(name)) == keccak256(bytes(nameIndex[Tributes[name].index])); 61 | } 62 | 63 | function addTributes(string memory name, string memory gender, uint age) public beforeGame returns(uint index) { 64 | require(!isTribute(name), "Will not allow duplicates"); 65 | require(age >= 12 && age <= 18, "Unqualifiable age"); 66 | Tributes[name].gender = gender; 67 | Tributes[name].age = age; 68 | Tributes[name].isAlive = true; 69 | Tributes[name].index = nameIndex.push(name)-1; 70 | 71 | if (keccak256(bytes(gender)) == keccak256(bytes("male"))) { 72 | Tributes[name].genderIndex = boyList.push(name)-1; 73 | } else { 74 | require(keccak256(bytes(gender)) == keccak256(bytes("female")), "Unspecified Gender"); 75 | Tributes[name].genderIndex = girlList.push(name)-1; 76 | } 77 | 78 | return nameIndex.push(name)-1; 79 | } 80 | 81 | function getMaleTributes() public view returns (uint) { 82 | return boyList.length; 83 | } 84 | 85 | function getFemaleTributes() public view returns (uint) { 86 | return girlList.length; 87 | } 88 | 89 | function selectTributes() public gameTime { 90 | emit selectedTributes(boyList[randomNumber], girlList[randomNumber]); 91 | } 92 | 93 | function randSelector() internal returns(bool) { 94 | if (randomNumber % 2 == 0) { 95 | Tributes[boyList[randomNumber]].isAlive = false; 96 | } else { 97 | Tributes[girlList[randomNumber]].isAlive = false; 98 | } 99 | return true; 100 | } 101 | 102 | function allSurviving(string memory name) public afterGame { 103 | require(isTribute(name), "Person requested is not Tribute"); 104 | randSelector(); 105 | emit allTributes(Tributes[name].gender, Tributes[name].age, Tributes[name].isAlive); 106 | } 107 | 108 | function __callback(bytes32 queryId, string memory result, bytes memory proof) public { 109 | require(msg.sender == provable_cbAddress()); 110 | 111 | if(provable_randomDS_proofVerify__returnCode(queryId, result, proof) == 0) { 112 | uint maxRange = boyList.length - 1; 113 | randomNumber = uint(keccak256(abi.encodePacked(result))) % maxRange; 114 | emit generatedRandomNumber(randomNumber); 115 | } else { 116 | // Proof verification failed 117 | } 118 | } 119 | 120 | function getRandomNumber() public beforeGame payable { 121 | require(boyList.length == girlList.length && boyList.length != 0, "Teams must be of equal size"); 122 | uint numberOfBytes = 4; 123 | uint delay = 0; 124 | uint callbackGas = 200000; 125 | bytes32 queryId = provable_newRandomDSQuery(delay, numberOfBytes, callbackGas); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /Inheritance.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.8; 2 | 3 | contract SafeMath { 4 | 5 | function add(int a, int b) internal pure returns (int) { 6 | int c = a + b; 7 | require(c >= a, "Addition: Interger overflow"); 8 | return c; 9 | } 10 | 11 | function subtract(int a, int b) internal pure returns (int) { 12 | require(a >= b, "Subtract: Interger underflow"); 13 | int c = a - b; 14 | return c; 15 | } 16 | 17 | function multiply(int a, int b) internal pure returns (int) { 18 | if (a == 0 || b == 0) { 19 | return 0; 20 | } 21 | int c = a * b; 22 | require(c / a == b, "Multiplication: Interger overflow"); 23 | return c; 24 | } 25 | 26 | } 27 | 28 | contract Owned { 29 | 30 | address contractOwner; 31 | 32 | constructor() public { 33 | contractOwner = msg.sender; 34 | } 35 | 36 | modifier onlyOwner() { 37 | require(contractOwner == msg.sender, "Only Contract Owner is authorized"); 38 | _; 39 | } 40 | 41 | function changeOwner(address newOwner) public onlyOwner { 42 | contractOwner = newOwner; 43 | } 44 | } 45 | 46 | contract IntergerState is Owned, SafeMath { 47 | 48 | int256 x; 49 | uint private lastStateChange; 50 | 51 | function stateVar() public onlyOwner returns(int) { 52 | x = add(x, int(now % 256)); 53 | x = multiply(x, int(now - lastStateChange)); 54 | x = subtract(x, int(block.gaslimit)); 55 | lastStateChange = now; 56 | return x; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /LemonICO.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.22 <0.6.2; 2 | 3 | 4 | contract ERC20Basic { 5 | function totalSupply() public view returns (uint256); 6 | function tokenBalance(address who) public view returns (uint256); 7 | function transfer(address to, uint256 value) internal returns (bool); 8 | event Transfer(address indexed from, address indexed to, uint256 value); 9 | } 10 | 11 | contract LemonToken is ERC20Basic { 12 | 13 | address payable owner; 14 | string public name; 15 | string public symbol; 16 | uint public decimals; 17 | uint256 public initialSupply; 18 | uint256 tokenSupply; 19 | 20 | mapping (address => uint) balances; 21 | 22 | constructor() public { 23 | owner = msg.sender; 24 | name = "LemonToken"; 25 | symbol = "LMN"; 26 | decimals = 18; 27 | initialSupply = 1000000; 28 | tokenSupply = initialSupply; 29 | balances[owner] = tokenSupply; 30 | } 31 | 32 | function totalSupply() public view returns (uint256 tokens) { 33 | return balances[owner]; 34 | } 35 | 36 | function tokenBalance(address _owner) public view returns (uint256 LMNtokens) { 37 | return balances[_owner]; 38 | } 39 | 40 | function transfer(address to, uint256 value) internal returns (bool success) { 41 | balances[owner] = tokenSupply; 42 | if (balances[owner] >= value && value > 0) { 43 | balances[owner] -= value; 44 | balances[to] += value; 45 | emit Transfer(owner, to, value); 46 | return true; 47 | } else { return false; } 48 | } 49 | 50 | } 51 | 52 | contract LemonCrowdsale is LemonToken { 53 | 54 | uint startTime; 55 | uint endTime; 56 | uint rateOfTokensToGivePerEth; 57 | address payable walletToStoreTheEthers; 58 | uint lemonTokens; 59 | mapping (address => uint) contribution; 60 | 61 | constructor() public payable { 62 | walletToStoreTheEthers = msg.sender; 63 | startTime = now + 2 minutes; 64 | endTime = startTime + 5 minutes; 65 | rateOfTokensToGivePerEth = 10; 66 | contribution[msg.sender] = 0; 67 | } 68 | 69 | modifier hasBegun() { 70 | require(startTime <= now, "ICO Launch has not begun"); 71 | _; 72 | } 73 | 74 | modifier timedICO() { 75 | require(!hasEnded(), "Crowdsale has ended!"); 76 | _; 77 | } 78 | 79 | modifier nonOwner() { 80 | require(walletToStoreTheEthers != msg.sender, "Contract Owner cannot partake in ICO"); 81 | _; 82 | } 83 | 84 | function hasEnded() public view returns (bool icoEnded) { 85 | return endTime <= now; 86 | } 87 | 88 | function ownerBalance() public view returns (uint weiProfits) { 89 | require(walletToStoreTheEthers == msg.sender, "Only Contract Owner is authorized"); 90 | return contribution[msg.sender]; 91 | } 92 | 93 | function contributions() public view nonOwner returns (uint weiContributions) { 94 | return contribution[msg.sender]; 95 | } 96 | 97 | function buyLemonTokens() public payable hasBegun timedICO nonOwner { 98 | lemonTokens = rateOfTokensToGivePerEth * (msg.value / 1 ether); 99 | require(msg.value > 0, "Cannot buy ZERO tokens"); 100 | contribution[walletToStoreTheEthers] += msg.value; 101 | contribution[msg.sender] += msg.value; 102 | LemonToken.transfer(msg.sender, lemonTokens); 103 | walletToStoreTheEthers.transfer(msg.value); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /PetSanctuary.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.22 <0.6.2; 2 | 3 | 4 | contract PetSanctuary { 5 | 6 | address owner; 7 | uint durationTime; 8 | mapping (string => bool) allowedPets; 9 | mapping (string => uint) pets; 10 | string[] private allPets; 11 | string[] private allCustomers; 12 | 13 | struct Customer { 14 | string gender; 15 | uint age; 16 | string pet; 17 | uint index; 18 | uint time; 19 | } 20 | 21 | mapping (string => Customer) private Customers; 22 | 23 | constructor() public { 24 | owner = msg.sender; 25 | 26 | allowedPets["fish"] = true; 27 | allowedPets["cat"] = true; 28 | allowedPets["dog"] = true; 29 | allowedPets["parrot"] = true; 30 | allowedPets["rabbit"] = true; 31 | 32 | pets["fish"] = 0; 33 | pets["cat"] = 0; 34 | pets["dog"] = 0; 35 | pets["parrot"] = 0; 36 | pets["rabbit"] = 0; 37 | } 38 | 39 | function isCustomer(string memory name) 40 | internal 41 | returns(bool) 42 | { 43 | if(allCustomers.length == 0) return false; 44 | 45 | return keccak256(bytes(name)) == keccak256(bytes(allCustomers[Customers[name].index])); 46 | } 47 | 48 | modifier onlyOwner() { 49 | require(owner == msg.sender, "Only Shop Owner is authorized"); 50 | _; 51 | } 52 | 53 | modifier onlyAllowed(string memory animal) { 54 | require(allowedPets[animal], "Animal provided is not allowed"); 55 | _; 56 | } 57 | 58 | modifier inTime(string memory customer) { 59 | durationTime = Customers[customer].time + 5 minutes; 60 | require(now <= durationTime, "Out of Time: Deadline to return your pet has been reached"); 61 | _; 62 | } 63 | 64 | function addPets(string memory animal, uint amount) public onlyOwner onlyAllowed(animal) { 65 | pets[animal] += amount; 66 | } 67 | 68 | function buyPet(string memory customer, 69 | uint cAge, 70 | string memory cGender, 71 | string memory animal) 72 | public onlyAllowed(animal) 73 | returns(bool successfulTransaction) { 74 | 75 | require(pets[animal] > 0, "Animal is no longer in stock"); 76 | 77 | if (isCustomer(customer)) { 78 | require(keccak256(bytes(Customers[customer].pet)) == keccak256(bytes("RETURNED")), 79 | "Only One pet for a Lifetime"); 80 | 81 | } else if (keccak256(bytes(cGender)) == keccak256(bytes("male"))) { 82 | 83 | require(keccak256(bytes(animal)) == keccak256(bytes("dog")) 84 | || keccak256(bytes(animal)) == keccak256(bytes("fish")), 85 | "You, Sir, are only allowed a pet Dog or Fish"); 86 | Customers[customer].index = allCustomers.push(customer)-1; 87 | 88 | } else if (keccak256(bytes(cGender)) == keccak256(bytes("female")) && cAge < 40) { 89 | 90 | require(keccak256(bytes(animal)) != keccak256(bytes("cat")), "You, Madam, are not allowed a Cat yet"); 91 | Customers[customer].index = allCustomers.push(customer)-1; 92 | } 93 | 94 | Customers[customer].gender = cGender; 95 | Customers[customer].age = cAge; 96 | Customers[customer].pet = animal; 97 | Customers[customer].time = block.timestamp; 98 | 99 | pets[animal]--; 100 | return true; 101 | } 102 | 103 | function returnPet(string memory customer, string memory pet) inTime(customer) public onlyAllowed(pet) 104 | returns(bool successfulReturn) { 105 | require(isCustomer(customer), "Must be a previous customer"); 106 | require(keccak256(bytes(Customers[customer].pet)) == keccak256(bytes(pet)), "Returning Pet does not match animal purchased"); 107 | Customers[customer].pet = "RETURNED"; 108 | pets[pet]++; 109 | return true; 110 | } 111 | 112 | function getReceipt(string memory customer) public view returns(uint cAge, 113 | string memory cGender, 114 | string memory pet, 115 | uint timeOfPurchase) { 116 | return (Customers[customer].age, 117 | Customers[customer].gender, 118 | Customers[customer].pet, 119 | Customers[customer].time); 120 | } 121 | 122 | function getPetCount(string memory animal) public view returns(uint amount) { 123 | return(pets[animal]); 124 | } 125 | 126 | function getInventory() public view returns(uint amount) { 127 | return(pets["fish"] + pets["cat"] + pets["dog"] + pets["parrot"] + pets["rabbit"]); 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Advanced Solidity Contracts 2 | Exercises about functions, modifiers, events, contracts, interactions, error handling and libraries in Solidity programming language. The goal of these exercises is to get practical skills in writing advanced smart contracts in Solidity, publishing and testing contracts in the Remix IDE. 3 | 4 | ## Table of Contents 5 | * [Receiving Funds from the Default Contract](#receiving-funds-from-the-default-contract) 6 | * [Inheritance](#inheritance) 7 | * [Simple Bank](#simple-bank) 8 | * [Simple Timed Auction](#simple-timed-auction) 9 | * [Simple Timed Auction (2)](#simple-timed-auction-2) 10 | * [Hunger Games](#hunger-games) 11 | * [Pet Adoption](#pet-adoption) 12 | 13 | ## Receiving Funds from the Default Contract 14 | Create a Deposit contract which: 15 | * Stores the owner of the contract 16 | * People can deposit ethers in the contract 17 | * People can get the balance of the contract 18 | * Owner can send amount 19 | * Upon sending, the contract self-destructs with the total amount in the contract 20 | 21 | Use modifiers where it is appropriate. Add appropriate events for the functions. 22 | 23 | ## Inheritance 24 | Write a SafeMath contract: 25 | * The contract has methods to safely add, subtract and multiply two numbers 26 | * The methods should throw if an integer overflow occurs! 27 | 28 | Write an Owned contract: 29 | * Which knows its owner 30 | * Has method to change the owner (called from current owner) 31 | * Implements an access modifier 32 | 33 | Write a contract that inherits SafeMath and Owned and uses their methods: 34 | * The contract should hold one int256 state variable 35 | * Has a method to change the state variable automatically by these rules: 36 | * Method is called by the owner 37 | * The state is incremented by now % 256 38 | * The state is multiplied by the amount of seconds since the last state change (initially 1) 39 | * The current block gas limit is subtracted from the state 40 | 41 | ## Simple Bank 42 | Create a simple Bank contract which: 43 | * holds balances of users 44 | * holds the owner of the contract 45 | * function deposit – user deposits ether to the bank 46 | * method must be payable 47 | * use require to validate corner cases (e.g. overflow) 48 | * return the balance of the user 49 | * function withdraw(amount) – user withdraws ether from the bank 50 | * use require to validate corner cases 51 | * use msg.sender.transfer 52 | * return the new balance of the user 53 | * function getBalance – returns the caller's balance 54 | 55 | Use modifiers where it is appropriate. Add appropriate events for the functions. 56 | 57 | ## Simple Timed Auction 58 | Write a contract for an auction, which continues for 1 minute after the contract is deployed. Use block.timestamp as a start time: `block.timestamp` (alias `now`) 59 | 60 | Contract stores: 61 | * owner of the contract 62 | * start time 63 | * duration time 64 | * stores each buyer's amount bought 65 | * constructor with a parameter – tokens amount to sell 66 | * function buyTokens(amount) – check whether the auction has ended 67 | 68 | Use modifiers where it is appropriate. Add appropriate events for the functions. 69 | 70 | ## Simple Timed Auction (2) 71 | Write a contract for an auction, which continues for 1 block after contract's creation: `block.number` 72 | 73 | ## Hunger Games 74 | 75 | Every year, in the ruins of what was once North America, the Capitol of the nation of Panem - a technologically advanced, utopian city where the nation's most wealthy and powerful citizens live, forces each of its 12 districts to send a teenage boy and a girl, between the ages of 12 and 18, to compete in the Hunger Games: a nationally televised event in which 'tributes' fight each other within an arena, until one survivor remains. 76 | This time of the year has come and it’s time for the 100th hunger game where you should send the new pair of teenage boy and girl. 77 | 78 | Create a Capitol contract which: 79 | * adds person by age and gender (hint: use struct for storing the person) 80 | * chooses one girl and one boy: 81 | * you are not allowed to choose the two people from the same gender 82 | * they should be between 12 and 18 years old 83 | * they should be chosen by random function (you can use block.timestamp but it is not safe or oraclize -> learn more about it from oraclize documentation) 84 | * you can check how many girls and boys are added -> returns a positive number 85 | * after choosing the pair (boy and girl) set the start date of the hunger games and the end date (the hunger games should last 5 minutes) 86 | * after the end of the hunger game, check if the boy and girl are alive (use random 0 - dead, 1 - alive, use modifier for checking if the hunger game ended) 87 | 88 | Use modifiers where it is appropriate. Add appropriate events for the functions. Test and play around with the contract! 89 | 90 | ## Pet Adoption 91 | 92 | In our adoption sanctuary, we have 5 kinds of animals: 93 | * Fish 94 | * Cat 95 | * Dog 96 | * Rabbit 97 | * Parrot 98 | 99 | The sanctuary will store information for all the people who have adopted a pet. After creating the contract, we should add the owner of the adoption sanctuary. 100 | 101 | Create a contract called PetSanctuary that has: 102 | * function add (animalKind, howManyPieces) – only the owner can give shelter to animals in the sanctuary 103 | * function buy (personAge, personGender, animalKind) 104 | * save when the animal is bought 105 | * you can only adopt one animal for lifetime 106 | * Men can only buy dog and fish 107 | * Women can buy from every kind, but if they are under 40, they are not allowed to buy a cat 108 | * function giveBackAnimal(animalKind) 109 | * you can give the animal back in the first 5 minutes after adoption 110 | * Think about how to store people’s information in the contract. 111 | 112 | Use modifiers where it is appropriate. Add appropriate events for the functions. 113 | 114 | ## Module 115 | MI3: Module 4: E3 116 | -------------------------------------------------------------------------------- /SimpleBank.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.8; 2 | 3 | contract SimpleBank { 4 | 5 | mapping(address => uint) bankBalance; 6 | 7 | event VaultDeposit(address accountHolder, uint deposit, uint newBalance); 8 | event VaultWithdrawal(address accountHolder, uint withdrawal, uint newBalance); 9 | 10 | address contractOwner; 11 | 12 | 13 | constructor() public payable { 14 | contractOwner = msg.sender; 15 | } 16 | 17 | modifier onlyOwner() { 18 | require(contractOwner == msg.sender, "Only Bank Owner is authorized"); 19 | _; 20 | } 21 | 22 | function deposit() public payable { 23 | require(bankBalance[msg.sender] + msg.value >= bankBalance[msg.sender], "Addition: balance overflow"); 24 | bankBalance[msg.sender] += msg.value; 25 | uint amount = msg.value; 26 | emit VaultDeposit(msg.sender, amount, bankBalance[msg.sender]); 27 | } 28 | 29 | function withdraw(uint amount) public returns (bool) { 30 | require(amount <= bankBalance[msg.sender], "Subtraction: balance underflow"); 31 | bankBalance[msg.sender] -= amount; 32 | emit VaultWithdrawal(msg.sender, amount, bankBalance[msg.sender]); 33 | msg.sender.transfer(amount); 34 | return true; 35 | } 36 | 37 | function getBalance() public view returns (uint) { 38 | return bankBalance[msg.sender]; 39 | } 40 | 41 | function vaultBalance() public view onlyOwner returns (uint) { 42 | return address(this).balance; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /TokenAuction1.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.8; 2 | 3 | contract TokenAuction { 4 | uint durationTime; 5 | address owner; 6 | mapping (address => uint) tokenBalances; 7 | uint public initialSupply; 8 | uint rateOfTokensToGivePerEth; 9 | 10 | event Auction(address tokenHolder, uint cost, uint tokenBalance); 11 | 12 | constructor() public payable { 13 | durationTime = now + 1 minutes; 14 | owner = msg.sender; 15 | initialSupply = 1000; 16 | tokenBalances[owner] = initialSupply; 17 | rateOfTokensToGivePerEth = 10; 18 | } 19 | 20 | modifier timeCheck() { 21 | require(durationTime >= now, "Auction Time is Over"); 22 | _; 23 | } 24 | 25 | modifier onlyOwner() { 26 | require(owner == msg.sender, "Only Auction Owner is authorized"); 27 | _; 28 | } 29 | 30 | function buyTokens() public payable timeCheck { 31 | uint tokens = rateOfTokensToGivePerEth * (msg.value / 1 ether); 32 | require(tokens <= initialSupply, "Token Underflow"); 33 | require(tokenBalances[msg.sender] + tokens >= tokenBalances[msg.sender], "Token Overflow"); 34 | tokenBalances[owner] -= tokens; 35 | tokenBalances[msg.sender] += tokens; 36 | 37 | emit Auction(msg.sender, msg.value, tokenBalances[msg.sender]); 38 | } 39 | 40 | function getBalance() public view returns (uint tokens) { 41 | return tokenBalances[msg.sender]; 42 | } 43 | 44 | function currentSupply() public view onlyOwner returns (uint tokensLeft) { 45 | return tokenBalances[owner]; 46 | } 47 | 48 | function auctionBalance() public view onlyOwner returns (uint profits) { 49 | return address(this).balance; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /TokenAuction2.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.8; 2 | 3 | contract TokenAuction { 4 | uint durationTime; 5 | address owner; 6 | mapping (address => uint) tokenBalances; 7 | uint public initialSupply; 8 | uint rateOfTokensToGivePerEth; 9 | 10 | event Auction(address tokenHolder, uint cost, uint tokenBalance); 11 | 12 | constructor() public payable { 13 | uint currentBlock = block.number; 14 | durationTime = currentBlock + 1; 15 | owner = msg.sender; 16 | initialSupply = 1000; 17 | tokenBalances[owner] = initialSupply; 18 | rateOfTokensToGivePerEth = 10; 19 | } 20 | 21 | modifier timeCheck() { 22 | require(durationTime >= block.number, "Auction Time is Over"); 23 | _; 24 | } 25 | 26 | modifier onlyOwner() { 27 | require(owner == msg.sender, "Only Auction Owner is authorized"); 28 | _; 29 | } 30 | 31 | function buyTokens() public payable timeCheck { 32 | uint tokens = rateOfTokensToGivePerEth * (msg.value / 1 ether); 33 | require(tokens <= initialSupply, "Token Underflow"); 34 | require(tokenBalances[msg.sender] + tokens >= tokenBalances[msg.sender], "Token Overflow"); 35 | tokenBalances[owner] -= tokens; 36 | tokenBalances[msg.sender] += tokens; 37 | emit Auction(msg.sender, msg.value, tokenBalances[msg.sender]); 38 | } 39 | 40 | function getBalance() public view returns (uint tokens) { 41 | return tokenBalances[msg.sender]; 42 | } 43 | 44 | function currentSupply() public view onlyOwner returns (uint tokensLeft) { 45 | return tokenBalances[owner]; 46 | } 47 | 48 | function auctionBalance() public view onlyOwner returns (uint profits) { 49 | return address(this).balance; 50 | } 51 | 52 | } 53 | --------------------------------------------------------------------------------