Skip to content

Commit c5e5487

Browse files
fix(LinguoToken.sol): add uniswap price
1 parent 91b8342 commit c5e5487

File tree

3 files changed

+173
-78
lines changed

3 files changed

+173
-78
lines changed

contracts/standard/arbitration/Linguo.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ contract Linguo is Arbitrable {
2525
using CappedMath for uint;
2626

2727
/* *** Contract variables *** */
28+
uint8 public constant VERSION_ID = 0; // Value that represents the version of the contract. The value is incremented each time the new version is deployed. Range for LinguoETH: 0-127, LinguoToken: 128-255.
2829
uint public constant MULTIPLIER_DIVISOR = 10000; // Divisor parameter for multipliers.
2930
uint constant NOT_PAYABLE_VALUE = (2**256-2)/2; // A value depositor won't be able to pay.
3031

contracts/standard/arbitration/LinguoToken.sol

Lines changed: 66 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* @authors: [@unknownunknown1]
3-
* @reviewers: [@remedcu]
3+
* @reviewers: [@remedcu*]
44
* @auditors: []
55
* @bounties: []
66
* @deployments: []
@@ -14,6 +14,12 @@ import "./Arbitrable.sol";
1414
import "../../libraries/CappedMath.sol";
1515
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
1616

17+
interface IUniswapV2Pair {
18+
19+
function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast);
20+
21+
}
22+
1723
/** @title LinguoToken
1824
* Linguo is a decentralized platform where anyone can submit a document for translation and have it translated by freelancers.
1925
* It has no platform fees and disputes about translation quality are handled by Kleros jurors.
@@ -27,6 +33,7 @@ contract LinguoToken is Arbitrable {
2733
using CappedMath for uint;
2834

2935
/* *** Contract variables *** */
36+
uint8 public constant VERSION_ID = 128; // Value that represents the version of the contract. The value is incremented each time the new version is deployed. Range for LinguoToken: 128-255, LinguoETH: 0-127.
3037
uint public constant MULTIPLIER_DIVISOR = 10000; // Divisor parameter for multipliers.
3138
uint constant NOT_PAYABLE_VALUE = (2**256-2)/2; // A value depositor won't be able to pay.
3239

@@ -53,6 +60,7 @@ contract LinguoToken is Arbitrable {
5360
uint disputeID; // The ID of the dispute created in arbitrator contract.
5461
Round[] rounds; // Tracks each appeal round of a dispute.
5562
uint ruling; // Ruling given to the dispute of the task by the arbitrator.
63+
uint priceETH; // Price of the task, converted into ETH. We store it for challenger, to make sure the token price for him doesn't differ from translator.
5664
}
5765

5866
// Rounds are only used in appeal funding.
@@ -63,10 +71,13 @@ contract LinguoToken is Arbitrable {
6371
mapping(address => uint[3]) contributions; // Maps contributors to their contributions for each side.
6472
}
6573

74+
ERC20 public WETH; // Address of the wETH token contract. It's required for token -> ETH conversion.
75+
address public uniswapFactory; // Address of the UniswapPair factory. It's required for token -> ETH conversion.
76+
6677
address public governor; // The governor of the contract.
6778
uint public reviewTimeout; // Time in seconds, during which the submitted translation can be challenged.
68-
uint public translatorBaseDeposit; // The base deposit a translator must pay to self-assign a task, in wei.
69-
uint public challengerBaseDeposit; // The base deposit a challenger must pay to challenge a translation, in wei.
79+
uint public translationMultiplier; // Multiplier for calculating the value of the deposit translator must pay to self-assign a task.
80+
uint public challengeMultiplier; // Multiplier for calculating the value of the deposit challenger must pay to challenge a translation.
7081

