-
Notifications
You must be signed in to change notification settings - Fork 19
[WIP] Credit #198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
[WIP] Credit #198
Changes from all commits
072d845
65bfee5
233f974
4e2d213
a93300b
7c6ebd7
4877e29
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
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 "../external/SafeMath.sol"; | ||
import "../token/TransfersAgent.sol"; | ||
|
||
|
||
/** | ||
* Credit rules allows a budget holder to credit a user with an amount | ||
* that the user can *only* spents in a token economy. A custom rule | ||
* is deployed with a CreditRule acting as a TransfersAgent to execute | ||
* transfers. CreditRule first transfers a minimum of credited amount and | ||
* needed transfer amount, afterwards delegate the transfer execution to | ||
* TransfersAgent itself. | ||
* | ||
* Steps to utilize CreditRule: | ||
* - A custom rule is deployed by passing a CreditRule address to act as | ||
* a transfers agent for the rule. | ||
* - A token holder signs an executable transaction to execute the custom rule. | ||
* - The budget holder signs an executable transaction to execute | ||
* CreditRule::executeRule function with a credit amount, and the token | ||
* holder's address and executeRule's function data as an argument. | ||
*/ | ||
contract CreditRule is TransfersAgent { | ||
|
||
/* Usings */ | ||
|
||
using SafeMath for uint256; | ||
|
||
|
||
/** Structs */ | ||
|
||
struct CreditInfo { | ||
uint256 amount; | ||
bool inProgress; | ||
} | ||
|
||
|
||
/* Storage */ | ||
|
||
address public budgetHolder; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should mention that budgetHolder is a tokenHolder address. It was difficult for me to understand that until I looked into the test cases 😜 |
||
|
||
TransfersAgent public transfersAgent; | ||
|
||
mapping(address => CreditInfo) public credits; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to handle use case where credits for a user are only valid for a particular duration or blockheight? 💭 |
||
|
||
|
||
/* Modifiers */ | ||
|
||
modifier onlyBudgetHolder() | ||
{ | ||
require( | ||
msg.sender == budgetHolder, | ||
"Only budget holder is allowed to call." | ||
); | ||
|
||
_; | ||
} | ||
|
||
|
||
/* Special Functions */ | ||
|
||
constructor( | ||
address _budgetHolder, | ||
address _transfersAgent | ||
) | ||
public | ||
{ | ||
require( | ||
_budgetHolder != address(0), | ||
"Budget holder's address is null." | ||
); | ||
|
||
require( | ||
_transfersAgent != address(0), | ||
"Transfers agent's address is null." | ||
); | ||
|
||
budgetHolder = _budgetHolder; | ||
|
||
transfersAgent = TransfersAgent(_transfersAgent); | ||
} | ||
|
||
|
||
/* 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_, | ||
bytes memory returnData_ | ||
) | ||
{ | ||
require( | ||
_creditAmount != 0, | ||
"Credit amount is 0." | ||
); | ||
|
||
require( | ||
_to != address(0), | ||
"To (token holder) address is null." | ||
); | ||
|
||
require( | ||
credits[_to].inProgress == false, | ||
"Re-entrancy occured in crediting process." | ||
); | ||
|
||
credits[_to].amount = _creditAmount; | ||
credits[_to].inProgress = true; | ||
|
||
// solium-disable-next-line security/no-call-value | ||
(executionStatus_, returnData_) = _to.call.value(msg.value)(_data); | ||
} | ||
|
||
function executeTransfers( | ||
address _from, | ||
address[] calldata _transfersTo, | ||
uint256[] calldata _transfersAmount | ||
) | ||
external | ||
{ | ||
if (credits[_from].inProgress) { | ||
uint256 creditAmount = credits[_from].amount; | ||
delete credits[_from]; | ||
|
||
uint256 sumAmount = 0; | ||
|
||
for(uint256 i = 0; i < _transfersAmount.length; ++i) { | ||
sumAmount = sumAmount.add(_transfersAmount[i]); | ||
} | ||
|
||
uint256 amountToTransferFromBudgetHolder = ( | ||
sumAmount > creditAmount ? creditAmount : sumAmount | ||
); | ||
|
||
executeTransfer( | ||
budgetHolder, | ||
_from, | ||
amountToTransferFromBudgetHolder | ||
); | ||
} | ||
|
||
transfersAgent.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; | ||
|
||
transfersAgent.executeTransfers( | ||
_from, | ||
transfersTo, | ||
transfersAmount | ||
); | ||
} | ||
} |
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 "../../../external/SafeMath.sol"; | ||
import "../../../rules/CreditRule.sol"; | ||
|
||
contract CustomRuleWithCredit { | ||
|
||
/* Usings */ | ||
|
||
using SafeMath for uint256; | ||
|
||
event Pay( | ||
address _to, | ||
uint256 _amount | ||
); | ||
|
||
/* Storage */ | ||
|
||
CreditRule public creditRule; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we introduce CreditRuleInterface contract for rules contract to integrate ❓ |
||
|
||
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); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we call inProgress to isAllocated/allocated ? I believe amount is the allocated amount to user.
Any specific reason to keep inProgress naming?