From c5e5487d7dbbd66ebbd8f54850f5f4afe7dbc3a7 Mon Sep 17 00:00:00 2001 From: unknownunknown1 Date: Wed, 29 Jul 2020 23:24:21 +1000 Subject: [PATCH 1/6] fix(LinguoToken.sol): add uniswap price --- contracts/standard/arbitration/Linguo.sol | 1 + .../standard/arbitration/LinguoToken.sol | 87 +++++++--- test/linguo-token.js | 163 ++++++++++++------ 3 files changed, 173 insertions(+), 78 deletions(-) diff --git a/contracts/standard/arbitration/Linguo.sol b/contracts/standard/arbitration/Linguo.sol index f10164bc..17f685d8 100644 --- a/contracts/standard/arbitration/Linguo.sol +++ b/contracts/standard/arbitration/Linguo.sol @@ -25,6 +25,7 @@ contract Linguo is Arbitrable { using CappedMath for uint; /* *** Contract variables *** */ + 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. uint public constant MULTIPLIER_DIVISOR = 10000; // Divisor parameter for multipliers. uint constant NOT_PAYABLE_VALUE = (2**256-2)/2; // A value depositor won't be able to pay. diff --git a/contracts/standard/arbitration/LinguoToken.sol b/contracts/standard/arbitration/LinguoToken.sol index f1350fc5..7a7997cf 100644 --- a/contracts/standard/arbitration/LinguoToken.sol +++ b/contracts/standard/arbitration/LinguoToken.sol @@ -1,6 +1,6 @@ /** * @authors: [@unknownunknown1] - * @reviewers: [@remedcu] + * @reviewers: [@remedcu*] * @auditors: [] * @bounties: [] * @deployments: [] @@ -14,6 +14,12 @@ import "./Arbitrable.sol"; import "../../libraries/CappedMath.sol"; import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; +interface IUniswapV2Pair { + + function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast); + +} + /** @title LinguoToken * Linguo is a decentralized platform where anyone can submit a document for translation and have it translated by freelancers. * It has no platform fees and disputes about translation quality are handled by Kleros jurors. @@ -27,6 +33,7 @@ contract LinguoToken is Arbitrable { using CappedMath for uint; /* *** Contract variables *** */ + 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. uint public constant MULTIPLIER_DIVISOR = 10000; // Divisor parameter for multipliers. uint constant NOT_PAYABLE_VALUE = (2**256-2)/2; // A value depositor won't be able to pay. @@ -53,6 +60,7 @@ contract LinguoToken is Arbitrable { uint disputeID; // The ID of the dispute created in arbitrator contract. Round[] rounds; // Tracks each appeal round of a dispute. uint ruling; // Ruling given to the dispute of the task by the arbitrator. + 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. } // Rounds are only used in appeal funding. @@ -63,10 +71,13 @@ contract LinguoToken is Arbitrable { mapping(address => uint[3]) contributions; // Maps contributors to their contributions for each side. } + ERC20 public WETH; // Address of the wETH token contract. It's required for token -> ETH conversion. + address public uniswapFactory; // Address of the UniswapPair factory. It's required for token -> ETH conversion. + address public governor; // The governor of the contract. uint public reviewTimeout; // Time in seconds, during which the submitted translation can be challenged. - uint public translatorBaseDeposit; // The base deposit a translator must pay to self-assign a task, in wei. - uint public challengerBaseDeposit; // The base deposit a challenger must pay to challenge a translation, in wei. + uint public translationMultiplier; // Multiplier for calculating the value of the deposit translator must pay to self-assign a task. + uint public challengeMultiplier; // Multiplier for calculating the value of the deposit challenger must pay to challenge a translation. // All multipliers below are in basis points. 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,9 +140,11 @@ contract LinguoToken is Arbitrable { /** @dev Constructor. * @param _arbitrator The arbitrator of the contract. * @param _arbitratorExtraData Extra data for the arbitrator. + * @param _WETH Address of the WETH token contract + * @param _uniswapFactory Address of the UniswapPair factory contract. * @param _reviewTimeout Time in seconds during which a translation can be challenged. - * @param _translatorBaseDeposit The base deposit that must be paid in order to self-assign the task, in wei. - * @param _challengerBaseDeposit The base deposit that must be paid in order to challenge the translation, in wei. + * @param _translationMultiplier Multiplier for calculating translator's deposit. In basis points. + * @param _challengeMultiplier Multiplier for calculating challenger's deposit. In basis points. * @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. * @param _winnerStakeMultiplier Multiplier of the appeal cost that the winner has to pay for a round. In basis points. * @param _loserStakeMultiplier Multiplier of the appeal cost that the loser has to pay for a round. In basis points. @@ -139,17 +152,21 @@ contract LinguoToken is Arbitrable { constructor( Arbitrator _arbitrator, bytes _arbitratorExtraData, + ERC20 _WETH, + address _uniswapFactory, uint _reviewTimeout, - uint _translatorBaseDeposit, - uint _challengerBaseDeposit, + uint _translationMultiplier, + uint _challengeMultiplier, uint _sharedStakeMultiplier, uint _winnerStakeMultiplier, uint _loserStakeMultiplier ) public Arbitrable(_arbitrator, _arbitratorExtraData){ governor = msg.sender; + WETH = _WETH; + uniswapFactory = _uniswapFactory; reviewTimeout = _reviewTimeout; - translatorBaseDeposit = _translatorBaseDeposit; - challengerBaseDeposit = _challengerBaseDeposit; + translationMultiplier = _translationMultiplier; + challengeMultiplier = _challengeMultiplier; sharedStakeMultiplier = _sharedStakeMultiplier; winnerStakeMultiplier = _winnerStakeMultiplier; loserStakeMultiplier = _loserStakeMultiplier; @@ -173,18 +190,18 @@ contract LinguoToken is Arbitrable { reviewTimeout = _reviewTimeout; } - /** @dev Changes the base deposit for translator. - * @param _translatorBaseDeposit A new value of the base deposit required for self-assigning the task, in wei. + /** @dev Changes the multiplier for translator's deposit. + * @param _translationMultiplier A new value of the multiplier for calculating translator's deposit. In basis points. */ - function changeTranslatorBaseDeposit(uint _translatorBaseDeposit) public onlyGovernor { - translatorBaseDeposit = _translatorBaseDeposit; + function changeTranslationMultiplier(uint _translationMultiplier) public onlyGovernor { + translationMultiplier = _translationMultiplier; } - /** @dev Changes the base deposit for challenger. - * @param _challengerBaseDeposit A new value of the base deposit required for challenging, in wei. + /** @dev Changes the multiplier for challenger's deposit. + * @param _challengeMultiplier A new value of the multiplier for calculating challenger's deposit. In basis points. */ - function changeChallengerBaseDeposit(uint _challengerBaseDeposit) public onlyGovernor { - challengerBaseDeposit = _challengerBaseDeposit; + function changeChallengeMultiplier(uint _challengeMultiplier) public onlyGovernor { + challengeMultiplier = _challengeMultiplier; } /** @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 { require(now - task.lastInteraction <= task.submissionTimeout, "The deadline has already passed."); uint price = task.minPrice + (task.maxPrice - task.minPrice) * (now - task.lastInteraction) / task.submissionTimeout; + + uint priceETH = getTaskPriceInETH(_taskID); uint arbitrationCost = arbitrator.arbitrationCost(arbitratorExtraData); - uint translatorDeposit = arbitrationCost.addCap(translatorBaseDeposit); + uint translatorDeposit = arbitrationCost.addCap((translationMultiplier.mulCap(priceETH)) / MULTIPLIER_DIVISOR); require(task.status == Status.Created, "Task has already been assigned or reimbursed."); require(msg.value >= translatorDeposit, "Not enough ETH to reach the required deposit value."); @@ -264,6 +283,8 @@ contract LinguoToken is Arbitrable { // Update requester's deposit since we reimbursed him the difference between maximal and actual price. task.requesterDeposit = price; + + task.priceETH = priceETH; task.sumDeposit += translatorDeposit; uint remainder = msg.value - translatorDeposit; @@ -336,7 +357,7 @@ contract LinguoToken is Arbitrable { Task storage task = tasks[_taskID]; uint arbitrationCost = arbitrator.arbitrationCost(arbitratorExtraData); - uint challengeDeposit = arbitrationCost.addCap(challengerBaseDeposit); + uint challengeDeposit = arbitrationCost.addCap((challengeMultiplier.mulCap(task.priceETH)) / MULTIPLIER_DIVISOR); require(task.status == Status.AwaitingReview, "The task is in the wrong status."); require(now - task.lastInteraction <= reviewTimeout, "The review phase has already passed."); @@ -592,8 +613,11 @@ contract LinguoToken is Arbitrable { if (now - task.lastInteraction > task.submissionTimeout || task.status != Status.Created) { deposit = NOT_PAYABLE_VALUE; } else { + uint priceETH = getTaskPriceInETH(_taskID); + uint arbitrationCost = arbitrator.arbitrationCost(arbitratorExtraData); - deposit = arbitrationCost.addCap(translatorBaseDeposit); + deposit = arbitrationCost.addCap((translationMultiplier.mulCap(priceETH)) / MULTIPLIER_DIVISOR); + } } @@ -607,7 +631,7 @@ contract LinguoToken is Arbitrable { deposit = NOT_PAYABLE_VALUE; } else { uint arbitrationCost = arbitrator.arbitrationCost(arbitratorExtraData); - deposit = arbitrationCost.addCap(challengerBaseDeposit); + deposit = arbitrationCost.addCap((challengeMultiplier.mulCap(task.priceETH)) / MULTIPLIER_DIVISOR); } } @@ -624,6 +648,27 @@ contract LinguoToken is Arbitrable { } } + /** @dev Gets the current price of a specified task in ETH. + * @param _taskID The ID of the task. + * @return price The price of the task. + */ + function getTaskPriceInETH(uint _taskID) public view returns (uint priceETH) { + Task storage task = tasks[_taskID]; + uint tokenPrice = task.minPrice + (task.maxPrice - task.minPrice) * (now - task.lastInteraction) / task.submissionTimeout; + if (now - task.lastInteraction > task.submissionTimeout || task.status != Status.Created) + priceETH = 0; + else if (task.token == WETH) + priceETH = tokenPrice; + else { + (ERC20 token0, ERC20 token1) = task.token < WETH ? (task.token, WETH) : (WETH, task.token); + IUniswapV2Pair pair = IUniswapV2Pair(address(uint(keccak256(abi.encodePacked(hex"ff", uniswapFactory, keccak256(abi.encodePacked(token0, token1)), hex"96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f"))))); + (uint reserve0, uint reserve1,) = pair.getReserves(); + (uint reserveA, uint reserveB) = token0 == task.token ? (reserve0, reserve1) : (reserve1, reserve0); + require(reserveA > 0 && reserveB > 0, "Could not calculate the price."); + priceETH = tokenPrice.mulCap(reserveB) / reserveA; + } + } + /** @dev Gets the total number of created tasks. * @return The number of created tasks. */ diff --git a/test/linguo-token.js b/test/linguo-token.js index 5c3681f3..db0b66b6 100644 --- a/test/linguo-token.js +++ b/test/linguo-token.js @@ -22,12 +22,13 @@ contract('Linguo', function(accounts) { const translator = accounts[2] const challenger = accounts[3] const other = accounts[4] + const fakeFactory = accounts[5] const arbitrationFee = 1000 const arbitratorExtraData = 0x85 const appealTimeOut = 100 const reviewTimeout = 2400 - const translatorBaseDeposit = 3000 - const challengerBaseDeposit = 2000 + const translationMultiplier = 1000 + const challengeMultiplier = 2000 const sharedMultiplier = 5000 const winnerMultiplier = 3000 const loserMultiplier = 7000 @@ -39,6 +40,7 @@ contract('Linguo', function(accounts) { const submissionTimeout = 3600 let arbitrator let linguo + let token let MULTIPLIER_DIVISOR let taskTx let currentTime @@ -54,25 +56,30 @@ contract('Linguo', function(accounts) { await arbitrator.changeArbitrator(arbitrator.address) + token = await ERC20Mock.new(requester, tokenBalance, { from: governor }) + linguo = await Linguo.new( arbitrator.address, arbitratorExtraData, + token.address, // WETH. + fakeFactory, // uniswapFactory. Can't test the uniswap getters because of the old compiler, so set it random value. reviewTimeout, - translatorBaseDeposit, - challengerBaseDeposit, + translationMultiplier, + challengeMultiplier, sharedMultiplier, winnerMultiplier, loserMultiplier, { from: governor } ) - token = await ERC20Mock.new(requester, tokenBalance, { from: governor }) await token.approve(linguo.address, 50000000, { from: requester }) MULTIPLIER_DIVISOR = (await linguo.MULTIPLIER_DIVISOR()).toNumber() currentTime = await latestTime() + + // Create the task using WETH token address, to test the simplest getPriceInETH scenario. taskTx = await linguo.createTask( currentTime + submissionTimeout, token.address, @@ -92,10 +99,12 @@ contract('Linguo', function(accounts) { it('Should set the correct values in constructor', async () => { assert.equal(await linguo.arbitrator(), arbitrator.address) assert.equal(await linguo.arbitratorExtraData(), arbitratorExtraData) + assert.equal(await linguo.WETH(), token.address) + assert.equal(await linguo.uniswapFactory(), fakeFactory) assert.equal(await linguo.governor(), governor) assert.equal(await linguo.reviewTimeout(), reviewTimeout) - assert.equal(await linguo.translatorBaseDeposit(), translatorBaseDeposit) - assert.equal(await linguo.challengerBaseDeposit(), challengerBaseDeposit) + assert.equal(await linguo.translationMultiplier(), translationMultiplier) + assert.equal(await linguo.challengeMultiplier(), challengeMultiplier) assert.equal(await linguo.sharedStakeMultiplier(), sharedMultiplier) assert.equal(await linguo.winnerStakeMultiplier(), winnerMultiplier) assert.equal(await linguo.loserStakeMultiplier(), loserMultiplier) @@ -175,9 +184,9 @@ contract('Linguo', function(accounts) { ) }) - it('Should not be possible to deposit less than min price when creating a task', async () => { + it('Should not be possible for max price to be less than min price', async () => { currentTime = await latestTime() - // Invert max and min price to make sure it throws when less than min price is deposited. + // Invert max and min price to make sure it throws. await expectThrow( linguo.createTask( currentTime + submissionTimeout, @@ -218,10 +227,20 @@ contract('Linguo', function(accounts) { 'Contract returns incorrect task price' ) + const priceETH = (await linguo.getTaskPriceInETH(0)).toNumber() assert.equal( - (await linguo.getDepositValue(0)).toNumber(), - 4000, // Arbitration fee + translation base deposit (1000 + 3000). - 'Contract returns incorrect translator deposit' + priceETH, + priceLinguo.toNumber(), + 'Contract returns incorrect price in ETH' + ) + + const deposit = Math.floor( + arbitrationFee + (priceETH * translationMultiplier) / MULTIPLIER_DIVISOR + ) + const depositLinguo = await linguo.getDepositValue(0) + assert( + Math.abs(depositLinguo.toNumber() - deposit) <= deposit / 100, + 'Contract returns incorrect required deposit' ) }) @@ -233,6 +252,14 @@ contract('Linguo', function(accounts) { 0, 'Contract returns incorrect task price after submission timeout ended' ) + + const priceETH = await linguo.getTaskPriceInETH(0) + assert.equal( + priceETH.toNumber(), + 0, + 'Contract returns incorrect task price in ETH after submission timeout ended' + ) + const deposit = NOT_PAYABLE_VALUE const depositLinguo = await linguo.getDepositValue(0) assert.equal( @@ -246,7 +273,7 @@ contract('Linguo', function(accounts) { const requiredDeposit = (await linguo.getDepositValue(0)).toNumber() await linguo.assignTask(0, { from: translator, - value: requiredDeposit + value: requiredDeposit + 1000 }) const expectedTaskPrice = 0 @@ -264,6 +291,13 @@ contract('Linguo', function(accounts) { expectedDeposit, 'Contract returns incorrect required deposit if status is not `created`' ) + + const priceETH = await linguo.getTaskPriceInETH(0) + assert.equal( + priceETH.toNumber(), + 0, + 'Contract returns incorrect task price in ETH if status is not `created`' + ) }) it('Should not be possible to pay less than required deposit value', async () => { @@ -280,7 +314,7 @@ contract('Linguo', function(accounts) { const requiredDeposit = (await linguo.getDepositValue(0)).toNumber() const assignTx = await linguo.assignTask(0, { from: translator, - value: requiredDeposit + value: requiredDeposit + 1000 }) assert.equal( @@ -297,7 +331,7 @@ contract('Linguo', function(accounts) { await linguo.assignTask(0, { from: translator, - value: requiredDeposit + value: requiredDeposit + 1000 }) const newBalance = await token.balanceOf(requester) @@ -313,10 +347,16 @@ contract('Linguo', function(accounts) { translator, 'The translator was not set up properly' ) + + assert( + Math.abs(task[8].toNumber() - requiredDeposit) <= requiredDeposit / 100, + 'The translator deposit was not set up properly' + ) + assert.equal( - task[8].toNumber(), - 4000, - 'Translator deposit was not set up correctly' + task[7].toNumber(), + task[11].toNumber(), + 'Incorrect price in ETH value' ) }) @@ -324,7 +364,7 @@ contract('Linguo', function(accounts) { const requiredDeposit = (await linguo.getDepositValue(0)).toNumber() await linguo.assignTask(0, { from: translator, - value: requiredDeposit + value: requiredDeposit + 1000 }) await increaseTime(submissionTimeout - secondsPassed + 1) await expectThrow( @@ -338,7 +378,7 @@ contract('Linguo', function(accounts) { const requiredDeposit = (await linguo.getDepositValue(0)).toNumber() await linguo.assignTask(0, { from: translator, - value: requiredDeposit + value: requiredDeposit + 1000 }) await expectThrow( linguo.submitTranslation(0, 'ipfs:/X', { @@ -351,7 +391,7 @@ contract('Linguo', function(accounts) { const requiredDeposit = (await linguo.getDepositValue(0)).toNumber() await linguo.assignTask(0, { from: translator, - value: requiredDeposit + value: requiredDeposit + 1000 }) submissionTx = await linguo.submitTranslation(0, 'ipfs:/X', { from: translator @@ -402,7 +442,7 @@ contract('Linguo', function(accounts) { const requiredDeposit = (await linguo.getDepositValue(0)).toNumber() await linguo.assignTask(0, { from: translator, - value: requiredDeposit + value: requiredDeposit + 1000 }) await increaseTime(submissionTimeout + 1) const oldBalance = await web3.eth.getBalance(requester) @@ -414,7 +454,7 @@ contract('Linguo', function(accounts) { const newTokenBalance = await token.balanceOf(requester) assert.equal( newBalance.toString(), - oldBalance.plus(requiredDeposit).toString(), + oldBalance.plus(task[8].toNumber()).toString(), 'The requester was not reimbursed correctly' ) assert.equal( @@ -437,7 +477,7 @@ contract('Linguo', function(accounts) { const requiredDeposit = (await linguo.getDepositValue(0)).toNumber() await linguo.assignTask(0, { from: translator, - value: requiredDeposit + value: requiredDeposit + 1000 }) await linguo.submitTranslation(0, 'ipfs:/X', { from: translator }) await increaseTime(reviewTimeout + 1) @@ -456,9 +496,7 @@ contract('Linguo', function(accounts) { assert.equal( newBalance.toString(), - oldBalance - .plus(4000) // Translator deposit - .toString(), + oldBalance.plus(task[8].toNumber()).toString(), 'The translator did not get his deposit back' ) assert.equal( @@ -476,7 +514,7 @@ contract('Linguo', function(accounts) { await linguo.assignTask(0, { from: translator, - value: requiredDeposit + value: requiredDeposit + 1000 }) await linguo.submitTranslation(0, 'ipfs:/X', { from: translator }) await expectThrow(linguo.acceptTranslation(0)) @@ -495,7 +533,7 @@ contract('Linguo', function(accounts) { await linguo.assignTask(0, { from: translator, - value: requiredDeposit + value: requiredDeposit + 1000 }) await linguo.submitTranslation(0, 'ipfs:/X', { from: translator }) @@ -508,6 +546,11 @@ contract('Linguo', function(accounts) { value: challengerDeposit - 1 }) ) + + let task = await linguo.tasks(0) + const expectedSumDeposit = + challengerDeposit + task[8].toNumber() - arbitrationFee + const challengeTx = await linguo.challengeTranslation( 0, 'ChallengeEvidence', @@ -553,7 +596,7 @@ contract('Linguo', function(accounts) { 'The Evidence event has wrong evidence string' ) - const task = await linguo.tasks(0) + task = await linguo.tasks(0) const taskInfo = await linguo.getTaskParties(0) assert.equal( taskInfo[2], @@ -563,7 +606,7 @@ contract('Linguo', function(accounts) { assert.equal( task[8].toNumber(), - 6000, // Translator deposit + challenger deposit - arbitration fees: 4000 + 3000 - 1000 + expectedSumDeposit, 'The sum of translator and challenger deposits was not set up properly' ) @@ -586,7 +629,7 @@ contract('Linguo', function(accounts) { await linguo.assignTask(0, { from: translator, - value: requiredDeposit + value: requiredDeposit + 1000 }) await linguo.submitTranslation(0, 'ipfs:/X', { from: translator }) const challengerDeposit = (await linguo.getChallengeValue(0)).toNumber() @@ -604,9 +647,9 @@ contract('Linguo', function(accounts) { await linguo.assignTask(0, { from: translator, - value: requiredDeposit + value: requiredDeposit + 1000 }) - let task = await linguo.tasks(0) + await linguo.submitTranslation(0, 'ipfs:/X', { from: translator }) const challengerDeposit = (await linguo.getChallengeValue(0)).toNumber() @@ -615,6 +658,9 @@ contract('Linguo', function(accounts) { value: challengerDeposit }) + let task = await linguo.tasks(0) + const halfSumDeposit = Math.floor(task[8].toNumber() / 2) + const oldTokenBalanceRequester = await token.balanceOf(requester) const oldBalance1 = await web3.eth.getBalance(translator) @@ -637,13 +683,13 @@ contract('Linguo', function(accounts) { assert.equal( newBalance1.toString(), - oldBalance1.plus(3000).toString(), // 3000 is a half of the sum of the eth deposits. + oldBalance1.plus(halfSumDeposit).toString(), 'The translator was not paid correctly' ) assert.equal( newBalance2.toString(), - oldBalance2.plus(3000).toString(), + oldBalance2.plus(halfSumDeposit).toString(), 'The challenger was not paid correctly' ) @@ -658,9 +704,8 @@ contract('Linguo', function(accounts) { await linguo.assignTask(0, { from: translator, - value: requiredDeposit + value: requiredDeposit + 1000 }) - let task = await linguo.tasks(0) await linguo.submitTranslation(0, 'ipfs:/X', { from: translator }) const challengerDeposit = (await linguo.getChallengeValue(0)).toNumber() @@ -669,6 +714,8 @@ contract('Linguo', function(accounts) { value: challengerDeposit }) + let task = await linguo.tasks(0) + const oldTokenBalanceRequester = await token.balanceOf(requester) const oldBalance1 = await web3.eth.getBalance(translator) const oldBalance2 = await web3.eth.getBalance(challenger) @@ -691,7 +738,7 @@ contract('Linguo', function(accounts) { assert.equal( newBalance1.toString(), - oldBalance1.plus(6000).toString(), + oldBalance1.plus(task[8].toNumber()).toString(), 'The translator was not paid correctly' ) assert.equal( @@ -715,9 +762,9 @@ contract('Linguo', function(accounts) { await linguo.assignTask(0, { from: translator, - value: requiredDeposit + value: requiredDeposit + 1000 }) - let task = await linguo.tasks(0) + await linguo.submitTranslation(0, 'ipfs:/X', { from: translator }) const challengerDeposit = (await linguo.getChallengeValue(0)).toNumber() @@ -726,6 +773,8 @@ contract('Linguo', function(accounts) { value: challengerDeposit }) + let task = await linguo.tasks(0) + const oldTokenBalanceRequester = await token.balanceOf(requester) const oldBalance1 = await web3.eth.getBalance(translator) const oldBalance2 = await web3.eth.getBalance(challenger) @@ -760,7 +809,7 @@ contract('Linguo', function(accounts) { assert.equal( newBalance2.toString(), - oldBalance2.plus(6000).toString(), + oldBalance2.plus(task[8].toNumber()).toString(), 'The challenger was not paid correctly' ) assert.equal( @@ -779,7 +828,7 @@ contract('Linguo', function(accounts) { await expectThrow( linguo.assignTask(0, { from: translator, - value: requiredDeposit + value: requiredDeposit + 1000 }) ) }) @@ -790,7 +839,7 @@ contract('Linguo', function(accounts) { await linguo.assignTask(0, { from: translator, - value: requiredDeposit + value: requiredDeposit + 1000 }) await linguo.submitTranslation(0, 'ipfs:/X', { from: translator }) @@ -901,7 +950,7 @@ contract('Linguo', function(accounts) { await linguo.assignTask(0, { from: translator, - value: requiredDeposit + value: requiredDeposit + 1000 }) await linguo.submitTranslation(0, 'ipfs:/X', { from: translator }) @@ -943,7 +992,7 @@ contract('Linguo', function(accounts) { assert.equal( newBalance1.toString(), - oldBalance1.plus(6000).toString(), + oldBalance1.plus(task[8].toNumber()).toString(), 'The translator was not paid correctly' ) assert.equal( @@ -967,7 +1016,7 @@ contract('Linguo', function(accounts) { await linguo.assignTask(0, { from: translator, - value: requiredDeposit + value: requiredDeposit + 1000 }) await linguo.submitTranslation(0, 'ipfs:/X', { from: translator }) @@ -1076,35 +1125,35 @@ contract('Linguo', function(accounts) { 22, 'Incorrect review timeout value' ) - // translator deposit + // translationMultiplier await expectThrow( - linguo.changeTranslatorBaseDeposit(44, { + linguo.changeTranslationMultiplier(44, { from: other }) ) - await linguo.changeTranslatorBaseDeposit(44, { + await linguo.changeTranslationMultiplier(44, { from: governor }) assert.equal( - (await linguo.translatorBaseDeposit()).toNumber(), + (await linguo.translationMultiplier()).toNumber(), 44, - 'Incorrect translatorBaseDeposit value' + 'Incorrect translationMultiplier value' ) - // challenger deposit + // changeChallengeMultiplier await expectThrow( - linguo.changeChallengerBaseDeposit(88, { + linguo.changeChallengeMultiplier(88, { from: other }) ) - await linguo.changeChallengerBaseDeposit(88, { + await linguo.changeChallengeMultiplier(88, { from: governor }) assert.equal( - (await linguo.challengerBaseDeposit()).toNumber(), + (await linguo.challengeMultiplier()).toNumber(), 88, - 'Incorrect challengerBaseDeposit value' + 'Incorrect challengeMultiplier value' ) // shared multiplier await expectThrow( From 4b7da22b6087800fdd08deb0fcd1fb9071d9070f Mon Sep 17 00:00:00 2001 From: unknownunknown1 Date: Wed, 29 Jul 2020 23:31:11 +1000 Subject: [PATCH 2/6] docs(LinguoToken): comment fix --- contracts/standard/arbitration/LinguoToken.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/standard/arbitration/LinguoToken.sol b/contracts/standard/arbitration/LinguoToken.sol index 7a7997cf..918304be 100644 --- a/contracts/standard/arbitration/LinguoToken.sol +++ b/contracts/standard/arbitration/LinguoToken.sol @@ -140,7 +140,7 @@ contract LinguoToken is Arbitrable { /** @dev Constructor. * @param _arbitrator The arbitrator of the contract. * @param _arbitratorExtraData Extra data for the arbitrator. - * @param _WETH Address of the WETH token contract + * @param _WETH Address of the WETH token contract. * @param _uniswapFactory Address of the UniswapPair factory contract. * @param _reviewTimeout Time in seconds during which a translation can be challenged. * @param _translationMultiplier Multiplier for calculating translator's deposit. In basis points. From fac6f06baaf9ddc33b70961f29843d46e0dff8e8 Mon Sep 17 00:00:00 2001 From: unknownunknown1 Date: Thu, 30 Jul 2020 02:12:43 +1000 Subject: [PATCH 3/6] docs(LinguoToken): comment update --- contracts/standard/arbitration/LinguoToken.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/standard/arbitration/LinguoToken.sol b/contracts/standard/arbitration/LinguoToken.sol index 918304be..8e9d3ff9 100644 --- a/contracts/standard/arbitration/LinguoToken.sol +++ b/contracts/standard/arbitration/LinguoToken.sol @@ -635,7 +635,7 @@ contract LinguoToken is Arbitrable { } } - /** @dev Gets the current price of a specified task. + /** @dev Gets the current price of a specified task. Returns 0 if the task can no longer be assigned. * @param _taskID The ID of the task. * @return price The price of the task. */ @@ -648,7 +648,7 @@ contract LinguoToken is Arbitrable { } } - /** @dev Gets the current price of a specified task in ETH. + /** @dev Gets the current price of a specified task in ETH. Returns 0 if the task can no longer be assigned. * @param _taskID The ID of the task. * @return price The price of the task. */ From 9facc46d3ae0e92476a567f00eaff102acb1addb Mon Sep 17 00:00:00 2001 From: unknownunknown1 Date: Thu, 30 Jul 2020 19:57:41 +1000 Subject: [PATCH 4/6] fix(LinguoToken): remove challenge multiplier --- .../standard/arbitration/LinguoToken.sol | 71 ++++++------------- test/linguo-token.js | 44 +++--------- 2 files changed, 31 insertions(+), 84 deletions(-) diff --git a/contracts/standard/arbitration/LinguoToken.sol b/contracts/standard/arbitration/LinguoToken.sol index 8e9d3ff9..84f6f016 100644 --- a/contracts/standard/arbitration/LinguoToken.sol +++ b/contracts/standard/arbitration/LinguoToken.sol @@ -55,12 +55,11 @@ contract LinguoToken is Arbitrable { uint lastInteraction; // The time of the last action performed on the task. Note that lastInteraction is updated only during timeout-related actions such as the creation of the task and the submission of the translation. address requester; // The party requesting the translation. uint requesterDeposit; // The deposit requester makes when creating the task. Once a task is assigned this deposit will be partially reimbursed and its value will be replaced by task price. - uint sumDeposit; // The sum of the deposits of translator and challenger, if any. This value (minus arbitration fees) will be paid to the party that wins the dispute. + uint translatorDeposit; // The deposit of the translator, if any. This value will be paid/reimbursed to the party that wins the dispute. address[3] parties; // Translator and challenger of the task. uint disputeID; // The ID of the dispute created in arbitrator contract. Round[] rounds; // Tracks each appeal round of a dispute. uint ruling; // Ruling given to the dispute of the task by the arbitrator. - 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. } // Rounds are only used in appeal funding. @@ -77,7 +76,6 @@ contract LinguoToken is Arbitrable { address public governor; // The governor of the contract. uint public reviewTimeout; // Time in seconds, during which the submitted translation can be challenged. uint public translationMultiplier; // Multiplier for calculating the value of the deposit translator must pay to self-assign a task. - uint public challengeMultiplier; // Multiplier for calculating the value of the deposit challenger must pay to challenge a translation. // All multipliers below are in basis points. 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"). @@ -144,7 +142,6 @@ contract LinguoToken is Arbitrable { * @param _uniswapFactory Address of the UniswapPair factory contract. * @param _reviewTimeout Time in seconds during which a translation can be challenged. * @param _translationMultiplier Multiplier for calculating translator's deposit. In basis points. - * @param _challengeMultiplier Multiplier for calculating challenger's deposit. In basis points. * @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. * @param _winnerStakeMultiplier Multiplier of the appeal cost that the winner has to pay for a round. In basis points. * @param _loserStakeMultiplier Multiplier of the appeal cost that the loser has to pay for a round. In basis points. @@ -156,7 +153,6 @@ contract LinguoToken is Arbitrable { address _uniswapFactory, uint _reviewTimeout, uint _translationMultiplier, - uint _challengeMultiplier, uint _sharedStakeMultiplier, uint _winnerStakeMultiplier, uint _loserStakeMultiplier @@ -166,7 +162,6 @@ contract LinguoToken is Arbitrable { uniswapFactory = _uniswapFactory; reviewTimeout = _reviewTimeout; translationMultiplier = _translationMultiplier; - challengeMultiplier = _challengeMultiplier; sharedStakeMultiplier = _sharedStakeMultiplier; winnerStakeMultiplier = _winnerStakeMultiplier; loserStakeMultiplier = _loserStakeMultiplier; @@ -197,13 +192,6 @@ contract LinguoToken is Arbitrable { translationMultiplier = _translationMultiplier; } - /** @dev Changes the multiplier for challenger's deposit. - * @param _challengeMultiplier A new value of the multiplier for calculating challenger's deposit. In basis points. - */ - function changeChallengeMultiplier(uint _challengeMultiplier) public onlyGovernor { - challengeMultiplier = _challengeMultiplier; - } - /** @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. * @param _sharedStakeMultiplier A new value of the multiplier of the appeal cost in case when there is no winner/loser in previous round. In basis point. */ @@ -283,9 +271,7 @@ contract LinguoToken is Arbitrable { // Update requester's deposit since we reimbursed him the difference between maximal and actual price. task.requesterDeposit = price; - - task.priceETH = priceETH; - task.sumDeposit += translatorDeposit; + task.translatorDeposit = translatorDeposit; uint remainder = msg.value - translatorDeposit; msg.sender.send(remainder); @@ -319,11 +305,11 @@ contract LinguoToken is Arbitrable { require(now - task.lastInteraction > task.submissionTimeout, "Can't reimburse if the deadline hasn't passed yet."); task.status = Status.Resolved; uint requesterDeposit = task.requesterDeposit; - uint sumDeposit = task.sumDeposit; + uint translatorDeposit = task.translatorDeposit; task.requesterDeposit = 0; - task.sumDeposit = 0; - // Requester gets his deposit back and also the deposit of the translator, if there was one. Note that sumDeposit can't contain challenger's deposit until the task is in DisputeCreated status. - task.requester.send(sumDeposit); + task.translatorDeposit = 0; + // Requester gets his deposit back and also the deposit of the translator, if there was one. + task.requester.send(translatorDeposit); require(task.token.transfer(task.requester, requesterDeposit), "The token transfer was unsuccessful."); emit TaskResolved(_taskID, "requester-reimbursed", now); @@ -337,13 +323,13 @@ contract LinguoToken is Arbitrable { require(task.status == Status.AwaitingReview, "The task is in the wrong status."); require(now - task.lastInteraction > reviewTimeout, "The review phase hasn't passed yet."); task.status = Status.Resolved; - // Translator gets the price of the task and his deposit back. Note that sumDeposit can't contain challenger's deposit until the task is in DisputeCreated status. + // Translator gets the price of the task and his deposit back. address translator = task.parties[uint(Party.Translator)]; uint requesterDeposit = task.requesterDeposit; - uint sumDeposit = task.sumDeposit; + uint translatorDeposit = task.translatorDeposit; task.requesterDeposit = 0; - task.sumDeposit = 0; - translator.send(sumDeposit); + task.translatorDeposit = 0; + translator.send(translatorDeposit); require(task.token.transfer(translator, requesterDeposit), "The token transfer was unsuccessful."); emit TaskResolved(_taskID, "translation-accepted", now); @@ -356,12 +342,12 @@ contract LinguoToken is Arbitrable { function challengeTranslation(uint _taskID, string _evidence) external payable { Task storage task = tasks[_taskID]; + // The challenger should only deposit the value of arbitration cost. uint arbitrationCost = arbitrator.arbitrationCost(arbitratorExtraData); - uint challengeDeposit = arbitrationCost.addCap((challengeMultiplier.mulCap(task.priceETH)) / MULTIPLIER_DIVISOR); require(task.status == Status.AwaitingReview, "The task is in the wrong status."); require(now - task.lastInteraction <= reviewTimeout, "The review phase has already passed."); - require(msg.value >= challengeDeposit, "Not enough ETH to cover challenge deposit."); + require(msg.value >= arbitrationCost, "Not enough ETH to cover challenge deposit."); task.status = Status.DisputeCreated; task.parties[uint(Party.Challenger)] = msg.sender; @@ -369,9 +355,8 @@ contract LinguoToken is Arbitrable { task.disputeID = arbitrator.createDispute.value(arbitrationCost)(2, arbitratorExtraData); disputeIDtoTaskID[task.disputeID] = _taskID; task.rounds.length++; - task.sumDeposit = task.sumDeposit.addCap(challengeDeposit).subCap(arbitrationCost); - uint remainder = msg.value - challengeDeposit; + uint remainder = msg.value - arbitrationCost; msg.sender.send(remainder); emit Dispute(arbitrator, task.disputeID, _taskID, _taskID); @@ -536,22 +521,22 @@ contract LinguoToken is Arbitrable { Task storage task = tasks[taskID]; task.status = Status.Resolved; task.ruling = _ruling; - uint sumDeposit = task.sumDeposit; + uint translatorDeposit = task.translatorDeposit; uint requesterDeposit = task.requesterDeposit; task.requesterDeposit = 0; - task.sumDeposit = 0; + task.translatorDeposit = 0; if(_ruling == uint(Party.None)){ - // The value of sumDeposit is split among parties in this case. If the sum is uneven the value of 1 wei can be burnt. - sumDeposit = sumDeposit / 2; - task.parties[uint(Party.Translator)].send(sumDeposit); - task.parties[uint(Party.Challenger)].send(sumDeposit); + // The value of translatorDeposit is split among parties in this case. If it's uneven the value of 1 wei can be burnt. + translatorDeposit = translatorDeposit / 2; + task.parties[uint(Party.Translator)].send(translatorDeposit); + task.parties[uint(Party.Challenger)].send(translatorDeposit); require(task.token.transfer(task.requester, requesterDeposit), "Could not transfer tokens to requester."); } else if (_ruling == uint(Party.Translator)) { - task.parties[uint(Party.Translator)].send(sumDeposit); + task.parties[uint(Party.Translator)].send(translatorDeposit); require(task.token.transfer(task.parties[uint(Party.Translator)], requesterDeposit), "Could not transfer tokens to translator."); } else { - task.parties[uint(Party.Challenger)].send(sumDeposit); + task.parties[uint(Party.Challenger)].send(translatorDeposit); require(task.token.transfer(task.requester, requesterDeposit), "Could not transfer tokens to requester."); } @@ -621,20 +606,6 @@ contract LinguoToken is Arbitrable { } } - /** @dev Gets the deposit required for challenging the translation. - * @param _taskID The ID of the task. - * @return deposit The challengers's deposit. - */ - function getChallengeValue(uint _taskID) public view returns (uint deposit) { - Task storage task = tasks[_taskID]; - if (now - task.lastInteraction > reviewTimeout || task.status != Status.AwaitingReview) { - deposit = NOT_PAYABLE_VALUE; - } else { - uint arbitrationCost = arbitrator.arbitrationCost(arbitratorExtraData); - deposit = arbitrationCost.addCap((challengeMultiplier.mulCap(task.priceETH)) / MULTIPLIER_DIVISOR); - } - } - /** @dev Gets the current price of a specified task. Returns 0 if the task can no longer be assigned. * @param _taskID The ID of the task. * @return price The price of the task. diff --git a/test/linguo-token.js b/test/linguo-token.js index db0b66b6..a8951c46 100644 --- a/test/linguo-token.js +++ b/test/linguo-token.js @@ -28,7 +28,6 @@ contract('Linguo', function(accounts) { const appealTimeOut = 100 const reviewTimeout = 2400 const translationMultiplier = 1000 - const challengeMultiplier = 2000 const sharedMultiplier = 5000 const winnerMultiplier = 3000 const loserMultiplier = 7000 @@ -65,7 +64,6 @@ contract('Linguo', function(accounts) { fakeFactory, // uniswapFactory. Can't test the uniswap getters because of the old compiler, so set it random value. reviewTimeout, translationMultiplier, - challengeMultiplier, sharedMultiplier, winnerMultiplier, loserMultiplier, @@ -104,7 +102,6 @@ contract('Linguo', function(accounts) { assert.equal(await linguo.governor(), governor) assert.equal(await linguo.reviewTimeout(), reviewTimeout) assert.equal(await linguo.translationMultiplier(), translationMultiplier) - assert.equal(await linguo.challengeMultiplier(), challengeMultiplier) assert.equal(await linguo.sharedStakeMultiplier(), sharedMultiplier) assert.equal(await linguo.winnerStakeMultiplier(), winnerMultiplier) assert.equal(await linguo.loserStakeMultiplier(), loserMultiplier) @@ -352,12 +349,6 @@ contract('Linguo', function(accounts) { Math.abs(task[8].toNumber() - requiredDeposit) <= requiredDeposit / 100, 'The translator deposit was not set up properly' ) - - assert.equal( - task[7].toNumber(), - task[11].toNumber(), - 'Incorrect price in ETH value' - ) }) it('Should not be possible to submit translation after submission timeout ended', async () => { @@ -469,7 +460,7 @@ contract('Linguo', function(accounts) { }) it('Should not be possible to reimburse if submission timeout has not passed', async () => { - await increaseTime(submissionTimeout - secondsPassed - 1) + await increaseTime(submissionTimeout - secondsPassed - 5) await expectThrow(linguo.reimburseRequester(0)) }) @@ -519,7 +510,7 @@ contract('Linguo', function(accounts) { await linguo.submitTranslation(0, 'ipfs:/X', { from: translator }) await expectThrow(linguo.acceptTranslation(0)) - const challengerDeposit = (await linguo.getChallengeValue(0)).toNumber() + const challengerDeposit = arbitrationFee await linguo.challengeTranslation(0, '', { from: challenger, value: challengerDeposit @@ -537,7 +528,7 @@ contract('Linguo', function(accounts) { }) await linguo.submitTranslation(0, 'ipfs:/X', { from: translator }) - const challengerDeposit = (await linguo.getChallengeValue(0)).toNumber() + const challengerDeposit = arbitrationFee // Check that reverts if the deposit is lower than expected await expectThrow( @@ -632,7 +623,7 @@ contract('Linguo', function(accounts) { value: requiredDeposit + 1000 }) await linguo.submitTranslation(0, 'ipfs:/X', { from: translator }) - const challengerDeposit = (await linguo.getChallengeValue(0)).toNumber() + const challengerDeposit = arbitrationFee await increaseTime(reviewTimeout + 1) await expectThrow( linguo.challengeTranslation(0, '', { @@ -652,7 +643,7 @@ contract('Linguo', function(accounts) { await linguo.submitTranslation(0, 'ipfs:/X', { from: translator }) - const challengerDeposit = (await linguo.getChallengeValue(0)).toNumber() + const challengerDeposit = arbitrationFee await linguo.challengeTranslation(0, '', { from: challenger, value: challengerDeposit @@ -708,7 +699,7 @@ contract('Linguo', function(accounts) { }) await linguo.submitTranslation(0, 'ipfs:/X', { from: translator }) - const challengerDeposit = (await linguo.getChallengeValue(0)).toNumber() + const challengerDeposit = arbitrationFee await linguo.challengeTranslation(0, '', { from: challenger, value: challengerDeposit @@ -767,7 +758,7 @@ contract('Linguo', function(accounts) { await linguo.submitTranslation(0, 'ipfs:/X', { from: translator }) - const challengerDeposit = (await linguo.getChallengeValue(0)).toNumber() + const challengerDeposit = arbitrationFee await linguo.challengeTranslation(0, '', { from: challenger, value: challengerDeposit @@ -843,7 +834,7 @@ contract('Linguo', function(accounts) { }) await linguo.submitTranslation(0, 'ipfs:/X', { from: translator }) - const challengerDeposit = (await linguo.getChallengeValue(0)).toNumber() + const challengerDeposit = arbitrationFee await linguo.challengeTranslation(0, '', { from: challenger, value: challengerDeposit @@ -954,7 +945,7 @@ contract('Linguo', function(accounts) { }) await linguo.submitTranslation(0, 'ipfs:/X', { from: translator }) - const challengerDeposit = (await linguo.getChallengeValue(0)).toNumber() + const challengerDeposit = arbitrationFee await linguo.challengeTranslation(0, '', { from: challenger, value: challengerDeposit @@ -1020,7 +1011,7 @@ contract('Linguo', function(accounts) { }) await linguo.submitTranslation(0, 'ipfs:/X', { from: translator }) - const challengerDeposit = (await linguo.getChallengeValue(0)).toNumber() + const challengerDeposit = arbitrationFee await linguo.challengeTranslation(0, '', { from: challenger, value: challengerDeposit @@ -1140,21 +1131,6 @@ contract('Linguo', function(accounts) { 44, 'Incorrect translationMultiplier value' ) - // changeChallengeMultiplier - await expectThrow( - linguo.changeChallengeMultiplier(88, { - from: other - }) - ) - await linguo.changeChallengeMultiplier(88, { - from: governor - }) - - assert.equal( - (await linguo.challengeMultiplier()).toNumber(), - 88, - 'Incorrect challengeMultiplier value' - ) // shared multiplier await expectThrow( linguo.changeSharedStakeMultiplier(5011, { From 4c38d93af0e70b272062e4b56989a9c5260f677a Mon Sep 17 00:00:00 2001 From: unknownunknown1 Date: Thu, 30 Jul 2020 23:29:53 +1000 Subject: [PATCH 5/6] refactor(LinguoToken.sol): variable renamed --- .../standard/arbitration/LinguoToken.sol | 46 ++++++++++++------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/contracts/standard/arbitration/LinguoToken.sol b/contracts/standard/arbitration/LinguoToken.sol index 84f6f016..152abe53 100644 --- a/contracts/standard/arbitration/LinguoToken.sol +++ b/contracts/standard/arbitration/LinguoToken.sol @@ -55,7 +55,7 @@ contract LinguoToken is Arbitrable { uint lastInteraction; // The time of the last action performed on the task. Note that lastInteraction is updated only during timeout-related actions such as the creation of the task and the submission of the translation. address requester; // The party requesting the translation. uint requesterDeposit; // The deposit requester makes when creating the task. Once a task is assigned this deposit will be partially reimbursed and its value will be replaced by task price. - uint translatorDeposit; // The deposit of the translator, if any. This value will be paid/reimbursed to the party that wins the dispute. + uint sumDeposit; // The sum of the deposits of translator and challenger, if any. This value (minus arbitration fees) will be paid to the party that wins the dispute. address[3] parties; // Translator and challenger of the task. uint disputeID; // The ID of the dispute created in arbitrator contract. Round[] rounds; // Tracks each appeal round of a dispute. @@ -271,7 +271,7 @@ contract LinguoToken is Arbitrable { // Update requester's deposit since we reimbursed him the difference between maximal and actual price. task.requesterDeposit = price; - task.translatorDeposit = translatorDeposit; + task.sumDeposit = translatorDeposit; uint remainder = msg.value - translatorDeposit; msg.sender.send(remainder); @@ -305,11 +305,11 @@ contract LinguoToken is Arbitrable { require(now - task.lastInteraction > task.submissionTimeout, "Can't reimburse if the deadline hasn't passed yet."); task.status = Status.Resolved; uint requesterDeposit = task.requesterDeposit; - uint translatorDeposit = task.translatorDeposit; + uint sumDeposit = task.sumDeposit; task.requesterDeposit = 0; - task.translatorDeposit = 0; + task.sumDeposit = 0; // Requester gets his deposit back and also the deposit of the translator, if there was one. - task.requester.send(translatorDeposit); + task.requester.send(sumDeposit); require(task.token.transfer(task.requester, requesterDeposit), "The token transfer was unsuccessful."); emit TaskResolved(_taskID, "requester-reimbursed", now); @@ -326,10 +326,10 @@ contract LinguoToken is Arbitrable { // Translator gets the price of the task and his deposit back. address translator = task.parties[uint(Party.Translator)]; uint requesterDeposit = task.requesterDeposit; - uint translatorDeposit = task.translatorDeposit; + uint sumDeposit = task.sumDeposit; task.requesterDeposit = 0; - task.translatorDeposit = 0; - translator.send(translatorDeposit); + task.sumDeposit = 0; + translator.send(sumDeposit); require(task.token.transfer(translator, requesterDeposit), "The token transfer was unsuccessful."); emit TaskResolved(_taskID, "translation-accepted", now); @@ -355,6 +355,7 @@ contract LinguoToken is Arbitrable { task.disputeID = arbitrator.createDispute.value(arbitrationCost)(2, arbitratorExtraData); disputeIDtoTaskID[task.disputeID] = _taskID; task.rounds.length++; + //We don't change sumDeposit because adding challenger's deposit while subtracting arbitration fee will give 0 as a result. uint remainder = msg.value - arbitrationCost; msg.sender.send(remainder); @@ -521,22 +522,22 @@ contract LinguoToken is Arbitrable { Task storage task = tasks[taskID]; task.status = Status.Resolved; task.ruling = _ruling; - uint translatorDeposit = task.translatorDeposit; + uint sumDeposit = task.sumDeposit; uint requesterDeposit = task.requesterDeposit; task.requesterDeposit = 0; - task.translatorDeposit = 0; + task.sumDeposit = 0; if(_ruling == uint(Party.None)){ - // The value of translatorDeposit is split among parties in this case. If it's uneven the value of 1 wei can be burnt. - translatorDeposit = translatorDeposit / 2; - task.parties[uint(Party.Translator)].send(translatorDeposit); - task.parties[uint(Party.Challenger)].send(translatorDeposit); + // The value of sumDeposit is split among parties in this case. If it's uneven the value of 1 wei can be burnt. + sumDeposit = sumDeposit / 2; + task.parties[uint(Party.Translator)].send(sumDeposit); + task.parties[uint(Party.Challenger)].send(sumDeposit); require(task.token.transfer(task.requester, requesterDeposit), "Could not transfer tokens to requester."); } else if (_ruling == uint(Party.Translator)) { - task.parties[uint(Party.Translator)].send(translatorDeposit); + task.parties[uint(Party.Translator)].send(sumDeposit); require(task.token.transfer(task.parties[uint(Party.Translator)], requesterDeposit), "Could not transfer tokens to translator."); } else { - task.parties[uint(Party.Challenger)].send(translatorDeposit); + task.parties[uint(Party.Challenger)].send(sumDeposit); require(task.token.transfer(task.requester, requesterDeposit), "Could not transfer tokens to requester."); } @@ -606,6 +607,19 @@ contract LinguoToken is Arbitrable { } } + /** @dev Gets the deposit required for challenging the translation. + * @param _taskID The ID of the task. + * @return deposit The challengers's deposit. + */ + function getChallengeValue(uint _taskID) public view returns (uint deposit) { + Task storage task = tasks[_taskID]; + if (now - task.lastInteraction > reviewTimeout || task.status != Status.AwaitingReview) { + deposit = NOT_PAYABLE_VALUE; + } else { + deposit = arbitrator.arbitrationCost(arbitratorExtraData); + } + } + /** @dev Gets the current price of a specified task. Returns 0 if the task can no longer be assigned. * @param _taskID The ID of the task. * @return price The price of the task. From eebcb4aeb034dc5c1fa053404d2f6203dcf3ae93 Mon Sep 17 00:00:00 2001 From: unknownunknown1 Date: Thu, 30 Jul 2020 23:42:42 +1000 Subject: [PATCH 6/6] docs(LinguoToken): styling --- contracts/standard/arbitration/LinguoToken.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/standard/arbitration/LinguoToken.sol b/contracts/standard/arbitration/LinguoToken.sol index 152abe53..ab8dcd69 100644 --- a/contracts/standard/arbitration/LinguoToken.sol +++ b/contracts/standard/arbitration/LinguoToken.sol @@ -355,7 +355,7 @@ contract LinguoToken is Arbitrable { task.disputeID = arbitrator.createDispute.value(arbitrationCost)(2, arbitratorExtraData); disputeIDtoTaskID[task.disputeID] = _taskID; task.rounds.length++; - //We don't change sumDeposit because adding challenger's deposit while subtracting arbitration fee will give 0 as a result. + // We don't change sumDeposit because adding challenger's deposit while subtracting arbitration fee will give 0 as a result. uint remainder = msg.value - arbitrationCost; msg.sender.send(remainder);