Last active
April 30, 2018 12:36
-
-
Save joshterrill/ab953ebeb36a3dba06dc893d41101de6 to your computer and use it in GitHub Desktop.
Payroll solidity contract example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
contract Payroll { | |
// define variables | |
address public CompanyOwner; | |
uint employeeId; | |
// create Employee object | |
struct Employee { | |
uint employeeId; | |
address employeeAddress; | |
uint wages; | |
uint balance; | |
} | |
// employees contain Employee | |
Employee[] public employees; | |
// run this on contract creation just once | |
function Payroll() { | |
// make CompanyOwner the person who deploys the contract | |
CompanyOwner = msg.sender; | |
employeeId = 0; | |
// add the company owner as an employee with a wage of 0 | |
AddEmployee(msg.sender, 0); | |
} | |
// function for checking number of employees | |
function NumberOfEmployees() returns (uint _numEmployees) { | |
return employeeId; | |
} | |
// allows function initiator to withdraw funds if they're an employee equal to their balance | |
function WithdrawPayroll() returns (bool _success) { | |
var employeeId = GetCurrentEmployeeId(); | |
if (employeeId != 999999) { | |
// they are an employee | |
if (employees[employeeId].balance > 0) { | |
// if they have a balance | |
if (this.balance >= employees[employeeId].balance) { | |
// if the balance of the contract is greater than or equal to employee balance | |
// then send them the money from the contract and set balance back to 0 | |
msg.sender.send(employees[employeeId].balance); | |
employees[employeeId].balance = 0; | |
return true; | |
} else { | |
return false; | |
} | |
} else { | |
return false; | |
} | |
} else { | |
return false; | |
} | |
} | |
function GetCurrentEmployeeId() returns (uint _employeeId) { | |
// loop through employees | |
for (var i = 0; i < employees.length; i++) { | |
// if the initiator of the function's address exists in the employeeAddress area of an Employee, return ID | |
if (msg.sender == employees[i].employeeAddress) { | |
return employees[i].employeeId; | |
} | |
} | |
return 999999; | |
} | |
// function for getting an ID by address if needed | |
function GetEmployeeIdByAddress(address _employee) returns (uint _employeeId) { | |
for (var i = 0; i < employees.length; i++) { | |
if (_employee == employees[i].employeeAddress) { | |
return employees[i].employeeId; | |
} | |
} | |
return 999999; | |
} | |
/* OWNER ONLY FUNCTIONS */ | |
// add an employee given an address and wages | |
function AddEmployee(address _employee, uint _wages) returns (bool _success) { | |
if (msg.sender != CompanyOwner) { | |
return false; | |
} else { | |
employees.push(Employee(employeeId, _employee, _wages, 0)); | |
employeeId++; | |
return true; | |
} | |
} | |
// pay the employee their wages given an employee ID | |
function PayEmployee(uint _employeeId) returns (bool _success) { | |
if (msg.sender != CompanyOwner) { | |
return false; | |
} else { | |
// TODO: need to figure out how to check to make sure employees[_employeeId] exists | |
employees[_employeeId].balance += employees[_employeeId].wages; | |
return true; | |
} | |
} | |
// modify the employee wages given an employeeId and a new wage | |
function ModifyEmployeeWages(uint _employeeId, uint _newWage) returns (bool _success) { | |
if (msg.sender != CompanyOwner) { | |
return false; | |
} else { | |
// TODO: need to figure out how to check to make sure employees[_employeeId] exists | |
// change employee wages to new wage | |
employees[_employeeId].wages = _newWage; | |
return true; | |
} | |
} | |
// check how much money is in the contract | |
function CheckContractBalance() returns (uint _balance) { | |
return this.balance; | |
} | |
} |
I stripped it down, took out the unneccessary methods (use public variable instead of coded accessors), and added a removeEmployee() method.
contract Payroll {
address public owner;
uint public nextEmpolyeeID;
struct Employee {
uint employeeId;
uint wages;
uint balance;
}
mapping (address => Employee) employees;
modifier onlyOwner {
if (msg.sender==owner)
_
}
function Payroll() {
owner = msg.sender;
addEmployee(msg.sender, 0);
}
// allows function initiator to withdraw funds if they're an employee equal to their balance
function withdrawPayroll() returns (bool _success) {
uint empBalance = employees[msg.sender].balance;
if (empBalance > 0 && this.balance >= empBalance) {
if (msg.sender.send(empBalance)){
employees[msg.sender].balance = 0;
return true;
}
}
return false;
}
// function for getting an ID by address if needed
function getEmployeeIdByAddress(address _employee) returns (uint _employeeId) {
return employees[_employee].employeeId;
}
/* OWNER ONLY FUNCTIONS */
// add an employee given an address and wages
function addEmployee(address _employee, uint _wages) onlyOwner returns (bool _success) {
nextEmpolyeeID++;
employees[_employee].employeeId=nextEmpolyeeID;
employees[_employee].wages=_wages;
//balance is 0 by default
return true;
}
function removeEmployee(address _employee) onlyOwner returns (bool _success) {
employees[_employee].wages=0;
employees[_employee].employeeId=0;
return true;
}
// pay the employee their wages given an employee ID
function payEmployee(address _employeeId) onlyOwner returns (bool _success) {
employees[_employeeId].balance += employees[_employeeId].wages;
//keep their balance so they can escape with their dignity
return true;
}
// modify the employee wages given an employeeId and a new wage
function modifyEmployeeWages(address _employeeId, uint _newWage) onlyOwner returns (bool _success) {
employees[_employeeId].wages = _newWage;
return true;
}
}
and actually, you don't even need to have such thing as an employeeId
in your struct...each address is unique so its safe to use this as a unique identifier for employees...
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Solid first contract! I ran it on my testnet and it worked as described :)
Just a couple of things I'd look into changing:
GetCurrentEmployeeId()
method is very inefficient and gets more expensive (gas cost) each time you add a new employee. A better way to find a callers own employee ID would be to save the employee ID in a mapping with a key of their address:mapping (address => uint) public employeeIDs
this way you can just find the callers ID by doing:employeeIDs[msg.sender]
- no need for the expensive for loop! This will help in a lot of your other methods too.