diff --git a/contracts/ether/ExpenseBase.sol b/contracts/ether/ExpenseBase.sol index 8ca2d25..9202cbf 100644 --- a/contracts/ether/ExpenseBase.sol +++ b/contracts/ether/ExpenseBase.sol @@ -14,83 +14,84 @@ import "zeppelin-solidity/contracts/ownership/Ownable.sol"; */ contract ExpenseBase { event ExpenseFlush(address _owner, uint _balance); - event ExpenseSetNeededWei(uint _totalWeiNeeded); + event ExpenseSetNeeded(uint _totalNeeded); event ExpenseSetPercents(uint _partsPerMillion); event ExpenseProcessFunds(address _sender, uint _value, uint _currentFlow); struct Expense { - uint128 totalWeiNeeded; - uint128 minWeiAmount; + uint128 totalNeeded; + uint128 minAmount; uint32 partsPerMillion; uint32 periodHours; - // PeriodType periodType; - bool isPeriodic; - bool isSlidingAmount; + PeriodType periodType; uint32 momentReceived; - // bool isMoneyReceived; - // bool isOpen; - // uint balance; + uint128 balance; - uint128 totalWeiReceived; + uint128 totalReceived; uint32 momentCreated; - // uint balanceOnMomentReceived; } enum PeriodType { NonPeriodic, Periodic, - PeriodicWithSlidingAmount + PeriodicSliding } /** * @dev constructExpense - * @param _totalWeiNeeded - absolute value. how much Ether this e should receive (in Wei). Can be zero (use _partsPerMillion in this case) + * @param _totalNeeded - absolute value. how much Ether this e should receive (in Wei). Can be zero (use _partsPerMillion in this case) * @param _partsPerMillion - if need to get % out of the input flow -> specify this parameter (1% is 10000 units) * @param _periodHours - if not isPeriodic and periodHours>0 ->no sense. if isPeriodic and periodHours == 0 -> needs money everytime. if isPeriodic and periodHours>0 -> needs money every period. - * @param _isSlidingAmount - if you don't pay in the current period -> will accumulate the needed amount (only for _totalWeiNeeded!) + * @param _isSlidingAmount - if you don't pay in the current period -> will accumulate the needed amount (only for _totalNeeded!) * @param _isPeriodic - if isPeriodic and periodHours>0 -> needs money every period. if isPeriodic and periodHours == 0 -> needs money everytime. */ - // _totalWeiNeeded divide _minWeiAmount == INTEGER - // all inputs divide _minWeiAmount == INTEGER - // if _totalWeiNeeded == 100 and _minWeiAmount == 5 + // _totalNeeded divide _minAmount == INTEGER + // all inputs divide _minAmount == INTEGER + // if _totalNeeded == 100 and _minAmount == 5 // you can send 5,10,15, but not 1, 2, 3, 4, 6, ... - function constructExpense(uint128 _totalWeiNeeded, uint128 _minWeiAmount, uint32 _partsPerMillion, uint32 _periodHours, bool _isSlidingAmount, bool _isPeriodic) internal view returns(Expense e){ + function constructExpense(uint128 _totalNeeded, uint128 _minAmount, uint32 _partsPerMillion, uint32 _periodHours, bool _isSlidingAmount, bool _isPeriodic) internal view returns(Expense e){ require(!((_isSlidingAmount) && (_periodHours == 0))); require(!(!(_isPeriodic) && (_periodHours != 0))); require(!((_isSlidingAmount) && (!_isPeriodic))); - require(!((_totalWeiNeeded == 0) && (_minWeiAmount != 0))); - require(!((_partsPerMillion != 0) && (_minWeiAmount != 0))); - require(!((_partsPerMillion != 0) && (_totalWeiNeeded != 0))); - require(_minWeiAmount <= _totalWeiNeeded); - if(_minWeiAmount != 0) { - require((_totalWeiNeeded % _minWeiAmount) == 0); + require(!((_totalNeeded == 0) && (_minAmount != 0))); + require(!((_partsPerMillion != 0) && (_minAmount != 0))); + require(!((_partsPerMillion != 0) && (_totalNeeded != 0))); + require(_minAmount <= _totalNeeded); + if(_minAmount != 0) { + require((_totalNeeded % _minAmount) == 0); } e.partsPerMillion = _partsPerMillion; e.periodHours = _periodHours; - e.totalWeiNeeded = _totalWeiNeeded; - e.isSlidingAmount = _isSlidingAmount; - e.isPeriodic = _isPeriodic; - e.minWeiAmount = _minWeiAmount; + e.totalNeeded = _totalNeeded; + e.minAmount = _minAmount; e.momentCreated = uint32(block.timestamp); + + if(!_isPeriodic) { + e.periodType = PeriodType.NonPeriodic; + } else if(_isPeriodic && !_isSlidingAmount) { + e.periodType = PeriodType.Periodic; + } else { + e.periodType = PeriodType.PeriodicSliding; + } } function processWeiFunds(Expense _e, uint _currentFlow, uint _value) internal view returns(Expense e) { e = _e; require(_value == getTotalNeeded(e, _currentFlow)); require(_currentFlow >= _value); - // all inputs divide _minWeiAmount == INTEGER + // all inputs divide _minAmount == INTEGER - e.totalWeiReceived += uint128(_value); + e.totalReceived += uint128(_value); // e.isMoneyReceived = true; - if((getTotalNeeded(_e, _value) == 0) || (_e.isPeriodic)) { + if((getTotalNeeded(_e, _value) == 0) || (_e.periodType == PeriodType.Periodic)) { e.momentReceived = uint32(block.timestamp); - // e.balanceOnMomentReceived = e.totalWeiReceived; + // e.balanceOnMomentReceived = e.totalReceived; } } @@ -100,73 +101,73 @@ contract ExpenseBase { uint periodLength = (_e.periodHours * 3600 * 1000); uint baseNeed; - if(_e.partsPerMillion != 0) { // if Absolute and (_e.minWeiAmount == _e.totalWeiNeeded) + if(_e.partsPerMillion != 0) { // if Absolute and (_e.minAmount == _e.totalNeeded) baseNeed = ((_e.partsPerMillion * _currentFlow) / 1000000); } else { - baseNeed = _e.totalWeiNeeded; + baseNeed = _e.totalNeeded; } - if(_e.minWeiAmount == _e.totalWeiNeeded) { - if(!_e.isPeriodic) { + if(_e.minAmount == _e.totalNeeded) { + if(_e.periodType == PeriodType.NonPeriodic) { need = baseNeed; - } else if(_e.isPeriodic && !_e.isSlidingAmount) { + } else if(_e.periodType == PeriodType.Periodic) { if(receiveTimeDelta >= periodLength) { need = baseNeed; } - } else if(_e.isPeriodic && _e.isSlidingAmount) { + } else if(_e.periodType == PeriodType.PeriodicSliding) { if(receiveTimeDelta >= periodLength) { - need = (baseNeed * numberOfEntitiesPlusOne(receiveTimeDelta, periodLength)) - _e.totalWeiReceived; + need = (baseNeed * numberOfEntitiesPlusOne(receiveTimeDelta, periodLength)) - _e.totalReceived; if(_e.momentReceived == 0) { need = baseNeed; } } - if((need > _currentFlow) && (_currentFlow > _e.totalWeiNeeded)) { - need = (_e.totalWeiNeeded * (_currentFlow / _e.totalWeiNeeded)) - _e.totalWeiReceived; + if((need > _currentFlow) && (_currentFlow > _e.totalNeeded)) { + need = (_e.totalNeeded * (_currentFlow / _e.totalNeeded)) - _e.totalReceived; } } - } else if(_e.minWeiAmount == 0) { - if(!_e.isPeriodic) { - if(_currentFlow >= (_e.totalWeiNeeded - _e.totalWeiReceived)) { - return (_e.totalWeiNeeded - _e.totalWeiReceived); + } else if(_e.minAmount == 0) { + if(_e.periodType == PeriodType.NonPeriodic) { + if(_currentFlow >= (_e.totalNeeded - _e.totalReceived)) { + return (_e.totalNeeded - _e.totalReceived); } else { return _currentFlow; } - } else if(_e.isPeriodic && !_e.isSlidingAmount) { + } else if(_e.periodType == PeriodType.Periodic) { need = getDebtIfNoSliding(_e); if(need > _currentFlow) { need = _currentFlow; } - } else if(_e.isPeriodic && _e.isSlidingAmount) { - need = ((numberOfEntitiesPlusOne(creationTimeDelta, periodLength) * _e.totalWeiNeeded) - _e.totalWeiReceived); + } else if(_e.periodType == PeriodType.PeriodicSliding) { + need = ((numberOfEntitiesPlusOne(creationTimeDelta, periodLength) * _e.totalNeeded) - _e.totalReceived); if(need > _currentFlow) { need = _currentFlow; } } - } else if(_e.minWeiAmount < _e.totalWeiNeeded) { - if(!_e.isPeriodic) { - if(_currentFlow >= (_e.totalWeiNeeded - _e.totalWeiReceived)) { - need = (_e.totalWeiNeeded - _e.totalWeiReceived); - } else if((_currentFlow < _e.totalWeiNeeded) && (_currentFlow >= _e.minWeiAmount)) { // change need for fund (with discrete input) if baseNeed >= _currentFlow - need = _currentFlow - (_currentFlow % _e.minWeiAmount); + } else if(_e.minAmount < _e.totalNeeded) { + if(_e.periodType == PeriodType.NonPeriodic) { + if(_currentFlow >= (_e.totalNeeded - _e.totalReceived)) { + need = (_e.totalNeeded - _e.totalReceived); + } else if((_currentFlow < _e.totalNeeded) && (_currentFlow >= _e.minAmount)) { // change need for fund (with discrete input) if baseNeed >= _currentFlow + need = _currentFlow - (_currentFlow % _e.minAmount); } - } else if(_e.isPeriodic && !_e.isSlidingAmount) { + } else if(_e.periodType == PeriodType.Periodic) { need = getDebtIfNoSliding(_e); - if((_currentFlow < _e.totalWeiNeeded) && (_currentFlow >= _e.minWeiAmount)) { // change need for fund (with discrete input) if baseNeed >= _currentFlow - need = _currentFlow - (_currentFlow % _e.minWeiAmount); + if((_currentFlow < _e.totalNeeded) && (_currentFlow >= _e.minAmount)) { // change need for fund (with discrete input) if baseNeed >= _currentFlow + need = _currentFlow - (_currentFlow % _e.minAmount); } - } else if(_e.isPeriodic && _e.isSlidingAmount) { - need = ((numberOfEntitiesPlusOne(creationTimeDelta, periodLength) * _e.totalWeiNeeded) - _e.totalWeiReceived); - if((_currentFlow < need) && (_currentFlow >= _e.minWeiAmount)) { // change need for fund (with discrete input) if baseNeed >= _currentFlow - need = _currentFlow - (_currentFlow % _e.minWeiAmount); + } else if(_e.periodType == PeriodType.PeriodicSliding) { + need = ((numberOfEntitiesPlusOne(creationTimeDelta, periodLength) * _e.totalNeeded) - _e.totalReceived); + if((_currentFlow < need) && (_currentFlow >= _e.minAmount)) { // change need for fund (with discrete input) if baseNeed >= _currentFlow + need = _currentFlow - (_currentFlow % _e.minAmount); } } } } function getMinNeeded(Expense _e, uint _currentFlow) internal view returns(uint minNeed) { - if( !((_e.minWeiAmount == 0) && (_e.totalWeiNeeded > 0)) + if( !((_e.minAmount == 0) && (_e.totalNeeded > 0)) && !(_e.partsPerMillion > 0) ) { minNeed = getTotalNeeded(_e, _currentFlow); } @@ -191,13 +192,13 @@ contract ExpenseBase { uint creationTimeDelta = (block.timestamp - _e.momentCreated); uint periodLength = (_e.periodHours * 3600 * 1000); - uint debtForAllPeriods = ((numberOfEntitiesPlusOne(creationTimeDelta, periodLength) * _e.totalWeiNeeded) - _e.totalWeiReceived); + uint debtForAllPeriods = ((numberOfEntitiesPlusOne(creationTimeDelta, periodLength) * _e.totalNeeded) - _e.totalReceived); if(debtForAllPeriods == 0) { return 0; - } else if((debtForAllPeriods % _e.totalWeiNeeded) > 0 ) { - return (debtForAllPeriods % _e.totalWeiNeeded); + } else if((debtForAllPeriods % _e.totalNeeded) > 0 ) { + return (debtForAllPeriods % _e.totalNeeded); } else if(numberOfEntitiesPlusOne(receiveTimeDelta, periodLength) > 1){ - return _e.totalWeiNeeded; + return _e.totalNeeded; } else { return 0; } diff --git a/contracts/ether/WeiExpense.sol b/contracts/ether/WeiExpense.sol index cde6132..ac2f1b2 100644 --- a/contracts/ether/WeiExpense.sol +++ b/contracts/ether/WeiExpense.sol @@ -35,11 +35,11 @@ contract WeiExpense is ExpenseBase, IWeiReceiver, IDestination, Ownable { } function getIsMoneyReceived() public view returns(bool) { - return expense.totalWeiReceived > 0; + return expense.totalReceived > 0; } function getNeededWei() public view returns(uint) { - return expense.totalWeiNeeded; + return expense.totalNeeded; } function getTotalWeiNeeded(uint _currentFlow)public view returns(uint) { @@ -74,8 +74,8 @@ contract WeiExpense is ExpenseBase, IWeiReceiver, IDestination, Ownable { } function setNeededWei(uint _totalWeiNeeded) public onlyOwner { - emit ExpenseSetNeededWei(_totalWeiNeeded); - expense.totalWeiNeeded = uint128(_totalWeiNeeded); + emit ExpenseSetNeeded(_totalWeiNeeded); + expense.totalNeeded = uint128(_totalWeiNeeded); } function setPercents(uint _partsPerMillion) public onlyOwner {