7182
// All multipliers below are in basis points.
7283
uint public sharedStakeMultiplier; // Multiplier for calculating the appeal fee that must be paid by submitter in the case where there is no winner or loser (e.g. when the arbitrator ruled "refuse to arbitrate").
@@ -129,27 +140,33 @@ contract LinguoToken is Arbitrable {
129140
/** @dev Constructor.
130141
* @param _arbitrator The arbitrator of the contract.
131142
* @param _arbitratorExtraData Extra data for the arbitrator.
143+
* @param _WETH Address of the WETH token contract
144+
* @param _uniswapFactory Address of the UniswapPair factory contract.
132145
* @param _reviewTimeout Time in seconds during which a translation can be challenged.
133-
* @param _translatorBaseDeposit The base deposit that must be paid in order to self-assign the task, in wei.
134-
* @param _challengerBaseDeposit The base deposit that must be paid in order to challenge the translation, in wei.
146+
* @param _translationMultiplier Multiplier for calculating translator's deposit. In basis points.
147+
* @param _challengeMultiplier Multiplier for calculating challenger's deposit. In basis points.
135148
* @param _sharedStakeMultiplier Multiplier of the appeal cost that submitter must pay for a round when there is no winner/loser in the previous round. In basis points.
136149
* @param _winnerStakeMultiplier Multiplier of the appeal cost that the winner has to pay for a round. In basis points.
137150
* @param _loserStakeMultiplier Multiplier of the appeal cost that the loser has to pay for a round. In basis points.
138151
*/
139152
constructor(
140153
Arbitrator _arbitrator,
141154
bytes _arbitratorExtraData,
155+
ERC20 _WETH,
156+
address _uniswapFactory,
142157
uint _reviewTimeout,
143-
uint _translatorBaseDeposit,
144-
uint _challengerBaseDeposit,
158+
uint _translationMultiplier,
159+
uint _challengeMultiplier,
145160
uint _sharedStakeMultiplier,
146161
uint _winnerStakeMultiplier,
147162
uint _loserStakeMultiplier
148163
) public Arbitrable(_arbitrator, _arbitratorExtraData){
149164
governor = msg.sender;
165+
WETH = _WETH;
166+
uniswapFactory = _uniswapFactory;
150167
reviewTimeout = _reviewTimeout;
151-
translatorBaseDeposit = _translatorBaseDeposit;
152-
challengerBaseDeposit = _challengerBaseDeposit;
168+
translationMultiplier = _translationMultiplier;
169+
challengeMultiplier = _challengeMultiplier;
153170
sharedStakeMultiplier = _sharedStakeMultiplier;
154171
winnerStakeMultiplier = _winnerStakeMultiplier;
155172
loserStakeMultiplier = _loserStakeMultiplier;
@@ -173,18 +190,18 @@ contract LinguoToken is Arbitrable {
173190
reviewTimeout = _reviewTimeout;
174191
}
175192

176-
/** @dev Changes the base deposit for translator.
177-
* @param _translatorBaseDeposit A new value of the base deposit required for self-assigning the task, in wei.
193+
/** @dev Changes the multiplier for translator's deposit.
194+
* @param _translationMultiplier A new value of the multiplier for calculating translator's deposit. In basis points.
178195
*/
179-
function changeTranslatorBaseDeposit(uint _translatorBaseDeposit) public onlyGovernor {
180-
translatorBaseDeposit = _translatorBaseDeposit;
196+
function changeTranslationMultiplier(uint _translationMultiplier) public onlyGovernor {
197+
translationMultiplier = _translationMultiplier;
181198
}
182199

183-
/** @dev Changes the base deposit for challenger.
184-
* @param _challengerBaseDeposit A new value of the base deposit required for challenging, in wei.
200+
/** @dev Changes the multiplier for challenger's deposit.
201+
* @param _challengeMultiplier A new value of the multiplier for calculating challenger's deposit. In basis points.
185202
*/
186-
function changeChallengerBaseDeposit(uint _challengerBaseDeposit) public onlyGovernor {
187-
challengerBaseDeposit = _challengerBaseDeposit;
203+
function changeChallengeMultiplier(uint _challengeMultiplier) public onlyGovernor {
204+
challengeMultiplier = _challengeMultiplier;
188205
}
189206

190207
/** @dev Changes the percentage of arbitration fees that must be paid by parties as a fee stake if there was no winner and loser in the previous round.
@@ -253,8 +270,10 @@ contract LinguoToken is Arbitrable {
253270
require(now - task.lastInteraction <= task.submissionTimeout, "The deadline has already passed.");
254271

255272
uint price = task.minPrice + (task.maxPrice - task.minPrice) * (now - task.lastInteraction) / task.submissionTimeout;
273+
274+
uint priceETH = getTaskPriceInETH(_taskID);
256275
uint arbitrationCost = arbitrator.arbitrationCost(arbitratorExtraData);
257-
uint translatorDeposit = arbitrationCost.addCap(translatorBaseDeposit);
276+
uint translatorDeposit = arbitrationCost.addCap((translationMultiplier.mulCap(priceETH)) / MULTIPLIER_DIVISOR);
258277

259278
require(task.status == Status.Created, "Task has already been assigned or reimbursed.");
260279
require(msg.value >= translatorDeposit, "Not enough ETH to reach the required deposit value.");
@@ -264,6 +283,8 @@ contract LinguoToken is Arbitrable {
264283

265284
// Update requester's deposit since we reimbursed him the difference between maximal and actual price.
266285
task.requesterDeposit = price;
286+
287+
task.priceETH = priceETH;
267288
task.sumDeposit += translatorDeposit;
268289

269290
uint remainder = msg.value - translatorDeposit;
@@ -336,7 +357,7 @@ contract LinguoToken is Arbitrable {
336357
Task storage task = tasks[_taskID];
337358

338359
uint arbitrationCost = arbitrator.arbitrationCost(arbitratorExtraData);
339-
uint challengeDeposit = arbitrationCost.addCap(challengerBaseDeposit);
360+
uint challengeDeposit = arbitrationCost.addCap((challengeMultiplier.mulCap(task.priceETH)) / MULTIPLIER_DIVISOR);
340361

341362
require(task.status == Status.AwaitingReview, "The task is in the wrong status.");
342363
require(now - task.lastInteraction <= reviewTimeout, "The review phase has already passed.");
@@ -592,8 +613,11 @@ contract LinguoToken is Arbitrable {
592613
if (now - task.lastInteraction > task.submissionTimeout || task.status != Status.Created) {
593614
deposit = NOT_PAYABLE_VALUE;
594615
} else {
616+
uint priceETH = getTaskPriceInETH(_taskID);
617+
595618
uint arbitrationCost = arbitrator.arbitrationCost(arbitratorExtraData);
596-
deposit = arbitrationCost.addCap(translatorBaseDeposit);
619+
deposit = arbitrationCost.addCap((translationMultiplier.mulCap(priceETH)) / MULTIPLIER_DIVISOR);
620+
597621
}
598622
}
599623

@@ -607,7 +631,7 @@ contract LinguoToken is Arbitrable {
607631
deposit = NOT_PAYABLE_VALUE;
608632
} else {
609633
uint arbitrationCost = arbitrator.arbitrationCost(arbitratorExtraData);
610-
deposit = arbitrationCost.addCap(challengerBaseDeposit);
634+
deposit = arbitrationCost.addCap((challengeMultiplier.mulCap(task.priceETH)) / MULTIPLIER_DIVISOR);
611635
}
612636
}
613637

@@ -624,6 +648,27 @@ contract LinguoToken is Arbitrable {
624648
}
625649
}
626650

651+
/** @dev Gets the current price of a specified task in ETH.
652+
* @param _taskID The ID of the task.
653+
* @return price The price of the task.
654+
*/
655+
function getTaskPriceInETH(uint _taskID) public view returns (uint priceETH) {
656+
Task storage task = tasks[_taskID];
657+
uint tokenPrice = task.minPrice + (task.maxPrice - task.minPrice) * (now - task.lastInteraction) / task.submissionTimeout;
658+
if (now - task.lastInteraction > task.submissionTimeout || task.status != Status.Created)
659+
priceETH = 0;
660+
else if (task.token == WETH)
661+
priceETH = tokenPrice;
662+
else {
663+
(ERC20 token0, ERC20 token1) = task.token < WETH ? (task.token, WETH) : (WETH, task.token);
664+
IUniswapV2Pair pair = IUniswapV2Pair(address(uint(keccak256(abi.encodePacked(hex"ff", uniswapFactory, keccak256(abi.encodePacked(token0, token1)), hex"96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f")))));
665+
(uint reserve0, uint reserve1,) = pair.getReserves();
666+
(uint reserveA, uint reserveB) = token0 == task.token ? (reserve0, reserve1) : (reserve1, reserve0);
667+
require(reserveA > 0 && reserveB > 0, "Could not calculate the price.");
668+
priceETH = tokenPrice.mulCap(reserveB) / reserveA;
669+
}
670+
}
671+
627672
/** @dev Gets the total number of created tasks.
628673
* @return The number of created tasks.
629674
*/

0 commit comments

Comments
 (0)