7
7
*/
8
8
9
9
/** @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.
11
11
* This can be used for buying goods, services and for paying freelancers.
12
12
* Parties are identified as "seller" and "buyer".
13
- * NOTE: All functions that interact with the ERC20 token contract as UNTRUSTED.
14
13
*/
15
14
16
15
pragma solidity ^ 0.4.24 ;
@@ -57,7 +56,7 @@ contract MultipleArbitrableTokenTransaction {
57
56
// **************************** //
58
57
59
58
/** @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` .
61
60
* @param _evidence A link to the meta-evidence JSON.
62
61
*/
63
62
event MetaEvidence (uint indexed _metaEvidenceID , string _evidence );
@@ -72,7 +71,7 @@ contract MultipleArbitrableTokenTransaction {
72
71
* @param _arbitrator The arbitrator of the contract.
73
72
* @param _disputeID ID of the dispute in the Arbitrator contract.
74
73
* @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) .
76
75
*/
77
76
event Evidence (Arbitrator indexed _arbitrator , uint indexed _disputeID , address indexed _party , string _evidence );
78
77
@@ -113,7 +112,7 @@ contract MultipleArbitrableTokenTransaction {
113
112
feeTimeout = _feeTimeout;
114
113
}
115
114
116
- /** @dev Create a transaction.
115
+ /** @dev Create a transaction. UNTRUSTED.
117
116
* @param _amount The amount of tokens in this transaction.
118
117
* @param _timeoutPayment Time after which a party automatically lose a dispute.
119
118
* @param _seller The recipient of the transaction.
@@ -126,7 +125,6 @@ contract MultipleArbitrableTokenTransaction {
126
125
address _seller ,
127
126
string _metaEvidence
128
127
) public returns (uint transactionIndex ) {
129
-
130
128
// Transfers token from sender wallet to contract.
131
129
require (token.transferFrom (msg .sender , address (this ), _amount), "Sender does not have enough funds. " );
132
130
@@ -146,7 +144,7 @@ contract MultipleArbitrableTokenTransaction {
146
144
return transactions.length - 1 ;
147
145
}
148
146
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.
150
148
* @param _transactionID The index of the transaction.
151
149
* @param _amount Amount to pay in tokens.
152
150
*/
@@ -156,11 +154,11 @@ contract MultipleArbitrableTokenTransaction {
156
154
require (transaction.status == Status.NoDispute, "The transaction can't be disputed. " );
157
155
require (_amount <= transaction.amount, "The amount paid has to be less or equal than the transaction. " );
158
156
159
- token.transfer (transaction.seller, _amount);
160
157
transaction.amount -= _amount;
158
+ require (token.transfer (transaction.seller, _amount) != false , "The `transfer` function must not returns `false`. " );
161
159
}
162
160
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.
164
162
* @param _transactionID The index of the transaction.
165
163
* @param _amountReimbursed Amount to reimburse in tokens.
166
164
*/
@@ -170,25 +168,27 @@ contract MultipleArbitrableTokenTransaction {
170
168
require (transaction.status == Status.NoDispute, "The transaction can't be disputed. " );
171
169
require (_amountReimbursed <= transaction.amount, "The amount reimbursed has to be less or equal than the transaction. " );
172
170
173
- token.transfer (transaction.buyer, _amountReimbursed);
174
171
transaction.amount -= _amountReimbursed;
172
+ token.transfer (transaction.buyer, _amountReimbursed);
175
173
}
176
174
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.
178
176
* @param _transactionID The index of the transaction.
179
177
*/
180
178
function executeTransaction (uint _transactionID ) public {
181
179
Transaction storage transaction = transactions[_transactionID];
182
180
require (now - transaction.lastInteraction >= transaction.timeoutPayment, "The timeout has not passed yet. " );
183
181
require (transaction.status == Status.NoDispute, "The transaction can't be disputed. " );
184
182
185
- token. transfer (transaction.seller, transaction.amount) ;
183
+ uint amount = transaction.amount;
186
184
transaction.amount = 0 ;
187
185
188
186
transaction.status = Status.Resolved;
187
+
188
+ token.transfer (transaction.seller, amount);
189
189
}
190
190
191
- /** @dev Reimburse buyer if seller fails to pay the fee.
191
+ /** @dev Reimburse buyer if seller fails to pay the fee. UNTRUSTED.
192
192
* @param _transactionID The index of the transaction.
193
193
*/
194
194
function timeOutByBuyer (uint _transactionID ) public {
@@ -200,7 +200,7 @@ contract MultipleArbitrableTokenTransaction {
200
200
executeRuling (_transactionID, uint (RulingOptions.BuyerWins));
201
201
}
202
202
203
- /** @dev Pay seller if buyer fails to pay the fee.
203
+ /** @dev Pay seller if buyer fails to pay the fee. UNTRUSTED.
204
204
* @param _transactionID The index of the transaction.
205
205
*/
206
206
function timeOutBySeller (uint _transactionID ) public {
@@ -237,7 +237,7 @@ contract MultipleArbitrableTokenTransaction {
237
237
}
238
238
239
239
/** @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.
241
241
* This is not a vulnerability as the arbitrator can rule in favor of one party anyway.
242
242
* @param _transactionID The index of the transaction.
243
243
*/
@@ -252,7 +252,7 @@ contract MultipleArbitrableTokenTransaction {
252
252
require (transaction.sellerFee >= arbitrationCost, "The seller fee must cover arbitration costs. " );
253
253
254
254
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.
256
256
if (transaction.buyerFee < arbitrationCost) {
257
257
transaction.status = Status.WaitingBuyer;
258
258
emit HasToPayFee (_transactionID, Party.Buyer);
@@ -300,7 +300,7 @@ contract MultipleArbitrableTokenTransaction {
300
300
emit Evidence (arbitrator, transaction.disputeId, msg .sender , _evidence);
301
301
}
302
302
303
- /** @dev Appeal an appealable ruling.
303
+ /** @dev Appeal an appealable ruling. UNTRUSTED.
304
304
* Transfer the funds to the arbitrator.
305
305
* Note that no checks are required as the checks are done by the arbitrator.
306
306
* @param _transactionID The index of the transaction.
@@ -329,28 +329,37 @@ contract MultipleArbitrableTokenTransaction {
329
329
330
330
/** @dev Execute a ruling of a dispute. It reimburses the fee to the winning party.
331
331
* @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.
333
333
*/
334
334
function executeRuling (uint _transactionID , uint _ruling ) internal {
335
335
Transaction storage transaction = transactions[_transactionID];
336
336
require (_ruling <= AMOUNT_OF_CHOICES, "Invalid ruling. " );
337
337
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;
349
341
350
342
transaction.amount = 0 ;
351
343
transaction.sellerFee = 0 ;
352
344
transaction.buyerFee = 0 ;
353
345
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
+ }
354
363
}
355
364
356
365
// **************************** //
0 commit comments