@@ -65,10 +65,11 @@ contract GeneralizedTCR is IArbitrable, IEvidence {
65
65
}
66
66
67
67
struct Round {
68
- uint [3 ] paidFees ; // Tracks the fees paid for each Party in this round.
68
+ uint [3 ] amountPaid ; // Tracks the sum for each Party in this round. Includes arbitration fees, fee stakes and deposits .
69
69
bool [3 ] hasPaid; // True if the Party has fully paid its fee in this round.
70
70
uint feeRewards; // Sum of reimbursable fees and stake rewards available to the parties that made contributions to the side that ultimately wins a dispute.
71
71
mapping (address => uint [3 ]) contributions; // Maps contributors to their contributions for each side.
72
+ uint [3 ] paidArbitrationFees; // The arbitration or appeal fees paid for each party.
72
73
}
73
74
74
75
struct RequestID {
@@ -297,8 +298,9 @@ contract GeneralizedTCR is IArbitrable, IEvidence {
297
298
: removalChallengeBaseDeposit;
298
299
uint totalCost = arbitrationCost.addCap (challengerBaseDeposit);
299
300
contribute (round, Party.Challenger, msg .sender , msg .value , totalCost);
300
- require (round.paidFees [uint (Party.Challenger)] >= totalCost, "You must fully fund your side. " );
301
+ require (round.amountPaid [uint (Party.Challenger)] >= totalCost, "You must fully fund your side. " );
301
302
round.hasPaid[uint (Party.Challenger)] = true ;
303
+ round.paidArbitrationFees[uint (Party.Challenger)] = arbitrationCost;
302
304
303
305
// Raise a dispute.
304
306
request.disputeID = request.arbitrator.createDispute.value (arbitrationCost)(RULING_OPTIONS, request.arbitratorExtraData);
@@ -364,6 +366,7 @@ contract GeneralizedTCR is IArbitrable, IEvidence {
364
366
uint appealCost = request.arbitrator.appealCost (request.disputeID, request.arbitratorExtraData);
365
367
uint totalCost = appealCost.addCap ((appealCost.mulCap (multiplier)) / MULTIPLIER_DIVISOR);
366
368
uint contribution = contribute (round, _side, msg .sender , msg .value , totalCost);
369
+ round.paidArbitrationFees[uint (_side)] += appealCost;
367
370
368
371
emit AppealContribution (
369
372
_itemID,
@@ -374,7 +377,7 @@ contract GeneralizedTCR is IArbitrable, IEvidence {
374
377
_side
375
378
);
376
379
377
- if (round.paidFees [uint (_side)] >= totalCost) {
380
+ if (round.amountPaid [uint (_side)] >= totalCost) {
378
381
round.hasPaid[uint (_side)] = true ;
379
382
emit HasPaidAppealFee (_itemID, items[_itemID].requests.length - 1 , request.rounds.length - 1 , _side);
380
383
}
@@ -403,20 +406,48 @@ contract GeneralizedTCR is IArbitrable, IEvidence {
403
406
if (! round.hasPaid[uint (Party.Requester)] || ! round.hasPaid[uint (Party.Challenger)]) {
404
407
// Reimburse if not enough fees were raised to appeal the ruling.
405
408
reward = round.contributions[_beneficiary][uint (Party.Requester)] + round.contributions[_beneficiary][uint (Party.Challenger)];
409
+ } else if (
410
+ request.ruling == Party.None &&
411
+ _round == 0
412
+ ) {
413
+ if (
414
+ _beneficiary != request.parties[uint (Party.Requester)] &&
415
+ _beneficiary != request.parties[uint (Party.Challenger)]
416
+ ) return ;
417
+
418
+ uint side = _beneficiary == request.parties[uint (Party.Requester)] ? 1 : 2 ;
419
+ if (round.contributions[_beneficiary][side] == 0 ) return ;
420
+
421
+ // The first round is special since it does not include crowdfunding fees,
422
+ // or stake multipliers. The only participants are the requester and challenger.
423
+ //
424
+ // Arbitration costs can rise or fall between when a request was made and when it was
425
+ // challenged. To keep things fair, we reimburse proportionally to the amount
426
+ // contributed.
427
+ reward = round.contributions[_beneficiary][side].subCap (round.paidArbitrationFees[side]); // Base deposit.
428
+ uint arbitrationFeesSide = round.paidArbitrationFees[side];
429
+ uint totalArbitrationFeesPaid = round.paidArbitrationFees[uint (Party.Requester)] + round.paidArbitrationFees[uint (Party.Requester)];
430
+
431
+ // Reimbursable fees are total amount paid minus the amount paid by the challenger
432
+ // because the amount paid by the challenger is the actual cost of the round.
433
+ uint reimbursableFeesAvailable = totalArbitrationFeesPaid - round.paidArbitrationFees[uint (Party.Challenger)];
434
+
435
+ reward += arbitrationFeesSide * reimbursableFeesAvailable / totalArbitrationFeesPaid;
436
+
406
437
} else if (request.ruling == Party.None) {
407
438
// Reimburse unspent fees proportionally if there is no winner or loser.
408
- uint rewardRequester = round.paidFees [uint (Party.Requester)] > 0
409
- ? (round.contributions[_beneficiary][uint (Party.Requester)] * round.feeRewards) / (round.paidFees [uint (Party.Challenger)] + round.paidFees [uint (Party.Requester)])
439
+ uint rewardRequester = round.amountPaid [uint (Party.Requester)] > 0
440
+ ? (round.contributions[_beneficiary][uint (Party.Requester)] * round.feeRewards) / (round.amountPaid [uint (Party.Challenger)] + round.amountPaid [uint (Party.Requester)])
410
441
: 0 ;
411
- uint rewardChallenger = round.paidFees [uint (Party.Challenger)] > 0
412
- ? (round.contributions[_beneficiary][uint (Party.Challenger)] * round.feeRewards) / (round.paidFees [uint (Party.Challenger)] + round.paidFees [uint (Party.Requester)])
442
+ uint rewardChallenger = round.amountPaid [uint (Party.Challenger)] > 0
443
+ ? (round.contributions[_beneficiary][uint (Party.Challenger)] * round.feeRewards) / (round.amountPaid [uint (Party.Challenger)] + round.amountPaid [uint (Party.Requester)])
413
444
: 0 ;
414
445
415
446
reward = rewardRequester + rewardChallenger;
416
447
} else {
417
448
// Reward the winner.
418
- reward = round.paidFees [uint (request.ruling)] > 0
419
- ? (round.contributions[_beneficiary][uint (request.ruling)] * round.feeRewards) / round.paidFees [uint (request.ruling)]
449
+ reward = round.amountPaid [uint (request.ruling)] > 0
450
+ ? (round.contributions[_beneficiary][uint (request.ruling)] * round.feeRewards) / round.amountPaid [uint (request.ruling)]
420
451
: 0 ;
421
452
422
453
}
@@ -624,8 +655,9 @@ contract GeneralizedTCR is IArbitrable, IEvidence {
624
655
uint arbitrationCost = request.arbitrator.arbitrationCost (request.arbitratorExtraData);
625
656
uint totalCost = arbitrationCost.addCap (_baseDeposit);
626
657
contribute (round, Party.Requester, msg .sender , msg .value , totalCost);
627
- require (round.paidFees [uint (Party.Requester)] >= totalCost, "You must fully fund your side. " );
658
+ require (round.amountPaid [uint (Party.Requester)] >= totalCost, "You must fully fund your side. " );
628
659
round.hasPaid[uint (Party.Requester)] = true ;
660
+ round.paidArbitrationFees[uint (Party.Requester)] = arbitrationCost;
629
661
630
662
emit ItemStatusChange (itemID, item.requests.length - 1 , request.rounds.length - 1 , false , false );
631
663
emit RequestSubmitted (itemID, item.requests.length - 1 , item.status);
@@ -660,9 +692,9 @@ contract GeneralizedTCR is IArbitrable, IEvidence {
660
692
// Take up to the amount necessary to fund the current round at the current costs.
661
693
uint contribution; // Amount contributed.
662
694
uint remainingETH; // Remaining ETH to send back.
663
- (contribution, remainingETH) = calculateContribution (_amount, _totalRequired.subCap (_round.paidFees [uint (_side)]));
695
+ (contribution, remainingETH) = calculateContribution (_amount, _totalRequired.subCap (_round.amountPaid [uint (_side)]));
664
696
_round.contributions[_contributor][uint (_side)] += contribution;
665
- _round.paidFees [uint (_side)] += contribution;
697
+ _round.amountPaid [uint (_side)] += contribution;
666
698
_round.feeRewards += contribution;
667
699
668
700
// Reimburse leftover ETH.
@@ -699,7 +731,7 @@ contract GeneralizedTCR is IArbitrable, IEvidence {
699
731
700
732
emit ItemStatusChange (itemID, item.requests.length - 1 , request.rounds.length - 1 , true , true );
701
733
702
- // Automatically withdraw.
734
+ // Automatically withdraw first deposits and reimbursements (first round only) .
703
735
if (winner == Party.None) {
704
736
withdrawFeesAndRewards (request.parties[uint (Party.Requester)], itemID, item.requests.length - 1 , 0 );
705
737
withdrawFeesAndRewards (request.parties[uint (Party.Challenger)], itemID, item.requests.length - 1 , 0 );
@@ -808,7 +840,7 @@ contract GeneralizedTCR is IArbitrable, IEvidence {
808
840
view
809
841
returns (
810
842
bool appealed ,
811
- uint [3 ] memory paidFees ,
843
+ uint [3 ] memory amountPaid ,
812
844
bool [3 ] memory hasPaid ,
813
845
uint feeRewards
814
846
)
@@ -818,7 +850,7 @@ contract GeneralizedTCR is IArbitrable, IEvidence {
818
850
Round storage round = request.rounds[_round];
819
851
return (
820
852
_round != (request.rounds.length - 1 ),
821
- round.paidFees ,
853
+ round.amountPaid ,
822
854
round.hasPaid,
823
855
round.feeRewards
824
856
);
0 commit comments