Created
April 15, 2017 15:18
-
-
Save Georgi87/d395f7d1db87a34d92fab9453b006074 to your computer and use it in GitHub Desktop.
This file contains 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
pragma solidity ^0.4.10; | |
/// @title Payroll contract - Allows employees to receive salary payments and to cash checks. | |
/// @author Stefan George - <[email protected]> | |
contract Payroll { | |
event EmployeeAddition(address indexed employee, uint startDate, uint endDate, uint yearlyUSDSalary); | |
event EmployeeDeletion(address indexed employee); | |
event PayoutSalary(address indexed employee, uint amount, uint ethPrice); | |
event PayoutCheck(address indexed receiver, uint amount, bytes subject, uint ethPrice); | |
event OwnerUpdate(address newOwner, address oldOwner); | |
event PriceOracleUpdate(address newPriceOracle, address oldPriceOracle); | |
uint constant public ORACLE_TIMEFRAME = 60 seconds; | |
uint8 constant OWNER = 0; | |
uint8 constant ORACLE = 1; | |
address public owner; | |
address public priceOracle; | |
mapping(address => Employee) public employees; | |
mapping(bytes32 => bool) public cashedChecks; | |
struct Employee { | |
uint endDate; | |
uint lastPaymentDate; | |
uint yearlyUSDSalary; | |
} | |
modifier isOwner() { | |
if (msg.sender != owner) | |
throw; | |
_; | |
} | |
modifier isValidPrice(uint ethPrice, uint timestamp, uint8 v, bytes32 r, bytes32 s) { | |
// Valid oracle signed price information. | |
if (priceOracle != ecrecover(sha3(ethPrice, timestamp), v, r, s)) | |
throw; | |
// Price information is not expired. | |
if (timestamp + ORACLE_TIMEFRAME < now || timestamp > now) | |
throw; | |
_; | |
} | |
/// @dev Constructor function sets owner and price oracle. | |
/// @param _priceOracle Price oracle address. | |
function Payments(address _priceOracle) | |
public | |
{ | |
owner = msg.sender; | |
priceOracle = _priceOracle; | |
} | |
/// @dev Allows owner to update owner address. | |
/// @param _owner New owner address. | |
function updateOwner(address _owner) | |
public | |
isOwner | |
{ | |
OwnerUpdate(_owner, owner); | |
owner = _owner; | |
} | |
/// @dev Allows owner to update price oracle address. | |
/// @param _priceOracle New price oracle address. | |
function updatePriceOracle(address _priceOracle) | |
public | |
isOwner | |
{ | |
PriceOracleUpdate(_priceOracle, priceOracle); | |
priceOracle = _priceOracle; | |
} | |
/// @dev Allows owner to add or update an employee. | |
/// @param employee Employee address. | |
/// @param startDate Start date of emplyment. | |
/// @param endDate End date of emplyment. | |
/// @param yearlyUSDSalary Yearly salary in USD. | |
function addEmployee(address employee, uint startDate, uint endDate, uint yearlyUSDSalary) | |
public | |
isOwner | |
{ | |
// Emplyment starts now if start date is not set. | |
if (startDate == 0) | |
startDate = now; | |
// Add or overwrite emplyee information. | |
employees[employee] = Employee({ | |
endDate: endDate, | |
lastPaymentDate: startDate, | |
yearlyUSDSalary: yearlyUSDSalary | |
}); | |
EmployeeAddition(employee, startDate, endDate,yearlyUSDSalary); | |
} | |
/// @dev Allows owner to delete an employee. | |
/// @param employee Employee address. | |
function deleteEmployee(address employee) | |
public | |
isOwner | |
{ | |
// Delete emplyee struct. | |
delete employees[employee]; | |
EmployeeDeletion(employee); | |
} | |
/// @dev Allows an employee to receive the share of his salary since his last withdrawal. | |
/// @param ethPrice Price of 1 USD in Wei. | |
/// @param timestamp Time when the price oracle signed the price. | |
/// @param v Price oracle signature parameter. | |
/// @param r Price oracle signature parameter. | |
/// @param s Price oracle signature parameter. | |
/// @return Received amount in Wei. | |
function receivePayment(uint ethPrice, uint timestamp, uint8 v, bytes32 r, bytes32 s) | |
public | |
isValidPrice(ethPrice, timestamp, v, r, s) | |
returns (uint amount) | |
{ | |
Employee employee = employees[msg.sender]; | |
// Employee is employed. | |
if (employee.endDate < now || now < employee.lastPaymentDate) | |
throw; | |
amount = (now - employee.lastPaymentDate) * employee.yearlyUSDSalary * ethPrice / 365 days; | |
employee.lastPaymentDate = now; | |
// Send salary. | |
if(msg.sender.send(amount)) | |
throw; | |
PayoutSalary(msg.sender, amount, ethPrice); | |
} | |
/// @dev Allows a check receiver to cash his check. | |
/// @param receiver Receiver address. | |
/// @param usd Check amount in USD. | |
/// @param subject Check subject. | |
/// @param ethPrice Price of 1 USD in Wei. | |
/// @param timestamp Time when the price oracle signed the price. | |
/// @param v Owner and price oracle signature parameter. | |
/// @param r Owner and price oracle signature parameter. | |
/// @param s Owner and price oracle signature parameter. | |
/// @return Received amount in Wei. | |
function cashCheck( | |
address receiver, | |
uint usd, | |
bytes subject, | |
uint ethPrice, | |
uint timestamp, | |
uint8[2] v, | |
bytes32[2] r, | |
bytes32[2] s | |
) | |
public | |
isValidPrice(ethPrice, timestamp, v[ORACLE], r[ORACLE], s[ORACLE]) | |
returns (uint amount) | |
{ | |
// Owner signed check. | |
bytes32 checkHash = sha3(this, receiver, usd, subject); | |
if (owner != ecrecover(checkHash, v[OWNER], r[OWNER], s[OWNER])) | |
throw; | |
// Cash has not been checked yet. | |
if (cashedChecks[checkHash]) | |
throw; | |
cashedChecks[checkHash] = true; | |
// Send amount. | |
amount = usd * ethPrice; | |
if(msg.sender.send(amount)) | |
throw; | |
PayoutCheck(receiver, amount, subject, ethPrice); | |
} | |
/// @dev Allows owner to delete contract and return remaining funds to owner. | |
function deleteContract() | |
public | |
isOwner | |
{ | |
// Delete contract and send all remaning funds to owner. | |
selfdestruct(owner); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment