pragma solidity ^0.6.0; contract RoseRent { address owner; address admin; struct ledger { uint initTimestamp; uint nextPaymentTimestamp; uint currentWithdrawAllowance; string reasonForUnemployement; } mapping (address => uint256) private studentRentPaid; // Mapping of students address => ammount the students paid for rent mapping (address => ledger) private unemploymentAccounts; // Mapping of students address => their account (ledger struct) address[] studentsAddresses; // Needed to loop over all the students /* * startUnemployment(): adds an account to the unemployment ledger so the owner can collect, * and initializes all the relevant variables. Made for users to call and can only affect the address calling it. * @arg _reasonForUnemployment - a string describing why. * @returns nothing */ function startUnemployment (string memory _reasonForUnemployement) public { require(unemploymentAccounts[msg.sender].initTimestamp == 0); // If they asked for it in the past, they can not again studentsAddresses.push(msg.sender); // saves keys to look up in the future unemploymentAccounts[msg.sender].initTimestamp = now; unemploymentAccounts[msg.sender].nextPaymentTimestamp = 604800 + unemploymentAccounts[msg.sender].initTimestamp; //604800 is the number of seconds in a week. unemploymentAccounts[msg.sender].currentWithdrawAllowance = 1000000000000000000; //1e18: Native value is in wei unemploymentAccounts[msg.sender].reasonForUnemployement = _reasonForUnemployement; } /* * claimUnemployment(): allows the account to collect unemployment. * @arg _amountToWithdraw - value that the user wants to withdraw. * @returns nothing */ function claimUnemployment (uint _amountToWithdraw) public { // We are checking to make sure the amount withdrawn is positive and wont result in a negative balance. require(unemploymentAccounts[msg.sender].currentWithdrawAllowance > 0); require(unemploymentAccounts[msg.sender].currentWithdrawAllowance - _amountToWithdraw > 0); unemploymentAccounts[msg.sender].currentWithdrawAllowance -= _amountToWithdraw; msg.sender.transfer(_amountToWithdraw); } /* * checkUnemploymentAllowance(): allows the account owner to check there account allowance. * @returns uint256 - available allowance. */ function checkUnemploymentAllowence() public view returns (uint256){ return unemploymentAccounts[msg.sender].currentWithdrawAllowance; } /* * getMoreAllowance(): allows the account to collect more unemployment after 1 week. * @returns nothing */ function getMoreAllowance() public{ require(unemploymentAccounts[msg.sender].nextPaymentTimestamp < now);// Checks if 1 weeks has passed. unemploymentAccounts[msg.sender].initTimestamp = now; unemploymentAccounts[msg.sender].nextPaymentTimestamp = 604800 + unemploymentAccounts[msg.sender].initTimestamp; //604800 is the number of seconds in a week. unemploymentAccounts[msg.sender].currentWithdrawAllowance += 1000000000000000000; // 1e18 Native value is in wei } /* * depositRent(): allows the sender to pay rent conveniently here. * @returns nothing */ function depositRent () public payable{ // realistically, we would reset the 'paid' status of students periodically, but won't here for simplicity. studentRentPaid[msg.sender] += msg.value; } /* * checkIfPaid(): allows for anyone to check if an address has paid rent. * @arg _studentAddress - the address to check if they paid. * @returns bool - true if they paid the minimum rent, false if they did not. */ function checkIfPaid (address _studentAddress) public view returns (bool){ if (studentRentPaid[_studentAddress] >= 4000000000000000000){ // 4 ETH Native value is in wei return true; }else{ return false; } } //---------------------------Not part of the lab--------------------------- /* * fundContract(): allows the additional funding of the smart contract easily. Anyone can call it. * @returns nothing */ function fundContract() public payable{ } /* * initialize(): first function to be called by the managers. * Sets the owner and admin and allows funding of the smart contract. * @arg _owner - address of the owner (Professor). * @arg _admin - address of the admin (TA). * @returns nothing */ function initialize(address _owner, address _admin) public payable{ // address(0) means a address of all 0's (0x000000000000000000000) and that is the default address. Meaning they have not been set yet. require ( (owner == address(0) && admin == address(0)) || msg.sender == admin || msg.sender == owner); owner = _owner; admin = _admin; } /* * restartAllAccounts(): allows the restart of all users who have called "startUnemployment()". Used by admins to reset all students when it is needed. * @returns nothing */ function restartAllAccounts() public payable{ //Will reset contract for everyone. Could send money here to add to the total balance require(msg.sender == admin || msg.sender == owner); for (uint i=0; i<studentsAddresses.length; i++) { restartAccount(studentsAddresses[i]); } } /* * restartAccount(): allows the restart of a specific user given. As long a manager. Used by admins to reset a spesific students when it is needed. * @arg _studentAddress - the students address which should be restarted. * @returns nothing */ function restartAccount(address _studentAddress) public{ //Note: the keyword delete does not work on mapping or structs, so we must iterate over a know key list. // since it has "_studentAddress" passed in, it does not rely on msg.sender. So the admins can reset any student, unlike startUnemployment which is caller restrictive. require(msg.sender == admin || msg.sender == owner); unemploymentAccounts[_studentAddress].initTimestamp = now; unemploymentAccounts[_studentAddress].nextPaymentTimestamp = 604800 + unemploymentAccounts[_studentAddress].initTimestamp; //604800 is the number of seconds in a week. unemploymentAccounts[_studentAddress].currentWithdrawAllowance = 1000000000000000000; //1e18 - Native value is in wei studentRentPaid[_studentAddress] = 0; } }