Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions contracts/src/arbitration/SortitionModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ contract SortitionModule is ISortitionModule, Initializable, UUPSProxiable {
address account; // The address of the juror.
uint96 courtID; // The ID of the court.
uint256 stake; // The new stake.
bool alreadyTransferred; // DEPRECATED. True if tokens were already transferred before delayed stake's execution.
}

struct Juror {
Expand All @@ -46,17 +45,14 @@ contract SortitionModule is ISortitionModule, Initializable, UUPSProxiable {
uint256 public minStakingTime; // The time after which the phase can be switched to Drawing if there are open disputes.
uint256 public maxDrawingTime; // The time after which the phase can be switched back to Staking.
uint256 public lastPhaseChange; // The last time the phase was changed.
uint256 public randomNumberRequestBlock; // DEPRECATED: to be removed in the next redeploy
uint256 public disputesWithoutJurors; // The number of disputes that have not finished drawing jurors.
IRNG public rng; // The random number generator.
uint256 public randomNumber; // Random number returned by RNG.
uint256 public rngLookahead; // DEPRECATED: to be removed in the next redeploy
uint256 public delayedStakeWriteIndex; // The index of the last `delayedStake` item that was written to the array. 0 index is skipped.
uint256 public delayedStakeReadIndex; // The index of the next `delayedStake` item that should be processed. Starts at 1 because 0 index is skipped.
mapping(TreeKey key => SortitionTrees.Tree) sortitionSumTrees; // The mapping of sortition trees by keys.
mapping(address account => Juror) public jurors; // The jurors.
mapping(uint256 => DelayedStake) public delayedStakes; // Stores the stakes that were changed during Drawing phase, to update them when the phase is switched to Staking.
mapping(address jurorAccount => mapping(uint96 courtId => uint256)) public latestDelayedStakeIndex; // DEPRECATED. Maps the juror to its latest delayed stake. If there is already a delayed stake for this juror then it'll be replaced. latestDelayedStakeIndex[juror][courtID].
uint256 public maxStakePerJuror;
uint256 public maxTotalStaked;
uint256 public totalStaked;
Expand Down
22 changes: 11 additions & 11 deletions contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
bool jumped; // True if dispute jumped to a parent dispute kit and won't be handled by this DK anymore.
mapping(uint256 => uint256) coreRoundIDToLocal; // Maps id of the round in the core contract to the index of the round of related local dispute.
bytes extraData; // Extradata for the dispute.
uint256[10] __gap; // Reserved slots for future upgrades.
}

struct Round {
Expand All @@ -41,14 +42,16 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
mapping(address account => mapping(uint256 choiceId => uint256)) contributions; // Maps contributors to their contributions for each choice.
uint256 feeRewards; // Sum of reimbursable appeal fees available to the parties that made contributions to the ruling that ultimately wins a dispute.
uint256[] fundedChoices; // Stores the choices that are fully funded.
uint256 nbVotes; // Maximal number of votes this dispute can get.
mapping(address drawnAddress => bool) alreadyDrawn; // True if the address has already been drawn, false by default.
uint256[10] __gap; // Reserved slots for future upgrades.
}

struct Vote {
address account; // The address of the juror.
bytes32 commit; // The commit of the juror. For courts with hidden votes.
uint256 choice; // The choice of the juror.
bool voted; // True if the vote has been cast.
uint256[10] __gap; // Reserved slots for future upgrades.
}

// ************************************* //
Expand All @@ -64,12 +67,11 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
Dispute[] public disputes; // Array of the locally created disputes.
mapping(uint256 => uint256) public coreDisputeIDToLocal; // Maps the dispute ID in Kleros Core to the local dispute ID.
bool public singleDrawPerJuror; // Whether each juror can only draw once per dispute, false by default.
mapping(uint256 localDisputeID => mapping(uint256 localRoundID => mapping(address drawnAddress => bool)))
public alreadyDrawn; // True if the address has already been drawn, false by default. To be added to the Round struct when fully redeploying rather than upgrading.
mapping(uint256 coreDisputeID => bool) public coreDisputeIDToActive; // True if this dispute kit is active for this core dispute ID.
address public wNative; // The wrapped native token for safeSend().
uint256 public jumpDisputeKitID; // The ID of the dispute kit in Kleros Core disputeKits array that the dispute should switch to after the court jump, in case the new court doesn't support this dispute kit.

uint256[50] private __gap; // Reserved slots for future upgrades.
// ************************************* //
// * Events * //
// ************************************* //
Expand Down Expand Up @@ -201,12 +203,11 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
/// @param _coreDisputeID The ID of the dispute in Kleros Core.
/// @param _numberOfChoices Number of choices of the dispute
/// @param _extraData Additional info about the dispute, for possible use in future dispute kits.
/// @param _nbVotes Number of votes for this dispute.
function createDispute(
uint256 _coreDisputeID,
uint256 _numberOfChoices,
bytes calldata _extraData,
uint256 _nbVotes
uint256 /*_nbVotes*/
) external override onlyByCore {
uint256 localDisputeID = disputes.length;
Dispute storage dispute = disputes.push();
Expand All @@ -218,7 +219,6 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
dispute.coreRoundIDToLocal[core.getNumberOfRounds(_coreDisputeID) - 1] = dispute.rounds.length;

Round storage round = dispute.rounds.push();
round.nbVotes = _nbVotes;
round.tied = true;

coreDisputeIDToLocal[_coreDisputeID] = localDisputeID;
Expand Down Expand Up @@ -249,8 +249,9 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
}

if (_postDrawCheck(round, _coreDisputeID, drawnAddress)) {
round.votes.push(Vote({account: drawnAddress, commit: bytes32(0), choice: 0, voted: false}));
alreadyDrawn[localDisputeID][localRoundID][drawnAddress] = true;
Vote storage vote = round.votes.push();
vote.account = drawnAddress;
round.alreadyDrawn[drawnAddress] = true;
} else {
drawnAddress = address(0);
}
Expand Down Expand Up @@ -422,7 +423,6 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
dispute.coreRoundIDToLocal[coreRoundID + 1] = dispute.rounds.length;

Round storage newRound = dispute.rounds.push();
newRound.nbVotes = core.getNumberOfVotes(_coreDisputeID);
newRound.tied = true;
}
core.appeal{value: appealCost}(_coreDisputeID, dispute.numberOfChoices, dispute.extraData);
Expand Down Expand Up @@ -768,8 +768,8 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
if (singleDrawPerJuror) {
uint256 localDisputeID = coreDisputeIDToLocal[_coreDisputeID];
Dispute storage dispute = disputes[localDisputeID];
uint256 localRoundID = dispute.rounds.length - 1;
result = !alreadyDrawn[localDisputeID][localRoundID][_juror];
Round storage round = dispute.rounds[dispute.rounds.length - 1];
result = !round.alreadyDrawn[_juror];
} else {
result = true;
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/src/arbitration/interfaces/IDisputeKit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ interface IDisputeKit {
/// @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
/// @param _numberOfChoices Number of choices of the dispute
/// @param _extraData Additional info about the dispute, for possible use in future dispute kits.
/// @param _nbVotes Maximal number of votes this dispute can get. DEPRECATED as we don't need to pass it now. KC handles the count.
/// @param _nbVotes Maximal number of votes this dispute can get. Added for future-proofing.
function createDispute(
uint256 _coreDisputeID,
uint256 _numberOfChoices,
Expand Down
48 changes: 16 additions & 32 deletions contracts/test/arbitration/staking-neo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,6 @@ describe("Staking", async () => {
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(0);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
await pnk.approve(core.target, PNK(1000));
expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
await expect(core.setStake(2, PNK(3000)))
.to.emit(sortition, "StakeDelayed")
.withArgs(deployer, 2, PNK(3000));
Expand All @@ -481,10 +480,9 @@ describe("Staking", async () => {
});

it("Should store the delayed stake for later", async () => {
expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(1);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(3000), false]);
expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(3000)]);
});
});

