{"id":18879504,"url":"https://github.com/fforbeck/payroll-smartcontract","last_synced_at":"2025-04-14T19:22:59.974Z","repository":{"id":144910004,"uuid":"121631225","full_name":"fforbeck/Payroll-SmartContract","owner":"fforbeck","description":"Solidity smart contract to manage an employee payroll based on ERC20 tokens","archived":false,"fork":false,"pushed_at":"2023-04-20T14:45:09.000Z","size":74,"stargazers_count":7,"open_issues_count":6,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-28T07:51:09.729Z","etag":null,"topics":["ethereum","ethereum-contract","ganache-cli","javascript","smart-contract","solidity","truffle"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fforbeck.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-02-15T13:10:28.000Z","updated_at":"2022-07-17T09:03:25.000Z","dependencies_parsed_at":null,"dependency_job_id":"41635fb2-e804-4de9-b20a-648f7f92f890","html_url":"https://github.com/fforbeck/Payroll-SmartContract","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fforbeck%2FPayroll-SmartContract","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fforbeck%2FPayroll-SmartContract/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fforbeck%2FPayroll-SmartContract/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fforbeck%2FPayroll-SmartContract/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fforbeck","download_url":"https://codeload.github.com/fforbeck/Payroll-SmartContract/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248943415,"owners_count":21186958,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ethereum","ethereum-contract","ganache-cli","javascript","smart-contract","solidity","truffle"],"created_at":"2024-11-08T06:36:53.075Z","updated_at":"2025-04-14T19:22:59.954Z","avatar_url":"https://github.com/fforbeck.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\n# Payroll Smart Contract\n\n## The challenge\n```\n// For the sake of simplicity lets assume EUR is a ERC20 token\n// Also lets assume we can 100% trust the exchange rate oracle\ncontract PayrollInterface {\n  /* OWNER ONLY */\n  function addEmployee(address accountAddress, address[] allowedTokens, uint256 initialYearlyEURSalary);\n  function setEmployeeSalary(uint256 employeeId, uint256 yearlyEURSalary);\n  function removeEmployee(uint256 employeeId);\n\n  function addFunds() payable;\n  function scapeHatch();\n  // function addTokenFunds()? // Use approveAndCall or ERC223 tokenFallback\n\n  function getEmployeeCount() constant returns (uint256);\n  function getEmployee(uint256 employeeId) constant returns (address employee); // Return all important info too\n\n  function calculatePayrollBurnrate() constant returns (uint256); // Monthly EUR amount spent in salaries\n  function calculatePayrollRunway() constant returns (uint256); // Days until the contract can run out of funds\n\n  /* EMPLOYEE ONLY */\n  function determineAllocation(address[] tokens, uint256[] distribution); // only callable once every 6 months\n  function payday(); // only callable once a month\n\n  /* ORACLE ONLY */\n  function setExchangeRate(address token, uint256 EURExchangeRate); // uses decimals from token\n}\n```\n\n## The solution\nThis is a solidity smart contract to manage an employee payroll based on ERC20 tokens. The contract owner may\nadd new supported tokens into the contract and whitelist different types of tokens for each employee, so they can withdraw their payments in tokens according to a distribution that is set by the employee.\n\nThe default token supported is the EURT, which is a token that represents the EUR currency. I also added the USD Token, USDT. Any transaction that attempts to send ether to the Payroll contract will be reverted. Ether is not allowed.\n\nEmployees are allowed to withdraw their payment only once a month and, each six months they can define a new token distribution, but for the whitelisted tokens.\n\nBesides that, the contract owner is able to block/allow payments in case of an emergency. Additional information about each employee, payments, distributions and supported tokens is available.\n\n\n\n### Constructor\n```solidity\nfunction Payroll(address _defaultOracle, address _tokenEURAddress, uint256 _EURExchangeRate) //default constructor with oracle address and default EUR token details\n```\n\n### Owner Functions\n```solidity\nfunction allowToken(address _employeeAddress, address _token, uint256 _EURExchangeRate) external;\nfunction addSupportedToken(address _token, uint256 _EURExchangeRate) public;\nfunction claimTokenFunds(address tokenAddress) external;\nfunction calculatePayrollBurnrate() public constant returns (uint256); // Monthly EUR amount spent in salaries\nfunction calculatePayrollRunway(address _token) external constant returns (uint256); // Days until the contract can run out of funds based on each token\nfunction blockPayments() external;\nfunction allowPayments() external;\nfunction setOracle(address _newOracleAddress) external;\nfunction destroy() external;\n\nfunction addEmployee(address _employeeAddress, uint256 _initialYearlyEURSalary) external;\nfunction getEmployee(address _employeeAddress) external constant returns (\n    uint256 _yearlyEURSalary,\n    uint256 _totalReceivedEUR,\n    address[] _allowedTokens);\nfunction removeEmployee(address _employeeAddress) external;\nfunction setEmployeeSalary(address _employeeAddress, uint256 _yearlyEURSalary) external;\nfunction getEmployeeCount() external constant returns (uint256);\nfunction getEmployeePayment(address _employeeAddress, address _token) external constant returns (\n    uint256 _EURExchangeRate,\n    uint _lastAllocationTime,\n    uint _lastPaymentTime,\n    uint256 _distributionMontlyAmount);\n```\n\n### Employee Functions\n```solidity\nfunction determineAllocation(address _token, uint256 _distributionMontlyAmount) external; // only callable once every 6 months\nfunction payday(address _token) external; // only callable once a month and releases the funds according to distribution so employee can withdraw\n```\n\n### Oracle Functions\n```solidity\nfunction setExchangeRate(address _token, uint256 _newEURExchangeRate) external; // uses decimals from token\n```\n\n### Considerations\n - Instead of passing a list of tokens with an arbitrary size to calculate \n the distribution or receive payments, it now accepts only 1 token at time, so it prevents problems with maximum block size and we don't have to implement loop caching for arrays with arbitraty length;\n - The destroy function terminates the contract and returns the funds to the contract owner;\n - Implemented a very basic ERC20 EURT and USDT tokens without allowance in order to transfer token funds using\n a token contract. The EURT is the default token. More tokens can be easily added; It is based on tokens from Open Zeppelin lib;\n - Assumed we can trust 100% in the oracle exchange rates; It can be improved later;\n - The contract relies on a default oracle address and default EURT address provided via constructor args;\n - Added fallback functions for token and ether;\n - The test accounts are available on `script/ganache-cli.sh` script which uses custom balances to \n execute the truffle test `test/PayrollContractTest.js`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffforbeck%2Fpayroll-smartcontract","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffforbeck%2Fpayroll-smartcontract","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffforbeck%2Fpayroll-smartcontract/lists"}