Skip to content

Commit

Permalink
Merge pull request #537 from hats-finance/init-hats-split
Browse files Browse the repository at this point in the history
Allow setting HAT bounty split on init
  • Loading branch information
jellegerbrandy authored Jan 2, 2024
2 parents 2b23ed1 + c8b29ed commit d3ea567
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 11 deletions.
19 changes: 11 additions & 8 deletions contracts/HATClaimsManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,9 @@ contract HATClaimsManager is IHATClaimsManager, OwnableUpgradeable, ReentrancyGu
arbitratorCanChangeBeneficiary = _params.arbitratorCanChangeBeneficiary;
arbitratorCanSubmitClaims = _params.arbitratorCanSubmitClaims;
isTokenLockRevocable = _params.isTokenLockRevocable;
_setHATBountySplit(_params.bountyGovernanceHAT, _params.bountyHackerHATVested);

// Set vault to use default registry values where applicable
bountyGovernanceHAT = NULL_UINT16;
bountyHackerHATVested = NULL_UINT16;
challengePeriod = NULL_UINT32;
challengeTimeOutPeriod = NULL_UINT32;
}
Expand Down Expand Up @@ -402,12 +401,7 @@ contract HATClaimsManager is IHATClaimsManager, OwnableUpgradeable, ReentrancyGu

/** @notice See {IHATClaimsManager-setHATBountySplit}. */
function setHATBountySplit(uint16 _bountyGovernanceHAT, uint16 _bountyHackerHATVested) external onlyRegistryOwner {
bountyGovernanceHAT = _bountyGovernanceHAT;
bountyHackerHATVested = _bountyHackerHATVested;

registry.validateHATSplit(getBountyGovernanceHAT(), getBountyHackerHATVested());

emit SetHATBountySplit(_bountyGovernanceHAT, _bountyHackerHATVested);
_setHATBountySplit(_bountyGovernanceHAT, _bountyHackerHATVested);
}

/** @notice See {IHATClaimsManager-setArbitrator}. */
Expand Down Expand Up @@ -526,6 +520,15 @@ contract HATClaimsManager is IHATClaimsManager, OwnableUpgradeable, ReentrancyGu
emit SetVestingParams(_duration, _periods);
}

function _setHATBountySplit(uint16 _bountyGovernanceHAT, uint16 _bountyHackerHATVested) internal {
bountyGovernanceHAT = _bountyGovernanceHAT;
bountyHackerHATVested = _bountyHackerHATVested;

registry.validateHATSplit(getBountyGovernanceHAT(), getBountyHackerHATVested());

emit SetHATBountySplit(_bountyGovernanceHAT, _bountyHackerHATVested);
}

/**
* @dev calculate the specific bounty payout distribution, according to the
* predefined bounty split and the given bounty percentage
Expand Down
4 changes: 4 additions & 0 deletions contracts/interfaces/IHATClaimsManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ interface IHATClaimsManager {
* hacker vested, and committee.
* Each entry is a number between 0 and `HUNDRED_PERCENT`.
* Total splits should be equal to `HUNDRED_PERCENT`.
* @param bountyGovernanceHAT The HAT bounty for governance
* @param bountyHackerHATVested The HAT bounty vested for the hacker
* @param asset The vault's native token
* @param owner The address of the vault's owner
* @param committee The address of the vault's committee
Expand All @@ -123,6 +125,8 @@ interface IHATClaimsManager {
uint32 vestingPeriods;
uint16 maxBounty;
BountySplit bountySplit;
uint16 bountyGovernanceHAT;
uint16 bountyHackerHATVested;
address owner;
address committee;
address arbitrator;
Expand Down
4 changes: 3 additions & 1 deletion contracts/mocks/PoolsManagerMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ contract VaultsManagerMock {
maxBounty: _maxBounty,
bountySplit: _bountySplit,
vestingDuration: 86400,
vestingPeriods: 10
vestingPeriods: 10,
bountyGovernanceHAT: type(uint16).max,
bountyHackerHATVested: type(uint16).max
}));
_rewardController.setAllocPoint(vault, _allocPoint);
}
Expand Down
8 changes: 7 additions & 1 deletion test/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ const utils = require("./utils.js");
const { deployHATVaults } = require("../scripts/deployments/hatvaultsregistry-deploy");

const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';

const MAX_UINT16 = 65535;

let epochRewardPerBlock = [
web3.utils.toWei("441.3"),
web3.utils.toWei("441.3"),
Expand Down Expand Up @@ -156,6 +159,8 @@ const setup = async function(
isTokenLockRevocable: options.isTokenLockRevocable,
maxBounty: options.maxBounty,
bountySplit: options.bountySplit,
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 86400,
vestingPeriods: 10
}
Expand Down Expand Up @@ -264,5 +269,6 @@ module.exports = {
advanceToNonSafetyPeriod,
submitClaim,
assertFunctionRaisesException,
ZERO_ADDRESS
ZERO_ADDRESS,
MAX_UINT16
};
5 changes: 5 additions & 0 deletions test/hattimelockcontroller.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const {
advanceToNonSafetyPeriod,
submitClaim,
assertFunctionRaisesException,
MAX_UINT16
} = require("./common.js");

const setup = async function(
Expand Down Expand Up @@ -113,6 +114,8 @@ const setup = async function(
isTokenLockRevocable: false,
maxBounty: maxBounty,
bountySplit: bountySplit,
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 86400,
vestingPeriods: 10
}
Expand Down Expand Up @@ -478,6 +481,8 @@ contract("HatTimelockController", (accounts) => {
isTokenLockRevocable: false,
maxBounty: maxBounty,
bountySplit: bountySplit,
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 86400,
vestingPeriods: 10
}
Expand Down
120 changes: 119 additions & 1 deletion test/hatvaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ const {
epochRewardPerBlock,
setup,
submitClaim,
ZERO_ADDRESS
ZERO_ADDRESS,
MAX_UINT16
} = require("./common.js");
const { assert } = require("chai");
const { web3 } = require("hardhat");
Expand Down Expand Up @@ -332,6 +333,8 @@ contract("HatVaults", (accounts) => {
isTokenLockRevocable: false,
maxBounty: 8000,
bountySplit: [7000, 2500, 500],
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 86400,
vestingPeriods: 10
}
Expand Down Expand Up @@ -779,6 +782,8 @@ contract("HatVaults", (accounts) => {
isTokenLockRevocable: false,
maxBounty: maxBounty,
bountySplit: bountySplit,
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 86400,
vestingPeriods: 10
}
Expand Down Expand Up @@ -841,6 +846,8 @@ contract("HatVaults", (accounts) => {
arbitrator: accounts[2],
maxBounty: 8000,
bountySplit: [7000, 2500, 500],
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
arbitratorCanChangeBounty: true,
arbitratorCanChangeBeneficiary: false,
arbitratorCanSubmitClaims: false,
Expand Down Expand Up @@ -878,6 +885,8 @@ contract("HatVaults", (accounts) => {
arbitrator: accounts[2],
maxBounty: maxBounty,
bountySplit: bountySplit,
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 86400,
vestingPeriods: 10
}
Expand All @@ -888,6 +897,85 @@ contract("HatVaults", (accounts) => {
}
});

it("cannot create vault with wrong hat bounty split", async () => {
await setUpGlobalVars(accounts);

let maxBounty = 8000;
let bountySplit = [7000, 2500, 500];
let stakingToken2 = await ERC20Mock.new("Staking", "STK");

try {
await hatVaultsRegistry.createVault(
{
asset: stakingToken2.address,
name: "VAULT",
symbol: "VLT",
rewardControllers: [rewardController.address],
owner: await hatVaultsRegistry.owner(),
isPaused: false,
descriptionHash: "_descriptionHash1",
},
{
owner: await hatVaultsRegistry.owner(),
committee: accounts[3],
arbitrator: accounts[2],
maxBounty: maxBounty,
bountySplit: bountySplit,
bountyGovernanceHAT: 1000,
bountyHackerHATVested: 1001,
vestingDuration: 86400,
vestingPeriods: 10
}
);
assert(false, "cannot create vault with wrong hat bounty split");
} catch (ex) {
assertVMException(ex, "TotalHatsSplitPercentageShouldBeUpToMaxHATSplit");
}

let tx = await hatVaultsRegistry.createVault(
{
asset: stakingToken2.address,
name: "VAULT",
symbol: "VLT",
rewardControllers: [rewardController.address],
owner: await hatVaultsRegistry.owner(),
isPaused: false,
descriptionHash: "_descriptionHash1",
},
{
owner: await hatVaultsRegistry.owner(),
committee: accounts[3],
arbitrator: accounts[2],
maxBounty: maxBounty,
bountySplit: bountySplit,
bountyGovernanceHAT: 100,
bountyHackerHATVested: 101,
vestingDuration: 86400,
vestingPeriods: 10
}
);

let newClaimsManager = await HATClaimsManager.at(tx.logs[2].args._claimsManager);

let logs = await newClaimsManager.getPastEvents('SetHATBountySplit', {
fromBlock: tx.blockNumber,
toBlock: tx.blockNumber
});

assert.equal(logs[0].event, "SetHATBountySplit");
assert.equal(logs[0].args._bountyGovernanceHAT, "100");
assert.equal(logs[0].args._bountyHackerHATVested, "101");

assert.equal(
(await newClaimsManager.getBountyGovernanceHAT()).toString(),
"100"
);
assert.equal(
(await newClaimsManager.getBountyHackerHATVested()).toString(),
"101"
);
});

it("setCommittee", async () => {
await setUpGlobalVars(accounts);
assert.equal(await claimsManager.committee(), accounts[1]);
Expand Down Expand Up @@ -927,6 +1015,8 @@ contract("HatVaults", (accounts) => {
isTokenLockRevocable: false,
maxBounty: maxBounty,
bountySplit: bountySplit,
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 86400,
vestingPeriods: 10
}
Expand Down Expand Up @@ -1457,6 +1547,8 @@ contract("HatVaults", (accounts) => {
isTokenLockRevocable: false,
maxBounty: 8000,
bountySplit: [7000, 2500, 500],
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 86400,
vestingPeriods: 10
},
Expand Down Expand Up @@ -1570,6 +1662,8 @@ contract("HatVaults", (accounts) => {
isTokenLockRevocable: false,
maxBounty: 8000,
bountySplit: [7000, 2500, 500],
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 86400,
vestingPeriods: 10
},
Expand Down Expand Up @@ -5047,6 +5141,8 @@ it("getVaultReward - no vault updates will return 0 ", async () => {
isTokenLockRevocable: false,
maxBounty: 8000,
bountySplit: [7000, 2500, 500],
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 86400,
vestingPeriods: 10
}
Expand Down Expand Up @@ -5179,6 +5275,8 @@ it("getVaultReward - no vault updates will return 0 ", async () => {
isTokenLockRevocable: false,
maxBounty: 8000,
bountySplit: [7000, 2500, 500],
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 86400,
vestingPeriods: 10
}
Expand Down Expand Up @@ -6205,6 +6303,8 @@ it("getVaultReward - no vault updates will return 0 ", async () => {
isTokenLockRevocable: false,
maxBounty: 8000,
bountySplit: [8400, 1500, 100],
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 86400,
vestingPeriods: 10
}
Expand Down Expand Up @@ -6933,6 +7033,8 @@ it("getVaultReward - no vault updates will return 0 ", async () => {
isTokenLockRevocable: false,
maxBounty: 8000,
bountySplit: [7000, 2500, 500],
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 86400,
vestingPeriods: 10
}
Expand Down Expand Up @@ -6990,6 +7092,8 @@ it("getVaultReward - no vault updates will return 0 ", async () => {
isTokenLockRevocable: false,
maxBounty: 8000,
bountySplit: [7000, 2500, 500],
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 86400,
vestingPeriods: 10
}
Expand Down Expand Up @@ -7054,6 +7158,8 @@ it("getVaultReward - no vault updates will return 0 ", async () => {
isTokenLockRevocable: false,
maxBounty: 8000,
bountySplit: [7000, 2500, 500],
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 10,
vestingPeriods: 86400
}
Expand Down Expand Up @@ -7084,6 +7190,8 @@ it("getVaultReward - no vault updates will return 0 ", async () => {
isTokenLockRevocable: false,
maxBounty: 8000,
bountySplit: [7000, 2500, 500],
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 121 * 24 * 3600,
vestingPeriods: 10
}
Expand Down Expand Up @@ -7114,6 +7222,8 @@ it("getVaultReward - no vault updates will return 0 ", async () => {
isTokenLockRevocable: false,
maxBounty: 8000,
bountySplit: [7000, 2500, 500],
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 86400,
vestingPeriods: 0
}
Expand Down Expand Up @@ -7142,6 +7252,8 @@ it("getVaultReward - no vault updates will return 0 ", async () => {
isTokenLockRevocable: false,
maxBounty: 8000,
bountySplit: [7000, 2500, 500],
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 86400,
vestingPeriods: 10
}
Expand Down Expand Up @@ -7227,6 +7339,8 @@ it("getVaultReward - no vault updates will return 0 ", async () => {
isTokenLockRevocable: false,
maxBounty: 8000,
bountySplit: [8400, 1500, 100],
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 86400,
vestingPeriods: 10
}
Expand Down Expand Up @@ -7400,6 +7514,8 @@ it("getVaultReward - no vault updates will return 0 ", async () => {
isTokenLockRevocable: false,
maxBounty: 8000,
bountySplit: [7000, 2500, 500],
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 86400,
vestingPeriods: 10
}
Expand Down Expand Up @@ -7508,6 +7624,8 @@ it("getVaultReward - no vault updates will return 0 ", async () => {
isTokenLockRevocable: false,
maxBounty: 8000,
bountySplit: [7000, 2500, 500],
bountyGovernanceHAT: MAX_UINT16,
bountyHackerHATVested: MAX_UINT16,
vestingDuration: 86400,
vestingPeriods: 10
}
Expand Down

0 comments on commit d3ea567

Please sign in to comment.