Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Payroll Milestone 1 - Addressing review comments #568

Merged
merged 38 commits into from
Dec 14, 2018

Conversation

lmcorbalan
Copy link
Contributor

@lmcorbalan lmcorbalan commented Nov 9, 2018

Resolves protofire#48

This PR is meant for addressing @sohkai, @bingen and @Quazia comments on PR #479

Following there is the list of comments that we are going to address in this PR:

  • sohkai - Remove contracts/Migrations.sol
  • sohkai - Remove migrations/2_deploy_contracts.js
  • sohkai - payroll/package.json - Pin dependecies version (@aragon/apps-finance, @aragon/os, @aragon/os, @aragon/ppf-contracts)

Payroll.sol

  • bingen - Use EtherTokenConstant from aragonOS
  • sohkai - prune public constants
  • bingen/sohkai - take name out of the struct and leave it in the event
  • sohkai - use uint256 for employeeId
  • bingen - tight variable packing
  • sohkai - indexing employee address in events
  • bingen - use messages for require
  • binge - use isContract for checking _finance
  • sohkai - about some role params
  • bingen/sohkai - addEmployee params and multiple implementations
  • sohkai - use _ prefix for function arguments
  • sohkai - remove escapeHatch function
  • sohkai - remove depositToFinance function
  • bingen - remove isInitialized from functions that also check for employeeMatches
  • bingen - remove unused variable in payday
  • sohkai - change to storage empoyee in getEmployeeByAddress and getEmployee
  • sohkai - make getters as public
  • sohkai - change getAllocation API, add _employeeId param
  • bingen - remove isInitialized from _addEmployee
  • sohkai - Improve gas efficiency when adding an employee
  • sohkai - Increase minimun rate expiry time
  • sohkai - employee enDate check on _payTokens
  • sohkai - add generic reference when calling finance.newPayment
  • sohkai - use storage variable for calling multiple times the same mapping (in _payTokens)
  • sohkai - Add dates check in _getOwnedSalary instead of using safe math
  • sohkai - Update getExchangeRate docs

PayrollKit.sol

  • Quazia/sohkai - initialize vault

Unit Tests

  • Check and fix unit tests broken by code review changes

- Make getters as public

- Delete Migrations.sol since it's been imported in TestImports.sol

- Remove unused migration file

- Prune some public constants

- Make employeeId uint256

- Fix some role params

- Add _ prefix for function arguments

- Move MAX_ACCRUED_VALUE check to _addAccruedValue function

- Remove escapeHatch function

- Some minor changes from code review

- Transform getAllocation into a more generic getter

- Improve gas efficiency when adding an employee

- Increase minimun rate expiry time

- Some minor changes from code review

- Add dates check in _getOwnedSalary

- Ammend _getExchangeRate docs

- Add generic reference when calling finance newPayment

- Bump some dependencies versions

- Fix contract unit test
@coveralls
Copy link

coveralls commented Nov 9, 2018

Coverage Status

Coverage remained the same at 96.124% when pulling d2818ac on protofire:payroll-milestone-1-review into e25aa4b on aragon:master.

Copy link
Contributor

@sohkai sohkai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lmcorbalan Thanks for making the changes! It's looking really good!

I added a number of commits, mostly just to smooth some things out that were easier to do myself, like little comment tweaks or rewording :).

