Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 175 additions & 0 deletions contracts/CreditRule.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
pragma solidity ^0.5.0;

// Copyright 2018 OpenST Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import "./SafeMath.sol";
import "./TokenRules.sol";
import "./TokenHolder.sol";
import "./EIP20TokenInterface.sol";

contract CreditRule {

/* Usings */

using SafeMath for uint256;


/* Struct */

struct CreditInfo {
uint256 amount;
bool inProgress;
}


/* Storage */

address public budgetHolder;

TokenRules public tokenRules;

mapping(address => CreditInfo) public credits;


/* Modifiers */

modifier onlyBudgetHolder()
{
require(
msg.sender == budgetHolder,
"Only budget holder is allowed to call."
);

_;
}


/* Special Functions */

constructor(
address _budgetHolder,
address _tokenRules
)
public
{
require(
_budgetHolder != address(0),
"Budget holder's address is null."
);

require(
_tokenRules != address(0),
"Token rules's address is null."
);

budgetHolder = _budgetHolder;

tokenRules = TokenRules(_tokenRules);
}


/* External Functions */

function executeRule(
uint256 _creditAmount,
address _to, // token holder address
bytes calldata _data // token holder execute rule data
)
external
payable
onlyBudgetHolder
returns(bool executionStatus_)
{
require(_to != address(0));

CreditInfo storage c = credits[_to];

require(
!c.inProgress,
"Re-entrancy occured in crediting process."
);

c.inProgress = true;
c.amount = _creditAmount;

bytes memory returnData;
// solium-disable-next-line security/no-call-value
(executionStatus_, returnData) = address(_to).call.value(msg.value)(_data);

c.amount = 0;
c.inProgress = false;
}

function executeTransfers(
address _from,
address[] calldata _transfersTo,
uint256[] calldata _transfersAmount
)
external
{
require(
credits[_from].inProgress,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

if no credit is in progress, executeTransfers should just pass on the data to TokenRules without transfering a credit and function normally, not revert

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Done.

"Crediting process is not in progress."
);

uint256 sumAmount = 0;

for(uint256 i = 0; i < _transfersAmount.length; ++i) {
sumAmount = sumAmount.add(_transfersAmount[i]);
}

uint256 creditAmount = credits[_from].amount;

uint256 amountToTransferFromBudgetHolder = (
sumAmount > creditAmount ? creditAmount : sumAmount
);

executeTransfer(
budgetHolder,
_from,
amountToTransferFromBudgetHolder
);

tokenRules.executeTransfers(
_from,
_transfersTo,
_transfersAmount
);
}


/* Private Functions */

function executeTransfer(
address _from,
address _beneficiary,
uint256 _amount
)
private
{
address[] memory transfersTo = new address[](1);
transfersTo[0] = _beneficiary;

uint256[] memory transfersAmount = new uint256[](1);
transfersAmount[0] = _amount;

tokenRules.executeTransfers(
_from,
transfersTo,
transfersAmount
);
}

}
76 changes: 66 additions & 10 deletions contracts/test_doubles/unit_tests/TokenRulesSpy.sol
Original file line number Diff line number Diff line change
@@ -1,18 +1,38 @@
pragma solidity ^0.5.0;

import "../../EIP20TokenInterface.sol";

contract TokenRulesSpy {

/* Structs */

struct TransactionEntry {
address from;
address[] transfersTo;
uint256[] transfersAmount;
}


/* Storage */

EIP20TokenInterface public token;

TransactionEntry[] public transactions;

uint256 public transactionsLength;

mapping (address => bool) public allowedTransfers;

address public recordedFrom;

address[] public recordedTransfersTo;
uint256 public recordedTransfersToLength;
/* Special Functions */

constructor(EIP20TokenInterface _token)
public
{
require(address(_token) != address(0), "Token address is null.");

uint256[] public recordedTransfersAmount;
uint256 public recordedTransfersAmountLength;
token = _token;
}


/* External Functions */
Expand All @@ -29,20 +49,56 @@ contract TokenRulesSpy {
allowedTransfers[msg.sender] = false;
}

function fromTransaction(uint256 index)
external
view
returns (address)
{
return transactions[index].from;
}

function transfersToTransaction(uint256 index)
external
view
returns (address[] memory)
{
return transactions[index].transfersTo;
}

function transfersAmountTransaction(uint256 index)
external
view
returns (uint256[] memory)
{
return transactions[index].transfersAmount;
}

function executeTransfers(
address _from,
address[] calldata _transfersTo,
uint256[] calldata _transfersAmount
)
external
{
recordedFrom = _from;
TransactionEntry memory entry = TransactionEntry({
from: _from,
transfersTo: new address[](0),
transfersAmount: new uint256[](0)
});

transactions.push(entry);

for (uint256 i = 0; i < _transfersTo.length; ++i) {
transactions[transactionsLength].transfersTo.push(_transfersTo[i]);
}

recordedTransfersTo = _transfersTo;
recordedTransfersToLength = _transfersTo.length;
for (uint256 i = 0; i < _transfersAmount.length; ++i) {
transactions[transactionsLength].transfersAmount.push(
_transfersAmount[i]
);
}

recordedTransfersAmount = _transfersAmount;
recordedTransfersAmountLength = _transfersAmount.length;
++transactionsLength;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
pragma solidity ^0.5.0;

// Copyright 2018 OpenST Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import "../../../SafeMath.sol";
import "../../../CreditRule.sol";

contract CustomRuleWithCredit {

/* Usings */

using SafeMath for uint256;

event Pay(
address _to,
uint256 _amount
);

/* Storage */

CreditRule public creditRule;

bool public markedToFail;


/* Special Functions */

constructor(
address _creditRule
)
public
{
require(
address(_creditRule) != address(0),
"Credit rule's address is null."
);

creditRule = CreditRule(_creditRule);
}


/* External Functions */

function makeMeFail()
external
{
markedToFail = true;
}

function pay(
address _to,
uint256 _amount
)
external
{
require(
!markedToFail,
"The function is marked to fail."
);

address[] memory transfersTo = new address[](1);
transfersTo[0] = _to;

uint256[] memory transfersAmount = new uint256[](1);
transfersAmount[0] = _amount;

creditRule.executeTransfers(
msg.sender,
transfersTo,
transfersAmount
);

emit Pay(_to, _amount);
}
}
Loading