Skip to content

Instantly share code, notes, and snippets.

@Georgi87
Created April 15, 2017 15:18
Show Gist options
  • Save Georgi87/d395f7d1db87a34d92fab9453b006074 to your computer and use it in GitHub Desktop.
Save Georgi87/d395f7d1db87a34d92fab9453b006074 to your computer and use it in GitHub Desktop.
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