Skip to content

Commit

Permalink
#45
Browse files Browse the repository at this point in the history
  • Loading branch information
enkogu committed Dec 21, 2018
1 parent a5f80ba commit 58aa851
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 70 deletions.
133 changes: 67 additions & 66 deletions contracts/ether/ExpenseBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand All @@ -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);
}
Expand All @@ -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;
}
Expand Down
8 changes: 4 additions & 4 deletions contracts/ether/WeiExpense.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit 58aa851

Please sign in to comment.