Skip to content

Commit

Permalink
feat: release 0.4.4 (#542)
Browse files Browse the repository at this point in the history
* refactor: reduce base strategy size (#422)

* refactor: reduce base strategy size

* fix: do not add onlyManagement

* fix: allow harvest on add strategy block (#428)

* fix: allow harvest on add strategy block

* docs: comment

Co-authored-by: El De-dog-lo <[email protected]>

Co-authored-by: El De-dog-lo <[email protected]>

* fix: updated setRewards (#474)

* feat: add deposit and withdraw events (#499)

* feat: add event to add_event_to_setLockedProfitDegradation (#506)

* fix: implement modifiers (#513)

* fix: implement modifiers

* fix: typo

* fix: formatting

* fix: test same time harvest not allowed

* fix: merge mistake

* fix: gov event

* fix: add pps protection

* chore: update solc version

* chore: add FeeReport event

* chore: update FeeReport

* chore: bump vyper version

* chore: bump brownie version

* test: fixes

* chore: bump ganache version

* style: fix format

* test: airdrop do not change pps

* test: make sure deposits are still possible

* ci: cancel same branch run

* style: fix python formating

* fix: wrong math operation

* fix: tests

* fix: add missing WithdrawFromStrategy event

* docs: fix comment

* chore: cleanup docs folder

* chore: remove not used code

* feat: prevent fork replay EIP712 signature (#3)

* chore: bump version

* fix: clone check (#5)

* fix: make sure strategy isn't in emergency mode when updating debt (#4)

* fix: change permit definition (#6)

* fix: change permit definition

* fix: tests

* chore: format

* fix: do not use external call

* fix: allow setEmergency after revoke (#7)

Co-authored-by: Steffel <[email protected]>
Co-authored-by: El De-dog-lo <[email protected]>
Co-authored-by: John Bergschneider <[email protected]>
Co-authored-by: jmonteer <[email protected]>
  • Loading branch information
5 people authored Oct 25, 2022
1 parent efb47d8 commit 3362e89
Show file tree
Hide file tree
Showing 38 changed files with 377 additions and 1,368 deletions.
8 changes: 6 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ on:
- develop
pull_request:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:

functional:
Expand All @@ -29,10 +33,10 @@ jobs:
- name: Setup node.js
uses: actions/setup-node@v1
with:
node-version: '12.x'
node-version: '14.x'

- name: Install ganache
run: npm install -g ganache[email protected]
run: npm install -g ganache

- name: Set up python 3.8
uses: actions/setup-python@v2
Expand Down
6 changes: 3 additions & 3 deletions brownie-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ autofetch_sources: true

# require OpenZepplin Contracts
dependencies:
- OpenZeppelin/openzeppelin-contracts@3.1.0
- OpenZeppelin/openzeppelin-contracts@4.7.1

# path remapping to support OpenZepplin imports with NPM-style path
compiler:
solc:
version: 0.6.12
version: 0.8.15
remappings:
- "@openzeppelin=OpenZeppelin/openzeppelin-contracts@3.1.0"
- "@openzeppelin=OpenZeppelin/openzeppelin-contracts@4.7.1"

reports:
exclude_paths:
Expand Down
109 changes: 70 additions & 39 deletions contracts/BaseStrategy.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.7.0;
pragma experimental ABIEncoderV2;
pragma solidity >=0.8.15;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

struct StrategyParams {
uint256 performanceFee;
Expand Down Expand Up @@ -32,7 +31,9 @@ interface VaultAPI is IERC20 {
address spender,
uint256 amount,
uint256 expiry,
bytes calldata signature
uint8 v,
bytes32 r,
bytes32 s
) external returns (bool);

// NOTE: Vyper produces multiple signatures for a given function with "default" args
Expand Down Expand Up @@ -187,7 +188,6 @@ interface HealthCheck {
*/

abstract contract BaseStrategy {
using SafeMath for uint256;
using SafeERC20 for IERC20;
string public metadataURI;

Expand All @@ -203,7 +203,7 @@ abstract contract BaseStrategy {
* @return A string which holds the current API version of this contract.
*/
function apiVersion() public pure returns (string memory) {
return "0.4.3";
return "0.4.4";
}

/**
Expand Down Expand Up @@ -287,46 +287,75 @@ abstract contract BaseStrategy {

// modifiers
modifier onlyAuthorized() {
require(msg.sender == strategist || msg.sender == governance(), "!authorized");
_onlyAuthorized();
_;
}

modifier onlyEmergencyAuthorized() {
require(
msg.sender == strategist || msg.sender == governance() || msg.sender == vault.guardian() || msg.sender == vault.management(),
"!authorized"
);
_onlyEmergencyAuthorized();
_;
}

modifier onlyStrategist() {
require(msg.sender == strategist, "!strategist");
_onlyStrategist();
_;
}

modifier onlyGovernance() {
require(msg.sender == governance(), "!authorized");
_onlyGovernance();
_;
}

modifier onlyRewarder() {
_onlyRewarder();
_;
}

modifier onlyKeepers() {
_onlyKeepers();
_;
}

modifier onlyVaultManagers() {
_onlyVaultManagers();
_;
}

function _onlyAuthorized() internal {
require(msg.sender == strategist || msg.sender == governance());
}

function _onlyEmergencyAuthorized() internal {
require(msg.sender == strategist || msg.sender == governance() || msg.sender == vault.guardian() || msg.sender == vault.management());
}

function _onlyStrategist() internal {
require(msg.sender == strategist);
}

function _onlyGovernance() internal {
require(msg.sender == governance());
}

function _onlyRewarder() internal {
require(msg.sender == governance() || msg.sender == strategist);
}

function _onlyKeepers() internal {
require(
msg.sender == keeper ||
msg.sender == strategist ||
msg.sender == governance() ||
msg.sender == vault.guardian() ||
msg.sender == vault.management(),
"!authorized"
msg.sender == vault.management()
);
_;
}

modifier onlyVaultManagers() {
require(msg.sender == vault.management() || msg.sender == governance(), "!authorized");
_;
function _onlyVaultManagers() internal {
require(msg.sender == vault.management() || msg.sender == governance());
}

constructor(address _vault) public {
constructor(address _vault) {
_initialize(_vault, msg.sender, msg.sender, msg.sender);
}

Expand All @@ -352,7 +381,7 @@ abstract contract BaseStrategy {

vault = VaultAPI(_vault);
want = IERC20(vault.token());
want.safeApprove(_vault, uint256(-1)); // Give Vault unlimited access (might save gas)
want.safeApprove(_vault, type(uint256).max); // Give Vault unlimited access (might save gas)
strategist = _strategist;
rewards = _rewards;
keeper = _keeper;
Expand All @@ -363,7 +392,7 @@ abstract contract BaseStrategy {
profitFactor = 100;
debtThreshold = 0;

vault.approve(rewards, uint256(-1)); // Allow rewards to be pulled
vault.approve(rewards, type(uint256).max); // Allow rewards to be pulled
}

function setHealthCheck(address _healthCheck) external onlyVaultManagers {
Expand Down Expand Up @@ -416,11 +445,11 @@ abstract contract BaseStrategy {
* This may only be called by the strategist.
* @param _rewards The address to use for pulling rewards.
*/
function setRewards(address _rewards) external onlyStrategist {
function setRewards(address _rewards) external onlyRewarder {
require(_rewards != address(0));
vault.approve(rewards, 0);
rewards = _rewards;
vault.approve(rewards, uint256(-1));
vault.approve(rewards, type(uint256).max);
emit UpdatedRewards(_rewards);
}

Expand Down Expand Up @@ -710,10 +739,10 @@ abstract contract BaseStrategy {
if (params.activation == 0) return false;

// Should not trigger if we haven't waited long enough since previous harvest
if (block.timestamp.sub(params.lastReport) < minReportDelay) return false;
if ((block.timestamp - params.lastReport) < minReportDelay) return false;

// Should trigger if hasn't been called in a while
if (block.timestamp.sub(params.lastReport) >= maxReportDelay) return true;
if ((block.timestamp - params.lastReport) >= maxReportDelay) return true;

// If some amount is owed, pay it back
// NOTE: Since debt is based on deposits, it makes sense to guard against large
Expand All @@ -726,15 +755,15 @@ abstract contract BaseStrategy {
// Check for profits and losses
uint256 total = estimatedTotalAssets();
// Trigger if we have a loss to report
if (total.add(debtThreshold) < params.totalDebt) return true;
if ((total + debtThreshold) < params.totalDebt) return true;

uint256 profit = 0;
if (total > params.totalDebt) profit = total.sub(params.totalDebt); // We've earned a profit!
if (total > params.totalDebt) profit = (total - params.totalDebt); // We've earned a profit!

// Otherwise, only trigger if it "makes sense" economically (gas cost
// is <N% of value moved)
uint256 credit = vault.creditAvailable();
return (profitFactor.mul(callCost) < credit.add(profit));
return ((profitFactor * callCost) < (credit + profit));
}

/**
Expand Down Expand Up @@ -763,11 +792,11 @@ abstract contract BaseStrategy {
// Free up as much capital as possible
uint256 amountFreed = liquidateAllPositions();
if (amountFreed < debtOutstanding) {
loss = debtOutstanding.sub(amountFreed);
loss = debtOutstanding - amountFreed;
} else if (amountFreed > debtOutstanding) {
profit = amountFreed.sub(debtOutstanding);
profit = amountFreed - debtOutstanding;
}
debtPayment = debtOutstanding.sub(loss);
debtPayment = debtOutstanding - loss;
} else {
// Free up returns for Vault to pull
(profit, loss, debtPayment) = prepareReturn(debtOutstanding);
Expand Down Expand Up @@ -849,7 +878,9 @@ abstract contract BaseStrategy {
*/
function setEmergencyExit() external onlyEmergencyAuthorized {
emergencyExit = true;
vault.revokeStrategy();
if (vault.strategies(address(this)).debtRatio != 0) {
vault.revokeStrategy();
}

emit EmergencyExitEnabled();
}
Expand Down Expand Up @@ -906,7 +937,7 @@ abstract contract BaseStrategyInitializable is BaseStrategy {
bool public isOriginal = true;
event Cloned(address indexed clone);

constructor(address _vault) public BaseStrategy(_vault) {}
constructor(address _vault) BaseStrategy(_vault) {}

function initialize(
address _vault,
Expand All @@ -918,16 +949,16 @@ abstract contract BaseStrategyInitializable is BaseStrategy {
}

function clone(address _vault) external returns (address) {
require(isOriginal, "!clone");
return this.clone(_vault, msg.sender, msg.sender, msg.sender);
return clone(_vault, msg.sender, msg.sender, msg.sender);
}

function clone(
address _vault,
address _strategist,
address _rewards,
address _keeper
) external returns (address newStrategy) {
) public returns (address newStrategy) {
require(isOriginal, "!clone");
// Copied from https://github.com/optionality/clone-factory/blob/master/contracts/CloneFactory.sol
bytes20 addressBytes = bytes20(address(this));

Expand Down
Loading

0 comments on commit 3362e89

Please sign in to comment.