Skip to content

Commit 71683c0

Browse files
committed
1 parent cd4f710 commit 71683c0

File tree

2 files changed

+40
-31
lines changed

2 files changed

+40
-31
lines changed

contracts/standard/arbitration/MultipleArbitrableTokenTransaction.sol

+38-29
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@
77
*/
88

99
/** @title Multiple Arbitrable ERC20 Token Transaction
10-
* This is a a contract for multiple arbitrated token transactions which can be reversed by an arbitrator.
10+
* This is a contract for multiple arbitrated token transactions which can be reversed by an arbitrator.
1111
* This can be used for buying goods, services and for paying freelancers.
1212
* Parties are identified as "seller" and "buyer".
13-
* NOTE: All functions that interact with the ERC20 token contract as UNTRUSTED.
1413
*/
1514

1615
pragma solidity ^0.4.24;
@@ -57,7 +56,7 @@ contract MultipleArbitrableTokenTransaction {
5756
// **************************** //
5857

5958
/** @dev To be emitted when meta-evidence is submitted.
60-
* @param _metaEvidenceID Unique identifier of meta-evidence. Should be the transactionID.
59+
* @param _metaEvidenceID Unique identifier of meta-evidence. Should be the `transactionID`.
6160
* @param _evidence A link to the meta-evidence JSON.
6261
*/
6362
event MetaEvidence(uint indexed _metaEvidenceID, string _evidence);
@@ -72,7 +71,7 @@ contract MultipleArbitrableTokenTransaction {
7271
* @param _arbitrator The arbitrator of the contract.
7372
* @param _disputeID ID of the dispute in the Arbitrator contract.
7473
* @param _party The address of the party submitting the evidence. Note that 0 is kept for evidences not submitted by any party.
75-
* @param _evidence A link to evidence or if it is short the evidence itself. Can be web link ("http://X"), IPFS ("ipfs:/X") or another storing service (using the URI, see https://en.wikipedia.org/wiki/Uniform_Resource_Identifier ). One usecase of short evidence is to include the hash of the plain English contract.
74+
* @param _evidence A link to an evidence JSON that follows the ERC 1497 Evidence standard (https://github.com/ethereum/EIPs/issues/1497).
7675
*/
7776
event Evidence(Arbitrator indexed _arbitrator, uint indexed _disputeID, address indexed _party, string _evidence);
7877

@@ -113,7 +112,7 @@ contract MultipleArbitrableTokenTransaction {
113112
feeTimeout = _feeTimeout;
114113
}
115114

116-
/** @dev Create a transaction.
115+
/** @dev Create a transaction. UNTRUSTED.
117116
* @param _amount The amount of tokens in this transaction.
118117
* @param _timeoutPayment Time after which a party automatically lose a dispute.
119118
* @param _seller The recipient of the transaction.
@@ -126,7 +125,6 @@ contract MultipleArbitrableTokenTransaction {
126125
address _seller,
127126
string _metaEvidence
128127
) public returns (uint transactionIndex) {
129-
130128
// Transfers token from sender wallet to contract.
131129
require(token.transferFrom(msg.sender, address(this), _amount), "Sender does not have enough funds.");
132130

@@ -146,7 +144,7 @@ contract MultipleArbitrableTokenTransaction {
146144
return transactions.length - 1;
147145
}
148146

149-
/** @dev Pay seller. To be called if the good or service is provided.
147+
/** @dev Pay seller. To be called if the good or service is provided. UNTRUSTED.
150148
* @param _transactionID The index of the transaction.
151149
* @param _amount Amount to pay in tokens.
152150
*/
@@ -156,11 +154,11 @@ contract MultipleArbitrableTokenTransaction {
156154
require(transaction.status == Status.NoDispute, "The transaction can't be disputed.");
157155
require(_amount <= transaction.amount, "The amount paid has to be less or equal than the transaction.");
158156

159-
token.transfer(transaction.seller, _amount);
160157
transaction.amount -= _amount;
158+
require(token.transfer(transaction.seller, _amount) != false, "The `transfer` function must not returns `false`.");
161159
}
162160

163-
/** @dev Reimburse buyer. To be called if the good or service can't be fully provided.
161+
/** @dev Reimburse buyer. To be called if the good or service can't be fully provided. UNTRUSTED.
164162
* @param _transactionID The index of the transaction.
165163
* @param _amountReimbursed Amount to reimburse in tokens.
166164
*/
@@ -170,25 +168,27 @@ contract MultipleArbitrableTokenTransaction {
170168
require(transaction.status == Status.NoDispute, "The transaction can't be disputed.");
171169
require(_amountReimbursed <= transaction.amount, "The amount reimbursed has to be less or equal than the transaction.");
172170

173-
token.transfer(transaction.buyer, _amountReimbursed);
174171
transaction.amount -= _amountReimbursed;
172+
token.transfer(transaction.buyer, _amountReimbursed);
175173
}
176174

177-
/** @dev Transfer the transaction's amount to the seller if the timeout has passed.
175+
/** @dev Transfer the transaction's amount to the seller if the timeout has passed. UNTRUSTED.
178176
* @param _transactionID The index of the transaction.
179177
*/
180178
function executeTransaction(uint _transactionID) public {
181179
Transaction storage transaction = transactions[_transactionID];
182180
require(now - transaction.lastInteraction >= transaction.timeoutPayment, "The timeout has not passed yet.");
183181
require(transaction.status == Status.NoDispute, "The transaction can't be disputed.");
184182

185-
token.transfer(transaction.seller, transaction.amount);
183+
uint amount = transaction.amount;
186184
transaction.amount = 0;
187185

188186
transaction.status = Status.Resolved;
187+
188+
token.transfer(transaction.seller, amount);
189189
}
190190

191-
/** @dev Reimburse buyer if seller fails to pay the fee.
191+
/** @dev Reimburse buyer if seller fails to pay the fee. UNTRUSTED.
192192
* @param _transactionID The index of the transaction.
193193
*/
194194
function timeOutByBuyer(uint _transactionID) public {
@@ -200,7 +200,7 @@ contract MultipleArbitrableTokenTransaction {
200200
executeRuling(_transactionID, uint(RulingOptions.BuyerWins));
201201
}
202202

203-
/** @dev Pay seller if buyer fails to pay the fee.
203+
/** @dev Pay seller if buyer fails to pay the fee. UNTRUSTED.
204204
* @param _transactionID The index of the transaction.
205205
*/
206206
function timeOutBySeller(uint _transactionID) public {
@@ -237,7 +237,7 @@ contract MultipleArbitrableTokenTransaction {
237237
}
238238

239239
/** @dev Pay the arbitration fee to raise a dispute. To be called by the seller. UNTRUSTED.
240-
* Note that the arbitrator can have createDispute throw, which will make this function throw and therefore lead to a party being timed-out.
240+
* Note that the arbitrator can have `createDispute` throw, which will make this function throw and therefore lead to a party being timed-out.
241241
* This is not a vulnerability as the arbitrator can rule in favor of one party anyway.
242242
* @param _transactionID The index of the transaction.
243243
*/
@@ -252,7 +252,7 @@ contract MultipleArbitrableTokenTransaction {
252252
require(transaction.sellerFee >= arbitrationCost, "The seller fee must cover arbitration costs.");
253253

254254
transaction.lastInteraction = now;
255-
// The buyer still has to pay. This can also happen if he has paid, but arbitrationCost has increased.
255+
// The buyer still has to pay. This can also happen if he has paid, but `arbitrationCost` has increased.
256256
if (transaction.buyerFee < arbitrationCost) {
257257
transaction.status = Status.WaitingBuyer;
258258
emit HasToPayFee(_transactionID, Party.Buyer);
@@ -300,7 +300,7 @@ contract MultipleArbitrableTokenTransaction {
300300
emit Evidence(arbitrator, transaction.disputeId, msg.sender, _evidence);
301301
}
302302

303-
/** @dev Appeal an appealable ruling.
303+
/** @dev Appeal an appealable ruling. UNTRUSTED.
304304
* Transfer the funds to the arbitrator.
305305
* Note that no checks are required as the checks are done by the arbitrator.
306306
* @param _transactionID The index of the transaction.
@@ -329,28 +329,37 @@ contract MultipleArbitrableTokenTransaction {
329329

330330
/** @dev Execute a ruling of a dispute. It reimburses the fee to the winning party.
331331
* @param _transactionID The index of the transaction.
332-
* @param _ruling Ruling given by the arbitrator. 1 : Reimburse the buyer. 2 : Pay the seller.
332+
* @param _ruling Ruling given by the arbitrator. 1: Reimburse the buyer. 2: Pay the seller.
333333
*/
334334
function executeRuling(uint _transactionID, uint _ruling) internal {
335335
Transaction storage transaction = transactions[_transactionID];
336336
require(_ruling <= AMOUNT_OF_CHOICES, "Invalid ruling.");
337337

338-
// Give the arbitration fee back.
339-
// Note that we use send to prevent a party from blocking the execution.
340-
if (_ruling == uint(RulingOptions.SellerWins)) {
341-
token.transfer(transaction.seller, transaction.amount);
342-
} else if (_ruling == uint(RulingOptions.BuyerWins)) {
343-
token.transfer(transaction.buyer, transaction.amount);
344-
} else {
345-
// FIXME uneven token amount?
346-
token.transfer(transaction.buyer, transaction.amount / 2);
347-
token.transfer(transaction.seller, transaction.amount / 2);
348-
}
338+
uint amount = transaction.amount;
339+
uint sellerFee = transaction.sellerFee;
340+
uint buyerFee = transaction.buyerFee;
349341

350342
transaction.amount = 0;
351343
transaction.sellerFee = 0;
352344
transaction.buyerFee = 0;
353345
transaction.status = Status.Resolved;
346+
347+
// Give the arbitration fee back.
348+
// Note that we use `send` to prevent a party from blocking the execution.
349+
if (_ruling == uint(RulingOptions.SellerWins)) {
350+
transaction.seller.send(sellerFee);
351+
token.transfer(transaction.seller, amount);
352+
} else if (_ruling == uint(RulingOptions.BuyerWins)) {
353+
transaction.buyer.send(buyerFee);
354+
token.transfer(transaction.buyer, amount);
355+
} else {
356+
uint split_arbitration_fee = (sellerFee + buyerFee - transaction.arbitrationCost) / 2;
357+
transaction.buyer.send(split_arbitration_fee);
358+
transaction.seller.send(split_arbitration_fee);
359+
// In the case of an uneven token amount, one token can be burnt.
360+
token.transfer(transaction.buyer, amount / 2);
361+
token.transfer(transaction.seller, amount / 2);
362+
}
354363
}
355364

356365
// **************************** //

test/multiple-arbitrable-token-transaction.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -153,15 +153,15 @@ contract('MultipleArbitrableTokenTransaction', function(accounts) {
153153
payerEtherBalanceAfter.toString(),
154154
payerEtherBalanceBefore
155155
.minus(actionData.payerTotalTxCost || 0)
156-
.plus(0)
156+
.plus(data.payer.etherDelta)
157157
.toString(),
158158
'The payer has not been reimbursed correctly in ether'
159159
)
160160
assert.equal(
161161
payeeEtherBalanceAfter.toString(),
162162
payeeEtherBalanceBefore
163163
.minus(actionData.payeeTotalTxCost || 0)
164-
.plus(0)
164+
.plus(data.payee.etherDelta)
165165
.toString(),
166166
'The payee has not been paid correctly in ether'
167167
)

0 commit comments

Comments
 (0)