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

Feat/feature flags #22

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
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
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# Changes -
tl'dr - The current RenBTC/wBTC Zap contract (`contracts/Zap.sol`) for ibBTC estimates the best mint route from all the available curve pools and byWBTC. Since we want Zaps to always go through the RenWBTC Curve Pool the Zap contract needs to be adjusted to remove the other options

- `calcMintWithRen`, `calcMintWithWbtc` functions in `Zap.sol` changed to calculate mint amount only from pool[0] ie. renWBTC Curve pool

# Interest-bearing Badger BTC (ibBTC)

- [bBTC.sol](./contracts/bBTC.sol) is the interest-bearing bitcoin ERC20 token.
Expand Down
49 changes: 37 additions & 12 deletions contracts/Core.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ import {IPeak} from "./interfaces/IPeak.sol";
import {IbBTC} from "./interfaces/IbBTC.sol";
import {ICore} from "./interfaces/ICore.sol";
import {GovernableProxy} from "./common/proxy/GovernableProxy.sol";
import {PausableSlot} from "./common/PausableSlot.sol";

contract Core is GovernableProxy, ICore {
contract Core is GovernableProxy, PausableSlot, ICore {
using SafeERC20 for IERC20;
using SafeMath for uint;
using Math for uint;
Expand All @@ -22,7 +23,7 @@ contract Core is GovernableProxy, ICore {

BadgerGuestListAPI public guestList;

enum PeakState { Extinct, Active, Dormant }
enum PeakState { Extinct, Active, RedeemOnly, MintOnly }
mapping(address => PeakState) public peaks;

address[] public peakAddresses;
Expand All @@ -31,7 +32,10 @@ contract Core is GovernableProxy, ICore {
uint public redeemFee;
uint public accumulatedFee;

uint256[50] private __gap;
address public guardian;
address constant public badgerGovernance = 0xB65cef03b9B89f99517643226d76e286ee999e77;

uint256[49] private __gap;

// END OF STORAGE VARIABLES

Expand All @@ -46,6 +50,16 @@ contract Core is GovernableProxy, ICore {
bBTC = IbBTC(_bBTC);
}

modifier onlyGuardianOrGovernance() {
require(msg.sender == guardian || msg.sender == owner(), "onlyGuardianOrGovernance");
_;
}

modifier onlyGovernanceOrBadgerGovernance() {
require(msg.sender == badgerGovernance || msg.sender == owner(), "onlyGovernanceOrBadgerGovernance");
_;
}

/**
* @notice Mint bBTC
* @dev Only whitelisted peaks can call this function
Expand All @@ -55,9 +69,10 @@ contract Core is GovernableProxy, ICore {
function mint(uint btc, address account, bytes32[] calldata merkleProof)
override
external
whenNotPaused
returns(uint)
{
require(peaks[msg.sender] == PeakState.Active, "PEAK_INACTIVE");
require(peaks[msg.sender] == PeakState.Active || peaks[msg.sender] == PeakState.MintOnly, "PEAK_INACTIVE_OR_MINTING_DISABLED");
if (address(guestList) != address(0)) {
require(
guestList.authorized(account, btc, merkleProof),
Expand Down Expand Up @@ -91,9 +106,9 @@ contract Core is GovernableProxy, ICore {
* @param bBtc bBTC amount to redeem
* @return btc amount redeemed, scaled by 1e36
*/
function redeem(uint bBtc, address account) override external returns (uint) {
function redeem(uint bBtc, address account) override external whenNotPaused returns (uint) {
require(bBtc > 0, "REDEEMING_0_bBTC");
require(peaks[msg.sender] != PeakState.Extinct, "PEAK_EXTINCT");
require(peaks[msg.sender] == PeakState.Active || peaks[msg.sender] == PeakState.RedeemOnly, "PEAK_INACTIVE_OR_REDEMPTION_DISABLED");
(uint btc, uint fee) = bBtcToBtc(bBtc);
accumulatedFee = accumulatedFee.add(fee);
bBTC.burn(account, bBtc);
Expand All @@ -119,7 +134,7 @@ contract Core is GovernableProxy, ICore {
/**
* @notice Collect all the accumulated fee (denominated in bBTC)
*/
function collectFee() external {
function collectFee() external whenNotPaused {
require(feeSink != address(0), "NULL_ADDRESS");
uint _fee = accumulatedFee;
require(_fee > 0, "NO_FEE");
Expand All @@ -141,15 +156,13 @@ contract Core is GovernableProxy, ICore {
}
}

/* ##### Governance ##### */

/**
* @notice Whitelist a new peak
* @param peak Address of the contract that interfaces with the 3rd-party protocol
*/
function whitelistPeak(address peak)
external
onlyGovernance
onlyGovernanceOrBadgerGovernance
{
require(
peaks[peak] == PeakState.Extinct,
Expand All @@ -173,7 +186,7 @@ contract Core is GovernableProxy, ICore {
*/
function setPeakStatus(address peak, PeakState state)
external
onlyGovernance
onlyGovernanceOrBadgerGovernance
{
require(
peaks[peak] != PeakState.Extinct,
Expand Down Expand Up @@ -211,9 +224,21 @@ contract Core is GovernableProxy, ICore {
feeSink = _feeSink;
}

function setGuestList(address _guestList) external onlyGovernance {
function setGuestList(address _guestList) external onlyGovernanceOrBadgerGovernance {
guestList = BadgerGuestListAPI(_guestList);
}

function setGuardian(address _guardian) external onlyGovernanceOrBadgerGovernance {
guardian = _guardian;
}

function pause() external onlyGuardianOrGovernance {
_pause();
}

function unpause() external onlyGovernanceOrBadgerGovernance {
_unpause();
}
}

interface BadgerGuestListAPI {
Expand Down
100 changes: 5 additions & 95 deletions contracts/Zap.sol
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ contract Zap is Initializable, Pausable, AccessControlDefendedBase {
}

/**
* @notice Calculate the most optimal route and expected ibbtc amount when minting with renBTC.
* @notice Calculate mint through renWBTC pool route and expected ibbtc amount when minting with renBTC.
* @dev Use returned params poolId, idx and bBTC in the call to mint(...)
The last param `minOut` in mint(...) should be a bit more than the returned bBTC value.
For instance 0.2% - 1% higher depending on slippage tolerange.
Expand All @@ -180,26 +180,10 @@ contract Zap is Initializable, Pausable, AccessControlDefendedBase {

// poolId=0, idx=0
(bBTC, fee) = curveLPToIbbtc(0, pools[0].deposit.calc_token_amount([amount,0], true));

(_ibbtc, _fee) = curveLPToIbbtc(1, pools[1].deposit.calc_token_amount([amount,0,0], true));
if (_ibbtc > bBTC) {
bBTC = _ibbtc;
fee = _fee;
poolId = 1;
// idx=0
}

(_ibbtc, _fee) = curveLPToIbbtc(2, pools[2].deposit.calc_token_amount([0,amount,0,0], true));
if (_ibbtc > bBTC) {
bBTC = _ibbtc;
fee = _fee;
poolId = 2;
idx = 1;
}
}

/**
* @notice Calculate the most optimal route and expected ibbtc amount when minting with wBTC.
* @notice Calculate mint through renWBTC pool route and expected ibbtc amount when minting with wBTC.
* @dev Use returned params poolId, idx and bBTC in the call to mint(...)
The last param `minOut` in mint(...) should be a bit more than the returned bBTC value.
For instance 0.2% - 1% higher depending on slippage tolerange.
Expand All @@ -216,31 +200,6 @@ contract Zap is Initializable, Pausable, AccessControlDefendedBase {
// poolId=0
(bBTC, fee) = curveLPToIbbtc(0, pools[0].deposit.calc_token_amount([0,amount], true));
idx = 1;

(_ibbtc, _fee) = curveLPToIbbtc(1, pools[1].deposit.calc_token_amount([0,amount,0], true));
if (_ibbtc > bBTC) {
bBTC = _ibbtc;
fee = _fee;
poolId = 1;
// idx=1
}

(_ibbtc, _fee) = curveLPToIbbtc(2, pools[2].deposit.calc_token_amount([0,0,amount,0], true));
if (_ibbtc > bBTC) {
bBTC = _ibbtc;
fee = _fee;
poolId = 2;
idx = 2;
}

// for byvwbtc, sett.pricePerShare returns a wbtc value, as opposed to lpToken amount in setts
(_ibbtc, _fee) = byvWbtcPeak.calcMint(amount.mul(1e8).div(IbyvWbtc(address(pools[3].sett)).pricePerShare()));
if (_ibbtc > bBTC) {
bBTC = _ibbtc;
fee = _fee;
poolId = 3;
// idx value will be ignored anyway
}
}

/**
Expand Down Expand Up @@ -279,7 +238,7 @@ contract Zap is Initializable, Pausable, AccessControlDefendedBase {
}

/**
* @notice Calculate the most optimal route and expected token amount when redeeming ibbtc.
* @notice Calculate redeem through renWBTC pool route and expected token amount when redeeming ibbtc.
* @dev Use returned params poolId, idx and out in the call to redeem(...)
The last param `redeem` in mint(...) should be a bit less than the returned `out` value.
For instance 0.2% - 1% lesser depending on slippage tolerange.
Expand All @@ -300,7 +259,7 @@ contract Zap is Initializable, Pausable, AccessControlDefendedBase {
}

/**
* @notice Calculate the most optimal route and expected renbtc amount when redeeming ibbtc.
* @notice Calculate redeem through renWBTC pool route and expected renbtc amount when redeeming ibbtc.
* @dev Use returned params poolId, idx and renAmount in the call to redeem(...)
The last param `minOut` in redeem(...) should be a bit less than the returned renAmount value.
For instance 0.2% - 1% lesser depending on slippage tolerange.
Expand All @@ -318,24 +277,6 @@ contract Zap is Initializable, Pausable, AccessControlDefendedBase {
// poolId=0, idx=0
(_lp, fee) = ibbtcToCurveLP(0, amount);
renAmount = pools[0].deposit.calc_withdraw_one_coin(_lp, 0);

(_lp, _fee) = ibbtcToCurveLP(1, amount);
_ren = pools[1].deposit.calc_withdraw_one_coin(_lp, 0);
if (_ren > renAmount) {
renAmount = _ren;
fee = _fee;
poolId = 1;
// idx=0
}

(_lp, _fee) = ibbtcToCurveLP(2, amount);
_ren = pools[2].deposit.calc_withdraw_one_coin(_lp, 1);
if (_ren > renAmount) {
renAmount = _ren;
fee = _fee;
poolId = 2;
idx = 1;
}
}

/**
Expand All @@ -358,37 +299,6 @@ contract Zap is Initializable, Pausable, AccessControlDefendedBase {
(_lp, fee) = ibbtcToCurveLP(0, amount);
wBTCAmount = pools[0].deposit.calc_withdraw_one_coin(_lp, 1);
idx = 1;

(_lp, _fee) = ibbtcToCurveLP(1, amount);
_wbtc = pools[1].deposit.calc_withdraw_one_coin(_lp, 1);
if (_wbtc > wBTCAmount) {
wBTCAmount = _wbtc;
fee = _fee;
poolId = 1;
// idx=1
}

(_lp, _fee) = ibbtcToCurveLP(2, amount);
_wbtc = pools[2].deposit.calc_withdraw_one_coin(_lp, 2);
if (_wbtc > wBTCAmount) {
wBTCAmount = _wbtc;
fee = _fee;
poolId = 2;
idx = 2;
}

uint _byvWbtc;
uint _max;
(_byvWbtc,_fee,_max) = byvWbtcPeak.calcRedeem(amount);
if (amount <= _max) {
uint strategyFee = _byvWbtc.mul(pools[3].sett.withdrawalFee()).div(10000);
_wbtc = _byvWbtc.sub(strategyFee).mul(pools[3].sett.pricePerShare()).div(1e8);
if (_wbtc > wBTCAmount) {
wBTCAmount = _wbtc;
fee = _fee.add(strategyFee);
poolId = 3;
}
}
}

function ibbtcToCurveLP(uint poolId, uint bBtc) public view returns(uint lp, uint fee) {
Expand All @@ -401,7 +311,7 @@ contract Zap is Initializable, Pausable, AccessControlDefendedBase {
} else {
// pesimistically charge 0.5% on the withdrawal.
// Actual fee might be lesser if the vault keeps keeps a buffer
uint strategyFee = sett.mul(controller.strategies(pool.lpToken).withdrawalFee()).div(1000);
uint strategyFee = sett.mul(controller.strategies(pool.lpToken).withdrawalFee()).div(10000);
lp = sett.sub(strategyFee).mul(pool.sett.getPricePerFullShare()).div(1e18);
fee = fee.add(strategyFee);
}
Expand Down
38 changes: 31 additions & 7 deletions contracts/common/AccessControlDefended.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
pragma solidity 0.6.11;

import {GovernableProxy} from "./proxy/GovernableProxy.sol";

import {PausableSlot} from "../common/PausableSlot.sol";
contract AccessControlDefendedBase {
mapping (address => bool) public approved;
mapping(address => uint256) public blockLock;

modifier defend() {
require(msg.sender == tx.origin || approved[msg.sender], "ACCESS_DENIED");
_;
Expand All @@ -17,7 +17,7 @@ contract AccessControlDefendedBase {
require(approved[msg.sender] || blockLock[msg.sender] < block.number, "BLOCK_LOCKED");
_;
}

function _lockForBlock(address account) internal {
blockLock[account] = block.number;
}
Expand All @@ -31,14 +31,38 @@ contract AccessControlDefendedBase {
}
}

contract AccessControlDefended is GovernableProxy, AccessControlDefendedBase {
uint256[50] private __gap;
contract AccessControlDefended is GovernableProxy, AccessControlDefendedBase, PausableSlot {
address constant public badgerGovernance = 0xB65cef03b9B89f99517643226d76e286ee999e77;
address public guardian;
uint256[49] private __gap;

modifier onlyGovernanceOrBadgerGovernance() {
require(msg.sender == badgerGovernance || msg.sender == owner(), "onlyGovernanceOrBadgerGovernance");
_;
}

function approveContractAccess(address account) external onlyGovernance {
modifier onlyGuardianOrGovernance() {
require(msg.sender == guardian || msg.sender == owner(), "onlyGuardianOrGovernance");
_;
}

function approveContractAccess(address account) external onlyGovernanceOrBadgerGovernance {
_approveContractAccess(account);
}

function revokeContractAccess(address account) external onlyGovernance {
function revokeContractAccess(address account) external onlyGovernanceOrBadgerGovernance {
_revokeContractAccess(account);
}

function setGuardian(address _guardian) external onlyGovernanceOrBadgerGovernance {
guardian = _guardian;
}

function pause() external onlyGuardianOrGovernance {
_pause();
}

function unpause() external onlyGovernanceOrBadgerGovernance {
_unpause();
}
}
Loading