Diff
checker
Text
Text
Images
Documents
Excel
Folders
Legal
Enterprise
Desktop
Pricing
Sign in
Download Diffchecker Desktop
Compare text
Find the difference between two text files
Tools
History
Real-time editor
Hide unchanged lines
Disable line wrap
Layout
Split
Unified
Diff precision
Smart
Word
Char
Syntax highlighting
Choose syntax
Ignore
Transform text
Go to first change
Edit input
Diffchecker Desktop
The most secure way to run Diffchecker. Get the Diffchecker Desktop app: your diffs never leave your computer!
Get Desktop
auraBal
Created
4 years ago
Diff never expires
Clear
Export
Share
The two texts are identical
There is no difference to show between these two texts
0 removals
Lines
Total
Removed
Characters
Total
Removed
To continue using this feature, upgrade to
Diff
checker
Pro
View Pricing
278 lines
Copy
0 additions
Lines
Total
Added
Characters
Total
Added
To continue using this feature, upgrade to
Diff
checker
Pro
View Pricing
278 lines
Copy
contract AuraBalStakerStrategy is BaseStrategy {
contract AuraBalStakerStrategy is BaseStrategy {
using SafeMathUpgradeable for uint256;
using SafeMathUpgradeable for uint256;
using SafeERC20Upgradeable for IERC20Upgradeable;
using SafeERC20Upgradeable for IERC20Upgradeable;
bool public claimRewardsOnWithdrawAll;
bool public claimRewardsOnWithdrawAll;
uint256 public balEthBptToAuraBalMinOutBps;
uint256 public balEthBptToAuraBalMinOutBps;
IBaseRewardPool public constant AURABAL_REWARDS =
IBaseRewardPool public constant AURABAL_REWARDS =
IBaseRewardPool(0x5e5ea2048475854a5702F5B8468A51Ba1296EFcC);
IBaseRewardPool(0x5e5ea2048475854a5702F5B8468A51Ba1296EFcC);
IVault public constant GRAVIAURA =
IVault public constant GRAVIAURA =
IVault(0xBA485b556399123261a5F9c95d413B4f93107407);
IVault(0xBA485b556399123261a5F9c95d413B4f93107407);
IBalancerVault public constant BALANCER_VAULT =
IBalancerVault public constant BALANCER_VAULT =
IBalancerVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8);
IBalancerVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8);
IAuraToken public constant AURA =
IAuraToken public constant AURA =
IAuraToken(0xC0c293ce456fF0ED870ADd98a0828Dd4d2903DBF);
IAuraToken(0xC0c293ce456fF0ED870ADd98a0828Dd4d2903DBF);
IERC20Upgradeable public constant AURABAL =
IERC20Upgradeable public constant AURABAL =
IERC20Upgradeable(0x616e8BfA43F920657B3497DBf40D6b1A02D4608d);
IERC20Upgradeable(0x616e8BfA43F920657B3497DBf40D6b1A02D4608d);
IERC20Upgradeable public constant WETH =
IERC20Upgradeable public constant WETH =
IERC20Upgradeable(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
IERC20Upgradeable(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
IERC20Upgradeable public constant BAL =
IERC20Upgradeable public constant BAL =
IERC20Upgradeable(0xba100000625a3754423978a60c9317c58a424e3D);
IERC20Upgradeable(0xba100000625a3754423978a60c9317c58a424e3D);
IERC20Upgradeable public constant BALETH_BPT =
IERC20Upgradeable public constant BALETH_BPT =
IERC20Upgradeable(0x5c6Ee304399DBdB9C8Ef030aB642B10820DB8F56);
IERC20Upgradeable(0x5c6Ee304399DBdB9C8Ef030aB642B10820DB8F56);
IERC20Upgradeable public constant BB_A_USD =
IERC20Upgradeable public constant BB_A_USD =
IERC20Upgradeable(0x7B50775383d3D6f0215A8F290f2C9e2eEBBEceb2);
IERC20Upgradeable(0x7B50775383d3D6f0215A8F290f2C9e2eEBBEceb2);
bytes32 public constant BAL_ETH_POOL_ID =
bytes32 public constant BAL_ETH_POOL_ID =
0x5c6ee304399dbdb9c8ef030ab642b10820db8f56000200000000000000000014;
0x5c6ee304399dbdb9c8ef030ab642b10820db8f56000200000000000000000014;
bytes32 public constant AURABAL_BALETH_BPT_POOL_ID =
bytes32 public constant AURABAL_BALETH_BPT_POOL_ID =
0x3dd0843a028c86e0b760b1a76929d1c5ef93a2dd000200000000000000000249;
0x3dd0843a028c86e0b760b1a76929d1c5ef93a2dd000200000000000000000249;
/// @dev Initialize the Strategy with security settings as well as tokens
/// @dev Initialize the Strategy with security settings as well as tokens
/// @notice Proxies will set any non constant variable you declare as default value
/// @notice Proxies will set any non constant variable you declare as default value
/// @dev add any extra changeable variable at end of initializer as shown
/// @dev add any extra changeable variable at end of initializer as shown
function initialize(address _vault) public initializer {
function initialize(address _vault) public initializer {
require(IVault(_vault).token() == address(AURABAL));
require(IVault(_vault).token() == address(AURABAL));
__BaseStrategy_init(_vault);
__BaseStrategy_init(_vault);
want = address(AURABAL);
want = address(AURABAL);
claimRewardsOnWithdrawAll = true;
claimRewardsOnWithdrawAll = true;
balEthBptToAuraBalMinOutBps = 9500; // max 5% slippage
balEthBptToAuraBalMinOutBps = 9500; // max 5% slippage
AURABAL.safeApprove(address(AURABAL_REWARDS), type(uint256).max);
AURABAL.safeApprove(address(AURABAL_REWARDS), type(uint256).max);
BAL.safeApprove(address(BALANCER_VAULT), type(uint256).max);
BAL.safeApprove(address(BALANCER_VAULT), type(uint256).max);
BALETH_BPT.safeApprove(address(BALANCER_VAULT), type(uint256).max);
BALETH_BPT.safeApprove(address(BALANCER_VAULT), type(uint256).max);
AURA.approve(address(GRAVIAURA), type(uint256).max);
AURA.approve(address(GRAVIAURA), type(uint256).max);
}
}
function setClaimRewardsOnWithdrawAll(bool _claimRewardsOnWithdrawAll)
function setClaimRewardsOnWithdrawAll(bool _claimRewardsOnWithdrawAll)
external
external
{
{
_onlyGovernanceOrStrategist();
_onlyGovernanceOrStrategist();
claimRewardsOnWithdrawAll = _claimRewardsOnWithdrawAll;
claimRewardsOnWithdrawAll = _claimRewardsOnWithdrawAll;
}
}
function setBalEthBptToAuraBalMinOutBps(uint256 _minOutBps) external {
function setBalEthBptToAuraBalMinOutBps(uint256 _minOutBps) external {
_onlyGovernanceOrStrategist();
_onlyGovernanceOrStrategist();
require(_minOutBps <= MAX_BPS, "Invalid minOutBps");
require(_minOutBps <= MAX_BPS, "Invalid minOutBps");
balEthBptToAuraBalMinOutBps = _minOutBps;
balEthBptToAuraBalMinOutBps = _minOutBps;
}
}
/// @dev Return the name of the strategy
/// @dev Return the name of the strategy
function getName() external pure override returns (string memory) {
function getName() external pure override returns (string memory) {
return "AuraBalStakerStrategy";
return "AuraBalStakerStrategy";
}
}
/// @dev Return a list of protected tokens
/// @dev Return a list of protected tokens
/// @notice It's very important all tokens that are meant to be in the strategy to be marked as protected
/// @notice It's very important all tokens that are meant to be in the strategy to be marked as protected
/// @notice this provides security guarantees to the depositors they can't be sweeped away
/// @notice this provides security guarantees to the depositors they can't be sweeped away
function getProtectedTokens()
function getProtectedTokens()
public
public
view
view
virtual
virtual
override
override
returns (address[] memory)
returns (address[] memory)
{
{
address[] memory protectedTokens = new address[](3);
address[] memory protectedTokens = new address[](3);
protectedTokens[0] = want; // AURABAL
protectedTokens[0] = want; // AURABAL
protectedTokens[1] = address(AURA);
protectedTokens[1] = address(AURA);
protectedTokens[2] = address(BAL);
protectedTokens[2] = address(BAL);
return protectedTokens;
return protectedTokens;
}
}
/// @dev Deposit `_amount` of want, investing it to earn yield
/// @dev Deposit `_amount` of want, investing it to earn yield
function _deposit(uint256 _amount) internal override {
function _deposit(uint256 _amount) internal override {
// Add code here to invest `_amount` of want to earn yield
// Add code here to invest `_amount` of want to earn yield
AURABAL_REWARDS.stake(_amount);
AURABAL_REWARDS.stake(_amount);
}
}
/// @dev Withdraw all funds, this is used for migrations, most of the time for emergency reasons
/// @dev Withdraw all funds, this is used for migrations, most of the time for emergency reasons
function _withdrawAll() internal override {
function _withdrawAll() internal override {
uint256 poolBalance = balanceOfPool();
uint256 poolBalance = balanceOfPool();
if (poolBalance > 0) {
if (poolBalance > 0) {
AURABAL_REWARDS.withdrawAll(claimRewardsOnWithdrawAll);
AURABAL_REWARDS.withdrawAll(claimRewardsOnWithdrawAll);
}
}
}
}
/// @dev Withdraw `_amount` of want, so that it can be sent to the vault / depositor
/// @dev Withdraw `_amount` of want, so that it can be sent to the vault / depositor
/// @notice just unlock the funds and return the amount you could unlock
/// @notice just unlock the funds and return the amount you could unlock
function _withdrawSome(uint256 _amount)
function _withdrawSome(uint256 _amount)
internal
internal
override
override
returns (uint256)
returns (uint256)
{
{
uint256 wantBalance = balanceOfWant();
uint256 wantBalance = balanceOfWant();
if (wantBalance < _amount) {
if (wantBalance < _amount) {
uint256 toWithdraw = _amount.sub(wantBalance);
uint256 toWithdraw = _amount.sub(wantBalance);
AURABAL_REWARDS.withdraw(toWithdraw, false);
AURABAL_REWARDS.withdraw(toWithdraw, false);
}
}
return MathUpgradeable.min(_amount, balanceOfWant());
return MathUpgradeable.min(_amount, balanceOfWant());
}
}
/// @dev Does this function require `tend` to be called?
/// @dev Does this function require `tend` to be called?
function _isTendable() internal pure override returns (bool) {
function _isTendable() internal pure override returns (bool) {
return false; // Change to true if the strategy should be tended
return false; // Change to true if the strategy should be tended
}
}
function _harvest()
function _harvest()
internal
internal
override
override
returns (TokenAmount[] memory harvested)
returns (TokenAmount[] memory harvested)
{
{
AURABAL_REWARDS.getReward();
AURABAL_REWARDS.getReward();
// Rewards are handled like this:
// Rewards are handled like this:
// BAL --> BAL/ETH BPT --> AURABAL (autocompounded)
// BAL --> BAL/ETH BPT --> AURABAL (autocompounded)
// AURA --> GRAVIAURA (emitted)
// AURA --> GRAVIAURA (emitted)
// BB_A_USD --> Left in strategy to be sweeped later
// BB_A_USD --> Left in strategy to be sweeped later
harvested = new TokenAmount[](2);
harvested = new TokenAmount[](2);
harvested[0].token = address(AURABAL);
harvested[0].token = address(AURABAL);
harvested[1].token = address(GRAVIAURA);
harvested[1].token = address(GRAVIAURA);
// BAL --> BAL/ETH BPT --> AURABAL
// BAL --> BAL/ETH BPT --> AURABAL
uint256 balBalance = BAL.balanceOf(address(this));
uint256 balBalance = BAL.balanceOf(address(this));
uint256 auraBalEarned;
uint256 auraBalEarned;
if (balBalance > 0) {
if (balBalance > 0) {
// Deposit BAL --> BAL/ETH BPT
// Deposit BAL --> BAL/ETH BPT
IAsset[] memory assets = new IAsset[](2);
IAsset[] memory assets = new IAsset[](2);
assets[0] = IAsset(address(BAL));
assets[0] = IAsset(address(BAL));
assets[1] = IAsset(address(WETH));
assets[1] = IAsset(address(WETH));
uint256[] memory maxAmountsIn = new uint256[](2);
uint256[] memory maxAmountsIn = new uint256[](2);
maxAmountsIn[0] = balBalance;
maxAmountsIn[0] = balBalance;
maxAmountsIn[1] = 0;
maxAmountsIn[1] = 0;
BALANCER_VAULT.joinPool(
BALANCER_VAULT.joinPool(
BAL_ETH_POOL_ID,
BAL_ETH_POOL_ID,
address(this),
address(this),
address(this),
address(this),
IBalancerVault.JoinPoolRequest({
IBalancerVault.JoinPoolRequest({
assets: assets,
assets: assets,
maxAmountsIn: maxAmountsIn,
maxAmountsIn: maxAmountsIn,
userData: abi.encode(
userData: abi.encode(
JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT,
JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT,
maxAmountsIn,
maxAmountsIn,
0 // minOut
0 // minOut
),
),
fromInternalBalance: false
fromInternalBalance: false
})
})
);
);
// Swap BAL/ETH BPT --> AURABAL
// Swap BAL/ETH BPT --> AURABAL
uint256 balEthBptBalance = IERC20Upgradeable(BALETH_BPT).balanceOf(
uint256 balEthBptBalance = IERC20Upgradeable(BALETH_BPT).balanceOf(
address(this)
address(this)
);
);
// Swap BAL/ETH BPT --> auraBal
// Swap BAL/ETH BPT --> auraBal
IBalancerVault.FundManagement memory fundManagement = IBalancerVault
IBalancerVault.FundManagement memory fundManagement = IBalancerVault
.FundManagement({
.FundManagement({
sender: address(this),
sender: address(this),
fromInternalBalance: false,
fromInternalBalance: false,
recipient: payable(address(this)),
recipient: payable(address(this)),
toInternalBalance: false
toInternalBalance: false
});
});
IBalancerVault.SingleSwap memory singleSwap = IBalancerVault
IBalancerVault.SingleSwap memory singleSwap = IBalancerVault
.SingleSwap({
.SingleSwap({
poolId: AURABAL_BALETH_BPT_POOL_ID,
poolId: AURABAL_BALETH_BPT_POOL_ID,
kind: IBalancerVault.SwapKind.GIVEN_IN,
kind: IBalancerVault.SwapKind.GIVEN_IN,
assetIn: IAsset(address(BALETH_BPT)),
assetIn: IAsset(address(BALETH_BPT)),
assetOut: IAsset(address(AURABAL)),
assetOut: IAsset(address(AURABAL)),
amount: balEthBptBalance,
amount: balEthBptBalance,
userData: new bytes(0)
userData: new bytes(0)
});
});
uint256 minOut = (balEthBptBalance * balEthBptToAuraBalMinOutBps) /
uint256 minOut = (balEthBptBalance * balEthBptToAuraBalMinOutBps) /
MAX_BPS;
MAX_BPS;
auraBalEarned = BALANCER_VAULT.swap(
auraBalEarned = BALANCER_VAULT.swap(
singleSwap,
singleSwap,
fundManagement,
fundManagement,
minOut,
minOut,
type(uint256).max
type(uint256).max
);
);
harvested[0].amount = auraBalEarned;
harvested[0].amount = auraBalEarned;
}
}
// AURA --> graviAURA
// AURA --> graviAURA
uint256 auraBalance = AURA.balanceOf(address(this));
uint256 auraBalance = AURA.balanceOf(address(this));
if (auraBalance > 0) {
if (auraBalance > 0) {
GRAVIAURA.deposit(auraBalance);
GRAVIAURA.deposit(auraBalance);
uint256 graviAuraBalance = GRAVIAURA.balanceOf(address(this));
uint256 graviAuraBalance = GRAVIAURA.balanceOf(address(this));
harvested[1].amount = graviAuraBalance;
harvested[1].amount = graviAuraBalance;
_processExtraToken(address(GRAVIAURA), graviAuraBalance);
_processExtraToken(address(GRAVIAURA), graviAuraBalance);
}
}
// Report harvest
// Report harvest
_reportToVault(auraBalEarned);
_reportToVault(auraBalEarned);
// Stake whatever is earned
// Stake whatever is earned
if (auraBalEarned > 0) {
if (auraBalEarned > 0) {
_deposit(auraBalEarned);
_deposit(auraBalEarned);
}
}
}
}
// Example tend is a no-op which returns the values, could also just revert
// Example tend is a no-op which returns the values, could also just revert
function _tend() internal override returns (TokenAmount[] memory tended) {
function _tend() internal override returns (TokenAmount[] memory tended) {
revert("no op");
revert("no op");
}
}
/// @dev Return the balance (in want) that the strategy has invested somewhere
/// @dev Return the balance (in want) that the strategy has invested somewhere
function balanceOfPool() public view override returns (uint256) {
function balanceOfPool() public view override returns (uint256) {
// Change this to return the amount of want invested in another protocol
// Change this to return the amount of want invested in another protocol
return AURABAL_REWARDS.balanceOf(address(this));
return AURABAL_REWARDS.balanceOf(address(this));
}
}
/// @dev Return the balance of rewards that the strategy has accrued
/// @dev Return the balance of rewards that the strategy has accrued
/// @notice Used for offChain APY and Harvest Health monitoring
/// @notice Used for offChain APY and Harvest Health monitoring
function balanceOfRewards()
function balanceOfRewards()
external
external
view
view
override
override
returns (TokenAmount[] memory rewards)
returns (TokenAmount[] memory rewards)
{
{
uint256 balEarned = AURABAL_REWARDS.earned(address(this));
uint256 balEarned = AURABAL_REWARDS.earned(address(this));
rewards = new TokenAmount[](2);
rewards = new TokenAmount[](2);
rewards[0] = TokenAmount(address(BAL), balEarned);
rewards[0] = TokenAmount(address(BAL), balEarned);
rewards[1] = TokenAmount(
rewards[1] = TokenAmount(
address(AURA),
address(AURA),
getMintableAuraRewards(balEarned)
getMintableAuraRewards(balEarned)
);
);
}
}
/// @notice Returns the expected amount of AURA to be minted given an amount of BAL rewards
/// @notice Returns the expected amount of AURA to be minted given an amount of BAL rewards
/// @dev ref: https://etherscan.io/address/0xc0c293ce456ff0ed870add98a0828dd4d2903dbf#code#F1#L86
/// @dev ref: https://etherscan.io/address/0xc0c293ce456ff0ed870add98a0828dd4d2903dbf#code#F1#L86
function getMintableAuraRewards(uint256 _balAmount)
function getMintableAuraRewards(uint256 _balAmount)
public
public
view
view
returns (uint256 amount)
returns (uint256 amount)
{
{
// NOTE: Only correct if AURA.minterMinted() == 0
// NOTE: Only correct if AURA.minterMinted() == 0
// minterMinted is a private var in the contract, so we can't access it directly
// minterMinted is a private var in the contract, so we can't access it directly
uint256 emissionsMinted = AURA.totalSupply() - AURA.INIT_MINT_AMOUNT();
uint256 emissionsMinted = AURA.totalSupply() - AURA.INIT_MINT_AMOUNT();
uint256 cliff = emissionsMinted.div(AURA.reductionPerCliff());
uint256 cliff = emissionsMinted.div(AURA.reductionPerCliff());
uint256 totalCliffs = AURA.totalCliffs();
uint256 totalCliffs = AURA.totalCliffs();
if (cliff < totalCliffs) {
if (cliff < totalCliffs) {
uint256 reduction = totalCliffs.sub(cliff).mul(5).div(2).add(700);
uint256 reduction = totalCliffs.sub(cliff).mul(5).div(2).add(700);
amount = _balAmount.mul(reduction).div(totalCliffs);
amount = _balAmount.mul(reduction).div(totalCliffs);
uint256 amtTillMax = AURA.EMISSIONS_MAX_SUPPLY().sub(
uint256 amtTillMax = AURA.EMISSIONS_MAX_SUPPLY().sub(
emissionsMinted
emissionsMinted
);
);
if (amount > amtTillMax) {
if (amount > amtTillMax) {
amount = amtTillMax;
amount = amtTillMax;
}
}
}
}
}
}
}
}
Saved diffs
Original text
Open file
contract AuraBalStakerStrategy is BaseStrategy { using SafeMathUpgradeable for uint256; using SafeERC20Upgradeable for IERC20Upgradeable; bool public claimRewardsOnWithdrawAll; uint256 public balEthBptToAuraBalMinOutBps; IBaseRewardPool public constant AURABAL_REWARDS = IBaseRewardPool(0x5e5ea2048475854a5702F5B8468A51Ba1296EFcC); IVault public constant GRAVIAURA = IVault(0xBA485b556399123261a5F9c95d413B4f93107407); IBalancerVault public constant BALANCER_VAULT = IBalancerVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8); IAuraToken public constant AURA = IAuraToken(0xC0c293ce456fF0ED870ADd98a0828Dd4d2903DBF); IERC20Upgradeable public constant AURABAL = IERC20Upgradeable(0x616e8BfA43F920657B3497DBf40D6b1A02D4608d); IERC20Upgradeable public constant WETH = IERC20Upgradeable(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); IERC20Upgradeable public constant BAL = IERC20Upgradeable(0xba100000625a3754423978a60c9317c58a424e3D); IERC20Upgradeable public constant BALETH_BPT = IERC20Upgradeable(0x5c6Ee304399DBdB9C8Ef030aB642B10820DB8F56); IERC20Upgradeable public constant BB_A_USD = IERC20Upgradeable(0x7B50775383d3D6f0215A8F290f2C9e2eEBBEceb2); bytes32 public constant BAL_ETH_POOL_ID = 0x5c6ee304399dbdb9c8ef030ab642b10820db8f56000200000000000000000014; bytes32 public constant AURABAL_BALETH_BPT_POOL_ID = 0x3dd0843a028c86e0b760b1a76929d1c5ef93a2dd000200000000000000000249; /// @dev Initialize the Strategy with security settings as well as tokens /// @notice Proxies will set any non constant variable you declare as default value /// @dev add any extra changeable variable at end of initializer as shown function initialize(address _vault) public initializer { require(IVault(_vault).token() == address(AURABAL)); __BaseStrategy_init(_vault); want = address(AURABAL); claimRewardsOnWithdrawAll = true; balEthBptToAuraBalMinOutBps = 9500; // max 5% slippage AURABAL.safeApprove(address(AURABAL_REWARDS), type(uint256).max); BAL.safeApprove(address(BALANCER_VAULT), type(uint256).max); BALETH_BPT.safeApprove(address(BALANCER_VAULT), type(uint256).max); AURA.approve(address(GRAVIAURA), type(uint256).max); } function setClaimRewardsOnWithdrawAll(bool _claimRewardsOnWithdrawAll) external { _onlyGovernanceOrStrategist(); claimRewardsOnWithdrawAll = _claimRewardsOnWithdrawAll; } function setBalEthBptToAuraBalMinOutBps(uint256 _minOutBps) external { _onlyGovernanceOrStrategist(); require(_minOutBps <= MAX_BPS, "Invalid minOutBps"); balEthBptToAuraBalMinOutBps = _minOutBps; } /// @dev Return the name of the strategy function getName() external pure override returns (string memory) { return "AuraBalStakerStrategy"; } /// @dev Return a list of protected tokens /// @notice It's very important all tokens that are meant to be in the strategy to be marked as protected /// @notice this provides security guarantees to the depositors they can't be sweeped away function getProtectedTokens() public view virtual override returns (address[] memory) { address[] memory protectedTokens = new address[](3); protectedTokens[0] = want; // AURABAL protectedTokens[1] = address(AURA); protectedTokens[2] = address(BAL); return protectedTokens; } /// @dev Deposit `_amount` of want, investing it to earn yield function _deposit(uint256 _amount) internal override { // Add code here to invest `_amount` of want to earn yield AURABAL_REWARDS.stake(_amount); } /// @dev Withdraw all funds, this is used for migrations, most of the time for emergency reasons function _withdrawAll() internal override { uint256 poolBalance = balanceOfPool(); if (poolBalance > 0) { AURABAL_REWARDS.withdrawAll(claimRewardsOnWithdrawAll); } } /// @dev Withdraw `_amount` of want, so that it can be sent to the vault / depositor /// @notice just unlock the funds and return the amount you could unlock function _withdrawSome(uint256 _amount) internal override returns (uint256) { uint256 wantBalance = balanceOfWant(); if (wantBalance < _amount) { uint256 toWithdraw = _amount.sub(wantBalance); AURABAL_REWARDS.withdraw(toWithdraw, false); } return MathUpgradeable.min(_amount, balanceOfWant()); } /// @dev Does this function require `tend` to be called? function _isTendable() internal pure override returns (bool) { return false; // Change to true if the strategy should be tended } function _harvest() internal override returns (TokenAmount[] memory harvested) { AURABAL_REWARDS.getReward(); // Rewards are handled like this: // BAL --> BAL/ETH BPT --> AURABAL (autocompounded) // AURA --> GRAVIAURA (emitted) // BB_A_USD --> Left in strategy to be sweeped later harvested = new TokenAmount[](2); harvested[0].token = address(AURABAL); harvested[1].token = address(GRAVIAURA); // BAL --> BAL/ETH BPT --> AURABAL uint256 balBalance = BAL.balanceOf(address(this)); uint256 auraBalEarned; if (balBalance > 0) { // Deposit BAL --> BAL/ETH BPT IAsset[] memory assets = new IAsset[](2); assets[0] = IAsset(address(BAL)); assets[1] = IAsset(address(WETH)); uint256[] memory maxAmountsIn = new uint256[](2); maxAmountsIn[0] = balBalance; maxAmountsIn[1] = 0; BALANCER_VAULT.joinPool( BAL_ETH_POOL_ID, address(this), address(this), IBalancerVault.JoinPoolRequest({ assets: assets, maxAmountsIn: maxAmountsIn, userData: abi.encode( JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT, maxAmountsIn, 0 // minOut ), fromInternalBalance: false }) ); // Swap BAL/ETH BPT --> AURABAL uint256 balEthBptBalance = IERC20Upgradeable(BALETH_BPT).balanceOf( address(this) ); // Swap BAL/ETH BPT --> auraBal IBalancerVault.FundManagement memory fundManagement = IBalancerVault .FundManagement({ sender: address(this), fromInternalBalance: false, recipient: payable(address(this)), toInternalBalance: false }); IBalancerVault.SingleSwap memory singleSwap = IBalancerVault .SingleSwap({ poolId: AURABAL_BALETH_BPT_POOL_ID, kind: IBalancerVault.SwapKind.GIVEN_IN, assetIn: IAsset(address(BALETH_BPT)), assetOut: IAsset(address(AURABAL)), amount: balEthBptBalance, userData: new bytes(0) }); uint256 minOut = (balEthBptBalance * balEthBptToAuraBalMinOutBps) / MAX_BPS; auraBalEarned = BALANCER_VAULT.swap( singleSwap, fundManagement, minOut, type(uint256).max ); harvested[0].amount = auraBalEarned; } // AURA --> graviAURA uint256 auraBalance = AURA.balanceOf(address(this)); if (auraBalance > 0) { GRAVIAURA.deposit(auraBalance); uint256 graviAuraBalance = GRAVIAURA.balanceOf(address(this)); harvested[1].amount = graviAuraBalance; _processExtraToken(address(GRAVIAURA), graviAuraBalance); } // Report harvest _reportToVault(auraBalEarned); // Stake whatever is earned if (auraBalEarned > 0) { _deposit(auraBalEarned); } } // Example tend is a no-op which returns the values, could also just revert function _tend() internal override returns (TokenAmount[] memory tended) { revert("no op"); } /// @dev Return the balance (in want) that the strategy has invested somewhere function balanceOfPool() public view override returns (uint256) { // Change this to return the amount of want invested in another protocol return AURABAL_REWARDS.balanceOf(address(this)); } /// @dev Return the balance of rewards that the strategy has accrued /// @notice Used for offChain APY and Harvest Health monitoring function balanceOfRewards() external view override returns (TokenAmount[] memory rewards) { uint256 balEarned = AURABAL_REWARDS.earned(address(this)); rewards = new TokenAmount[](2); rewards[0] = TokenAmount(address(BAL), balEarned); rewards[1] = TokenAmount( address(AURA), getMintableAuraRewards(balEarned) ); } /// @notice Returns the expected amount of AURA to be minted given an amount of BAL rewards /// @dev ref: https://etherscan.io/address/0xc0c293ce456ff0ed870add98a0828dd4d2903dbf#code#F1#L86 function getMintableAuraRewards(uint256 _balAmount) public view returns (uint256 amount) { // NOTE: Only correct if AURA.minterMinted() == 0 // minterMinted is a private var in the contract, so we can't access it directly uint256 emissionsMinted = AURA.totalSupply() - AURA.INIT_MINT_AMOUNT(); uint256 cliff = emissionsMinted.div(AURA.reductionPerCliff()); uint256 totalCliffs = AURA.totalCliffs(); if (cliff < totalCliffs) { uint256 reduction = totalCliffs.sub(cliff).mul(5).div(2).add(700); amount = _balAmount.mul(reduction).div(totalCliffs); uint256 amtTillMax = AURA.EMISSIONS_MAX_SUPPLY().sub( emissionsMinted ); if (amount > amtTillMax) { amount = amtTillMax; } } } }
Changed text
Open file
contract AuraBalStakerStrategy is BaseStrategy { using SafeMathUpgradeable for uint256; using SafeERC20Upgradeable for IERC20Upgradeable; bool public claimRewardsOnWithdrawAll; uint256 public balEthBptToAuraBalMinOutBps; IBaseRewardPool public constant AURABAL_REWARDS = IBaseRewardPool(0x5e5ea2048475854a5702F5B8468A51Ba1296EFcC); IVault public constant GRAVIAURA = IVault(0xBA485b556399123261a5F9c95d413B4f93107407); IBalancerVault public constant BALANCER_VAULT = IBalancerVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8); IAuraToken public constant AURA = IAuraToken(0xC0c293ce456fF0ED870ADd98a0828Dd4d2903DBF); IERC20Upgradeable public constant AURABAL = IERC20Upgradeable(0x616e8BfA43F920657B3497DBf40D6b1A02D4608d); IERC20Upgradeable public constant WETH = IERC20Upgradeable(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); IERC20Upgradeable public constant BAL = IERC20Upgradeable(0xba100000625a3754423978a60c9317c58a424e3D); IERC20Upgradeable public constant BALETH_BPT = IERC20Upgradeable(0x5c6Ee304399DBdB9C8Ef030aB642B10820DB8F56); IERC20Upgradeable public constant BB_A_USD = IERC20Upgradeable(0x7B50775383d3D6f0215A8F290f2C9e2eEBBEceb2); bytes32 public constant BAL_ETH_POOL_ID = 0x5c6ee304399dbdb9c8ef030ab642b10820db8f56000200000000000000000014; bytes32 public constant AURABAL_BALETH_BPT_POOL_ID = 0x3dd0843a028c86e0b760b1a76929d1c5ef93a2dd000200000000000000000249; /// @dev Initialize the Strategy with security settings as well as tokens /// @notice Proxies will set any non constant variable you declare as default value /// @dev add any extra changeable variable at end of initializer as shown function initialize(address _vault) public initializer { require(IVault(_vault).token() == address(AURABAL)); __BaseStrategy_init(_vault); want = address(AURABAL); claimRewardsOnWithdrawAll = true; balEthBptToAuraBalMinOutBps = 9500; // max 5% slippage AURABAL.safeApprove(address(AURABAL_REWARDS), type(uint256).max); BAL.safeApprove(address(BALANCER_VAULT), type(uint256).max); BALETH_BPT.safeApprove(address(BALANCER_VAULT), type(uint256).max); AURA.approve(address(GRAVIAURA), type(uint256).max); } function setClaimRewardsOnWithdrawAll(bool _claimRewardsOnWithdrawAll) external { _onlyGovernanceOrStrategist(); claimRewardsOnWithdrawAll = _claimRewardsOnWithdrawAll; } function setBalEthBptToAuraBalMinOutBps(uint256 _minOutBps) external { _onlyGovernanceOrStrategist(); require(_minOutBps <= MAX_BPS, "Invalid minOutBps"); balEthBptToAuraBalMinOutBps = _minOutBps; } /// @dev Return the name of the strategy function getName() external pure override returns (string memory) { return "AuraBalStakerStrategy"; } /// @dev Return a list of protected tokens /// @notice It's very important all tokens that are meant to be in the strategy to be marked as protected /// @notice this provides security guarantees to the depositors they can't be sweeped away function getProtectedTokens() public view virtual override returns (address[] memory) { address[] memory protectedTokens = new address[](3); protectedTokens[0] = want; // AURABAL protectedTokens[1] = address(AURA); protectedTokens[2] = address(BAL); return protectedTokens; } /// @dev Deposit `_amount` of want, investing it to earn yield function _deposit(uint256 _amount) internal override { // Add code here to invest `_amount` of want to earn yield AURABAL_REWARDS.stake(_amount); } /// @dev Withdraw all funds, this is used for migrations, most of the time for emergency reasons function _withdrawAll() internal override { uint256 poolBalance = balanceOfPool(); if (poolBalance > 0) { AURABAL_REWARDS.withdrawAll(claimRewardsOnWithdrawAll); } } /// @dev Withdraw `_amount` of want, so that it can be sent to the vault / depositor /// @notice just unlock the funds and return the amount you could unlock function _withdrawSome(uint256 _amount) internal override returns (uint256) { uint256 wantBalance = balanceOfWant(); if (wantBalance < _amount) { uint256 toWithdraw = _amount.sub(wantBalance); AURABAL_REWARDS.withdraw(toWithdraw, false); } return MathUpgradeable.min(_amount, balanceOfWant()); } /// @dev Does this function require `tend` to be called? function _isTendable() internal pure override returns (bool) { return false; // Change to true if the strategy should be tended } function _harvest() internal override returns (TokenAmount[] memory harvested) { AURABAL_REWARDS.getReward(); // Rewards are handled like this: // BAL --> BAL/ETH BPT --> AURABAL (autocompounded) // AURA --> GRAVIAURA (emitted) // BB_A_USD --> Left in strategy to be sweeped later harvested = new TokenAmount[](2); harvested[0].token = address(AURABAL); harvested[1].token = address(GRAVIAURA); // BAL --> BAL/ETH BPT --> AURABAL uint256 balBalance = BAL.balanceOf(address(this)); uint256 auraBalEarned; if (balBalance > 0) { // Deposit BAL --> BAL/ETH BPT IAsset[] memory assets = new IAsset[](2); assets[0] = IAsset(address(BAL)); assets[1] = IAsset(address(WETH)); uint256[] memory maxAmountsIn = new uint256[](2); maxAmountsIn[0] = balBalance; maxAmountsIn[1] = 0; BALANCER_VAULT.joinPool( BAL_ETH_POOL_ID, address(this), address(this), IBalancerVault.JoinPoolRequest({ assets: assets, maxAmountsIn: maxAmountsIn, userData: abi.encode( JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT, maxAmountsIn, 0 // minOut ), fromInternalBalance: false }) ); // Swap BAL/ETH BPT --> AURABAL uint256 balEthBptBalance = IERC20Upgradeable(BALETH_BPT).balanceOf( address(this) ); // Swap BAL/ETH BPT --> auraBal IBalancerVault.FundManagement memory fundManagement = IBalancerVault .FundManagement({ sender: address(this), fromInternalBalance: false, recipient: payable(address(this)), toInternalBalance: false }); IBalancerVault.SingleSwap memory singleSwap = IBalancerVault .SingleSwap({ poolId: AURABAL_BALETH_BPT_POOL_ID, kind: IBalancerVault.SwapKind.GIVEN_IN, assetIn: IAsset(address(BALETH_BPT)), assetOut: IAsset(address(AURABAL)), amount: balEthBptBalance, userData: new bytes(0) }); uint256 minOut = (balEthBptBalance * balEthBptToAuraBalMinOutBps) / MAX_BPS; auraBalEarned = BALANCER_VAULT.swap( singleSwap, fundManagement, minOut, type(uint256).max ); harvested[0].amount = auraBalEarned; } // AURA --> graviAURA uint256 auraBalance = AURA.balanceOf(address(this)); if (auraBalance > 0) { GRAVIAURA.deposit(auraBalance); uint256 graviAuraBalance = GRAVIAURA.balanceOf(address(this)); harvested[1].amount = graviAuraBalance; _processExtraToken(address(GRAVIAURA), graviAuraBalance); } // Report harvest _reportToVault(auraBalEarned); // Stake whatever is earned if (auraBalEarned > 0) { _deposit(auraBalEarned); } } // Example tend is a no-op which returns the values, could also just revert function _tend() internal override returns (TokenAmount[] memory tended) { revert("no op"); } /// @dev Return the balance (in want) that the strategy has invested somewhere function balanceOfPool() public view override returns (uint256) { // Change this to return the amount of want invested in another protocol return AURABAL_REWARDS.balanceOf(address(this)); } /// @dev Return the balance of rewards that the strategy has accrued /// @notice Used for offChain APY and Harvest Health monitoring function balanceOfRewards() external view override returns (TokenAmount[] memory rewards) { uint256 balEarned = AURABAL_REWARDS.earned(address(this)); rewards = new TokenAmount[](2); rewards[0] = TokenAmount(address(BAL), balEarned); rewards[1] = TokenAmount( address(AURA), getMintableAuraRewards(balEarned) ); } /// @notice Returns the expected amount of AURA to be minted given an amount of BAL rewards /// @dev ref: https://etherscan.io/address/0xc0c293ce456ff0ed870add98a0828dd4d2903dbf#code#F1#L86 function getMintableAuraRewards(uint256 _balAmount) public view returns (uint256 amount) { // NOTE: Only correct if AURA.minterMinted() == 0 // minterMinted is a private var in the contract, so we can't access it directly uint256 emissionsMinted = AURA.totalSupply() - AURA.INIT_MINT_AMOUNT(); uint256 cliff = emissionsMinted.div(AURA.reductionPerCliff()); uint256 totalCliffs = AURA.totalCliffs(); if (cliff < totalCliffs) { uint256 reduction = totalCliffs.sub(cliff).mul(5).div(2).add(700); amount = _balAmount.mul(reduction).div(totalCliffs); uint256 amtTillMax = AURA.EMISSIONS_MAX_SUPPLY().sub( emissionsMinted ); if (amount > amtTillMax) { amount = amtTillMax; } } } }
Find difference