Skip to content

Commit

Permalink
fix: add max fisherman rewards cut (OZ L-02)
Browse files Browse the repository at this point in the history
  • Loading branch information
Maikol committed Aug 24, 2024
1 parent b56567e commit dc3add0
Show file tree
Hide file tree
Showing 9 changed files with 221 additions and 12 deletions.
8 changes: 6 additions & 2 deletions packages/subgraph-service/contracts/DisputeManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ contract DisputeManager is
using TokenUtils for IGraphToken;
using PPMMath for uint256;

// -- Constants --

// Maximum value for fisherman reward cut in PPM
uint32 public constant MAX_FISHERMAN_REWARD_CUT = 500000;

// -- Modifiers --

/**
Expand Down Expand Up @@ -659,8 +664,7 @@ contract DisputeManager is
* @param _fishermanRewardCut Reward as a percentage of indexer stake
*/
function _setFishermanRewardCut(uint32 _fishermanRewardCut) private {
// Must be within 0% to 100% (inclusive)
require(PPMMath.isValidPPM(_fishermanRewardCut), DisputeManagerInvalidFishermanReward(_fishermanRewardCut));
require(_fishermanRewardCut <= MAX_FISHERMAN_REWARD_CUT, DisputeManagerInvalidFishermanReward(_fishermanRewardCut));
fishermanRewardCut = _fishermanRewardCut;
emit FishermanRewardCutSet(fishermanRewardCut);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/subgraph-service/test/SubgraphBaseTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ abstract contract SubgraphBaseTest is Utils, Constants {
)
);
disputeManager = DisputeManager(disputeManagerProxy);
disputeManager.transferOwnership(users.governor);