Expand All @@ -507,9 +505,8 @@ describe("Staking", async () => {
]); // stake unchanged, delayed
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(1);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(2);
expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 1st delayed stake got deleted
expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 2nd delayed stake got deleted
expect(await sortition.latestDelayedStakeIndex(deployer, 1)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 1st delayed stake got deleted
expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 2nd delayed stake got deleted
});

it("Should transfer PNK after delayed stake execution", async () => {
Expand All @@ -535,7 +532,6 @@ describe("Staking", async () => {
it("Should delay the stake decrease", async () => {
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(0);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
await expect(core.setStake(2, PNK(1000)))
.to.emit(sortition, "StakeDelayed")
.withArgs(deployer, 2, PNK(1000));
Expand All @@ -547,10 +543,9 @@ describe("Staking", async () => {
});

it("Should store the delayed stake for later", async () => {
expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(1);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(1000), false]);
expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(1000)]);
});
});

Expand All @@ -572,9 +567,8 @@ describe("Staking", async () => {
]); // stake unchanged, delayed
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(1);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(2);
expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 1st delayed stake got deleted
expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 2nd delayed stake got deleted
expect(await sortition.latestDelayedStakeIndex(deployer, 1)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 1st delayed stake got deleted
expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 2nd delayed stake got deleted
});

