refactor: decouple arbitration licenses from disputes
This commit is contained in:
parent
551c0bc67c
commit
dd2acd5540
|
@ -1,6 +1,109 @@
|
||||||
|
/* solium-disable security/no-block-members */
|
||||||
|
|
||||||
pragma solidity ^0.5.8;
|
pragma solidity ^0.5.8;
|
||||||
|
|
||||||
interface Arbitrable {
|
import "./License.sol";
|
||||||
function setArbitrationResult(uint _escrowId, bool _releaseFunds, address _arbitrator) external;
|
|
||||||
function getArbitrator(uint _escrowId) external view returns(address);
|
contract Arbitrable {
|
||||||
}
|
mapping(uint => ArbitrationCase) public arbitrationCases;
|
||||||
|
|
||||||
|
struct ArbitrationCase {
|
||||||
|
bool open;
|
||||||
|
address openBy;
|
||||||
|
address arbitrator;
|
||||||
|
ArbitrationResult result;
|
||||||
|
string motive;
|
||||||
|
}
|
||||||
|
|
||||||
|
event ArbitratorChanged(address arbitrator);
|
||||||
|
event ArbitrationCanceled(uint escrowId, uint date);
|
||||||
|
event ArbitrationRequired(uint escrowId, uint date);
|
||||||
|
event ArbitrationResolved(uint escrowId, ArbitrationResult result, address arbitrator, uint date);
|
||||||
|
|
||||||
|
enum ArbitrationResult {UNSOLVED, BUYER, SELLER}
|
||||||
|
|
||||||
|
License public arbitratorLicenses;
|
||||||
|
|
||||||
|
constructor(address _arbitratorLicenses) public {
|
||||||
|
arbitratorLicenses = License(_arbitratorLicenses);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Abstract functions
|
||||||
|
function solveDispute(uint _escrowId, bool _releaseFunds, address _arbitrator) internal;
|
||||||
|
function getArbitrator(uint _escrowId) public view returns(address);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice arbitration exists
|
||||||
|
* @param _escrowId Escrow to verify
|
||||||
|
* @return bool result
|
||||||
|
*/
|
||||||
|
function isDisputed(uint _escrowId) public view returns (bool) {
|
||||||
|
return arbitrationCases[_escrowId].open || arbitrationCases[_escrowId].result != ArbitrationResult.UNSOLVED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice cancel arbitration
|
||||||
|
* @param _escrowId Escrow to cancel
|
||||||
|
*/
|
||||||
|
function cancelArbitration(uint _escrowId) public {
|
||||||
|
require(arbitrationCases[_escrowId].openBy == msg.sender, "Arbitration can only be canceled by the opener");
|
||||||
|
require(arbitrationCases[_escrowId].result == ArbitrationResult.UNSOLVED && arbitrationCases[_escrowId].open,
|
||||||
|
"Arbitration already solved or not open");
|
||||||
|
|
||||||
|
delete arbitrationCases[_escrowId];
|
||||||
|
|
||||||
|
emit ArbitrationCanceled(_escrowId, block.timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function openDispute(uint _escrowId, address _openBy, string memory motive) internal {
|
||||||
|
require(!arbitrationCases[_escrowId].open, "Arbitration already open");
|
||||||
|
require(arbitrationCases[_escrowId].result == ArbitrationResult.UNSOLVED, "Arbitration already solved");
|
||||||
|
|
||||||
|
arbitrationCases[_escrowId] = ArbitrationCase({
|
||||||
|
open: true,
|
||||||
|
openBy: _openBy,
|
||||||
|
arbitrator: address(0),
|
||||||
|
result: ArbitrationResult.UNSOLVED,
|
||||||
|
motive: motive
|
||||||
|
});
|
||||||
|
|
||||||
|
emit ArbitrationRequired(_escrowId, block.timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice Set arbitration result in favour of the buyer or seller and transfer funds accordingly
|
||||||
|
* @param _escrowId Id of the escrow
|
||||||
|
* @param _result Result of the arbitration
|
||||||
|
*/
|
||||||
|
function setArbitrationResult(uint _escrowId, ArbitrationResult _result) public {
|
||||||
|
require(arbitrationCases[_escrowId].open && arbitrationCases[_escrowId].result == ArbitrationResult.UNSOLVED,
|
||||||
|
"Case must be open and unsolved");
|
||||||
|
require(_result != ArbitrationResult.UNSOLVED, "Arbitration does not have result");
|
||||||
|
require(arbitratorLicenses.isLicenseOwner(msg.sender), "Only arbitrators can invoke this function");
|
||||||
|
require(getArbitrator(_escrowId) == msg.sender, "Invalid escrow arbitrator");
|
||||||
|
|
||||||
|
|
||||||
|
arbitrationCases[_escrowId].open = false;
|
||||||
|
arbitrationCases[_escrowId].result = _result;
|
||||||
|
arbitrationCases[_escrowId].arbitrator = msg.sender;
|
||||||
|
|
||||||
|
// TODO: incentive mechanism for opening arbitration process
|
||||||
|
// if(arbitrationCases[_escrowId].openBy != trx.seller || arbitrationCases[_escrowId].openBy != trx.buyer){
|
||||||
|
// Consider deducting a fee as reward for whoever opened the arbitration process.
|
||||||
|
// }
|
||||||
|
|
||||||
|
emit ArbitrationResolved(_escrowId, _result, msg.sender, block.timestamp);
|
||||||
|
|
||||||
|
if(_result == ArbitrationResult.BUYER){
|
||||||
|
solveDispute(_escrowId, true, msg.sender);
|
||||||
|
} else {
|
||||||
|
solveDispute(_escrowId, false, msg.sender);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,124 +0,0 @@
|
||||||
/* solium-disable security/no-block-members */
|
|
||||||
|
|
||||||
pragma solidity ^0.5.8;
|
|
||||||
|
|
||||||
import "../common/Ownable.sol";
|
|
||||||
import "./Arbitrable.sol";
|
|
||||||
import "./License.sol";
|
|
||||||
|
|
||||||
|
|
||||||
contract Arbitration is Ownable, License {
|
|
||||||
|
|
||||||
mapping(uint => ArbitrationCase) public arbitrationCases;
|
|
||||||
|
|
||||||
struct ArbitrationCase {
|
|
||||||
bool open;
|
|
||||||
address openBy;
|
|
||||||
address arbitrator;
|
|
||||||
ArbitrationResult result;
|
|
||||||
string motive;
|
|
||||||
}
|
|
||||||
|
|
||||||
event ArbitratorChanged(address arbitrator);
|
|
||||||
event ArbitrationCanceled(uint escrowId, uint date);
|
|
||||||
event ArbitrationRequired(uint escrowId, uint date);
|
|
||||||
event ArbitrationResolved(uint escrowId, ArbitrationResult result, address arbitrator, uint date);
|
|
||||||
|
|
||||||
enum ArbitrationResult {UNSOLVED, BUYER, SELLER}
|
|
||||||
|
|
||||||
Arbitrable public escrow;
|
|
||||||
|
|
||||||
constructor(address payable _tokenAddress, uint256 _price)
|
|
||||||
License(_tokenAddress, _price)
|
|
||||||
public {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
function setEscrowAddress(address _escrow) public onlyOwner {
|
|
||||||
escrow = Arbitrable(_escrow);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @notice Determine if address is arbitrator
|
|
||||||
* @param _addr Address to be verified
|
|
||||||
* @return result
|
|
||||||
*/
|
|
||||||
function isArbitrator(address _addr) public view returns(bool){
|
|
||||||
return isLicenseOwner(_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @notice arbitration exists
|
|
||||||
* @param _escrowId Escrow to verify
|
|
||||||
* @return bool result
|
|
||||||
*/
|
|
||||||
function exists(uint _escrowId) public view returns (bool) {
|
|
||||||
return arbitrationCases[_escrowId].open || arbitrationCases[_escrowId].result != ArbitrationResult.UNSOLVED;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @notice cancel arbitration
|
|
||||||
* @param _escrowId Escrow to cancel
|
|
||||||
*/
|
|
||||||
function cancelArbitration(uint _escrowId) public {
|
|
||||||
require(arbitrationCases[_escrowId].openBy == msg.sender, "Arbitration can only be canceled by the opener");
|
|
||||||
require(arbitrationCases[_escrowId].result == ArbitrationResult.UNSOLVED && arbitrationCases[_escrowId].open,
|
|
||||||
"Arbitration already solved or not open");
|
|
||||||
|
|
||||||
delete arbitrationCases[_escrowId];
|
|
||||||
|
|
||||||
emit ArbitrationCanceled(_escrowId, block.timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function openCase(uint _escrowId, address _openBy, string memory motive) public {
|
|
||||||
assert(msg.sender == address(escrow)); // Only the escrow address can open cases
|
|
||||||
require(!arbitrationCases[_escrowId].open, "Arbitration already open");
|
|
||||||
require(arbitrationCases[_escrowId].result == ArbitrationResult.UNSOLVED, "Arbitration already solved");
|
|
||||||
|
|
||||||
arbitrationCases[_escrowId] = ArbitrationCase({
|
|
||||||
open: true,
|
|
||||||
openBy: _openBy,
|
|
||||||
arbitrator: address(0),
|
|
||||||
result: ArbitrationResult.UNSOLVED,
|
|
||||||
motive: motive
|
|
||||||
});
|
|
||||||
|
|
||||||
emit ArbitrationRequired(_escrowId, block.timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @notice Set arbitration result in favour of the buyer or seller and transfer funds accordingly
|
|
||||||
* @param _escrowId Id of the escrow
|
|
||||||
* @param _result Result of the arbitration
|
|
||||||
*/
|
|
||||||
function setArbitrationResult(uint _escrowId, ArbitrationResult _result) public {
|
|
||||||
require(arbitrationCases[_escrowId].open && arbitrationCases[_escrowId].result == ArbitrationResult.UNSOLVED,
|
|
||||||
"Case must be open and unsolved");
|
|
||||||
require(_result != ArbitrationResult.UNSOLVED, "Arbitration does not have result");
|
|
||||||
require(isArbitrator(msg.sender), "Only arbitrators can invoke this function");
|
|
||||||
require(escrow.getArbitrator(_escrowId) == msg.sender, "Invalid escrow arbitrator");
|
|
||||||
|
|
||||||
|
|
||||||
arbitrationCases[_escrowId].open = false;
|
|
||||||
arbitrationCases[_escrowId].result = _result;
|
|
||||||
arbitrationCases[_escrowId].arbitrator = msg.sender;
|
|
||||||
|
|
||||||
// TODO: incentive mechanism for opening arbitration process
|
|
||||||
// if(arbitrationCases[_escrowId].openBy != trx.seller || arbitrationCases[_escrowId].openBy != trx.buyer){
|
|
||||||
// Consider deducting a fee as reward for whoever opened the arbitration process.
|
|
||||||
// }
|
|
||||||
|
|
||||||
emit ArbitrationResolved(_escrowId, _result, msg.sender, block.timestamp);
|
|
||||||
|
|
||||||
if(_result == ArbitrationResult.BUYER){
|
|
||||||
escrow.setArbitrationResult(_escrowId, true, msg.sender);
|
|
||||||
} else {
|
|
||||||
escrow.setArbitrationResult(_escrowId, false, msg.sender);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -10,7 +10,6 @@ import "../token/ERC20Token.sol";
|
||||||
import "./License.sol";
|
import "./License.sol";
|
||||||
import "./MetadataStore.sol";
|
import "./MetadataStore.sol";
|
||||||
import "./Fees.sol";
|
import "./Fees.sol";
|
||||||
import "./Arbitration.sol";
|
|
||||||
import "./Arbitrable.sol";
|
import "./Arbitrable.sol";
|
||||||
import "tabookey-gasless/contracts/RelayRecipient.sol";
|
import "tabookey-gasless/contracts/RelayRecipient.sol";
|
||||||
|
|
||||||
|
@ -26,14 +25,15 @@ contract Escrow is Pausable, MessageSigned, Fees, Arbitrable, RelayRecipient {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
address _license,
|
address _license,
|
||||||
address _arbitration,
|
address _arbitrationLicense,
|
||||||
address _metadataStore,
|
address _metadataStore,
|
||||||
address _feeToken,
|
address _feeToken,
|
||||||
address _feeDestination,
|
address _feeDestination,
|
||||||
uint _feeAmount)
|
uint _feeAmount)
|
||||||
Fees(_feeToken, _feeDestination, _feeAmount) public {
|
Fees(_feeToken, _feeDestination, _feeAmount)
|
||||||
|
Arbitrable(_arbitrationLicense)
|
||||||
|
public {
|
||||||
license = License(_license);
|
license = License(_license);
|
||||||
arbitration = Arbitration(_arbitration);
|
|
||||||
metadataStore = MetadataStore(_metadataStore);
|
metadataStore = MetadataStore(_metadataStore);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,8 +41,6 @@ contract Escrow is Pausable, MessageSigned, Fees, Arbitrable, RelayRecipient {
|
||||||
set_relay_hub(RelayHub(_relayHub));
|
set_relay_hub(RelayHub(_relayHub));
|
||||||
}
|
}
|
||||||
|
|
||||||
Arbitration arbitration;
|
|
||||||
|
|
||||||
struct EscrowTransaction {
|
struct EscrowTransaction {
|
||||||
uint256 offerId;
|
uint256 offerId;
|
||||||
uint256 tokenAmount;
|
uint256 tokenAmount;
|
||||||
|
@ -423,7 +421,7 @@ contract Escrow is Pausable, MessageSigned, Fees, Arbitrable, RelayRecipient {
|
||||||
function rateTransaction(uint _escrowId, uint _rate) external whenNotPaused {
|
function rateTransaction(uint _escrowId, uint _rate) external whenNotPaused {
|
||||||
require(_rate >= 1, "Rating needs to be at least 1");
|
require(_rate >= 1, "Rating needs to be at least 1");
|
||||||
require(_rate <= 5, "Rating needs to be at less than or equal to 5");
|
require(_rate <= 5, "Rating needs to be at less than or equal to 5");
|
||||||
require(!arbitration.exists(_escrowId), "Can't rate a transaction that has an arbitration process");
|
require(!isDisputed(_escrowId), "Can't rate a transaction that has an arbitration process");
|
||||||
|
|
||||||
EscrowTransaction storage trx = transactions[_escrowId];
|
EscrowTransaction storage trx = transactions[_escrowId];
|
||||||
|
|
||||||
|
@ -445,11 +443,11 @@ contract Escrow is Pausable, MessageSigned, Fees, Arbitrable, RelayRecipient {
|
||||||
function openCase(uint _escrowId, string calldata motive) external {
|
function openCase(uint _escrowId, string calldata motive) external {
|
||||||
EscrowTransaction storage trx = transactions[_escrowId];
|
EscrowTransaction storage trx = transactions[_escrowId];
|
||||||
|
|
||||||
require(!arbitration.exists(_escrowId), "Case already exist");
|
require(!isDisputed(_escrowId), "Case already exist");
|
||||||
require(trx.buyer == get_sender() || metadataStore.getOfferOwner(trx.offerId) == get_sender(), "Only a buyer or seller can open a case");
|
require(trx.buyer == get_sender() || metadataStore.getOfferOwner(trx.offerId) == get_sender(), "Only a buyer or seller can open a case");
|
||||||
require(trx.status == EscrowStatus.PAID, "Cases can only be open for paid transactions");
|
require(trx.status == EscrowStatus.PAID, "Cases can only be open for paid transactions");
|
||||||
|
|
||||||
arbitration.openCase(_escrowId, get_sender(), motive);
|
openDispute(_escrowId, get_sender(), motive);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -458,19 +456,18 @@ contract Escrow is Pausable, MessageSigned, Fees, Arbitrable, RelayRecipient {
|
||||||
* @param _signature Signed message result of openCaseSignHash(uint256)
|
* @param _signature Signed message result of openCaseSignHash(uint256)
|
||||||
* @dev Consider opening a dispute in aragon court.
|
* @dev Consider opening a dispute in aragon court.
|
||||||
*/
|
*/
|
||||||
function openCaseWithSignature(uint _escrowId, bytes calldata _signature) external {
|
function openCaseWithSignature(uint _escrowId, string calldata motive, bytes calldata _signature) external {
|
||||||
EscrowTransaction storage trx = transactions[_escrowId];
|
EscrowTransaction storage trx = transactions[_escrowId];
|
||||||
|
|
||||||
require(!arbitration.exists(_escrowId), "Case already exist");
|
require(!isDisputed(_escrowId), "Case already exist");
|
||||||
require(trx.status == EscrowStatus.PAID, "Cases can only be open for paid transactions");
|
require(trx.status == EscrowStatus.PAID, "Cases can only be open for paid transactions");
|
||||||
|
|
||||||
address senderAddress = recoverAddress(getSignHash(openCaseSignHash(_escrowId)), _signature);
|
address senderAddress = recoverAddress(getSignHash(openCaseSignHash(_escrowId, motive)), _signature);
|
||||||
|
|
||||||
require(trx.buyer == senderAddress || metadataStore.getOfferOwner(trx.offerId) == senderAddress,
|
require(trx.buyer == senderAddress || metadataStore.getOfferOwner(trx.offerId) == senderAddress,
|
||||||
"Only a buyer or seller can open a case");
|
"Only a buyer or seller can open a case");
|
||||||
|
|
||||||
// FIXME get actual motive from the signature if possible
|
openDispute(_escrowId, get_sender(), motive);
|
||||||
arbitration.openCase(_escrowId, get_sender(), '');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -479,9 +476,7 @@ contract Escrow is Pausable, MessageSigned, Fees, Arbitrable, RelayRecipient {
|
||||||
* @param _releaseFunds Release funds to buyer or cancel escrow
|
* @param _releaseFunds Release funds to buyer or cancel escrow
|
||||||
* @param _arbitrator Arbitrator address
|
* @param _arbitrator Arbitrator address
|
||||||
*/
|
*/
|
||||||
function setArbitrationResult(uint _escrowId, bool _releaseFunds, address _arbitrator) external {
|
function solveDispute(uint _escrowId, bool _releaseFunds, address _arbitrator) internal {
|
||||||
assert(get_sender() == address(arbitration)); // Only arbitration contract can invoke this
|
|
||||||
|
|
||||||
EscrowTransaction storage trx = transactions[_escrowId];
|
EscrowTransaction storage trx = transactions[_escrowId];
|
||||||
|
|
||||||
address payable seller = metadataStore.getOfferOwner(trx.offerId);
|
address payable seller = metadataStore.getOfferOwner(trx.offerId);
|
||||||
|
@ -511,12 +506,13 @@ contract Escrow is Pausable, MessageSigned, Fees, Arbitrable, RelayRecipient {
|
||||||
* @return message hash
|
* @return message hash
|
||||||
* @dev Once message is signed, pass it as _signature of openCase(uint256,bytes)
|
* @dev Once message is signed, pass it as _signature of openCase(uint256,bytes)
|
||||||
*/
|
*/
|
||||||
function openCaseSignHash(uint _escrowId) public view returns(bytes32){
|
function openCaseSignHash(uint _escrowId, string memory motive) public view returns(bytes32){
|
||||||
return keccak256(
|
return keccak256(
|
||||||
abi.encodePacked(
|
abi.encodePacked(
|
||||||
address(this),
|
address(this),
|
||||||
"openCase(uint256)",
|
"openCase(uint256)",
|
||||||
_escrowId
|
_escrowId,
|
||||||
|
motive
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,25 +69,29 @@ module.exports = {
|
||||||
|
|
||||||
contracts: {
|
contracts: {
|
||||||
License: {
|
License: {
|
||||||
|
deploy: false
|
||||||
|
},
|
||||||
|
SellerLicense: {
|
||||||
|
instanceOf: "License",
|
||||||
args: [
|
args: [
|
||||||
"$SNT",
|
"$SNT",
|
||||||
LICENSE_PRICE
|
LICENSE_PRICE
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"MetadataStore": {
|
"MetadataStore": {
|
||||||
args: ["$License", "$Arbitration"]
|
args: ["$SellerLicense", "$ArbitrationLicense"]
|
||||||
},
|
},
|
||||||
Arbitration: {
|
ArbitrationLicense: {
|
||||||
|
instanceOf: "License",
|
||||||
args: [
|
args: [
|
||||||
"$SNT",
|
"$SNT",
|
||||||
ARB_LICENSE_PRICE
|
ARB_LICENSE_PRICE
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
Escrow: {
|
Escrow: {
|
||||||
args: ["$License", "$Arbitration", "$MetadataStore", "$SNT", BURN_ADDRESS, FEE_AMOUNT],
|
args: ["$SellerLicense", "$ArbitrationLicense", "$MetadataStore", "$SNT", BURN_ADDRESS, FEE_AMOUNT],
|
||||||
deps: ['RelayHub'],
|
deps: ['RelayHub'],
|
||||||
onDeploy: [
|
onDeploy: [
|
||||||
"Arbitration.methods.setEscrowAddress('$Escrow').send()",
|
|
||||||
"MetadataStore.methods.setEscrowAddress('$Escrow').send()",
|
"MetadataStore.methods.setEscrowAddress('$Escrow').send()",
|
||||||
"Escrow.methods.setRelayHubAddress('$RelayHub').send()",
|
"Escrow.methods.setRelayHubAddress('$RelayHub').send()",
|
||||||
"RelayHub.methods.depositFor('$Escrow').send({value: 1000000000000000000})"
|
"RelayHub.methods.depositFor('$Escrow').send({value: 1000000000000000000})"
|
||||||
|
@ -264,10 +268,9 @@ module.exports = {
|
||||||
tracking: 'shared.ropsten.chains.json',
|
tracking: 'shared.ropsten.chains.json',
|
||||||
contracts: {
|
contracts: {
|
||||||
Escrow: {
|
Escrow: {
|
||||||
args: ["$License", "$Arbitration", "$MetadataStore", "$SNT", BURN_ADDRESS, FEE_AMOUNT],
|
args: ["$SellerLicense", "$ArbitrationLicense", "$MetadataStore", "$SNT", BURN_ADDRESS, FEE_AMOUNT],
|
||||||
deps: ['RelayHub'],
|
deps: ['RelayHub'],
|
||||||
onDeploy: [
|
onDeploy: [
|
||||||
"Arbitration.methods.setEscrowAddress('$Escrow').send()",
|
|
||||||
"MetadataStore.methods.setEscrowAddress('$Escrow').send()",
|
"MetadataStore.methods.setEscrowAddress('$Escrow').send()",
|
||||||
"Escrow.methods.setRelayHubAddress('$RelayHub').send()",
|
"Escrow.methods.setRelayHubAddress('$RelayHub').send()",
|
||||||
"RelayHub.methods.depositFor('$Escrow').send({value: 300000000000000000})"
|
"RelayHub.methods.depositFor('$Escrow').send({value: 300000000000000000})"
|
||||||
|
|
|
@ -39,11 +39,8 @@ module.exports = async (licensePrice, arbitrationLicensePrice, feeAmount, deps)
|
||||||
|
|
||||||
console.log("Buy arbitration license");
|
console.log("Buy arbitration license");
|
||||||
{
|
{
|
||||||
console.log(deps.contracts.Arbitration._address);
|
const buyLicense = deps.contracts.ArbitrationLicense.methods.buy().encodeABI();
|
||||||
console.log(arbitrationLicensePrice);
|
const toSend = deps.contracts.SNT.methods.approveAndCall(deps.contracts.ArbitrationLicense._address, arbitrationLicensePrice, buyLicense);
|
||||||
|
|
||||||
const buyLicense = deps.contracts.Arbitration.methods.buy().encodeABI();
|
|
||||||
const toSend = deps.contracts.SNT.methods.approveAndCall(deps.contracts.Arbitration._address, arbitrationLicensePrice, buyLicense);
|
|
||||||
|
|
||||||
const gas = await toSend.estimateGas({from: arbitrator});
|
const gas = await toSend.estimateGas({from: arbitrator});
|
||||||
await toSend.send({from: arbitrator, gas});
|
await toSend.send({from: arbitrator, gas});
|
||||||
|
@ -51,8 +48,8 @@ module.exports = async (licensePrice, arbitrationLicensePrice, feeAmount, deps)
|
||||||
|
|
||||||
console.log('Buy Licenses...');
|
console.log('Buy Licenses...');
|
||||||
await Promise.all(addresses.slice(1, 8).map(async (address) => {
|
await Promise.all(addresses.slice(1, 8).map(async (address) => {
|
||||||
const buyLicense = deps.contracts.License.methods.buy().encodeABI();
|
const buyLicense = deps.contracts.SellerLicense.methods.buy().encodeABI();
|
||||||
const toSend = deps.contracts.SNT.methods.approveAndCall(deps.contracts.License._address, licensePrice, buyLicense);
|
const toSend = deps.contracts.SNT.methods.approveAndCall(deps.contracts.SellerLicense._address, licensePrice, buyLicense);
|
||||||
|
|
||||||
const gas = await toSend.estimateGas({from: address});
|
const gas = await toSend.estimateGas({from: address});
|
||||||
return toSend.send({from: address, gas});
|
return toSend.send({from: address, gas});
|
||||||
|
@ -148,7 +145,7 @@ module.exports = async (licensePrice, arbitrationLicensePrice, feeAmount, deps)
|
||||||
const accounts = await Promise.all(addresses.map(async(address) => {
|
const accounts = await Promise.all(addresses.map(async(address) => {
|
||||||
const ethBalance = await deps.web3.eth.getBalance(address);
|
const ethBalance = await deps.web3.eth.getBalance(address);
|
||||||
const sntBalance = await deps.contracts.SNT.methods.balanceOf(address).call();
|
const sntBalance = await deps.contracts.SNT.methods.balanceOf(address).call();
|
||||||
const isLicenseOwner = await deps.contracts.License.methods.isLicenseOwner(address).call();
|
const isLicenseOwner = await deps.contracts.SellerLicense.methods.isLicenseOwner(address).call();
|
||||||
let user = {};
|
let user = {};
|
||||||
let offers = [];
|
let offers = [];
|
||||||
const isUser = await deps.contracts.MetadataStore.methods.userWhitelist(address).call();
|
const isUser = await deps.contracts.MetadataStore.methods.userWhitelist(address).call();
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import {ARBITRATION_UNSOLVED, GET_DISPUTED_ESCROWS, RESOLVE_DISPUTE, RESOLVE_DISPUTE_FAILED, BUY_LICENSE, CHECK_LICENSE_OWNER, LOAD_PRICE, LOAD_ARBITRATION, GET_ARBITRATORS, OPEN_DISPUTE, CANCEL_DISPUTE} from './constants';
|
import {ARBITRATION_UNSOLVED, GET_DISPUTED_ESCROWS, RESOLVE_DISPUTE, RESOLVE_DISPUTE_FAILED, BUY_LICENSE, CHECK_LICENSE_OWNER, LOAD_PRICE, LOAD_ARBITRATION, GET_ARBITRATORS, OPEN_DISPUTE, CANCEL_DISPUTE} from './constants';
|
||||||
import Escrow from '../../../embarkArtifacts/contracts/Escrow';
|
import Escrow from '../../../embarkArtifacts/contracts/Escrow';
|
||||||
import Arbitration from '../../../embarkArtifacts/contracts/Arbitration';
|
|
||||||
|
|
||||||
export const getDisputedEscrows = () => ({type: GET_DISPUTED_ESCROWS});
|
export const getDisputedEscrows = () => ({type: GET_DISPUTED_ESCROWS});
|
||||||
|
|
||||||
|
@ -15,13 +14,13 @@ export const resolveDispute = (escrowId, result) => {
|
||||||
type: RESOLVE_DISPUTE,
|
type: RESOLVE_DISPUTE,
|
||||||
escrowId,
|
escrowId,
|
||||||
result,
|
result,
|
||||||
toSend: Arbitration.methods.setArbitrationResult(escrowId, result)
|
toSend: Escrow.methods.setArbitrationResult(escrowId, result)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const openDispute = (escrowId, motive) => ({type: OPEN_DISPUTE, escrowId, toSend: Escrow.methods.openCase(escrowId, motive || '')});
|
export const openDispute = (escrowId, motive) => ({type: OPEN_DISPUTE, escrowId, toSend: Escrow.methods.openCase(escrowId, motive || '')});
|
||||||
|
|
||||||
export const cancelDispute = (escrowId) => ({type: CANCEL_DISPUTE, escrowId, toSend: Arbitration.methods.cancelArbitration(escrowId)});
|
export const cancelDispute = (escrowId) => ({type: CANCEL_DISPUTE, escrowId, toSend: Escrow.methods.cancelArbitration(escrowId)});
|
||||||
|
|
||||||
export const loadArbitration = (escrowId) => {
|
export const loadArbitration = (escrowId) => {
|
||||||
return {type: LOAD_ARBITRATION, escrowId};
|
return {type: LOAD_ARBITRATION, escrowId};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* global web3 */
|
/* global web3 */
|
||||||
import Escrow from '../../../embarkArtifacts/contracts/Escrow';
|
import Escrow from '../../../embarkArtifacts/contracts/Escrow';
|
||||||
import Arbitration from '../../../embarkArtifacts/contracts/Arbitration';
|
import ArbitrationLicense from '../../../embarkArtifacts/contracts/ArbitrationLicense';
|
||||||
import SNT from '../../../embarkArtifacts/contracts/SNT';
|
import SNT from '../../../embarkArtifacts/contracts/SNT';
|
||||||
import MetadataStore from '../../../embarkArtifacts/contracts/MetadataStore';
|
import MetadataStore from '../../../embarkArtifacts/contracts/MetadataStore';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
@ -31,10 +31,10 @@ export function *onCancelDispute() {
|
||||||
|
|
||||||
export function *doGetArbitrators() {
|
export function *doGetArbitrators() {
|
||||||
try {
|
try {
|
||||||
const cnt = yield call(Arbitration.methods.getNumLicenseOwners().call);
|
const cnt = yield call(ArbitrationLicense.methods.getNumLicenseOwners().call);
|
||||||
const arbitrators = [];
|
const arbitrators = [];
|
||||||
for(let i = 0; i < cnt; i++){
|
for(let i = 0; i < cnt; i++){
|
||||||
arbitrators.push(yield call(Arbitration.methods.licenseOwners(i).call));
|
arbitrators.push(yield call(ArbitrationLicense.methods.licenseOwners(i).call));
|
||||||
}
|
}
|
||||||
yield put({type: GET_ARBITRATORS_SUCCEEDED, arbitrators});
|
yield put({type: GET_ARBITRATORS_SUCCEEDED, arbitrators});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -45,7 +45,7 @@ export function *doGetArbitrators() {
|
||||||
|
|
||||||
export function *doGetEscrows() {
|
export function *doGetEscrows() {
|
||||||
try {
|
try {
|
||||||
const events = yield Arbitration.getPastEvents('ArbitrationRequired', {fromBlock: 1});
|
const events = yield Escrow.getPastEvents('ArbitrationRequired', {fromBlock: 1});
|
||||||
|
|
||||||
const escrows = [];
|
const escrows = [];
|
||||||
for (let i = 0; i < events.length; i++) {
|
for (let i = 0; i < events.length; i++) {
|
||||||
|
@ -56,7 +56,7 @@ export function *doGetEscrows() {
|
||||||
|
|
||||||
escrow.escrowId = escrowId;
|
escrow.escrowId = escrowId;
|
||||||
escrow.seller = offer.owner;
|
escrow.seller = offer.owner;
|
||||||
escrow.arbitration = yield call(Arbitration.methods.arbitrationCases(escrowId).call);
|
escrow.arbitration = yield call(Escrow.methods.arbitrationCases(escrowId).call);
|
||||||
escrow.arbitration.createDate = moment(events[i].returnValues.date * 1000).format("DD.MM.YY");
|
escrow.arbitration.createDate = moment(events[i].returnValues.date * 1000).format("DD.MM.YY");
|
||||||
|
|
||||||
escrows.push(escrow);
|
escrows.push(escrow);
|
||||||
|
@ -88,7 +88,7 @@ export function *doLoadArbitration({escrowId}) {
|
||||||
escrow.escrowId = escrowId;
|
escrow.escrowId = escrowId;
|
||||||
escrow.seller = offer.owner;
|
escrow.seller = offer.owner;
|
||||||
escrow.offer = offer;
|
escrow.offer = offer;
|
||||||
escrow.arbitration = yield call(Arbitration.methods.arbitrationCases(escrowId).call);
|
escrow.arbitration = yield call(Escrow.methods.arbitrationCases(escrowId).call);
|
||||||
|
|
||||||
yield put({type: LOAD_ARBITRATION_SUCCEEDED, escrow});
|
yield put({type: LOAD_ARBITRATION_SUCCEEDED, escrow});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -104,9 +104,9 @@ export function *onLoadArbitration() {
|
||||||
|
|
||||||
export function *doBuyLicense() {
|
export function *doBuyLicense() {
|
||||||
try {
|
try {
|
||||||
const price = yield call(Arbitration.methods.price().call);
|
const price = yield call(ArbitrationLicense.methods.price().call);
|
||||||
const encodedCall = Arbitration.methods.buy().encodeABI();
|
const encodedCall = ArbitrationLicense.methods.buy().encodeABI();
|
||||||
const toSend = SNT.methods.approveAndCall(Arbitration.options.address, price, encodedCall);
|
const toSend = SNT.methods.approveAndCall(ArbitrationLicense.options.address, price, encodedCall);
|
||||||
const estimatedGas = yield call(toSend.estimateGas);
|
const estimatedGas = yield call(toSend.estimateGas);
|
||||||
const promiseEvent = toSend.send({gasLimit: estimatedGas + 2000});
|
const promiseEvent = toSend.send({gasLimit: estimatedGas + 2000});
|
||||||
const channel = eventChannel(promiseEventEmitter.bind(null, promiseEvent));
|
const channel = eventChannel(promiseEventEmitter.bind(null, promiseEvent));
|
||||||
|
@ -134,7 +134,7 @@ export function *onBuyLicense() {
|
||||||
|
|
||||||
export function *loadPrice() {
|
export function *loadPrice() {
|
||||||
try {
|
try {
|
||||||
const price = yield call(Arbitration.methods.price().call);
|
const price = yield call(ArbitrationLicense.methods.price().call);
|
||||||
yield put({type: LOAD_PRICE_SUCCEEDED, price});
|
yield put({type: LOAD_PRICE_SUCCEEDED, price});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
@ -148,7 +148,7 @@ export function *onLoadPrice() {
|
||||||
|
|
||||||
export function *doCheckLicenseOwner() {
|
export function *doCheckLicenseOwner() {
|
||||||
try {
|
try {
|
||||||
const isLicenseOwner = yield call(Arbitration.methods.isLicenseOwner(web3.eth.defaultAccount).call);
|
const isLicenseOwner = yield call(ArbitrationLicense.methods.isLicenseOwner(web3.eth.defaultAccount).call);
|
||||||
yield put({type: CHECK_LICENSE_OWNER_SUCCEEDED, isLicenseOwner});
|
yield put({type: CHECK_LICENSE_OWNER_SUCCEEDED, isLicenseOwner});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*global web3*/
|
/*global web3*/
|
||||||
import License from '../../../embarkArtifacts/contracts/License';
|
import SellerLicense from '../../../embarkArtifacts/contracts/SellerLicense';
|
||||||
import SNT from '../../../embarkArtifacts/contracts/SNT';
|
import SNT from '../../../embarkArtifacts/contracts/SNT';
|
||||||
import {fork, takeEvery, call, put, take} from 'redux-saga/effects';
|
import {fork, takeEvery, call, put, take} from 'redux-saga/effects';
|
||||||
import {
|
import {
|
||||||
|
@ -18,9 +18,9 @@ window.SNT = SNT;
|
||||||
|
|
||||||
export function *doBuyLicense() {
|
export function *doBuyLicense() {
|
||||||
try {
|
try {
|
||||||
const price = yield call(License.methods.price().call);
|
const price = yield call(SellerLicense.methods.price().call);
|
||||||
const encodedCall = License.methods.buy().encodeABI();
|
const encodedCall = SellerLicense.methods.buy().encodeABI();
|
||||||
const toSend = SNT.methods.approveAndCall(License.options.address, price, encodedCall);
|
const toSend = SNT.methods.approveAndCall(SellerLicense.options.address, price, encodedCall);
|
||||||
const estimatedGas = yield call(toSend.estimateGas);
|
const estimatedGas = yield call(toSend.estimateGas);
|
||||||
const promiseEvent = toSend.send({gasLimit: estimatedGas + 2000});
|
const promiseEvent = toSend.send({gasLimit: estimatedGas + 2000});
|
||||||
const channel = eventChannel(promiseEventEmitter.bind(null, promiseEvent));
|
const channel = eventChannel(promiseEventEmitter.bind(null, promiseEvent));
|
||||||
|
@ -48,7 +48,7 @@ export function *onBuyLicense() {
|
||||||
|
|
||||||
export function *loadPrice() {
|
export function *loadPrice() {
|
||||||
try {
|
try {
|
||||||
const price = yield call(License.methods.price().call);
|
const price = yield call(SellerLicense.methods.price().call);
|
||||||
yield put({type: LOAD_PRICE_SUCCEEDED, price});
|
yield put({type: LOAD_PRICE_SUCCEEDED, price});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
@ -62,7 +62,7 @@ export function *onLoadPrice() {
|
||||||
|
|
||||||
export function *doCheckLicenseOwner() {
|
export function *doCheckLicenseOwner() {
|
||||||
try {
|
try {
|
||||||
const isLicenseOwner = yield call(License.methods.isLicenseOwner(web3.eth.defaultAccount).call);
|
const isLicenseOwner = yield call(SellerLicense.methods.isLicenseOwner(web3.eth.defaultAccount).call);
|
||||||
yield put({type: CHECK_LICENSE_OWNER_SUCCEEDED, isLicenseOwner});
|
yield put({type: CHECK_LICENSE_OWNER_SUCCEEDED, isLicenseOwner});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
@ -77,7 +77,7 @@ export function *onCheckLicenseOwner() {
|
||||||
export function *doGetLicenseOwners() {
|
export function *doGetLicenseOwners() {
|
||||||
try {
|
try {
|
||||||
// TODO get more information like position and rate
|
// TODO get more information like position and rate
|
||||||
const events = yield License.getPastEvents('Bought', {fromBlock: 1});
|
const events = yield SellerLicense.getPastEvents('Bought', {fromBlock: 1});
|
||||||
const licenseOwners = events.map(event => {
|
const licenseOwners = events.map(event => {
|
||||||
return {address: event.returnValues.buyer};
|
return {address: event.returnValues.buyer};
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import MetadataStore from '../../../embarkArtifacts/contracts/MetadataStore';
|
import MetadataStore from '../../../embarkArtifacts/contracts/MetadataStore';
|
||||||
import Arbitration from '../../../embarkArtifacts/contracts/Arbitration';
|
import ArbitrationLicense from '../../../embarkArtifacts/contracts/ArbitrationLicense';
|
||||||
import Escrow from '../../../embarkArtifacts/contracts/Escrow';
|
import Escrow from '../../../embarkArtifacts/contracts/Escrow';
|
||||||
|
|
||||||
import {fork, takeEvery, put, all} from 'redux-saga/effects';
|
import {fork, takeEvery, put, all} from 'redux-saga/effects';
|
||||||
|
@ -16,7 +16,7 @@ import {getLocation} from '../../services/googleMap';
|
||||||
|
|
||||||
export function *loadUser({address}) {
|
export function *loadUser({address}) {
|
||||||
try {
|
try {
|
||||||
const isArbitrator = yield Arbitration.methods.isArbitrator(address).call();
|
const isArbitrator = yield ArbitrationLicense.methods.isLicenseOwner(address).call();
|
||||||
const isUser = yield MetadataStore.methods.userWhitelist(address).call();
|
const isUser = yield MetadataStore.methods.userWhitelist(address).call();
|
||||||
|
|
||||||
let user = {
|
let user = {
|
||||||
|
|
|
@ -78,9 +78,6 @@ class EditMyContact extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
console.log(this.props);
|
|
||||||
console.log(this.state);
|
|
||||||
|
|
||||||
if(!this.props.profile){
|
if(!this.props.profile){
|
||||||
return <Loading />;
|
return <Loading />;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
const EthUtil = require('ethereumjs-util');
|
const EthUtil = require('ethereumjs-util');
|
||||||
const TestUtils = require("../utils/testUtils");
|
const TestUtils = require("../utils/testUtils");
|
||||||
|
|
||||||
const License = embark.require('Embark/contracts/License');
|
const SellerLicense = embark.require('Embark/contracts/SellerLicense');
|
||||||
|
const ArbitrationLicense = embark.require('Embark/contracts/ArbitrationLicense');
|
||||||
const MetadataStore = embark.require('Embark/contracts/MetadataStore');
|
const MetadataStore = embark.require('Embark/contracts/MetadataStore');
|
||||||
const Escrow = embark.require('Embark/contracts/Escrow');
|
const Escrow = embark.require('Embark/contracts/Escrow');
|
||||||
const StandardToken = embark.require('Embark/contracts/StandardToken');
|
const StandardToken = embark.require('Embark/contracts/StandardToken');
|
||||||
const SNT = embark.require('Embark/contracts/SNT');
|
const SNT = embark.require('Embark/contracts/SNT');
|
||||||
const Arbitration = embark.require('Embark/contracts/Arbitration');
|
|
||||||
|
|
||||||
|
|
||||||
const ESCROW_CREATED = 0;
|
const ESCROW_CREATED = 0;
|
||||||
|
@ -54,20 +54,22 @@ config({
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
License: {
|
License: {
|
||||||
|
deploy: false
|
||||||
|
},
|
||||||
|
SellerLicense: {
|
||||||
|
instanceOf: "License",
|
||||||
|
args: ["$SNT", 10]
|
||||||
|
},
|
||||||
|
ArbitrationLicense: {
|
||||||
|
instanceOf: "License",
|
||||||
args: ["$SNT", 10]
|
args: ["$SNT", 10]
|
||||||
},
|
},
|
||||||
MetadataStore: {
|
MetadataStore: {
|
||||||
args: ["$License", "$Arbitration"]
|
args: ["$SellerLicense", "$ArbitrationLicense"]
|
||||||
},
|
|
||||||
Arbitration: {
|
|
||||||
args: ["$SNT", 10]
|
|
||||||
},
|
},
|
||||||
Escrow: {
|
Escrow: {
|
||||||
args: ["$License", "$Arbitration", "$MetadataStore", "$SNT", "0x0000000000000000000000000000000000000001", feeAmount],
|
args: ["$SellerLicense", "$ArbitrationLicense", "$MetadataStore", "$SNT", "0x0000000000000000000000000000000000000001", feeAmount],
|
||||||
onDeploy: [
|
onDeploy: ["MetadataStore.methods.setEscrowAddress('$Escrow').send()"]
|
||||||
"Arbitration.methods.setEscrowAddress('$Escrow').send()",
|
|
||||||
"MetadataStore.methods.setEscrowAddress('$Escrow').send()"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
StandardToken: {
|
StandardToken: {
|
||||||
}
|
}
|
||||||
|
@ -95,27 +97,21 @@ contract("Escrow", function() {
|
||||||
this.timeout(0);
|
this.timeout(0);
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
|
|
||||||
const escrowEvents = Escrow.options.jsonInterface.filter(x => x.type === 'event');
|
|
||||||
const arbitrationEvents = Arbitration.options.jsonInterface.filter(x => x.type === 'event');
|
|
||||||
|
|
||||||
Escrow.options.jsonInterface = Escrow.options.jsonInterface.concat(arbitrationEvents);
|
|
||||||
Arbitration.options.jsonInterface = Arbitration.options.jsonInterface.concat(escrowEvents);
|
|
||||||
|
|
||||||
await SNT.methods.generateTokens(accounts[0], 1000).send();
|
await SNT.methods.generateTokens(accounts[0], 1000).send();
|
||||||
const encodedCall = License.methods.buy().encodeABI();
|
const encodedCall = SellerLicense.methods.buy().encodeABI();
|
||||||
await SNT.methods.approveAndCall(License.options.address, 10, encodedCall).send({from: accounts[0]});
|
await SNT.methods.approveAndCall(SellerLicense.options.address, 10, encodedCall).send({from: accounts[0]});
|
||||||
|
|
||||||
// Register arbitrators
|
// Register arbitrators
|
||||||
await SNT.methods.generateTokens(arbitrator, 1000).send();
|
await SNT.methods.generateTokens(arbitrator, 1000).send();
|
||||||
await SNT.methods.generateTokens(arbitrator2, 1000).send();
|
await SNT.methods.generateTokens(arbitrator2, 1000).send();
|
||||||
const encodedCall2 = Arbitration.methods.buy().encodeABI();
|
|
||||||
await SNT.methods.approveAndCall(Arbitration.options.address, 10, encodedCall2).send({from: arbitrator});
|
|
||||||
await SNT.methods.approveAndCall(Arbitration.options.address, 10, encodedCall2).send({from: arbitrator2});
|
|
||||||
|
|
||||||
receipt = await MetadataStore.methods.addOffer(TestUtils.zeroAddress, License.address, "London", "USD", "Iuri", [0], 1, arbitrator).send({from: accounts[0]});
|
const encodedCall2 = ArbitrationLicense.methods.buy().encodeABI();
|
||||||
|
await SNT.methods.approveAndCall(ArbitrationLicense.options.address, 10, encodedCall2).send({from: arbitrator});
|
||||||
|
await SNT.methods.approveAndCall(ArbitrationLicense.options.address, 10, encodedCall2).send({from: arbitrator2});
|
||||||
|
|
||||||
|
receipt = await MetadataStore.methods.addOffer(TestUtils.zeroAddress, SellerLicense.address, "London", "USD", "Iuri", [0], 1, arbitrator).send({from: accounts[0]});
|
||||||
ethOfferId = receipt.events.OfferAdded.returnValues.offerId;
|
ethOfferId = receipt.events.OfferAdded.returnValues.offerId;
|
||||||
receipt = await MetadataStore.methods.addOffer(StandardToken.options.address, License.address, "London", "USD", "Iuri", [0], 1, arbitrator).send({from: accounts[0]});
|
receipt = await MetadataStore.methods.addOffer(StandardToken.options.address, SellerLicense.address, "London", "USD", "Iuri", [0], 1, arbitrator).send({from: accounts[0]});
|
||||||
tokenOfferId = receipt.events.OfferAdded.returnValues.offerId;
|
tokenOfferId = receipt.events.OfferAdded.returnValues.offerId;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -676,12 +672,12 @@ contract("Escrow", function() {
|
||||||
|
|
||||||
receipt = await Escrow.methods['pay(uint256,bytes)'](escrowId, signatureRPC).send({from: accounts[8]});
|
receipt = await Escrow.methods['pay(uint256,bytes)'](escrowId, signatureRPC).send({from: accounts[8]});
|
||||||
|
|
||||||
messageToSign = await Escrow.methods.openCaseSignHash(escrowId).call();
|
messageToSign = await Escrow.methods.openCaseSignHash(escrowId, "My motive is...").call();
|
||||||
msgHash = EthUtil.hashPersonalMessage(Buffer.from(EthUtil.stripHexPrefix(messageToSign), 'hex'));
|
msgHash = EthUtil.hashPersonalMessage(Buffer.from(EthUtil.stripHexPrefix(messageToSign), 'hex'));
|
||||||
signature = EthUtil.ecsign(msgHash, privateKey);
|
signature = EthUtil.ecsign(msgHash, privateKey);
|
||||||
signatureRPC = EthUtil.toRpcSig(signature.v, signature.r, signature.s);
|
signatureRPC = EthUtil.toRpcSig(signature.v, signature.r, signature.s);
|
||||||
|
|
||||||
receipt = await Escrow.methods.openCaseWithSignature(escrowId, signatureRPC).send({from: accounts[9]});
|
receipt = await Escrow.methods.openCaseWithSignature(escrowId, "My motive is...", signatureRPC).send({from: accounts[9]});
|
||||||
const arbitrationRequired = receipt.events.ArbitrationRequired;
|
const arbitrationRequired = receipt.events.ArbitrationRequired;
|
||||||
assert(!!arbitrationRequired, "ArbitrationRequired() not triggered");
|
assert(!!arbitrationRequired, "ArbitrationRequired() not triggered");
|
||||||
assert.equal(arbitrationRequired.returnValues.escrowId, escrowId, "Invalid escrowId");
|
assert.equal(arbitrationRequired.returnValues.escrowId, escrowId, "Invalid escrowId");
|
||||||
|
@ -695,7 +691,7 @@ contract("Escrow", function() {
|
||||||
await Escrow.methods.openCase(escrowId, 'Motive').send({from: accounts[1]});
|
await Escrow.methods.openCase(escrowId, 'Motive').send({from: accounts[1]});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
receipt = await Arbitration.methods.setArbitrationResult(escrowId, ARBITRATION_SOLVED_BUYER).send({from: accounts[1]});
|
receipt = await Escrow.methods.setArbitrationResult(escrowId, ARBITRATION_SOLVED_BUYER).send({from: accounts[1]});
|
||||||
assert.fail('should have reverted before');
|
assert.fail('should have reverted before');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
assert.strictEqual(error.message, "VM Exception while processing transaction: revert Only arbitrators can invoke this function");
|
assert.strictEqual(error.message, "VM Exception while processing transaction: revert Only arbitrators can invoke this function");
|
||||||
|
@ -707,7 +703,7 @@ contract("Escrow", function() {
|
||||||
await Escrow.methods.openCase(escrowId, 'Motive').send({from: accounts[1]});
|
await Escrow.methods.openCase(escrowId, 'Motive').send({from: accounts[1]});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
receipt = await Arbitration.methods.setArbitrationResult(escrowId, ARBITRATION_SOLVED_BUYER).send({from: arbitrator2});
|
receipt = await Escrow.methods.setArbitrationResult(escrowId, ARBITRATION_SOLVED_BUYER).send({from: arbitrator2});
|
||||||
assert.fail('should have reverted before');
|
assert.fail('should have reverted before');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
TestUtils.assertJump(error);
|
TestUtils.assertJump(error);
|
||||||
|
@ -719,13 +715,13 @@ contract("Escrow", function() {
|
||||||
receipt = await Escrow.methods.openCase(escrowId, 'Motive').send({from: accounts[1]});
|
receipt = await Escrow.methods.openCase(escrowId, 'Motive').send({from: accounts[1]});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
receipt = await Arbitration.methods.cancelArbitration(escrowId).send({from: accounts[0]});
|
receipt = await Escrow.methods.cancelArbitration(escrowId).send({from: accounts[0]});
|
||||||
assert.fail('should have reverted before');
|
assert.fail('should have reverted before');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
assert.strictEqual(error.message, "VM Exception while processing transaction: revert Arbitration can only be canceled by the opener");
|
assert.strictEqual(error.message, "VM Exception while processing transaction: revert Arbitration can only be canceled by the opener");
|
||||||
}
|
}
|
||||||
|
|
||||||
receipt = await Arbitration.methods.cancelArbitration(escrowId).send({from: accounts[1]});
|
receipt = await Escrow.methods.cancelArbitration(escrowId).send({from: accounts[1]});
|
||||||
const arbitrationCanceled = receipt.events.ArbitrationCanceled;
|
const arbitrationCanceled = receipt.events.ArbitrationCanceled;
|
||||||
assert(!!arbitrationCanceled, "ArbitrationCanceled() not triggered");
|
assert(!!arbitrationCanceled, "ArbitrationCanceled() not triggered");
|
||||||
assert.equal(arbitrationCanceled.returnValues.escrowId, escrowId, "Invalid escrowId");
|
assert.equal(arbitrationCanceled.returnValues.escrowId, escrowId, "Invalid escrowId");
|
||||||
|
@ -735,7 +731,7 @@ contract("Escrow", function() {
|
||||||
await Escrow.methods.pay(escrowId).send({from: accounts[1]});
|
await Escrow.methods.pay(escrowId).send({from: accounts[1]});
|
||||||
await Escrow.methods.openCase(escrowId, 'Motive').send({from: accounts[1]});
|
await Escrow.methods.openCase(escrowId, 'Motive').send({from: accounts[1]});
|
||||||
|
|
||||||
receipt = await Arbitration.methods.setArbitrationResult(escrowId, ARBITRATION_SOLVED_BUYER).send({from: arbitrator});
|
receipt = await Escrow.methods.setArbitrationResult(escrowId, ARBITRATION_SOLVED_BUYER).send({from: arbitrator});
|
||||||
const released = receipt.events.Released;
|
const released = receipt.events.Released;
|
||||||
assert(!!released, "Released() not triggered");
|
assert(!!released, "Released() not triggered");
|
||||||
});
|
});
|
||||||
|
@ -744,7 +740,7 @@ contract("Escrow", function() {
|
||||||
await Escrow.methods.pay(escrowId).send({from: accounts[1]});
|
await Escrow.methods.pay(escrowId).send({from: accounts[1]});
|
||||||
await Escrow.methods.openCase(escrowId, 'Motive').send({from: accounts[1]});
|
await Escrow.methods.openCase(escrowId, 'Motive').send({from: accounts[1]});
|
||||||
|
|
||||||
receipt = await Arbitration.methods.setArbitrationResult(escrowId, ARBITRATION_SOLVED_SELLER).send({from: arbitrator});
|
receipt = await Escrow.methods.setArbitrationResult(escrowId, ARBITRATION_SOLVED_SELLER).send({from: arbitrator});
|
||||||
|
|
||||||
const released = receipt.events.Canceled;
|
const released = receipt.events.Canceled;
|
||||||
assert(!!released, "Canceled() not triggered");
|
assert(!!released, "Canceled() not triggered");
|
||||||
|
@ -753,10 +749,10 @@ contract("Escrow", function() {
|
||||||
it("cannot cancel a solved arbitration", async() => {
|
it("cannot cancel a solved arbitration", async() => {
|
||||||
await Escrow.methods.pay(escrowId).send({from: accounts[1]});
|
await Escrow.methods.pay(escrowId).send({from: accounts[1]});
|
||||||
receipt = await Escrow.methods.openCase(escrowId, 'Motive').send({from: accounts[1]});
|
receipt = await Escrow.methods.openCase(escrowId, 'Motive').send({from: accounts[1]});
|
||||||
receipt = await Arbitration.methods.setArbitrationResult(escrowId, ARBITRATION_SOLVED_SELLER).send({from: arbitrator});
|
receipt = await Escrow.methods.setArbitrationResult(escrowId, ARBITRATION_SOLVED_SELLER).send({from: arbitrator});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
receipt = await Arbitration.methods.cancelArbitration(escrowId).send({from: accounts[1]});
|
receipt = await Escrow.methods.cancelArbitration(escrowId).send({from: accounts[1]});
|
||||||
assert.fail('should have reverted before');
|
assert.fail('should have reverted before');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
assert.strictEqual(error.message, "VM Exception while processing transaction: revert Arbitration already solved or not open");
|
assert.strictEqual(error.message, "VM Exception while processing transaction: revert Arbitration already solved or not open");
|
||||||
|
@ -868,10 +864,10 @@ contract("Escrow", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("arbitrator should be valid", async () => {
|
it("arbitrator should be valid", async () => {
|
||||||
const isArbitrator = await Arbitration.methods.isArbitrator(arbitrator).call();
|
const isArbitrator = await ArbitrationLicense.methods.isLicenseOwner(arbitrator).call();
|
||||||
assert.equal(isArbitrator, true, "Invalid arbitrator");
|
assert.equal(isArbitrator, true, "Invalid arbitrator");
|
||||||
|
|
||||||
const nonArbitrator = await Arbitration.methods.isArbitrator(accounts[5]).call();
|
const nonArbitrator = await ArbitrationLicense.methods.isLicenseOwner(accounts[5]).call();
|
||||||
assert.equal(nonArbitrator, false, "Account should not be an arbitrator");
|
assert.equal(nonArbitrator, false, "Account should not be an arbitrator");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/*global contract, config, it, embark, web3, before, describe, beforeEach*/
|
/*global contract, config, it, embark, web3, before, describe, beforeEach*/
|
||||||
const TestUtils = require("../utils/testUtils");
|
const TestUtils = require("../utils/testUtils");
|
||||||
|
|
||||||
const License = embark.require('Embark/contracts/License');
|
const SellerLicense = embark.require('Embark/contracts/SellerLicense');
|
||||||
const MetadataStore = embark.require('Embark/contracts/MetadataStore');
|
const MetadataStore = embark.require('Embark/contracts/MetadataStore');
|
||||||
const Arbitration = embark.require('Embark/contracts/Arbitration');
|
const ArbitrationLicense = embark.require('Embark/contracts/ArbitrationLicense');
|
||||||
const Escrow = embark.require('Embark/contracts/Escrow');
|
const Escrow = embark.require('Embark/contracts/Escrow');
|
||||||
const StandardToken = embark.require('Embark/contracts/StandardToken');
|
const StandardToken = embark.require('Embark/contracts/StandardToken');
|
||||||
const SNT = embark.require('Embark/contracts/SNT');
|
const SNT = embark.require('Embark/contracts/SNT');
|
||||||
|
@ -36,18 +36,22 @@ config({
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
License: {
|
License: {
|
||||||
|
deploy: false
|
||||||
|
},
|
||||||
|
SellerLicense: {
|
||||||
|
instanceOf: "License",
|
||||||
args: ["$SNT", 10]
|
args: ["$SNT", 10]
|
||||||
},
|
},
|
||||||
MetadataStore: {
|
MetadataStore: {
|
||||||
args: ["$License", "$Arbitration"]
|
args: ["$SellerLicense", "$ArbitrationLicense"]
|
||||||
},
|
},
|
||||||
Arbitration: {
|
ArbitrationLicense: {
|
||||||
|
instanceOf: "License",
|
||||||
args: ["$SNT", 10]
|
args: ["$SNT", 10]
|
||||||
},
|
},
|
||||||
Escrow: {
|
Escrow: {
|
||||||
args: ["$License", "$accounts[5]", "$MetadataStore", "$SNT", "0x0000000000000000000000000000000000000001", feeAmount],
|
args: ["$SellerLicense", "$ArbitrationLicense", "$MetadataStore", "$SNT", "0x0000000000000000000000000000000000000001", feeAmount],
|
||||||
onDeploy: [
|
onDeploy: [
|
||||||
"Arbitration.methods.setEscrowAddress('$Escrow').send()",
|
|
||||||
"MetadataStore.methods.setEscrowAddress('$Escrow').send()"
|
"MetadataStore.methods.setEscrowAddress('$Escrow').send()"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -75,22 +79,22 @@ contract("Escrow Funding", function() {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
await StandardToken.methods.mint(accounts[0], 100000000).send();
|
await StandardToken.methods.mint(accounts[0], 100000000).send();
|
||||||
await SNT.methods.generateTokens(accounts[0], 100000000).send();
|
await SNT.methods.generateTokens(accounts[0], 100000000).send();
|
||||||
const encodedCall = License.methods.buy().encodeABI();
|
const encodedCall = SellerLicense.methods.buy().encodeABI();
|
||||||
await SNT.methods.approveAndCall(License.options.address, 10, encodedCall).send({from: accounts[0]});
|
await SNT.methods.approveAndCall(SellerLicense.options.address, 10, encodedCall).send({from: accounts[0]});
|
||||||
|
|
||||||
// Register arbitrators
|
// Register arbitrators
|
||||||
arbitrator = accounts[9];
|
arbitrator = accounts[9];
|
||||||
await SNT.methods.generateTokens(arbitrator, 1000).send();
|
await SNT.methods.generateTokens(arbitrator, 1000).send();
|
||||||
const encodedCall2 = Arbitration.methods.buy().encodeABI();
|
const encodedCall2 = ArbitrationLicense.methods.buy().encodeABI();
|
||||||
await SNT.methods.approveAndCall(Arbitration.options.address, 10, encodedCall2).send({from: arbitrator});
|
await SNT.methods.approveAndCall(ArbitrationLicense.options.address, 10, encodedCall2).send({from: arbitrator});
|
||||||
|
|
||||||
receipt = await MetadataStore.methods.addOffer(TestUtils.zeroAddress, License.address, "London", "USD", "Iuri", [0], 1, arbitrator).send({from: accounts[0]});
|
receipt = await MetadataStore.methods.addOffer(TestUtils.zeroAddress, SellerLicense.address, "London", "USD", "Iuri", [0], 1, arbitrator).send({from: accounts[0]});
|
||||||
ethOfferId = receipt.events.OfferAdded.returnValues.offerId;
|
ethOfferId = receipt.events.OfferAdded.returnValues.offerId;
|
||||||
|
|
||||||
receipt = await MetadataStore.methods.addOffer(StandardToken.options.address, License.address, "London", "USD", "Iuri", [0], 1, arbitrator).send({from: accounts[0]});
|
receipt = await MetadataStore.methods.addOffer(StandardToken.options.address, SellerLicense.address, "London", "USD", "Iuri", [0], 1, arbitrator).send({from: accounts[0]});
|
||||||
tokenOfferId = receipt.events.OfferAdded.returnValues.offerId;
|
tokenOfferId = receipt.events.OfferAdded.returnValues.offerId;
|
||||||
|
|
||||||
receipt = await MetadataStore.methods.addOffer(SNT.options.address, License.address, "London", "USD", "Iuri", [0], 1, arbitrator).send({from: accounts[0]});
|
receipt = await MetadataStore.methods.addOffer(SNT.options.address, SellerLicense.address, "London", "USD", "Iuri", [0], 1, arbitrator).send({from: accounts[0]});
|
||||||
SNTOfferId = receipt.events.OfferAdded.returnValues.offerId;
|
SNTOfferId = receipt.events.OfferAdded.returnValues.offerId;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
/*global contract, config, it, assert, before*/
|
/*global contract, config, it, assert, before*/
|
||||||
|
|
||||||
const License = require('Embark/contracts/License');
|
const SellerLicense = require('Embark/contracts/SellerLicense');
|
||||||
|
const ArbitrationLicense = require('Embark/contracts/ArbitrationLicense');
|
||||||
|
|
||||||
const SNT = require('Embark/contracts/SNT');
|
const SNT = require('Embark/contracts/SNT');
|
||||||
const MetadataStore = require('Embark/contracts/MetadataStore');
|
const MetadataStore = require('Embark/contracts/MetadataStore');
|
||||||
|
|
||||||
|
@ -24,14 +26,19 @@ config({
|
||||||
true
|
true
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
Arbitration: {
|
License: {
|
||||||
|
deploy: false
|
||||||
|
},
|
||||||
|
SellerLicense: {
|
||||||
|
instanceOf: "License",
|
||||||
args: ["$SNT", 10]
|
args: ["$SNT", 10]
|
||||||
},
|
},
|
||||||
License: {
|
ArbitrationLicense: {
|
||||||
|
instanceOf: "License",
|
||||||
args: ["$SNT", 10]
|
args: ["$SNT", 10]
|
||||||
},
|
},
|
||||||
MetadataStore: {
|
MetadataStore: {
|
||||||
args: ["$License", "$Arbitration"]
|
args: ["$SellerLicense", "$ArbitrationLicense"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, (_err, web3_accounts) => {
|
}, (_err, web3_accounts) => {
|
||||||
|
@ -45,7 +52,7 @@ contract("MetadataStore", function () {
|
||||||
|
|
||||||
it("should not allow to add new user when not license owner", async function () {
|
it("should not allow to add new user when not license owner", async function () {
|
||||||
try {
|
try {
|
||||||
await MetadataStore.methods.addOffer(SNT.address, License.address, "London", "USD", "Iuri", [0], 1, accounts[9]).send();
|
await MetadataStore.methods.addOffer(SNT.address, SellerLicense.address, "London", "USD", "Iuri", [0], 1, accounts[9]).send();
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
const usersSize = await MetadataStore.methods.usersSize().call();
|
const usersSize = await MetadataStore.methods.usersSize().call();
|
||||||
assert.strictEqual(usersSize, '0');
|
assert.strictEqual(usersSize, '0');
|
||||||
|
@ -53,9 +60,9 @@ contract("MetadataStore", function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should allow to add new user and offer when license owner", async function () {
|
it("should allow to add new user and offer when license owner", async function () {
|
||||||
const encodedCall = License.methods.buy().encodeABI();
|
const encodedCall = SellerLicense.methods.buy().encodeABI();
|
||||||
await SNT.methods.approveAndCall(License.options.address, 10, encodedCall).send();
|
await SNT.methods.approveAndCall(SellerLicense.options.address, 10, encodedCall).send();
|
||||||
await MetadataStore.methods.addOffer(SNT.address, License.address, "London", "USD", "Iuri", [0], 1, accounts[9]).send();
|
await MetadataStore.methods.addOffer(SNT.address, SellerLicense.address, "London", "USD", "Iuri", [0], 1, accounts[9]).send();
|
||||||
const usersSize = await MetadataStore.methods.usersSize().call();
|
const usersSize = await MetadataStore.methods.usersSize().call();
|
||||||
assert.strictEqual(usersSize, '1');
|
assert.strictEqual(usersSize, '1');
|
||||||
const offersSize = await MetadataStore.methods.offersSize().call();
|
const offersSize = await MetadataStore.methods.offersSize().call();
|
||||||
|
@ -63,7 +70,7 @@ contract("MetadataStore", function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should allow to add new offer only when already a user", async function () {
|
it("should allow to add new offer only when already a user", async function () {
|
||||||
await MetadataStore.methods.addOffer(SNT.address, License.address, "London", "EUR", "Iuri", [0], 1, accounts[9]).send();
|
await MetadataStore.methods.addOffer(SNT.address, SellerLicense.address, "London", "EUR", "Iuri", [0], 1, accounts[9]).send();
|
||||||
const usersSize = await MetadataStore.methods.usersSize().call();
|
const usersSize = await MetadataStore.methods.usersSize().call();
|
||||||
assert.strictEqual(usersSize, '1');
|
assert.strictEqual(usersSize, '1');
|
||||||
const offersSize = await MetadataStore.methods.offersSize().call();
|
const offersSize = await MetadataStore.methods.offersSize().call();
|
||||||
|
@ -72,7 +79,7 @@ contract("MetadataStore", function () {
|
||||||
|
|
||||||
it("should not allow to add new offer when margin is more than 100", async function () {
|
it("should not allow to add new offer when margin is more than 100", async function () {
|
||||||
try {
|
try {
|
||||||
await MetadataStore.methods.addOffer(SNT.address, License.address, "London", "USD", "Iuri", [0], 101, accounts[9]).send();
|
await MetadataStore.methods.addOffer(SNT.address, SellerLicense.address, "London", "USD", "Iuri", [0], 101, accounts[9]).send();
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
const usersSize = await MetadataStore.methods.usersSize().call();
|
const usersSize = await MetadataStore.methods.usersSize().call();
|
||||||
assert.strictEqual(usersSize, '1');
|
assert.strictEqual(usersSize, '1');
|
||||||
|
@ -80,7 +87,7 @@ contract("MetadataStore", function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should allow to update a user and offer", async function () {
|
it("should allow to update a user and offer", async function () {
|
||||||
await MetadataStore.methods.updateOffer(0, SNT.address, License.address, "Paris", "EUR", "Iuri", [0], 1, accounts[9]).send();
|
await MetadataStore.methods.updateOffer(0, SNT.address, SellerLicense.address, "Paris", "EUR", "Iuri", [0], 1, accounts[9]).send();
|
||||||
const usersSize = await MetadataStore.methods.usersSize().call();
|
const usersSize = await MetadataStore.methods.usersSize().call();
|
||||||
assert.strictEqual(usersSize, '1');
|
assert.strictEqual(usersSize, '1');
|
||||||
const user = await MetadataStore.methods.users(0).call();
|
const user = await MetadataStore.methods.users(0).call();
|
||||||
|
@ -100,7 +107,7 @@ contract("MetadataStore", function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should allow to delete an offer", async function () {
|
it("should allow to delete an offer", async function () {
|
||||||
const receipt = await MetadataStore.methods.addOffer(SNT.address, License.address, "London", "EUR", "Iuri", [0], 1, accounts[9]).send();
|
const receipt = await MetadataStore.methods.addOffer(SNT.address, SellerLicense.address, "London", "EUR", "Iuri", [0], 1, accounts[9]).send();
|
||||||
const offerAdded = receipt.events.OfferAdded;
|
const offerAdded = receipt.events.OfferAdded;
|
||||||
const offerId = offerAdded.returnValues.offerId;
|
const offerId = offerAdded.returnValues.offerId;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue