Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove HAT bounty and use vault token for fee [wait with merging] #544

Draft
wants to merge 3 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
54 changes: 14 additions & 40 deletions config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ module.exports = {
"rewardControllersConf": [],
"hatToken": "0x07865c6E87B9F70255377e024ace6630C1Eaa37F", // USDC
"hatVaultsRegistryConf": {
"swapToken": "0x07865c6E87B9F70255377e024ace6630C1Eaa37F", // USDC
"bountyGovernanceHAT": "1000",
"bountyHackerHATVested": "0"
"governanceFee": "1000"
},
"hatVaultsNFTConf": {
"merkleTreeIPFSRef": "",
Expand All @@ -39,9 +37,7 @@ module.exports = {
"rewardControllersConf": [],
"hatToken": "0x07865c6E87B9F70255377e024ace6630C1Eaa37F", // USDC
"hatVaultsRegistryConf": {
"swapToken": "0x07865c6E87B9F70255377e024ace6630C1Eaa37F", // USDC
"bountyGovernanceHAT": "1000",
"bountyHackerHATVested": "0"
"governanceFee": "1000"
},
"hatVaultsNFTConf": {
"merkleTreeIPFSRef": "",
Expand Down Expand Up @@ -86,8 +82,7 @@ module.exports = {
]
}],
"hatVaultsRegistryConf": {
"bountyGovernanceHAT": "1000",
"bountyHackerHATVested": "500"
"governanceFee": "1000"
},
"hatVaultsNFTConf": {
"merkleTreeIPFSRef": "",
Expand Down Expand Up @@ -129,9 +124,7 @@ module.exports = {
"rewardToken": "HATToken"
}],
"hatVaultsRegistryConf": {
"bountyGovernanceHAT": "1000",
"bountyHackerHATVested": "500",
"swapToken": "HATToken"
"governanceFee": "1000"
},
"hatVaultsNFTConf": {
"merkleTreeIPFSRef": "",
Expand All @@ -146,8 +139,7 @@ module.exports = {
"rewardControllersConf": [], // no reward controllers
"hatToken": "", // deploy a fresh HATToken contract
"hatVaultsRegistryConf": {
"bountyGovernanceHAT": "0",
"bountyHackerHATVested": "0"
"governanceFee": "1000"
}
},
"polygon": {
Expand All @@ -165,9 +157,7 @@ module.exports = {
"rewardControllersConf": [],
"hatToken": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", // USDC
"hatVaultsRegistryConf": {
"swapToken": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", // USDC
"bountyGovernanceHAT": "1000",
"bountyHackerHATVested": "0"
"governanceFee": "1000"
},
"hatVaultsNFTConf": {
"merkleTreeIPFSRef": "",
Expand All @@ -190,9 +180,7 @@ module.exports = {
"rewardControllersConf": [],
"hatToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
"hatVaultsRegistryConf": {
"swapToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
"bountyGovernanceHAT": "1000",
"bountyHackerHATVested": "0"
"governanceFee": "1000"
},
"hatVaultsNFTConf": {
"merkleTreeIPFSRef": "",
Expand All @@ -215,9 +203,7 @@ module.exports = {
"rewardControllersConf": [],
"hatToken": "0x7F5c764cBc14f9669B88837ca1490cCa17c31607", // USDC
"hatVaultsRegistryConf": {
"swapToken": "0x7F5c764cBc14f9669B88837ca1490cCa17c31607", // USDC
"bountyGovernanceHAT": "1000",
"bountyHackerHATVested": "0"
"governanceFee": "1000"
},
"hatVaultsNFTConf": {
"merkleTreeIPFSRef": "",
Expand All @@ -240,9 +226,7 @@ module.exports = {
"rewardControllersConf": [],
"hatToken": "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8", // USDC
"hatVaultsRegistryConf": {
"swapToken": "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8", // USDC
"bountyGovernanceHAT": "1000",
"bountyHackerHATVested": "0"
"governanceFee": "1000"
},
"hatVaultsNFTConf": {
"merkleTreeIPFSRef": "",
Expand All @@ -265,9 +249,7 @@ module.exports = {
"rewardControllersConf": [],
"hatToken": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", // USDC
"hatVaultsRegistryConf": {
"swapToken": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", // USDC
"bountyGovernanceHAT": "1000",
"bountyHackerHATVested": "0"
"governanceFee": "1000"
},
"hatVaultsNFTConf": {
"merkleTreeIPFSRef": "",
Expand All @@ -290,9 +272,7 @@ module.exports = {
"rewardControllersConf": [],
"hatToken": "0x4200000000000000000000000000000000000006", // WETH
"hatVaultsRegistryConf": {
"swapToken": "0x4200000000000000000000000000000000000006", // WETH
"bountyGovernanceHAT": "1000",
"bountyHackerHATVested": "0"
"governanceFee": "1000"
},
"hatVaultsNFTConf": {
"merkleTreeIPFSRef": "",
Expand All @@ -315,9 +295,7 @@ module.exports = {
"rewardControllersConf": [],
"hatToken": "NEED ADDRESS", // USDC
"hatVaultsRegistryConf": {
"swapToken": "NEED ADDRESS", // USDC
"bountyGovernanceHAT": "1000",
"bountyHackerHATVested": "0"
"governanceFee": "1000"
},
"hatVaultsNFTConf": {
"merkleTreeIPFSRef": "",
Expand All @@ -340,9 +318,7 @@ module.exports = {
"rewardControllersConf": [],
"hatToken": "0xd86e243fc0007e6226b07c9a50c9d70d78299eb5", // USDC
"hatVaultsRegistryConf": {
"swapToken": "0xd86e243fc0007e6226b07c9a50c9d70d78299eb5", // USDC
"bountyGovernanceHAT": "1000",
"bountyHackerHATVested": "0"
"governanceFee": "1000"
},
"hatVaultsNFTConf": {
"merkleTreeIPFSRef": "",
Expand All @@ -365,9 +341,7 @@ module.exports = {
"rewardControllersConf": [],
"hatToken": "0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83", // USDC
"hatVaultsRegistryConf": {
"swapToken": "0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83", // USDC
"bountyGovernanceHAT": "1000",
"bountyHackerHATVested": "0"
"governanceFee": "1000"
},
"hatVaultsNFTConf": {
"merkleTreeIPFSRef": "",
Expand Down
97 changes: 31 additions & 66 deletions contracts/HATClaimsManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,8 @@ contract HATClaimsManager is IHATClaimsManager, OwnableUpgradeable, ReentrancyGu

PendingMaxBounty public pendingMaxBounty;

// the percentage of the total bounty to be swapped to HATs and sent to governance (out of {HUNDRED_PERCENT})
uint16 internal bountyGovernanceHAT;
// the percentage of the total bounty to be swapped to HATs and sent to the hacker via vesting contract (out of {HUNDRED_PERCENT})
uint16 internal bountyHackerHATVested;
// the fee percentage of the total bounty to be paid to the governance
uint16 internal governanceFee;

// address of the arbitrator - which can dispute claims and override the committee's decisions
address internal arbitrator;
Expand Down Expand Up @@ -122,11 +120,14 @@ contract HATClaimsManager is IHATClaimsManager, OwnableUpgradeable, ReentrancyGu
function initialize(IHATVault _vault, IHATClaimsManager.ClaimsManagerInitParams calldata _params) external initializer {
if (_params.maxBounty > MAX_BOUNTY_LIMIT && _params.maxBounty != HUNDRED_PERCENT)
revert MaxBountyCannotBeMoreThanMaxBountyLimit();
HATVaultsRegistry _registry = HATVaultsRegistry(msg.sender);
if (_params.governanceFee > _registry.MAX_GOVERNANCE_FEE() && _params.governanceFee != NULL_UINT16)
revert FeeCannotBeMoreThanMaxFee();
_validateSplit(_params.bountySplit);
_setVestingParams(_params.vestingDuration, _params.vestingPeriods);
HATVaultsRegistry _registry = HATVaultsRegistry(msg.sender);
maxBounty = _params.maxBounty;
bountySplit = _params.bountySplit;
governanceFee = _params.governanceFee;
committee = _params.committee;
registry = _registry;
vault = _vault;
Expand All @@ -138,7 +139,6 @@ 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
challengePeriod = NULL_UINT32;
Expand Down Expand Up @@ -175,8 +175,7 @@ contract HATClaimsManager is IHATClaimsManager, OwnableUpgradeable, ReentrancyGu
// solhint-disable-next-line not-rely-on-time
createdAt: uint32(block.timestamp),
challengedAt: 0,
bountyGovernanceHAT: getBountyGovernanceHAT(),
bountyHackerHATVested: getBountyHackerHATVested(),
governanceFee: getGovernanceFee(),
arbitrator: arbitratorAddress,
challengePeriod: getChallengePeriod(),
challengeTimeOutPeriod: getChallengeTimeOutPeriod(),
Expand Down Expand Up @@ -254,17 +253,12 @@ contract HATClaimsManager is IHATClaimsManager, OwnableUpgradeable, ReentrancyGu

address tokenLock;

IHATClaimsManager.ClaimBounty memory claimBounty = _calcClaimBounty(
_claim.bountyPercentage,
_claim.bountyGovernanceHAT,
_claim.bountyHackerHATVested
);
IHATClaimsManager.ClaimBounty memory claimBounty = _calcClaimBounty(_claim.bountyPercentage, _claim.governanceFee);

vault.makePayout(
claimBounty.committee +
claimBounty.governanceHat +
claimBounty.governanceFee +
claimBounty.hacker +
claimBounty.hackerHatVested +
claimBounty.hackerVested
);

Expand Down Expand Up @@ -292,19 +286,7 @@ contract HATClaimsManager is IHATClaimsManager, OwnableUpgradeable, ReentrancyGu
_asset.safeTransfer(_claim.beneficiary, claimBounty.hacker);
_asset.safeTransfer(_claim.committee, claimBounty.committee);

// send to the registry the amount of tokens which should be swapped
// to HAT so it could call swapAndSend in a separate tx.
IHATVaultsRegistry _registry = registry;
_asset.safeApprove(address(_registry), claimBounty.hackerHatVested + claimBounty.governanceHat);
_registry.addTokensToSwap(
_asset,
_claim.beneficiary,
claimBounty.hackerHatVested,
claimBounty.governanceHat
);

// make sure to reset approval
_asset.safeApprove(address(_registry), 0);
_asset.safeTransfer(registry.governanceFeeReceiver(), claimBounty.governanceFee);

emit ApproveClaim(
_claimId,
Expand Down Expand Up @@ -399,9 +381,15 @@ contract HATClaimsManager is IHATClaimsManager, OwnableUpgradeable, ReentrancyGu
emit SetMaxBounty(_maxBounty);
}

/** @notice See {IHATClaimsManager-setHATBountySplit}. */
function setHATBountySplit(uint16 _bountyGovernanceHAT, uint16 _bountyHackerHATVested) external onlyRegistryOwner {
_setHATBountySplit(_bountyGovernanceHAT, _bountyHackerHATVested);
/** @notice See {IHATClaimsManager-setGoveranceFee}. */
function setGovernanceFee(uint16 _governanceFee) external onlyRegistryOwner {
if (_governanceFee > registry.MAX_GOVERNANCE_FEE() && _governanceFee != NULL_UINT16) {
revert FeeCannotBeMoreThanMaxFee();
}

governanceFee = _governanceFee;

emit SetGovernanceFee(_governanceFee);
}

/** @notice See {IHATClaimsManager-setArbitrator}. */
Expand Down Expand Up @@ -452,23 +440,13 @@ contract HATClaimsManager is IHATClaimsManager, OwnableUpgradeable, ReentrancyGu

/* --------------------------------- Getters -------------------------------------- */

/** @notice See {IHATClaimsManager-getBountyGovernanceHAT}. */
function getBountyGovernanceHAT() public view returns(uint16) {
uint16 _bountyGovernanceHAT = bountyGovernanceHAT;
if (_bountyGovernanceHAT != NULL_UINT16) {
return _bountyGovernanceHAT;
} else {
return registry.defaultBountyGovernanceHAT();
}
}

/** @notice See {IHATClaimsManager-getBountyHackerHATVested}. */
function getBountyHackerHATVested() public view returns(uint16) {
uint16 _bountyHackerHATVested = bountyHackerHATVested;
if (_bountyHackerHATVested != NULL_UINT16) {
return _bountyHackerHATVested;
/** @notice See {IHATClaimsManager-getGovernanceFee}. */
function getGovernanceFee() public view returns(uint16) {
uint16 _getGovernanceFee = governanceFee;
if (_getGovernanceFee != NULL_UINT16) {
return _getGovernanceFee;
} else {
return registry.defaultBountyHackerHATVested();
return registry.defaultGovernanceFee();
}
}

Expand Down Expand Up @@ -520,28 +498,17 @@ 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
* @param _bountyPercentage The percentage of the vault's funds to be paid
* out as bounty
* @param _bountyGovernanceHAT The bountyGovernanceHAT at the time the claim was submitted
* @param _bountyHackerHATVested The bountyHackerHATVested at the time the claim was submitted
* @param _governanceFee The governanceFee at the time the claim was submitted
* @return claimBounty The bounty distribution for this specific claim
*/
function _calcClaimBounty(
uint256 _bountyPercentage,
uint256 _bountyGovernanceHAT,
uint256 _bountyHackerHATVested
uint16 _bountyPercentage,
uint16 _governanceFee
) internal view returns(IHATClaimsManager.ClaimBounty memory claimBounty) {
uint256 _totalAssets = vault.totalAssets();
if (_totalAssets == 0) {
Expand All @@ -554,13 +521,11 @@ contract HATClaimsManager is IHATClaimsManager, OwnableUpgradeable, ReentrancyGu

uint256 _totalBountyAmount = _totalAssets * _bountyPercentage;

uint256 _governanceHatAmount = _totalBountyAmount.mulDiv(_bountyGovernanceHAT, HUNDRED_PERCENT_SQRD);
uint256 _hackerHatVestedAmount = _totalBountyAmount.mulDiv(_bountyHackerHATVested, HUNDRED_PERCENT_SQRD);
uint256 _governanceFeeAmount = _totalBountyAmount.mulDiv(_governanceFee, HUNDRED_PERCENT_SQRD);

_totalBountyAmount -= (_governanceHatAmount + _hackerHatVestedAmount) * HUNDRED_PERCENT;
_totalBountyAmount -= _governanceFeeAmount * HUNDRED_PERCENT;

claimBounty.governanceHat = _governanceHatAmount;
claimBounty.hackerHatVested = _hackerHatVestedAmount;
claimBounty.governanceFee = _governanceFeeAmount;

uint256 _hackerVestedAmount = _totalBountyAmount.mulDiv(bountySplit.hackerVested, HUNDRED_PERCENT_SQRD);
uint256 _hackerAmount = _totalBountyAmount.mulDiv(bountySplit.hacker, HUNDRED_PERCENT_SQRD);
Expand Down
19 changes: 0 additions & 19 deletions contracts/HATTimelockController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,25 +46,6 @@ contract HATTimelockController is TimelockController {
_rewardController.setAllocPoint(address(_vault), _allocPoint);
}

function swapAndSend(
IHATVaultsRegistry _registry,
address _asset,
address[] calldata _beneficiaries,
uint256 _amountOutMinimum,
address _routingContract,
bytes calldata _routingPayload
)
external
onlyRole(PROPOSER_ROLE) {
_registry.swapAndSend(
_asset,
_beneficiaries,
_amountOutMinimum,
_routingContract,
_routingPayload
);
}

function setEmergencyPaused(IHATVaultsRegistry _registry, bool _isEmergencyPaused) external onlyRole(PROPOSER_ROLE) {
_registry.setEmergencyPaused(_isEmergencyPaused);
}
Expand Down
Loading
Loading