it("Should withdraw some PNK", async () => {
Expand All @@ -600,7 +594,6 @@ describe("Staking", async () => {
it("Should delay the stake decrease", async () => {
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(0);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
await expect(core.setStake(2, PNK(1000)))
.to.emit(sortition, "StakeDelayed")
.withArgs(deployer, 2, PNK(1000));
Expand All @@ -612,17 +605,15 @@ describe("Staking", async () => {
});

it("Should store the delayed stake for later", async () => {
expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(1);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(1000), false]);
expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(1000)]);
});
});

describe("When stake is increased back to the previous amount", () => {
it("Should delay the stake increase", async () => {
balanceBefore = await pnk.balanceOf(deployer);
expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
await expect(core.setStake(2, PNK(2000)))
.to.emit(sortition, "StakeDelayed")
.withArgs(deployer, 2, PNK(2000));
Expand All @@ -634,11 +625,10 @@ describe("Staking", async () => {
});

it("Should store the delayed stake for later", async () => {
expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(2);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(1000), false]);
expect(await sortition.delayedStakes(2)).to.be.deep.equal([deployer, 2, PNK(2000), false]);
expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(1000)]);
expect(await sortition.delayedStakes(2)).to.be.deep.equal([deployer, 2, PNK(2000)]);
});
});

Expand All @@ -663,9 +653,8 @@ describe("Staking", async () => {
]); // stake unchanged, delayed
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(2);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(3);
expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 1st delayed stake got deleted
expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 2nd delayed stake got deleted
expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 1st delayed stake got deleted
expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 2nd delayed stake got deleted
});

it("Should not transfer any PNK", async () => {
Expand All @@ -692,7 +681,6 @@ describe("Staking", async () => {
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(0);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
await pnk.approve(core.target, PNK(1000));
expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
await expect(core.setStake(2, PNK(3000)))
.to.emit(sortition, "StakeDelayed")
.withArgs(deployer, 2, PNK(3000));
Expand All @@ -704,17 +692,15 @@ describe("Staking", async () => {
});

it("Should store the delayed stake for later", async () => {
expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(1);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(3000), false]);
expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(3000)]);
});
});

describe("When stake is decreased back to the previous amount", () => {
it("Should cancel out the stake decrease back", async () => {
balanceBefore = await pnk.balanceOf(deployer);
expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
await expect(core.setStake(2, PNK(2000)))
.to.emit(sortition, "StakeDelayed")
.withArgs(deployer, 2, PNK(2000));
Expand All @@ -726,11 +712,10 @@ describe("Staking", async () => {
});

it("Should store the delayed stake for later", async () => {
expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(2);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(1);
expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(3000), false]);
expect(await sortition.delayedStakes(2)).to.be.deep.equal([deployer, 2, PNK(2000), false]);
expect(await sortition.delayedStakes(1)).to.be.deep.equal([deployer, 2, PNK(3000)]);
expect(await sortition.delayedStakes(2)).to.be.deep.equal([deployer, 2, PNK(2000)]);
});
});

Expand All @@ -753,9 +738,8 @@ describe("Staking", async () => {
]); // stake unchanged, delayed
expect(await sortition.delayedStakeWriteIndex()).to.be.equal(2);
expect(await sortition.delayedStakeReadIndex()).to.be.equal(3);
expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 1st delayed stake got deleted
expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0, false]); // the 2nd delayed stake got deleted
expect(await sortition.latestDelayedStakeIndex(deployer, 2)).to.be.equal(0); // Deprecated. Always 0
expect(await sortition.delayedStakes(1)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 1st delayed stake got deleted
expect(await sortition.delayedStakes(2)).to.be.deep.equal([ethers.ZeroAddress, 0, 0]); // the 2nd delayed stake got deleted
});

it("Should not transfer any PNK", async () => {
Expand Down
Loading
Loading