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

build: refund accountant #27

Merged
merged 11 commits into from
Nov 17, 2023
Merged
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
171 changes: 126 additions & 45 deletions contracts/accountants/HealthCheckAccountant.sol

Large diffs are not rendered by default.

122 changes: 122 additions & 0 deletions contracts/accountants/RefundAccountant.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// SPDX-License-Identifier: GNU AGPLv3
pragma solidity 0.8.18;

import {HealthCheckAccountant, ERC20, SafeERC20, IVault} from "./HealthCheckAccountant.sol";

/// @title Refund Accountant
/// @dev Allows for configurable refunds to be given to specific strategies for a vault.
/// This can be used to auto compound reward into vault or provide retroactive refunds
/// from a previous loss.
contract RefundAccountant is HealthCheckAccountant {
using SafeERC20 for ERC20;

/// @notice An event emitted when a refund is added for a strategy.
event UpdateRefund(
address indexed vault,
address indexed strategy,
bool refund,
uint256 amount
);

/// @notice Struct to hold refund info for a strategy.
struct Refund {
// If the accountant should refund on the report.
bool refund;
// The amount if any to refund.
uint248 amount;
}

/// @notice Mapping of vault => strategy => struct if there is a reward refund to give.
mapping(address => mapping(address => Refund)) public refund;

constructor(
address _feeManager,
address _feeRecipient,
uint16 defaultManagement,
uint16 defaultPerformance,
uint16 defaultRefund,
uint16 defaultMaxFee,
uint16 defaultMaxGain,
uint16 defaultMaxLoss
)
HealthCheckAccountant(
_feeManager,
_feeRecipient,
defaultManagement,
defaultPerformance,
defaultRefund,
defaultMaxFee,
defaultMaxGain,
defaultMaxLoss
)
{}

/**
* @notice Called by a vault when a `strategy` is reporting.
* @dev The msg.sender must have been added to the `vaults` mapping.
* @param strategy Address of the strategy reporting.
* @param gain Amount of the gain if any.
* @param loss Amount of the loss if any.
* @return totalFees if any to charge.
* @return totalRefunds if any for the vault to pull.
*/
function report(
address strategy,
uint256 gain,
uint256 loss
)
public
virtual
override
returns (uint256 totalFees, uint256 totalRefunds)
{
(totalFees, totalRefunds) = super.report(strategy, gain, loss);

Refund memory refundConfig = refund[msg.sender][strategy];
// Check if the strategy is being given a refund.
if (refundConfig.refund) {
// Add it to the existing refunds.
totalRefunds += uint256(refundConfig.amount);

// Make sure the vault is approved correctly.
_checkAllowance(
msg.sender,
IVault(msg.sender).asset(),
totalRefunds
);

// Always reset the refund amount so it can't be reused.
delete refund[msg.sender][strategy];
}
}

/**
* @notice Set a strategy to use to refund a reward amount for
* aut compounding reward tokens.
*
* @param _vault Address of the vault to refund.
* @param _strategy Address of the strategy to refund during the report.
* @param _refund Bool to turn it on or off.
* @param _amount Amount to refund per report.
*/
function setRefund(
address _vault,
address _strategy,
bool _refund,
uint256 _amount
) external virtual onlyFeeManager {
require(vaults[_vault], "not added");
require(
IVault(_vault).strategies(_strategy).activation != 0,
"!active"
);
require(_refund || _amount == 0, "no refund and non zero amount");

refund[_vault][_strategy] = Refund({
refund: _refund,
amount: uint248(_amount)
});

emit UpdateRefund(_vault, _strategy, _refund, uint256(_amount));
}
}
2 changes: 0 additions & 2 deletions contracts/debtAllocators/GenericDebtAllocator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,6 @@ contract GenericDebtAllocator is Governance {
uint256 _targetRatio,
uint256 _maxRatio
) external virtual onlyGovernance {
// Make sure the strategy is added to the vault.
require(IVault(vault).strategies(_strategy).activation != 0, "!active");
// Make sure a minimumChange has been set.
require(minimumChange != 0, "!minimum");
// Cannot be more than 100%.
Expand Down
25 changes: 15 additions & 10 deletions scripts/deploy_accountant.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,11 @@ def deploy_accountant():
print(f"Salt we are using {salt}")
print("Init balance:", deployer.balance / 1e18)

if (
input(
"Would you like to deploy a Generic Accountant or a HealthCheck Accountant? g/h "
).lower()
== "g"
):
version = input(
"Would you like to deploy a Generic Accountant, HealthCheck Accountant or a Refund Accountant? g/h/r "
).lower()

if version == "g":
print("Deploying a Generic accountant.")
print("Enter the default amounts to use in Base Points. (100% == 10_000)")

Expand All @@ -65,10 +64,15 @@ def deploy_accountant():
)

else:
print("Deploying a HealthCheck accountant.")
print("Enter the default amounts to use in Base Points. (100% == 10_000)")
if version == "h":
print("Deploying a HealthCheck accountant.")
accountant = project.HealthCheckAccountant

accountant = project.HealthCheckAccountant
else:
print("Deploying a Refund accountant.")
accountant = project.RefundAccountant

print("Enter the default amounts to use in Base Points. (100% == 10_000)")

management_fee = input("Default management fee? ")
assert int(management_fee) <= 200
Expand Down Expand Up @@ -112,9 +116,10 @@ def deploy_accountant():

address = event[0].addr

print("------------------")
print(f"Deployed the Accountant to {address}")
print("------------------")
print(f"Encoded Constructor to use for verifaction {constructor.hex()}")
print(f"Encoded Constructor to use for verifaction {constructor.hex()[2:]}")


def main():
Expand Down
3 changes: 2 additions & 1 deletion scripts/deploy_address_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@ def deploy_address_provider():

address = event[0].addr

print("------------------")
print(f"Deployed the address provider to {address}")
print("------------------")
print(f"Encoded Constructor to use for verifaction {constructor.hex()}")
print(f"Encoded Constructor to use for verifaction {constructor.hex()[2:]}")


def main():
Expand Down
2 changes: 2 additions & 0 deletions scripts/deploy_allocator_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ def deploy_allocator_factory():

address = event[0].addr

print("------------------")
print(f"Deployed the Factory to {address}")
print("------------------")


def main():
Expand Down
3 changes: 2 additions & 1 deletion scripts/deploy_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,10 @@ def deploy_release_and_factory():

deployed_factory = factory.at(factory_event[0].addr)

print("------------------")
print(f"Deployed Registry Factory to {deployed_factory.address}")
print("------------------")
print(f"Encoded Constructor to use for verifaction {factory_constructor.hex()}")
print(f"Encoded Constructor to use for verifaction {factory_constructor.hex()[2:]}")


def main():
Expand Down
Loading