Skip to content
2 changes: 2 additions & 0 deletions contracts/deploy/00-home-chain-arbitration-neo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ const deployArbitration: DeployFunction = async (hre: HardhatRuntimeEnvironment)
args: [core.target, disputeTemplateRegistry.target],
log: true,
});
console.log(`core.changeArbitrableWhitelistEnabled(true)`);
await core.changeArbitrableWhitelistEnabled(true);
console.log(`core.changeArbitrableWhitelist(${resolver.address}, true)`);
await core.changeArbitrableWhitelist(resolver.address, true);

Expand Down
10 changes: 8 additions & 2 deletions contracts/src/arbitration/KlerosCoreNeo.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ contract KlerosCoreNeo is KlerosCoreBase {
// ************************************* //

mapping(address => bool) public arbitrableWhitelist; // Arbitrable whitelist.
bool public arbitrableWhitelistEnabled; // Whether the arbitrable whitelist is enabled.
IERC721 public jurorNft; // Eligible jurors NFT.

// ************************************* //
Expand Down Expand Up @@ -93,6 +94,11 @@ contract KlerosCoreNeo is KlerosCoreBase {
arbitrableWhitelist[_arbitrable] = _allowed;
}

/// @dev Enables or disables the arbitrable whitelist.
function changeArbitrableWhitelistEnabled(bool _enabled) external onlyByOwner {
arbitrableWhitelistEnabled = _enabled;
}

// ************************************* //
// * State Modifiers * //
// ************************************* //
Expand All @@ -103,7 +109,7 @@ contract KlerosCoreNeo is KlerosCoreBase {
/// @param _newStake The new stake.
/// Note that the existing delayed stake will be nullified as non-relevant.
function setStake(uint96 _courtID, uint256 _newStake) external override whenNotPaused {
if (jurorNft.balanceOf(msg.sender) == 0) revert NotEligibleForStaking();
if (address(jurorNft) != address(0) && jurorNft.balanceOf(msg.sender) == 0) revert NotEligibleForStaking();
super._setStake(msg.sender, _courtID, _newStake, false, OnError.Revert);
}

Expand All @@ -117,7 +123,7 @@ contract KlerosCoreNeo is KlerosCoreBase {
IERC20 _feeToken,
uint256 _feeAmount
) internal override returns (uint256 disputeID) {
if (!arbitrableWhitelist[msg.sender]) revert ArbitrableNotWhitelisted();
if (arbitrableWhitelistEnabled && !arbitrableWhitelist[msg.sender]) revert ArbitrableNotWhitelisted();
return super._createDispute(_numberOfChoices, _extraData, _feeToken, _feeAmount);
}

Expand Down
98 changes: 68 additions & 30 deletions contracts/test/arbitration/staking-neo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,60 +128,98 @@ describe("Staking", async () => {
SHOULD BEHAVE LIKE A NEO ARBITRATOR
************************************************************************************************/

describe("When arbitrable is not whitelisted", () => {
describe("When arbitrable whitelist is disabled", () => {
before("Setup", async () => {
await deployUnhappy();
await core.changeArbitrableWhitelist(resolver.target, false);
await core.changeArbitrableWhitelistEnabled(false);
});

it("Should fail to create a dispute", async () => {
it("Should create a dispute", async () => {
const arbitrationCost = ETH(0.5);
await expect(
resolver.createDisputeForTemplate(extraData, "", "", 2, { value: arbitrationCost })
).to.be.revertedWithCustomError(core, "ArbitrableNotWhitelisted");
expect(await resolver.createDisputeForTemplate(extraData, "", "", 2, { value: arbitrationCost }))
.to.emit(core, "DisputeCreation")
.withArgs(0, resolver.target);
});
});

describe("When arbitrable is whitelisted", () => {
describe("When arbitrable whitelist is enabled", () => {
before("Setup", async () => {
await deployUnhappy();
await core.changeArbitrableWhitelist(resolver.target, true);
await core.changeArbitrableWhitelistEnabled(true);
});

it("Should create a dispute", async () => {
const arbitrationCost = ETH(0.5);
expect(await resolver.createDisputeForTemplate(extraData, "", "", 2, { value: arbitrationCost }))
.to.emit(core, "DisputeCreation")
.withArgs(0, resolver.target);
describe("When arbitrable is not whitelisted", () => {
before("Setup", async () => {
await core.changeArbitrableWhitelist(resolver.target, false);
});

it("Should fail to create a dispute", async () => {
const arbitrationCost = ETH(0.5);
await expect(
resolver.createDisputeForTemplate(extraData, "", "", 2, { value: arbitrationCost })
).to.be.revertedWithCustomError(core, "ArbitrableNotWhitelisted");
});
});

describe("When arbitrable is whitelisted", () => {
before("Setup", async () => {
await core.changeArbitrableWhitelist(resolver.target, true);
});

it("Should create a dispute", async () => {
const arbitrationCost = ETH(0.5);
expect(await resolver.createDisputeForTemplate(extraData, "", "", 2, { value: arbitrationCost }))
.to.emit(core, "DisputeCreation")
.withArgs(0, resolver.target);
});
});
});

describe("When juror has no NFT", async () => {
describe("When juror NFT is not set", async () => {
before("Setup", async () => {
await deployUnhappy();
await core.changeJurorNft(ethers.ZeroAddress);
});

it("Should not be able to stake", async () => {
await pnk.connect(juror).approve(core.target, PNK(1000));
await expect(core.connect(juror).setStake(1, PNK(1000))).to.be.revertedWithCustomError(
core,
"NotEligibleForStaking"
);
describe("When juror has no NFT", async () => {
it("Should be able to stake", async () => {
await pnk.connect(juror).approve(core.target, PNK(1000));
await expect(await core.connect(juror).setStake(1, PNK(1000)))
.to.emit(sortition, "StakeSet")
.withArgs(juror.address, 1, PNK(1000), PNK(1000));
expect(await sortition.totalStaked()).to.be.equal(PNK(1000));
});
});
});

describe("When juror does have a NFT", async () => {
before("Setup", async () => {
await deployUnhappy();
await nft.safeMint(juror.address);
describe("When juror NFT is set", async () => {
describe("When juror has no NFT", async () => {
before("Setup", async () => {
await deployUnhappy();
});

it("Should not be able to stake", async () => {
await pnk.connect(juror).approve(core.target, PNK(1000));
await expect(core.connect(juror).setStake(1, PNK(1000))).to.be.revertedWithCustomError(
core,
"NotEligibleForStaking"
);
});
});

it("Should be able to stake", async () => {
await pnk.connect(juror).approve(core.target, PNK(1000));
await expect(await core.connect(juror).setStake(1, PNK(1000)))
.to.emit(sortition, "StakeSet")
.withArgs(juror.address, 1, PNK(1000), PNK(1000));
expect(await sortition.totalStaked()).to.be.equal(PNK(1000));
describe("When juror does have a NFT", async () => {
before("Setup", async () => {
await deployUnhappy();
await nft.safeMint(juror.address);
});

it("Should be able to stake", async () => {
await pnk.connect(juror).approve(core.target, PNK(1000));
await expect(await core.connect(juror).setStake(1, PNK(1000)))
.to.emit(sortition, "StakeSet")
.withArgs(juror.address, 1, PNK(1000), PNK(1000));
expect(await sortition.totalStaked()).to.be.equal(PNK(1000));
});
});
});

Expand Down
Loading