Skip to content

Commit 5534768

Browse files
committed
refactor: minor refactor and fixed the tests
1 parent 62e4e75 commit 5534768

File tree

3 files changed

+90
-83
lines changed

3 files changed

+90
-83
lines changed

contracts/src/arbitration/KlerosCore.sol

+46-55
Original file line numberDiff line numberDiff line change
@@ -483,14 +483,14 @@ contract KlerosCore is IArbitratorV2 {
483483

484484
/// @dev Sets the caller's stake in a court.
485485
/// @param _courtID The ID of the court.
486-
/// @param _stake The new stake.
487-
function setStake(uint96 _courtID, uint256 _stake) external {
488-
if (!_setStakeForAccount(msg.sender, _courtID, _stake)) revert StakingFailed();
486+
/// @param _newStake The new stake.
487+
function setStake(uint96 _courtID, uint256 _newStake) external {
488+
if (!_setStakeForAccount(msg.sender, _courtID, _newStake)) revert StakingFailed();
489489
}
490490

491-
function setStakeBySortitionModule(address _account, uint96 _courtID, uint256 _stake) external {
491+
function setStakeBySortitionModule(address _account, uint96 _courtID, uint256 _newStake) external {
492492
if (msg.sender != address(sortitionModule)) revert WrongCaller();
493-
_setStakeForAccount(_account, _courtID, _stake);
493+
_setStakeForAccount(_account, _courtID, _newStake);
494494
}
495495

496496
/// @inheritdoc IArbitratorV2
@@ -611,17 +611,16 @@ contract KlerosCore is IArbitratorV2 {
611611
IDisputeKit disputeKit = disputeKitNodes[round.disputeKitID].disputeKit;
612612

613613
uint256 startIndex = round.drawIterations;
614-
// TODO: cap the iterations?
615-
for (uint256 i = startIndex; i < startIndex + _iterations; i++) {
614+
for (uint256 i = startIndex; i < startIndex + _iterations && round.drawnJurors.length < round.nbVotes; i++) {
616615
address drawnAddress = disputeKit.draw(_disputeID, i);
617-
if (drawnAddress != address(0)) {
618-
jurors[drawnAddress].lockedPnk += round.pnkAtStakePerJuror;
619-
emit Draw(drawnAddress, _disputeID, currentRound, round.drawnJurors.length);
620-
round.drawnJurors.push(drawnAddress);
621-
622-
if (round.drawnJurors.length == round.nbVotes) {
623-
sortitionModule.postDrawHook(_disputeID, currentRound);
624-
}
616+
if (drawnAddress == address(0)) {
617+
continue;
618+
}
619+
jurors[drawnAddress].lockedPnk += round.pnkAtStakePerJuror;
620+
emit Draw(drawnAddress, _disputeID, currentRound, round.drawnJurors.length);
621+
round.drawnJurors.push(drawnAddress);
622+
if (round.drawnJurors.length == round.nbVotes) {
623+
sortitionModule.postDrawHook(_disputeID, currentRound);
625624
}
626625
}
627626
round.drawIterations += _iterations;
@@ -1110,35 +1109,40 @@ contract KlerosCore is IArbitratorV2 {
11101109
/// and `j` is the maximum number of jurors that ever staked in one of these courts simultaneously.
11111110
/// @param _account The address of the juror.
11121111
/// @param _courtID The ID of the court.
1113-
/// @param _stake The new stake.
1112+
/// @param _newStake The new stake.
11141113
/// @return succeeded True if the call succeeded, false otherwise.
1115-
function _setStakeForAccount(address _account, uint96 _courtID, uint256 _stake) internal returns (bool succeeded) {
1114+
function _setStakeForAccount(
1115+
address _account,
1116+
uint96 _courtID,
1117+
uint256 _newStake
1118+
) internal returns (bool succeeded) {
11161119
if (_courtID == FORKING_COURT || _courtID > courts.length) return false;
11171120

11181121
Juror storage juror = jurors[_account];
11191122
uint256 currentStake = juror.stakedPnkByCourt[_courtID];
11201123

1121-
if (_stake != 0) {
1122-
if (_stake < courts[_courtID].minStake) return false;
1124+
if (_newStake != 0) {
1125+
if (_newStake < courts[_courtID].minStake) return false;
11231126
} else if (currentStake == 0) {
11241127
return false;
11251128
}
11261129

1127-
ISortitionModule.preStakeHookResult result = sortitionModule.preStakeHook(_account, _courtID, _stake);
1130+
ISortitionModule.preStakeHookResult result = sortitionModule.preStakeHook(_account, _courtID, _newStake);
11281131
if (result == ISortitionModule.preStakeHookResult.failed) {
11291132
return false;
11301133
} else if (result == ISortitionModule.preStakeHookResult.delayed) {
1131-
emit StakeDelayed(_account, _courtID, _stake);
1134+
emit StakeDelayed(_account, _courtID, _newStake);
11321135
return true;
11331136
}
11341137

11351138
uint256 transferredAmount;
1136-
if (_stake >= currentStake) {
1139+
if (_newStake >= currentStake) {
1140+
// Stake increase
11371141
// When stakedPnk becomes lower than lockedPnk count the locked tokens in when transferring tokens from juror.
11381142
// (E.g. stakedPnk = 0, lockedPnk = 150) which can happen if the juror unstaked fully while having some tokens locked.
1139-
uint256 previouslyLocked = (juror.lockedPnk >= juror.stakedPnk) ? juror.lockedPnk - juror.stakedPnk : 0;
1140-
transferredAmount = (_stake >= currentStake + previouslyLocked)
1141-
? _stake - currentStake - previouslyLocked
1143+
uint256 previouslyLocked = (juror.lockedPnk >= juror.stakedPnk) ? juror.lockedPnk - juror.stakedPnk : 0; // underflow guard
1144+
transferredAmount = (_newStake >= currentStake + previouslyLocked) // underflow guard
1145+
? _newStake - currentStake - previouslyLocked
11421146
: 0;
11431147
if (transferredAmount > 0) {
11441148
if (!pinakion.safeTransferFrom(_account, address(this), transferredAmount)) {
@@ -1149,49 +1153,36 @@ contract KlerosCore is IArbitratorV2 {
11491153
juror.courtIDs.push(_courtID);
11501154
}
11511155
} else {
1152-
if (_stake == 0) {
1153-
// Make sure locked tokens always stay in the contract. They can only be released during Execution.
1154-
if (juror.stakedPnk >= currentStake + juror.lockedPnk) {
1155-
// We have enough pnk staked to afford withdrawal of the current stake while keeping locked tokens.
1156-
transferredAmount = currentStake;
1157-
} else if (juror.stakedPnk >= juror.lockedPnk) {
1158-
// Can't afford withdrawing the current stake fully. Take whatever is available while keeping locked tokens.
1159-
transferredAmount = juror.stakedPnk - juror.lockedPnk;
1160-
}
1161-
if (transferredAmount > 0) {
1162-
if (!pinakion.safeTransfer(_account, transferredAmount)) {
1163-
return false;
1164-
}
1156+
// Stake decrease: make sure locked tokens always stay in the contract. They can only be released during Execution.
1157+
if (juror.stakedPnk >= currentStake - _newStake + juror.lockedPnk) {
1158+
// We have enough pnk staked to afford withdrawal while keeping locked tokens.
1159+
transferredAmount = currentStake - _newStake;
1160+
} else if (juror.stakedPnk >= juror.lockedPnk) {
1161+
// Can't afford withdrawing the current stake fully. Take whatever is available while keeping locked tokens.
1162+
transferredAmount = juror.stakedPnk - juror.lockedPnk;
1163+
}
1164+
if (transferredAmount > 0) {
1165+
if (!pinakion.safeTransfer(_account, transferredAmount)) {
1166+
return false;
11651167
}
1168+
}
1169+
if (_newStake == 0) {
11661170
for (uint256 i = juror.courtIDs.length; i > 0; i--) {
11671171
if (juror.courtIDs[i - 1] == _courtID) {
11681172
juror.courtIDs[i - 1] = juror.courtIDs[juror.courtIDs.length - 1];
11691173
juror.courtIDs.pop();
11701174
break;
11711175
}
11721176
}
1173-
} else {
1174-
if (juror.stakedPnk >= currentStake - _stake + juror.lockedPnk) {
1175-
// We have enough pnk staked to afford withdrawal while keeping locked tokens.
1176-
transferredAmount = currentStake - _stake;
1177-
} else if (juror.stakedPnk >= juror.lockedPnk) {
1178-
// Can't afford withdrawing the current stake fully. Take whatever is available while keeping locked tokens.
1179-
transferredAmount = juror.stakedPnk - juror.lockedPnk;
1180-
}
1181-
if (transferredAmount > 0) {
1182-
if (!pinakion.safeTransfer(_account, transferredAmount)) {
1183-
return false;
1184-
}
1185-
}
11861177
}
11871178
}
11881179

11891180
// Note that stakedPnk can become async with currentStake (e.g. after penalty).
1190-
juror.stakedPnk = (juror.stakedPnk >= currentStake) ? juror.stakedPnk - currentStake + _stake : _stake;
1191-
juror.stakedPnkByCourt[_courtID] = _stake;
1181+
juror.stakedPnk = (juror.stakedPnk >= currentStake) ? juror.stakedPnk - currentStake + _newStake : _newStake;
1182+
juror.stakedPnkByCourt[_courtID] = _newStake;
11921183

1193-
sortitionModule.setStake(_account, _courtID, _stake);
1194-
emit StakeSet(_account, _courtID, _stake);
1184+
sortitionModule.setStake(_account, _courtID, _newStake);
1185+
emit StakeSet(_account, _courtID, _newStake);
11951186
return true;
11961187
}
11971188

contracts/test/arbitration/draw.ts

+31-19
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import { DrawEvent } from "../../typechain-types/src/kleros-v1/kleros-liquid-xda
1515
/* eslint-disable no-unused-vars */
1616
/* eslint-disable no-unused-expressions */ // https://github.com/standard/standard/issues/690#issuecomment-278533482
1717

18-
// FIXME: This test fails on Github actions, cannot figure why, skipping for now.
1918
describe("Draw Benchmark", async () => {
2019
const ONE_TENTH_ETH = BigNumber.from(10).pow(17);
2120
const ONE_THOUSAND_PNK = BigNumber.from(10).pow(21);
@@ -170,8 +169,7 @@ describe("Draw Benchmark", async () => {
170169
}
171170

172171
await sortitionModule.passPhase(); // Generating -> Drawing
173-
174-
await expectFromDraw(core.draw(0, 1000, { gasLimit: 1000000 }));
172+
await expectFromDraw(core.draw(0, 20, { gasLimit: 1000000 }));
175173

176174
await network.provider.send("evm_increaseTime", [2000]); // Wait for maxDrawingTime
177175
await sortitionModule.passPhase(); // Drawing -> Staking
@@ -197,8 +195,9 @@ describe("Draw Benchmark", async () => {
197195
await core.connect(wallet).setStake(PARENT_COURT, ONE_THOUSAND_PNK.mul(5), { gasLimit: 5000000 });
198196

199197
expect(await core.getJurorBalance(wallet.address, 1)).to.deep.equal([
198+
ONE_THOUSAND_PNK.mul(5), // totalStaked
199+
0, // totalLocked
200200
ONE_THOUSAND_PNK.mul(5), // stakedInCourt
201-
0, // lockedInCourt
202201
PARENT_COURT, // nbOfCourts
203202
]);
204203
};
@@ -216,13 +215,15 @@ describe("Draw Benchmark", async () => {
216215
countedDraws = await countDraws(tx.blockNumber);
217216
for (const [address, draws] of Object.entries(countedDraws)) {
218217
expect(await core.getJurorBalance(address, PARENT_COURT)).to.deep.equal([
218+
ONE_THOUSAND_PNK.mul(5), // totalStaked
219+
parentCourtMinStake.mul(draws), // totalLocked
219220
ONE_THOUSAND_PNK.mul(5), // stakedInCourt
220-
parentCourtMinStake.mul(draws), // lockedInCourt
221221
1, // nbOfCourts
222222
]);
223223
expect(await core.getJurorBalance(address, CHILD_COURT)).to.deep.equal([
224+
ONE_THOUSAND_PNK.mul(5), // totalStaked
225+
parentCourtMinStake.mul(draws), // totalLocked
224226
0, // stakedInCourt
225-
0, // lockedInCourt
226227
1, // nbOfCourts
227228
]);
228229
}
@@ -235,16 +236,18 @@ describe("Draw Benchmark", async () => {
235236
await core.getJurorBalance(wallet.address, PARENT_COURT),
236237
"Drawn jurors have a locked stake in the parent court"
237238
).to.deep.equal([
239+
0, // totalStaked
240+
locked, // totalLocked
238241
0, // stakedInCourt
239-
locked, // lockedInCourt
240242
0, // nbOfCourts
241243
]);
242244
expect(
243245
await core.getJurorBalance(wallet.address, CHILD_COURT),
244246
"No locked stake in the child court"
245247
).to.deep.equal([
248+
0, // totalStaked
249+
locked, // totalLocked
246250
0, // stakedInCourt
247-
0, // lockedInCourt
248251
0, // nbOfCourts
249252
]);
250253
};
@@ -267,16 +270,18 @@ describe("Draw Benchmark", async () => {
267270
await core.getJurorBalance(wallet.address, PARENT_COURT),
268271
"No locked stake in the parent court"
269272
).to.deep.equal([
273+
0, // totalStaked
274+
0, // totalLocked
270275
0, // stakedInCourt
271-
0, // lockedInCourt
272276
0, // nbOfCourts
273277
]);
274278
expect(
275279
await core.getJurorBalance(wallet.address, CHILD_COURT),
276280
"No locked stake in the child court"
277281
).to.deep.equal([
282+
0, // totalStaked
283+
0, // totalLocked
278284
0, // stakedInCourt
279-
0, // lockedInCourt
280285
0, // nbOfCourts
281286
]);
282287
};
@@ -302,13 +307,15 @@ describe("Draw Benchmark", async () => {
302307
countedDraws = await countDraws(tx.blockNumber);
303308
for (const [address, draws] of Object.entries(countedDraws)) {
304309
expect(await core.getJurorBalance(address, PARENT_COURT)).to.deep.equal([
310+
ONE_THOUSAND_PNK.mul(5), // totalStaked
311+
parentCourtMinStake.mul(draws), // totalLocked
305312
0, // stakedInCourt
306-
parentCourtMinStake.mul(draws), // lockedInCourt
307313
1, // nbOfCourts
308314
]);
309315
expect(await core.getJurorBalance(address, CHILD_COURT)).to.deep.equal([
316+
ONE_THOUSAND_PNK.mul(5), // totalStaked
317+
parentCourtMinStake.mul(draws), // totalLocked
310318
ONE_THOUSAND_PNK.mul(5), // stakedInCourt
311-
0, // lockedInCourt
312319
1, // nbOfCourts
313320
]);
314321
}
@@ -317,21 +324,22 @@ describe("Draw Benchmark", async () => {
317324
const unstake = async (wallet: Wallet) => {
318325
await core.connect(wallet).setStake(CHILD_COURT, 0, { gasLimit: 5000000 });
319326
const locked = parentCourtMinStake.mul(countedDraws[wallet.address] ?? 0);
320-
console.log(`draws for ${wallet.address}: ${countedDraws[wallet.address] ?? 0}, locked: ${locked}`);
321327
expect(
322328
await core.getJurorBalance(wallet.address, PARENT_COURT),
323329
"No locked stake in the parent court"
324330
).to.deep.equal([
331+
0, // totalStaked
332+
locked, // totalLocked
325333
0, // stakedInCourt
326-
0, // lockedInCourt
327334
0, // nbOfCourts
328335
]);
329336
expect(
330337
await core.getJurorBalance(wallet.address, CHILD_COURT),
331338
"Drawn jurors have a locked stake in the child court"
332339
).to.deep.equal([
340+
0, // totalStaked
341+
locked, // totalLocked
333342
0, // stakedInCourt
334-
locked, // lockedInCourt
335343
0, // nbOfCourts
336344
]);
337345
};
@@ -357,13 +365,15 @@ describe("Draw Benchmark", async () => {
357365
countedDraws = await countDraws(tx.blockNumber);
358366
for (const [address, draws] of Object.entries(countedDraws)) {
359367
expect(await core.getJurorBalance(address, PARENT_COURT)).to.deep.equal([
368+
ONE_THOUSAND_PNK.mul(5), // totalStaked
369+
childCourtMinStake.mul(draws), // totalLocked
360370
0, // stakedInCourt
361-
0, // lockedInCourt
362371
1, // nbOfCourts
363372
]);
364373
expect(await core.getJurorBalance(address, CHILD_COURT)).to.deep.equal([
374+
ONE_THOUSAND_PNK.mul(5), // totalStaked
375+
childCourtMinStake.mul(draws), // totalLocked
365376
ONE_THOUSAND_PNK.mul(5), // stakedInCourt
366-
childCourtMinStake.mul(draws), // lockedInCourt
367377
1, // nbOfCourts
368378
]);
369379
}
@@ -376,16 +386,18 @@ describe("Draw Benchmark", async () => {
376386
await core.getJurorBalance(wallet.address, PARENT_COURT),
377387
"No locked stake in the parent court"
378388
).to.deep.equal([
389+
0, // totalStaked
390+
locked, // totalLocked
379391
0, // stakedInCourt
380-
0, // lockedInCourt
381392
0, // nbOfCourts
382393
]);
383394
expect(
384395
await core.getJurorBalance(wallet.address, CHILD_COURT),
385396
"Drawn jurors have a locked stake in the child court"
386397
).to.deep.equal([
398+
0, // totalStaked
399+
locked, // totalLocked
387400
0, // stakedInCourt
388-
locked, // lockedInCourt
389401
0, // nbOfCourts
390402
]);
391403
};

contracts/test/integration/index.ts

+13-9
Original file line numberDiff line numberDiff line change
@@ -67,29 +67,29 @@ describe("Integration tests", async () => {
6767

6868
await core.setStake(1, ONE_THOUSAND_PNK);
6969
await core.getJurorBalance(deployer, 1).then((result) => {
70-
expect(result.staked).to.equal(ONE_THOUSAND_PNK);
71-
expect(result.locked).to.equal(0);
70+
expect(result.totalStaked).to.equal(ONE_THOUSAND_PNK);
71+
expect(result.totalLocked).to.equal(0);
7272
logJurorBalance(result);
7373
});
7474

7575
await core.setStake(1, ONE_HUNDRED_PNK.mul(5));
7676
await core.getJurorBalance(deployer, 1).then((result) => {
77-
expect(result.staked).to.equal(ONE_HUNDRED_PNK.mul(5));
78-
expect(result.locked).to.equal(0);
77+
expect(result.totalStaked).to.equal(ONE_HUNDRED_PNK.mul(5));
78+
expect(result.totalLocked).to.equal(0);
7979
logJurorBalance(result);
8080
});
8181

8282
await core.setStake(1, 0);
8383
await core.getJurorBalance(deployer, 1).then((result) => {
84-
expect(result.staked).to.equal(0);
85-
expect(result.locked).to.equal(0);
84+
expect(result.totalStaked).to.equal(0);
85+
expect(result.totalLocked).to.equal(0);
8686
logJurorBalance(result);
8787
});
8888

8989
await core.setStake(1, ONE_THOUSAND_PNK.mul(4));
9090
await core.getJurorBalance(deployer, 1).then((result) => {
91-
expect(result.staked).to.equal(ONE_THOUSAND_PNK.mul(4));
92-
expect(result.locked).to.equal(0);
91+
expect(result.totalStaked).to.equal(ONE_THOUSAND_PNK.mul(4));
92+
expect(result.totalLocked).to.equal(0);
9393
logJurorBalance(result);
9494
});
9595
const tx = await arbitrable.functions["createDispute(string)"]("future of france", {
@@ -183,5 +183,9 @@ describe("Integration tests", async () => {
183183
});
184184

185185
const logJurorBalance = async (result) => {
186-
console.log("staked=%s, locked=%s", ethers.utils.formatUnits(result.staked), ethers.utils.formatUnits(result.locked));
186+
console.log(
187+
"staked=%s, locked=%s",
188+
ethers.utils.formatUnits(result.totalStaked),
189+
ethers.utils.formatUnits(result.totalLocked)
190+
);
187191
};

0 commit comments

Comments
 (0)