Skip to content

Commit

Permalink
EscrowReward condition support for distributing different rewards to …
Browse files Browse the repository at this point in the history
…multiple addresses.

This allows the implementation of the use cases where the reward can be distributed between the data publisher and a different party (marketplace, infrastructure provider, ..)
  • Loading branch information
aaitor committed Jan 26, 2021
1 parent 938c304 commit 8c20ada
Show file tree
Hide file tree
Showing 6 changed files with 415 additions and 76 deletions.
258 changes: 217 additions & 41 deletions contracts/conditions/rewards/EscrowReward.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,27 @@ contract EscrowReward is Reward {
uint256 _amount
);

/**
* @notice initialize init the
* contract with the following parameters
* @param _owner contract's owner account address
* @param _conditionStoreManagerAddress condition store manager address
* @param _tokenAddress Ocean token contract address
*/
event Fulfilled(
bytes32 indexed _agreementId,
address[] _receivers,
bytes32 _conditionId,
uint256[] _amounts
);

/**
* @notice initialize init the
* contract with the following parameters
* @param _owner contract's owner account address
* @param _conditionStoreManagerAddress condition store manager address
* @param _tokenAddress Ocean token contract address
*/
function initialize(
address _owner,
address _conditionStoreManagerAddress,
address _tokenAddress
)
external
initializer()
external
initializer()
{
require(
_tokenAddress != address(0) &&
Expand All @@ -56,25 +63,25 @@ contract EscrowReward is Reward {
token = ERC20Upgradeable(_tokenAddress);
}

/**
* @notice hashValues generates the hash of condition inputs
* with the following parameters
* @param _amount token amount to be locked/released
* @param _receiver receiver's address
* @param _sender sender's address
* @param _lockCondition lock condition identifier
* @param _releaseCondition release condition identifier
* @return bytes32 hash of all these values
*/
/**
* @notice hashValues generates the hash of condition inputs
* with the following parameters
* @param _amount token amount to be locked/released
* @param _receiver receiver's address
* @param _sender sender's address
* @param _lockCondition lock condition identifier
* @param _releaseCondition release condition identifier
* @return bytes32 hash of all these values
*/
function hashValues(
uint256 _amount,
address _receiver,
address _sender,
bytes32 _lockCondition,
bytes32 _releaseCondition
)
public pure
returns (bytes32)
public pure
returns (bytes32)
{
return keccak256(
abi.encodePacked(
Expand All @@ -87,20 +94,56 @@ contract EscrowReward is Reward {
);
}

/**
* @notice fulfill escrow reward condition
* @dev fulfill method checks whether the lock and
* release conditions are fulfilled in order to
* release/refund the reward to receiver/sender
* respectively.
* @param _agreementId agreement identifier
* @param _amount token amount to be locked/released
* @param _receiver receiver's address
* @param _sender sender's address
* @param _lockCondition lock condition identifier
* @param _releaseCondition release condition identifier
* @return condition state (Fulfilled/Aborted)
*/
/**
* @notice hashValues generates the hash of condition inputs
* with the following parameters
* @param _amounts token amounts to be locked/released
* @param _receivers receiver's addresses
* @param _sender sender's address
* @param _lockCondition lock condition identifier
* @param _releaseCondition release condition identifier
* @return bytes32 hash of all these values
*/
function hashMultipleValues(
uint256[] memory _amounts,
address[] memory _receivers,
address _sender,
bytes32 _lockCondition,
bytes32 _releaseCondition
)
public pure
returns (bytes32)
{
require(
_amounts.length == _receivers.length,
'Amounts and Receivers arguments have wrong length'
);
return keccak256(
abi.encodePacked(
_amounts,
_receivers,
_sender,
_lockCondition,
_releaseCondition
)
);
}


/**
* @notice fulfill escrow reward condition
* @dev fulfill method checks whether the lock and
* release conditions are fulfilled in order to
* release/refund the reward to receiver/sender
* respectively.
* @param _agreementId agreement identifier
* @param _amount token amount to be locked/released
* @param _receiver receiver's address
* @param _sender sender's address
* @param _lockCondition lock condition identifier
* @param _releaseCondition release condition identifier
* @return condition state (Fulfilled/Aborted)
*/
function fulfill(
bytes32 _agreementId,
uint256 _amount,
Expand All @@ -109,8 +152,8 @@ contract EscrowReward is Reward {
bytes32 _lockCondition,
bytes32 _releaseCondition
)
external
returns (ConditionStoreLibrary.ConditionState)
external
returns (ConditionStoreLibrary.ConditionState)
{
bytes32 id = generateId(
_agreementId,
Expand All @@ -125,7 +168,7 @@ contract EscrowReward is Reward {
address lockConditionTypeRef;
ConditionStoreLibrary.ConditionState lockConditionState;
(lockConditionTypeRef,lockConditionState,,,,,) = conditionStoreManager
.getCondition(_lockCondition);
.getCondition(_lockCondition);

bytes32 generatedLockConditionId = keccak256(
abi.encodePacked(
Expand Down Expand Up @@ -154,7 +197,7 @@ contract EscrowReward is Reward {
);

ConditionStoreLibrary.ConditionState state = conditionStoreManager
.getConditionState(_releaseCondition);
.getConditionState(_releaseCondition);

address escrowReceiver = address(0x0);
if (state == ConditionStoreLibrary.ConditionState.Fulfilled)
Expand All @@ -180,6 +223,101 @@ contract EscrowReward is Reward {
return state;
}

/**
* @notice fulfill escrow reward condition
* @dev fulfill method checks whether the lock and
* release conditions are fulfilled in order to
* release/refund the reward to receiver/sender
* respectively.
* @param _agreementId agreement identifier
* @param _amounts token amounts to be locked/released
* @param _receivers receiver's address
* @param _sender sender's address
* @param _lockCondition lock condition identifier
* @param _releaseCondition release condition identifier
* @return condition state (Fulfilled/Aborted)
*/
function fulfillMultipleRewards(
bytes32 _agreementId,
uint256[] memory _amounts,
address[] memory _receivers,
address _sender,
bytes32 _lockCondition,
bytes32 _releaseCondition
)
external
returns (ConditionStoreLibrary.ConditionState)
{
require(
_amounts.length == _receivers.length,
'Amounts and Receivers arguments have wrong length'
);

bytes32 id = generateId(
_agreementId,
hashMultipleValues(
_amounts,
_receivers,
_sender,
_lockCondition,
_releaseCondition
)
);
address lockConditionTypeRef;
ConditionStoreLibrary.ConditionState lockConditionState;
(lockConditionTypeRef,lockConditionState,,,,,) = conditionStoreManager
.getCondition(_lockCondition);

uint256 _totalAmount = 0;
for(uint i = 0; i < _amounts.length; i++)
_totalAmount = _totalAmount + _amounts[i];

bytes32 generatedLockConditionId = keccak256(
abi.encodePacked(
_agreementId,
lockConditionTypeRef,
keccak256(
abi.encodePacked(
address(this),
_totalAmount
)
)
)
);
require(
generatedLockConditionId == _lockCondition,
'LockCondition ID does not match'
);
require(
lockConditionState ==
ConditionStoreLibrary.ConditionState.Fulfilled,
'LockCondition needs to be Fulfilled'
);
require(
token.balanceOf(address(this)) >= _totalAmount,
'Not enough balance'
);

ConditionStoreLibrary.ConditionState state = conditionStoreManager
.getConditionState(_releaseCondition);

if (state == ConditionStoreLibrary.ConditionState.Fulfilled)
{
state = _transferAndFulfillMultipleRewards(id, _receivers, _amounts);
emit Fulfilled(_agreementId, _receivers, id, _amounts);
} else if (state == ConditionStoreLibrary.ConditionState.Aborted)
{
state = _transferAndFulfill(id, _sender, _totalAmount);
emit Fulfilled(_agreementId, _sender, id, _totalAmount);
} else
{
return conditionStoreManager.getConditionState(id);
}

return state;
}


/**
* @notice _transferAndFulfill transfer tokens and
* fulfill the condition
Expand All @@ -193,8 +331,8 @@ contract EscrowReward is Reward {
address _receiver,
uint256 _amount
)
private
returns (ConditionStoreLibrary.ConditionState)
private
returns (ConditionStoreLibrary.ConditionState)
{
require(
_receiver != address(0),
Expand All @@ -213,6 +351,44 @@ contract EscrowReward is Reward {
ConditionStoreLibrary.ConditionState.Fulfilled
);
}


/**
* @notice _transferAndFulfill transfer tokens and
* fulfill the condition
* @param _id condition identifier
* @param _receivers receiver's address
* @param _amounts token amount to be locked/released
* @return condition state (Fulfilled/Aborted)
*/
function _transferAndFulfillMultipleRewards(
bytes32 _id,
address[] memory _receivers,
uint256[] memory _amounts
)
private
returns (ConditionStoreLibrary.ConditionState)
{
for(uint i = 0; i < _receivers.length; i++) {
require(
_receivers[i] != address(0),
'Null address is impossible to fulfill'
);
require(
_receivers[i] != address(this),
'EscrowReward contract can not be a receiver'
);
require(
token.transfer(_receivers[i], _amounts[i]),
'Could not transfer token'
);
}
return super.fulfill(
_id,
ConditionStoreLibrary.ConditionState.Fulfilled
);
}

}


Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nevermined-io/contracts",
"version": "0.6.1",
"version": "0.6.2",
"description": "Nevermined implementation of Ocean Protocol in Solidity",
"bugs": {
"url": "https://github.com/nevermined-io/contracts/issues"
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<groupId>io.keyko.nevermined</groupId>
<artifactId>contracts</artifactId>
<packaging>jar</packaging>
<version>0.6.1</version>
<version>0.6.2</version>
<name>Nevermined Contracts</name>
<description>Nevermined Data Plarform Smart Contracts in Solidity</description>
<url>https://github.com/nevermined-io/contracts</url>
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,6 @@
test_suite='tests',
tests_require=test_requirements,
url='https://github.com/nevermined-io/contracts',
version='0.6.1',
version='0.6.2',
zip_safe=False,
)

0 comments on commit 8c20ada

Please sign in to comment.