I think there's still three changes we could make (cc @bingen @izqui):

  1. Add a recoverToVault() or recoverToFinance() function, since it's nicer to do it this way to generate an event from the Vault rather than using the generic recoverability functionality. Debating if we should just deposit straight into the Vault that the Finance app's attached to (leaning towards it, since it's leaner as a recovery mechanism).
  2. Decide if we should remove the deletion of terminated employees, or remove the terminated storage. Given the latter being leaner, and realistically there being very little chance you'd want to know if an employee was terminated on-chain rather than an employee simply existing, I'm also leaning on the latter.
    ⚠️ Note that the latter would mean you can do things like change someone's salary, add accrued value, or even change their termination date up to their actual termination date, rather when the call to terminate() happened (as it is now). I find the current behaviour a bug.
  3. Add the ability for an employee to withdraw their accrued value, without factoring in the time from their last pay date. I think this is a much more robust way to solve the denial of service issue that's somewhat mitigated by MAX_ACCRUED_VALUE.

I couldn't get coverage to run in a reasonable amount of time, due to how dependencies completely blow up the instrumentation, so it might be time to give up on it for the moment...

@@ -57,47 +58,42 @@ contract('Payroll, adding and removing employees,', function(accounts) {
})

it("adds employee", async () => {
let name = ''
let name = 'Kakaroto'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😄 🐵

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I had to google it, I didn't know it has this name too, haha.

string private constant ERROR_EMPLOYEE_ALREADY_EXIST = "PAYROLL_EMPLOYEE_ALREADY_EXIST";
string private constant ERROR_NULL_ADDRESS = "PAYROLL_NULL_ADDRESS";
string private constant ERROR_NO_FORWARD = "PAYROLL_NO_FORWARD";
string private constant ERROR_RATE_EXPIRY_TIME_TOO_SHORT = "PAYROLL_RATE_EXPIRE_TIME_TOO_SHORT";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bingen can confirm, but I think we need to limit the error strings' length to be <= 32 chars to avoid eating up another 32 bytes of memory?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, @izqui knows better, but that was the assumption when we added them to aragon OS.

uint256 initialDenominationSalary,
string name,
uint64 startDate
function addEmployeeWithStartDate(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we just make this an overload of addEmployee()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function overload still not working with Truffle... 😞
trufflesuite/truffle#737
trufflesuite/truffle#569

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh yeah, we generally fix that with a mock, e.g. VotingMock

string private constant ERROR_RATE_EXPIRY_TIME_TOO_SHORT = "PAYROLL_RATE_EXPIRE_TIME_TOO_SHORT";
string private constant ERROR_EXCHANGE_RATE_ZERO = "PAYROLL_EXCHANGE_RATE_ZERO";
string private constant ERROR_PAST_TERMINATION_DATE = "PAYROLL_PAST_TERMINATION_DATE";


struct Employee {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed in #576 and in our designs we have a "role" field...

If this is going to work we'll need to add another param to addEmployee() and capture the role in an event.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been thinking about this, and I think we should either remove the "role" field entirely from the mock ups, or include a way to change an employee's title. Leaning towards the latter, as a function protected behind a MANAGE_EMPLOYEE_TITLE_ROLE role, that could just emit an event with the employee's id and their new title.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'd rather to do this change in #576, it will affect the app state management and we made a big change on it there

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We finally made this change here, this is the most "updated" contract version, once it gets merged we can make the changes in the front end.

Copy link
Contributor

@bingen bingen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really good job indeed, @lmcorbalan !!
Replying to @sohkai:

  1. But this is what the old functions escapeHatch and depositToFinance were doing, isn't it? I thought you wanted to remove them. If we do a custom recovery here, I would go through Finance, as this way it gets properly registered there.
  2. I would just remove terminated employees to avoid having to deal with re-enabling. I don't think I fully understand your Note there.
  3. It's quite a hard problem. I like this idea of being able to withdraw accrued value independently from Payroll. But we would still have the problem of the employer setting a value larger than existing funds. See discussion here

@@ -43,53 +61,56 @@ contract Payroll is AragonApp { //, IForwarder { // makes coverage crash (remove
uint64 lastPayroll;
uint64 endDate;
bool terminated;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need terminated? Isn't it enough with endDate? See discussion here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, not really, see more discussion here

}
}

function _terminateEmployee(uint128 employeeId, uint64 endDate) internal {
// prevent past termination dates
require(endDate >= getTimestamp64());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See this comment. Pinging @izqui

@sohkai
Copy link
Contributor

sohkai commented Nov 19, 2018

@bingen

But this is what the old functions escapeHatch and depositToFinance were doing, isn't it?

I think a depositToFinance() or depositToVault() would still be useful, since it'll properly register the deposit with an event rather than being a silent transfer. The previous implementation didn't support ETH though.

I would just remove terminated employees to avoid having to deal with re-enabling. I don't think I fully understand your Note there.

Hmm, interesting note in #394 (comment).

My warning was that right now, it would be impossible to change an employee's details once they've been terminated due to the employeeExists modifier. Even if you terminate an employee, you may still want to change their salary, or even change their end date before their termination date (e.g., you might sign a 1-year contract and automatically set the end date to a year in the future).

Perhaps changing this modifier's behaviour may be better.

It's quite a hard problem. I like this idea of being able to withdraw accrued value independently from Payroll. But we would still have the problem of the employer setting a value larger than existing funds.

This seems like a general problem with this app and how it does accounting. Unless the employee can verify the employer's funds, they have no way to know if even payday() will work regardless of accumulated value. Having a cap of 2**128 is pretty artificial too; it's unlikely any employer would have enough if you add that much.

Maybe instead of choosing whether payday() should also pay your regular salary, we can instead add an optional value to let you choose how much you'd like to take out?

@lmcorbalan
Copy link
Contributor Author

lmcorbalan commented Nov 20, 2018

I think a depositToFinance() or depositToVault() would still be useful, since it'll properly register the deposit with an event rather than being a silent transfer. The previous implementation didn't support ETH though.

Something like?

function depositToFinance(address _token) public isInitialized {
    ERC20 tokenContract = ERC20(_token);
    uint256 amount = _token == ETH ? address(this).balance : tokenContract.balanceOf(this);
    require(amount > 0, ERROR_RECOVER_AMOUNT_ZERO);
    
    tokenContract.approve(address(finance), value);
    finance.deposit(tokenContract,  amount,  "Adding Funds");
}

@sohkai
Copy link
Contributor

sohkai commented Dec 14, 2018

@lmcorbalan I've added a few commits that clean up some formatting and a bit of the testing.

Going on the depositToVault() discussion, I realized that this contract disallows receiving ETH and so only tokens can be mistakenly sent to it. Given that this is not a contract that is meant to receive tokens (unlike the Finance app), I think we can treat it as any other app and just use the default recoverability functionality included in all apps.


The remaining things left to think about, then, are:

  1. terminated status (see PR: Payroll: remove terminated storage and change exist modifier for activeness check #610)
  2. Accrued value denial-of-service mitigation (is there a strategy that better protects the receiver from the employer acting in bad faith; e.g. out of fund situations or overflowing an employee's accrued value?)

And will be addressed later.

@sohkai sohkai merged commit 487e0f8 into aragon:master Dec 14, 2018
@sohkai sohkai deleted the payroll-milestone-1-review branch December 14, 2018 10:52
ramilexe pushed a commit to ConsiderItDone/aragon-apps that referenced this pull request Dec 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Address review comments related to contract and kit on Milestone 1 PR #479
4 participants