Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
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
170 changes: 170 additions & 0 deletions contracts/CreditRule.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
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";

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
{
if (credits[_from].inProgress) {
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