Skip to content

Commit

Permalink
feat: Temple v2 & TLC (#788)
Browse files Browse the repository at this point in the history
* fix: addliquidity calculation (#728) (#729)

* feat: temple v2 interfaces

* feat: dUSD initial implementation. testing wip

* feat: cleanup, more tests

* feat: cleanup, more tests

* feat: dUSD implementation and tests

* feat: minor updates, improved tests

* slither updates

* feat: start of strategies

* feat: add dusd testnet admin contract

* feat: added DSR base strategy

* feat: initial TRV - still WIP

* feat: still WIP

* feat: strategies report asset balances

* feat: strategies report asset balances

* feat: tests

* feat: gnosis strategy tests

* feat: wip dsr base strategy tests

* feat: wip continues

* Add safe guard

* Convert to revert string error for Safe UI

* Refactor elevated access

* Add v2 readme

* Add v2 readme

* Updated access

* Updated readme, batch update on guard

* Update README.md

Cleaned up the wording for clarity / readability

* TLC pre-requisites (#804)

* Updated Temple v2 to support TLC

* Add the RAMOS strategy (#805)

* implement the RAMOS strategy reporting the underlying assets

* add tests for RAMOS strategy

* disable the ETH balance report

* update tests for RAMOS strategy

* add TPI on TRV constructor in RAMOS strategy test

* implement functions to add/remove liquidity on RAMOS strategy

* proportional add liquidity

* update the addLiquidity function on RAMOS and the quote functions on PoolHelper

* update RAMOS contract and tests

* implement borrow/repay features on RAMOS strategy and add tests for borrow

* fix bpt total supply issue and add tests for repay

* fix issues on RAMOS contract

* remove operators from RAMOS strategy

* update tests for adding/removing the liquidity

* fix tests for RAMOS and PoolHelper contracts

* update the RAMOS access control mechanism and fix the tests for RAMOS and RAMOS strategy

* set the explicit access to RAMOS on RAMOS strategy test

* Tlc (#806)

* Updated Temple v2 to support TLC

* Updated Temple v2 to support TLC

* Updated Temple v2 to support TLC

* Initial TLC

* Make TLC a strategy

* Use an index accumulator instead of shares

* Updates, gas golfing

* comment out logs

* Tlc reworked (#807)

* Reworked to fit size - strategy split out

* Tlc delegatecall (#808)

* delegatecall

* Reworked to fit size - strategy split out

* added storage to interfaces

* fix up (#809)

* update names

* remove loops

* add expiry to fund request window

* refactor to take token address as input

* further tests

* tests, tests, tests

* split fund request types, tests

* positive interest rate only

* add more tests, cleanup

* comment all of the things

* a couple of extra tests

* remove oud, update tests

* flatten TLC contract

* fix edge cases on interest rate model

* interface tweaks to shutdown, asset balances

* PR feedback, solhint

* refactor ramos imports, ramos strategy updates

* Update ramos tests

* Add comments to Ramos, autoshutdown ramos

* Move TPI into a separate oracle contract

* rename temple/stable in ramos

* ramos rebalance up/down join & exit

* Add fees to ramos

* review feedback (#814)

* review feedback

---------

Co-authored-by: frost ostrich <frost_ostrich@proton.me>
Co-authored-by: frost-ostrich <127277105+frost-ostrich@users.noreply.github.com>

* gh hardhat tests

* slither

---------

Co-authored-by: Nicho <nichosystem@protonmail.com>
Co-authored-by: jebsley3 <96315255+jebsley3@users.noreply.github.com>
Co-authored-by: Marshall <99344331+marshall2112@users.noreply.github.com>
Co-authored-by: temple-advocate <92966776+temple-advocate@users.noreply.github.com>
Co-authored-by: cool-eth <82349338+cool-eth@users.noreply.github.com>
Co-authored-by: frost ostrich <frost_ostrich@proton.me>
Co-authored-by: frost-ostrich <127277105+frost-ostrich@users.noreply.github.com>
  • Loading branch information
8 people authored Jul 7, 2023
1 parent f6253fb commit d832d88
Show file tree
Hide file tree
Showing 129 changed files with 71,899 additions and 1,639 deletions.
8 changes: 6 additions & 2 deletions .github/workflows/slither.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@ on:
- ".github/workflows/slither.yaml"
jobs:
analyze:
if: ${{ false }} # Slither has an issue with ternary operators (used in RAMOS). Quite unmaintained...
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive

- name: install foundry
uses: foundry-rs/foundry-toolchain@v1.0.9

- uses: actions/setup-python@v4
with:
python-version: 3.9
Expand All @@ -34,4 +38,4 @@ jobs:
run: cd protocol && yarn

- name: run slither
run: cd protocol && slither .
run: cd protocol && yarn slither-check
2 changes: 1 addition & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
"semi": true,
"singleQuote": true,
"useTabs": false
}
}
2 changes: 1 addition & 1 deletion protocol/.solcover.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ module.exports = {
'util/ABDKMath', // ABDKMath has issues compiling in solcover
'fakes', // Ignore fakes
]
};
};
8 changes: 8 additions & 0 deletions protocol/.solhint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "solhint:recommended",
"rules": {
"func-visibility": ["warn",{"ignoreConstructors":true}],
"compiler-version": ["error","^0.8.17"],
"reason-string": ["warn",{"maxLength":32}]
}
}
41 changes: 0 additions & 41 deletions protocol/contracts/admin/Operators.sol

This file was deleted.

133 changes: 51 additions & 82 deletions protocol/contracts/amo/AuraStaking.sol
Original file line number Diff line number Diff line change
@@ -1,77 +1,51 @@
pragma solidity ^0.8.4;
pragma solidity 0.8.18;
// SPDX-License-Identifier: AGPL-3.0-or-later
// Temple (amo/AuraStaking.sol)

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

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./interfaces/AMO__IBaseRewardPool.sol";
import "./interfaces/AMO__IAuraBooster.sol";
import "./helpers/AMOCommon.sol";
import { TempleElevatedAccess } from "contracts/v2/access/TempleElevatedAccess.sol";
import { IAuraStaking } from "contracts/interfaces/amo/IAuraStaking.sol";
import { IAuraBaseRewardPool } from "contracts/interfaces/external/aura/IAuraBaseRewardPool.sol";
import { IAuraBooster } from "contracts/interfaces/external/aura/IAuraBooster.sol";

contract AuraStaking is Ownable {
contract AuraStaking is IAuraStaking, TempleElevatedAccess {
using SafeERC20 for IERC20;

address public operator;
// @notice BPT tokens for balancer pool
IERC20 public immutable bptToken;
AuraPoolInfo public auraPoolInfo;
// @notice Aura booster
AMO__IAuraBooster public immutable booster;

address public rewardsRecipient;
address[] public rewardTokens;

struct AuraPoolInfo {
address token;
address rewards;
uint32 pId;
}
IERC20 public immutable override bptToken;

struct Position {
uint256 staked;
uint256 earned;
}
AuraPoolInfo public override auraPoolInfo;

error NotOperator();
error NotOperatorOrOwner();
// @notice Aura booster
IAuraBooster public immutable override booster;

event SetAuraPoolInfo(uint32 indexed pId, address token, address rewards);
event SetOperator(address operator);
event RecoveredToken(address token, address to, uint256 amount);
event SetRewardsRecipient(address recipient);
address public override rewardsRecipient;
address[] public override rewardTokens;

constructor(
address _operator,
address _initialRescuer,
address _initialExecutor,
IERC20 _bptToken,
AMO__IAuraBooster _booster,
IAuraBooster _booster,
address[] memory _rewardTokens
) {
operator = _operator;
) TempleElevatedAccess(_initialRescuer, _initialExecutor)
{
bptToken = _bptToken;
booster = _booster;
rewardTokens = _rewardTokens;
}

function setAuraPoolInfo(uint32 _pId, address _token, address _rewards) external onlyOwner {
function setAuraPoolInfo(uint32 _pId, address _token, address _rewards) external override onlyElevatedAccess {
auraPoolInfo.pId = _pId;
auraPoolInfo.token = _token;
auraPoolInfo.rewards = _rewards;

emit SetAuraPoolInfo(_pId, _token, _rewards);
}

/**
* @notice Set operator
* @param _operator New operator
*/
function setOperator(address _operator) external onlyOwner {
operator = _operator;

emit SetOperator(_operator);
}

function setRewardsRecipient(address _recipeint) external onlyOwner {
function setRewardsRecipient(address _recipeint) external override onlyElevatedAccess {
rewardsRecipient = _recipeint;

emit SetRewardsRecipient(_recipeint);
Expand All @@ -83,19 +57,19 @@ contract AuraStaking is Ownable {
* @param to Recipient address
* @param amount Amount to recover
*/
function recoverToken(address token, address to, uint256 amount) external onlyOwner {
function recoverToken(address token, address to, uint256 amount) external override onlyElevatedAccess {
IERC20(token).safeTransfer(to, amount);

emit RecoveredToken(token, to, amount);
}

function isAuraShutdown() public view returns (bool) {
function isAuraShutdown() public override view returns (bool) {
// It's not necessary to check that the booster itself is shutdown, as that can only
// be shutdown once all the pools are shutdown - see Aura BoosterOwner.shutdownSystem()
return booster.poolInfo(auraPoolInfo.pId).shutdown;
}

function depositAndStake(uint256 amount) external onlyOperator {
function depositAndStake(uint256 amount) external override onlyElevatedAccess {
// Only deposit if the aura pool is open. Otherwise leave the BPT in this contract.
if (!isAuraShutdown()) {
bptToken.safeIncreaseAllowance(address(booster), amount);
Expand All @@ -104,65 +78,60 @@ contract AuraStaking is Ownable {
}

// withdraw deposit token and unwrap to bpt tokens
function withdrawAndUnwrap(uint256 amount, bool claim, address to) external onlyOperatorOrOwner {
function withdrawAndUnwrap(uint256 amount, bool claim, address recipient) external override onlyElevatedAccess {
// Optimistically use BPT balance in this contract, and then try and unstake any remaining
uint256 bptBalance = bptToken.balanceOf(address(this));
uint256 toUnstake = (amount < bptBalance) ? 0 : amount - bptBalance;
if (toUnstake > 0) {
AMO__IBaseRewardPool(auraPoolInfo.rewards).withdrawAndUnwrap(toUnstake, claim);
IAuraBaseRewardPool(auraPoolInfo.rewards).withdrawAndUnwrap(toUnstake, claim);
}

if (to != address(0)) {
if (recipient != address(0)) {
// unwrapped amount is 1 to 1
bptToken.safeTransfer(to, amount);
bptToken.safeTransfer(recipient, amount);
}
}

function withdrawAllAndUnwrap(bool claim, bool sendToOperator) external onlyOwner {
AMO__IBaseRewardPool(auraPoolInfo.rewards).withdrawAllAndUnwrap(claim);
if (sendToOperator) {
uint256 totalBalance = bptToken.balanceOf(address(this));
bptToken.safeTransfer(operator, totalBalance);
function withdrawAllAndUnwrap(bool claim, address recipient) external override onlyElevatedAccess {
IAuraBaseRewardPool(auraPoolInfo.rewards).withdrawAllAndUnwrap(claim);
if (recipient != address(0)) {
uint256 bptBalance = bptToken.balanceOf(address(this));
bptToken.safeTransfer(recipient, bptBalance);
}
}

function getReward(bool claimExtras) external {
AMO__IBaseRewardPool(auraPoolInfo.rewards).getReward(address(this), claimExtras);
function getReward(bool claimExtras) external override {
IAuraBaseRewardPool(auraPoolInfo.rewards).getReward(address(this), claimExtras);
if (rewardsRecipient != address(0)) {
for (uint i=0; i<rewardTokens.length; i++) {
uint256 length = rewardTokens.length;
for (uint i; i < length; ++i) {
uint256 balance = IERC20(rewardTokens[i]).balanceOf(address(this));
IERC20(rewardTokens[i]).safeTransfer(rewardsRecipient, balance);
}
}
}

function stakedBalance() public view returns (uint256 balance) {
balance = AMO__IBaseRewardPool(auraPoolInfo.rewards).balanceOf(address(this));
function stakedBalance() public override view returns (uint256 balance) {
balance = IAuraBaseRewardPool(auraPoolInfo.rewards).balanceOf(address(this));
}

function earned() public view returns (uint256 earnedRewards) {
earnedRewards = AMO__IBaseRewardPool(auraPoolInfo.rewards).earned(address(this));
/**
* @notice The total balance of BPT owned by this contract - either staked in Aura
* or unstaked
*/
function totalBalance() external override view returns (uint256) {
return stakedBalance() + bptToken.balanceOf(address(this));
}

function earned() public override view returns (uint256 earnedRewards) {
earnedRewards = IAuraBaseRewardPool(auraPoolInfo.rewards).earned(address(this));
}

/**
* @notice show staked position and earned rewards
*/
function showPositions() external view returns (Position memory position){
function showPositions() external override view returns (Position memory position){
position.staked = stakedBalance();
position.earned = earned();
}

modifier onlyOperator() {
if (msg.sender != operator) {
revert NotOperator();
}
_;
}

modifier onlyOperatorOrOwner() {
if (msg.sender != operator && msg.sender != owner()) {
revert NotOperatorOrOwner();
}
_;
}
}
Loading

0 comments on commit d832d88

Please sign in to comment.