tapCollector = new TAPCollector("TAPCollector", "1", address(controller));
address subgraphServiceImplementation = address(
Expand All @@ -154,8 +155,6 @@ abstract contract SubgraphBaseTest is Utils, Constants {
);
subgraphService = SubgraphService(subgraphServiceProxy);

disputeManager.setSubgraphService(address(subgraphService));

stakingExtension = new HorizonStakingExtension(
address(controller),
address(subgraphService)
Expand All @@ -177,6 +176,7 @@ abstract contract SubgraphBaseTest is Utils, Constants {
);

resetPrank(users.governor);
disputeManager.setSubgraphService(address(subgraphService));
proxyAdmin.upgrade(stakingProxy, address(stakingBase));
proxyAdmin.acceptProxy(stakingBase, stakingProxy);
staking = IHorizonStaking(address(stakingProxy));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ contract DisputeManagerTest is SubgraphServiceSharedTest {
* MODIFIERS
*/

modifier useGovernor() {
vm.startPrank(users.governor);
_;
vm.stopPrank();
}

modifier useFisherman {
vm.startPrank(users.fisherman);
_;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import "forge-std/Test.sol";

import { PPMMath } from "@graphprotocol/horizon/contracts/libraries/PPMMath.sol";
import { GraphDirectory } from "@graphprotocol/horizon/contracts/utilities/GraphDirectory.sol";
import { UnsafeUpgrades } from "openzeppelin-foundry-upgrades/Upgrades.sol";
import { DisputeManager } from "../../../contracts/DisputeManager.sol";
import { DisputeManagerTest } from "../DisputeManager.t.sol";
import { IDisputeManager } from "../../../contracts/interfaces/IDisputeManager.sol";

contract DisputeManagerConstructorTest is DisputeManagerTest {
using PPMMath for uint256;

/*
* MODIFIERS
*/

modifier useDeployer() {
vm.startPrank(users.deployer);
_;
vm.stopPrank();
}

/*
* HELPERS
*/

function _initializeDisputeManager(
address implementation,
address arbitrator,
uint64 disputePeriod,
uint256 disputeDeposit,
uint32 fishermanRewardPercentage,
uint32 maxSlashingPercentage
) private returns (address) {
return UnsafeUpgrades.deployTransparentProxy(
implementation,
users.governor,
abi.encodeCall(
DisputeManager.initialize,
(arbitrator, disputePeriod, disputeDeposit, fishermanRewardPercentage, maxSlashingPercentage)
)
);
}

/*
* TESTS
*/

function test_Constructor(
uint32 fishermanRewardPercentage
) public useDeployer {
vm.assume(fishermanRewardPercentage <= disputeManager.MAX_FISHERMAN_REWARD_CUT());
address disputeManagerImplementation = address(new DisputeManager(address(controller)));
address proxy = _initializeDisputeManager(
disputeManagerImplementation,
users.arbitrator,
disputePeriod,
disputeDeposit,
fishermanRewardPercentage,
maxSlashingPercentage
);

DisputeManager disputeManager = DisputeManager(proxy);
assertEq(disputeManager.arbitrator(), users.arbitrator);
assertEq(disputeManager.disputePeriod(), disputePeriod);
assertEq(disputeManager.disputeDeposit(), disputeDeposit);
assertEq(disputeManager.fishermanRewardCut(), fishermanRewardPercentage);
}

function test_Constructor_RevertIf_ControllerAddressIsZero() public useDeployer {
bytes memory expectedError = abi.encodeWithSelector(
GraphDirectory.GraphDirectoryInvalidZeroAddress.selector,
"Controller"
);
vm.expectRevert(expectedError);
new DisputeManager(address(0));
}

function test_Constructor_RevertIf_ArbitratorAddressIsZero() public useDeployer {
address disputeManagerImplementation = address(new DisputeManager(address(controller)));
bytes memory expectedError = abi.encodeWithSelector(
IDisputeManager.DisputeManagerInvalidZeroAddress.selector
);
vm.expectRevert(expectedError);
_initializeDisputeManager(
disputeManagerImplementation,
address(0),
disputePeriod,
disputeDeposit,
fishermanRewardPercentage,
maxSlashingPercentage
);
}

function test_Constructor_RevertIf_InvalidDisputePeriod() public useDeployer {
address disputeManagerImplementation = address(new DisputeManager(address(controller)));
bytes memory expectedError = abi.encodeWithSelector(
IDisputeManager.DisputeManagerDisputePeriodZero.selector
);
vm.expectRevert(expectedError);
_initializeDisputeManager(
disputeManagerImplementation,
users.arbitrator,
0,
disputeDeposit,
fishermanRewardPercentage,
maxSlashingPercentage
);
}

function test_Constructor_RevertIf_InvalidDisputeDeposit() public useDeployer {
address disputeManagerImplementation = address(new DisputeManager(address(controller)));
bytes memory expectedError = abi.encodeWithSelector(
IDisputeManager.DisputeManagerInvalidDisputeDeposit.selector,
0
);
vm.expectRevert(expectedError);
_initializeDisputeManager(
disputeManagerImplementation,
users.arbitrator,
disputePeriod,
0,
fishermanRewardPercentage,
maxSlashingPercentage
);
}

function test_Constructor_RevertIf_InvalidFishermanRewardPercentage(uint32 _fishermanRewardPercentage) public useDeployer {
vm.assume(_fishermanRewardPercentage > disputeManager.MAX_FISHERMAN_REWARD_CUT());
address disputeManagerImplementation = address(new DisputeManager(address(controller)));
bytes memory expectedError = abi.encodeWithSelector(
IDisputeManager.DisputeManagerInvalidFishermanReward.selector,
_fishermanRewardPercentage
);
vm.expectRevert(expectedError);
_initializeDisputeManager(
disputeManagerImplementation,
users.arbitrator,
disputePeriod,
disputeDeposit,
_fishermanRewardPercentage,
maxSlashingPercentage
);
}

function test_Constructor_RevertIf_InvalidMaxSlashingPercentage(uint32 _maxSlashingPercentage) public useDeployer {
vm.assume(_maxSlashingPercentage > PPMMath.MAX_PPM);
address disputeManagerImplementation = address(new DisputeManager(address(controller)));
bytes memory expectedError = abi.encodeWithSelector(
IDisputeManager.DisputeManagerInvalidMaxSlashingCut.selector,
_maxSlashingPercentage
);
vm.expectRevert(expectedError);
_initializeDisputeManager(
disputeManagerImplementation,
users.arbitrator,
disputePeriod,
disputeDeposit,
fishermanRewardPercentage,
_maxSlashingPercentage
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ pragma solidity 0.8.26;
import "forge-std/Test.sol";

import { PPMMath } from "@graphprotocol/horizon/contracts/libraries/PPMMath.sol";
import { IDisputeManager } from "../../contracts/interfaces/IDisputeManager.sol";
import { DisputeManagerTest } from "./DisputeManager.t.sol";
import { IDisputeManager } from "../../../contracts/interfaces/IDisputeManager.sol";
import { DisputeManagerTest } from "../DisputeManager.t.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";

contract DisputeManagerAcceptDisputeTest is DisputeManagerTest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ pragma solidity 0.8.26;

import "forge-std/Test.sol";

import { IDisputeManager } from "../../contracts/interfaces/IDisputeManager.sol";
import { DisputeManagerTest } from "./DisputeManager.t.sol";
import { IDisputeManager } from "../../../contracts/interfaces/IDisputeManager.sol";
import { DisputeManagerTest } from "../DisputeManager.t.sol";

contract DisputeManagerCancelDisputeTest is DisputeManagerTest {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ pragma solidity 0.8.26;

import "forge-std/Test.sol";

import { IDisputeManager } from "../../contracts/interfaces/IDisputeManager.sol";
import { DisputeManagerTest } from "./DisputeManager.t.sol";
import { IDisputeManager } from "../../../contracts/interfaces/IDisputeManager.sol";
import { DisputeManagerTest } from "../DisputeManager.t.sol";

contract DisputeManagerCreateDisputeTest is DisputeManagerTest {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ pragma solidity 0.8.26;
import "forge-std/Test.sol";

import { PPMMath } from "@graphprotocol/horizon/contracts/libraries/PPMMath.sol";
import { IDisputeManager } from "../../contracts/interfaces/IDisputeManager.sol";
import { DisputeManagerTest } from "./DisputeManager.t.sol";
import { IDisputeManager } from "../../../contracts/interfaces/IDisputeManager.sol";
import { DisputeManagerTest } from "../DisputeManager.t.sol";

contract DisputeManagerDrawDisputeTest is DisputeManagerTest {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import "forge-std/Test.sol";

import { IDisputeManager } from "../../../contracts/interfaces/IDisputeManager.sol";
import { DisputeManagerTest } from "../DisputeManager.t.sol";
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

contract DisputeManagerGovernanceFishermanRewardCutTest is DisputeManagerTest {

/*
* TESTS
*/

function test_Governance_SetFishermanRewardCut() public useGovernor {
uint32 fishermanRewardCut = 1000;
disputeManager.setFishermanRewardCut(fishermanRewardCut);
assertEq(disputeManager.fishermanRewardCut(), fishermanRewardCut, "Fisherman reward cut should be set.");
}

function test_Governance_RevertWhen_OverMaximumValue(uint32 fishermanRewardCut) public useGovernor {
vm.assume(fishermanRewardCut > disputeManager.MAX_FISHERMAN_REWARD_CUT());
vm.expectRevert(abi.encodeWithSelector(IDisputeManager.DisputeManagerInvalidFishermanReward.selector, fishermanRewardCut));
disputeManager.setFishermanRewardCut(fishermanRewardCut);
}

function test_Governance_RevertWhen_NotGovernor() public useFisherman {
uint32 fishermanRewardCut = 1000;
vm.expectRevert(abi.encodeWithSelector(OwnableUpgradeable.OwnableUnauthorizedAccount.selector, users.fisherman));
disputeManager.setFishermanRewardCut(fishermanRewardCut);
}
}

0 comments on commit dc3add0

Please sign in to comment.