Skip to content

Commit

Permalink
#40
Browse files Browse the repository at this point in the history
  • Loading branch information
enkogu committed Dec 20, 2018
1 parent 2bee904 commit e36ea1f
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 156 deletions.
170 changes: 83 additions & 87 deletions contracts/WeiTable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,25 +50,10 @@ contract WeiTable is IWeiReceiver, Ownable {
bool isOpen;
uint[] outputs;
Type splitterChildrenType;

}

modifier nothingIfClosed(uint _eId) {
if(isOpenAt(_eId)) {
_;
}
}

modifier nothingIfClosedOrNoNeed(uint _eId) {
if(isNeedsMoneyAt(_eId) && isOpenAt(_eId)) {
_;
}
}

modifier isCorrectId(uint _eId) {
if(_eId > (nodesCount - 1)) {
revert();
}
require(_eId <= (nodesCount - 1));
_;
}

Expand All @@ -77,7 +62,7 @@ contract WeiTable is IWeiReceiver, Ownable {
}

function getLastNodeId() public returns(uint) {
if(nodesCount==0) {
if(nodesCount == 0) {
return 0;
} else {
return nodesCount - 1;
Expand All @@ -89,29 +74,33 @@ contract WeiTable is IWeiReceiver, Ownable {
ppm = expenses[_eId].neededPpm;
}

function isNeedsMoneyAt(uint _eId) public view nothingIfClosed(_eId) isCorrectId(_eId) returns(bool isNeed) {
function isNeedsMoneyAt(uint _eId) public view isCorrectId(_eId) returns(bool) {
if(!isOpenAt(_eId)) {
return false;
}

if(isExpenseAt(_eId)) {
isNeed = isNeedsMoneyExpenseAt(_eId);
return isNeedsMoneyExpenseAt(_eId);
}else {
isNeed = isNeedsMoneySplitterAt(_eId);
return isNeedsMoneySplitterAt(_eId);
}
}

function isNeedsMoneySplitterAt(uint _eId) internal view nothingIfClosed(_eId) isCorrectId(_eId) returns(bool isNeed) {
function isNeedsMoneySplitterAt(uint _eId) internal view returns(bool isNeed) {
for(uint i=0; i<splitters[_eId].outputs.length; i++) { // if at least 1 child needs money -> return true
if(isNeedsMoneyAt(splitters[_eId].outputs[i])) {
isNeed = true;
}
}
}

function isNeedsMoneyExpenseAt(uint _eId) internal view nothingIfClosed(_eId) isCorrectId(_eId) returns(bool isNeed) {
function isNeedsMoneyExpenseAt(uint _eId) internal view returns(bool isNeed) {
Expense e = expenses[_eId];
if(e.isPeriodic) {
if ((uint64(block.timestamp) - e.momentReceived) >= e.periodHours * 3600 * 1000) {
isNeed = true;
}
} else if((e.minWeiAmount==0)&&(e.totalWeiNeeded>0)) {
} else if((e.minWeiAmount == 0) && (e.totalWeiNeeded>0)) {
isNeed = ((getDebtMultiplierAt(_eId) * e.totalWeiNeeded) - e.totalWeiReceived) > 0;
} else if((e.minWeiAmount>0) && (e.minWeiAmount < e.totalWeiNeeded)) {
isNeed = (e.totalWeiNeeded - e.totalWeiReceived) > 0;
Expand All @@ -120,66 +109,68 @@ contract WeiTable is IWeiReceiver, Ownable {
}
}

function processFundsAt(uint _eId, uint _currentFlow, uint _amount) internal nothingIfClosed(_eId) isCorrectId(_eId) {
if(isExpenseAt(_eId)) {
function processFundsAt(uint _eId, uint _currentFlow, uint _amount) internal isCorrectId(_eId) {
require(isNeedsMoneyAt(_eId));
require(_amount >= getMinWeiNeededAt(_eId, _currentFlow));
require(_amount == getTotalWeiNeededAt(_eId, _currentFlow));
require(_currentFlow >= getMinWeiNeededAt(_eId, _currentFlow));
require(_currentFlow >= _amount);
if(isExpenseAt(_eId)) {
processFundsExpenseAt(_eId, _currentFlow, _amount);
} else {
processFundsSplitterAt(_eId, _currentFlow, _amount);
}
}

function processFundsSplitterAt(uint _eId, uint _currentFlow, uint _amount) internal nothingIfClosedOrNoNeed(_eId) isCorrectId(_eId) {
function processFundsSplitterAt(uint _eId, uint _currentFlow, uint _amount) internal {
FlowBuffer memory b = FlowBuffer(_currentFlow, false, 0, 0, 0);
for(uint i=0; i<splitters[_eId].outputs.length; i++) {
b.i = i;
b.need = getTotalWeiNeededAt(splitters[_eId].outputs[i], b.flow);
b = _relativesStreak(_eId, b);
if(b.need!=0) {
b = _processRelativeSeries(_eId, b);
if(b.need != 0) {
processFundsAt(splitters[_eId].outputs[i], b.flow, b.need);
}
b = _modifyFlow(b);
}
// require(b.flow==0); TODO
// require(b.flow == 0); TODO
}

function processFundsExpenseAt(uint _eId, uint _currentFlow, uint _amount) internal nothingIfClosedOrNoNeed(_eId) isCorrectId(_eId) {
// TODO: check requires
require(isNeedsMoneyAt(_eId));
require(_amount >= getMinWeiNeededAt(_eId, _currentFlow));
require(_amount == getTotalWeiNeededAt(_eId, _currentFlow));
require(_currentFlow >= getMinWeiNeededAt(_eId, _currentFlow));
require(_currentFlow >= _amount);
// all inputs divide _minWeiAmount == INTEGER
function processFundsExpenseAt(uint _eId, uint _currentFlow, uint _amount) internal {
expenses[_eId].totalWeiReceived += _amount;
expenses[_eId].balance += _amount;
expenses[_eId].isMoneyReceived = true;

if((getTotalWeiNeededAt(_eId, _amount)==0) || (expenses[_eId].isPeriodic)) {
if((getTotalWeiNeededAt(_eId, _amount) == 0) || (expenses[_eId].isPeriodic)) {
expenses[_eId].momentReceived = block.timestamp;
expenses[_eId].balanceOnMomentReceived = expenses[_eId].totalWeiReceived;
}
}

function getMinWeiNeededAt(uint _eId, uint _currentFlow) public view nothingIfClosedOrNoNeed(_eId) isCorrectId(_eId) returns(uint minNeed) {
function getMinWeiNeededAt(uint _eId, uint _currentFlow) public view isCorrectId(_eId) returns(uint) {
if(!isNeedsMoneyAt(_eId)) {
return 0;
}

if(isExpenseAt(_eId)) {
minNeed = getMinWeiNeededExpenseAt(_eId, _currentFlow);
return getMinWeiNeededExpenseAt(_eId, _currentFlow);
}else {
minNeed = getMinWeiNeededSplitterAt(_eId, _currentFlow);
return getMinWeiNeededSplitterAt(_eId, _currentFlow);
}
}

function getMinWeiNeededSplitterAt(uint _eId, uint _currentFlow) internal view nothingIfClosedOrNoNeed(_eId) isCorrectId(_eId) returns(uint minNeed) {
function getMinWeiNeededSplitterAt(uint _eId, uint _currentFlow) internal view returns(uint minNeed) {
FlowBuffer memory b = FlowBuffer(_currentFlow, false, 0, 0, 0);
for(uint i=0; i<splitters[_eId].outputs.length; i++) {
b.i = i;
b.need = getMinWeiNeededAt(splitters[_eId].outputs[i], b.flow);
b = _relativesStreak(_eId, b);
b = _processRelativeSeries(_eId, b);
minNeed += b.need;
b = _modifyFlow(b);
}
}

function getMinWeiNeededExpenseAt(uint _eId, uint _currentFlow) internal view nothingIfClosedOrNoNeed(_eId) isCorrectId(_eId) returns(uint totalNeed) {
function getMinWeiNeededExpenseAt(uint _eId, uint _currentFlow) internal view returns(uint totalNeed) {
if( !((expenses[_eId].minWeiAmount == 0) && (expenses[_eId].totalWeiNeeded > 0))
&& !(expenses[_eId].neededPpm > 0) ) {
totalNeed = getTotalWeiNeededAt(_eId, _currentFlow);
Expand All @@ -188,46 +179,51 @@ contract WeiTable is IWeiReceiver, Ownable {

function getDebtMultiplierAt(uint _eId) internal isCorrectId(_eId) view returns(uint) {
Expense e = expenses[_eId];
if((e.isPeriodic)&&(!e.isSlidingAmount)&&((block.timestamp - e.momentReceived) / (e.periodHours * 3600 * 1000) >=1)) {
if(0!=e.neededPpm) {
// if periodic, not sliding amount and periods Count From Last Receive > 1
if((e.isPeriodic) && (!e.isSlidingAmount) && (((block.timestamp - e.momentReceived) / (e.periodHours * 3600 * 1000)) >= 1)) {
if(0 != e.neededPpm) {
return 1;
} else {
return (e.balanceOnMomentReceived/e.totalWeiNeeded) + 1;
}
} else if((e.isPeriodic)&&(e.isSlidingAmount)) {
return 1 + ((block.timestamp - e.momentCreated) / (e.periodHours * 3600 * 1000));
} else if((e.isPeriodic) && (e.isSlidingAmount)) {
return 1 + ((block.timestamp - e.momentReceived) / (e.periodHours * 3600 * 1000));
} else {
return 1;
}
}

function getTotalWeiNeededAt(uint _eId, uint _currentFlow) public view nothingIfClosedOrNoNeed(_eId) isCorrectId(_eId) returns(uint totalNeed) {
function getTotalWeiNeededAt(uint _eId, uint _currentFlow) public view isCorrectId(_eId) returns(uint) {
if(!isNeedsMoneyAt(_eId)) {
return 0;
}

if(isExpenseAt(_eId)) {
totalNeed = getTotalWeiNeededExpenseAt(_eId, _currentFlow);
return getTotalWeiNeededExpenseAt(_eId, _currentFlow);
} else {
totalNeed = getTotalWeiNeededSplitterAt(_eId, _currentFlow);
return getTotalWeiNeededSplitterAt(_eId, _currentFlow);
}
}

function getTotalWeiNeededSplitterAt(uint _eId, uint _currentFlow)internal view nothingIfClosedOrNoNeed(_eId) isCorrectId(_eId) returns(uint totalNeed) {
function getTotalWeiNeededSplitterAt(uint _eId, uint _currentFlow)internal view returns(uint totalNeed) {
FlowBuffer memory b = FlowBuffer(_currentFlow, false, 0, 0, 0);
for(uint i=0; i<splitters[_eId].outputs.length; i++) {
for(uint i = 0; i < splitters[_eId].outputs.length; i++) {
b.i = i;
b.need = getTotalWeiNeededAt(splitters[_eId].outputs[i], b.flow);
b = _relativesStreak(_eId, b);
b = _processRelativeSeries(_eId, b);
totalNeed += b.need;
b = _modifyFlow(b);
}
}

function getTotalWeiNeededExpenseAt(uint _eId, uint _currentFlow)internal view nothingIfClosedOrNoNeed(_eId) isCorrectId(_eId) returns(uint totalNeed) {
function getTotalWeiNeededExpenseAt(uint _eId, uint _currentFlow)internal view returns(uint totalNeed) {
Expense e = expenses[_eId];
if(0!=e.neededPpm) {
totalNeed = ((getDebtMultiplierAt(_eId)*(e.neededPpm * _currentFlow)) / 1000000);
if(0 != e.neededPpm) {
totalNeed = ((getDebtMultiplierAt(_eId) * (e.neededPpm * _currentFlow)) / 1000000);

} else if(getDebtMultiplierAt(_eId)*e.totalWeiNeeded > e.totalWeiReceived) {
totalNeed = getDebtMultiplierAt(_eId)*e.totalWeiNeeded - e.totalWeiReceived;
if((e.minWeiAmount==0)&&(e.totalWeiNeeded>0)) {
} else if(getDebtMultiplierAt(_eId) * e.totalWeiNeeded > e.totalWeiReceived) {
totalNeed = getDebtMultiplierAt(_eId) * e.totalWeiNeeded - e.totalWeiReceived;
if((e.minWeiAmount == 0) && (e.totalWeiNeeded>0)) {
if(totalNeed > _currentFlow) {
totalNeed = _currentFlow;
}
Expand All @@ -245,12 +241,12 @@ contract WeiTable is IWeiReceiver, Ownable {
}
}

function balanceAt(uint _eId)public view isCorrectId(_eId) returns(uint) {
function balanceAt(uint _eId) public view isCorrectId(_eId) returns(uint) {
return expenses[_eId].balance;
}

// -------------------- public IWEIRECEIVER FUNCTIONS -------------------- for all table
function isNeedsMoney()view public returns(bool) {
function isNeedsMoney() public view returns(bool) {
return isNeedsMoneyAt(0);
}

Expand All @@ -264,11 +260,11 @@ contract WeiTable is IWeiReceiver, Ownable {
return processFundsAt(0, _currentFlow, msg.value);
}

function getMinWeiNeeded(uint _currentFlow)public view returns(uint) {
function getMinWeiNeeded(uint _currentFlow) public view returns(uint) {
return getMinWeiNeededAt(0, _currentFlow);
}

function getTotalWeiNeeded(uint _currentFlow)public view returns(uint) {
function getTotalWeiNeeded(uint _currentFlow) public view returns(uint) {
return getTotalWeiNeededAt(0, _currentFlow);
}

Expand All @@ -283,22 +279,22 @@ contract WeiTable is IWeiReceiver, Ownable {
emit NodeAdded(nodesCount, Type.Absolute);
nodesCount += 1;
// TODO: add requires
require(!((_isSlidingAmount)&&(_periodHours==0)));
require(!(!(_isPeriodic)&&(_periodHours!=0)));
require(!((_isSlidingAmount)&&(!_isPeriodic)));
require(!((_totalWeiNeeded==0)&&(_minWeiAmount!=0)));

require(_minWeiAmount<=_totalWeiNeeded);
if(_minWeiAmount!=0) {
require(_totalWeiNeeded%_minWeiAmount==0);
require(!((_isSlidingAmount) && (_periodHours == 0)));
require(!(!(_isPeriodic) && (_periodHours != 0)));
require(!((_isSlidingAmount) && (!_isPeriodic)));
require(!((_totalWeiNeeded == 0) && (_minWeiAmount != 0)));

require(_minWeiAmount <= _totalWeiNeeded);
if(_minWeiAmount != 0) {
require(_totalWeiNeeded%_minWeiAmount == 0);
}
}

function addRelativeExpense(uint _neededPpm, bool _isPeriodic, bool _isSlidingAmount, uint _periodHours)public onlyOwner {
function addRelativeExpense(uint _neededPpm, bool _isPeriodic, bool _isSlidingAmount, uint _periodHours) public onlyOwner {
// TODO: add requires
require(!((_isSlidingAmount)&&(_periodHours==0)));
require(!(!(_isPeriodic)&&(_periodHours!=0)));
require(!((_isSlidingAmount)&&(!_isPeriodic)));
require(!((_isSlidingAmount) && (_periodHours == 0)));
require(!(!(_isPeriodic) && (_periodHours != 0)));
require(!((_isSlidingAmount) && (!_isPeriodic)));
expenses[nodesCount] = Expense(
0, 0, _neededPpm,
_periodHours, _isPeriodic, _isSlidingAmount,
Expand All @@ -309,17 +305,17 @@ contract WeiTable is IWeiReceiver, Ownable {
nodesCount += 1;
}

function addSplitter()public onlyOwner {
function addSplitter() public onlyOwner {
uint[] memory emptyOutputs;
splitters[nodesCount] = Splitter(true, emptyOutputs, Type.Splitter);
nodesType[nodesCount] = Type.Splitter;
emit NodeAdded(nodesCount, Type.Splitter);
nodesCount += 1;
}

function addChildAt(uint _splitterId, uint _childId)public onlyOwner {
if((splitters[_splitterId].splitterChildrenType!=Type.Splitter)
&&(getReceiverTypeAt(_childId)!=Type.Splitter)) {
function addChildAt(uint _splitterId, uint _childId) public onlyOwner {
if((splitters[_splitterId].splitterChildrenType != Type.Splitter)
&& (getReceiverTypeAt(_childId) != Type.Splitter)) {
require(getReceiverTypeAt(_childId) == splitters[_splitterId].splitterChildrenType);
} else {
splitters[_splitterId].splitterChildrenType = getReceiverTypeAt(_childId);
Expand Down Expand Up @@ -359,7 +355,7 @@ contract WeiTable is IWeiReceiver, Ownable {
}
}

function closeAt(uint _eId)public onlyOwner isCorrectId(_eId) {
function closeAt(uint _eId) public onlyOwner isCorrectId(_eId) {
if(isExpenseAt(_eId)) {
expenses[_eId].isOpen = false;
}else if(isSplitterAt(_eId)) {
Expand All @@ -377,24 +373,24 @@ contract WeiTable is IWeiReceiver, Ownable {
}
}

function getChildrenCountAt(uint _eId)public view isCorrectId(_eId) returns(uint) {
function getChildrenCountAt(uint _eId) public view isCorrectId(_eId) returns(uint) {
require(isSplitterAt(_eId));
return splitters[_eId].outputs.length;
}

function getChildIdAt(uint _eId, uint _index)public view isCorrectId(_eId) returns(uint) {
function getChildIdAt(uint _eId, uint _index) public view isCorrectId(_eId) returns(uint) {
require(isSplitterAt(_eId));
require(splitters[_eId].outputs.length > _index);
return splitters[_eId].outputs[_index];
}

function flushAt(uint _eId)public onlyOwner isCorrectId(_eId) {
function flushAt(uint _eId) public onlyOwner isCorrectId(_eId) {
owner.transfer(expenses[_eId].balance);
emit NodeFlushTo(_eId, owner, expenses[_eId].balance);
expenses[_eId].balance = 0;
}

function flushToAt(uint _eId, address _to)public onlyOwner isCorrectId(_eId) {
function flushToAt(uint _eId, address _to) public onlyOwner isCorrectId(_eId) {
_to.transfer(expenses[_eId].balance);
emit NodeFlushTo(_eId, _to, expenses[_eId].balance);
expenses[_eId].balance = 0;
Expand All @@ -415,7 +411,7 @@ contract WeiTable is IWeiReceiver, Ownable {
return b;
}

function _relativesStreak(uint _splitterId, FlowBuffer _b) internal view returns(FlowBuffer) {
function _processRelativeSeries(uint _splitterId, FlowBuffer _b) internal view returns(FlowBuffer) {
FlowBuffer memory b = _b;
if(b.relSeqQ) {
b.needAcc += b.need;
Expand All @@ -426,7 +422,7 @@ contract WeiTable is IWeiReceiver, Ownable {

if((b.i+1) < splitters[_splitterId].outputs.length) {
if((getReceiverTypeAt(splitters[_splitterId].outputs[b.i]) == Type.Relative)
&&(getReceiverTypeAt(splitters[_splitterId].outputs[b.i+1]) == Type.Relative)) {
&& (getReceiverTypeAt(splitters[_splitterId].outputs[b.i+1]) == Type.Relative)) {
b.relSeqQ = true;
}
}
Expand Down
12 changes: 0 additions & 12 deletions contracts/ether/SplitterBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,6 @@ contract SplitterBase is ISplitter, Ownable {
bool opened = true;
mapping (uint=>address) children;
uint childrenCount = 0;

modifier zeroIfClosed() {
if(isOpen()) {
_;
}
}

modifier falseIfClosed() {
if(isOpen()) {
_;
}
}

modifier onlyIfOpen() {
require(isOpen());
Expand Down
Loading

0 comments on commit e36ea1f

Please sign in to comment.