Diff
checker
Text
Text
Bilder
Dokumente
Excel
Ordner
Legal
Enterprise
Desktop-App
Preise
Einloggen
Diffchecker Desktop herunterladen
Texte vergleichen
Finde den Unterschied zwischen zwei Textdateien
Werkzeuge
Verlauf
Live-Editor
Gleiches ausblenden
Zeilenumbruch aus
Ansicht
Zweispaltig
Einspaltig
Vergleichsgenauigkeit
Intelligent
Wort
Zeichen
Syntaxhervorhebung
Syntax auswählen
Ignorieren
Text umwandeln
Zur ersten Änderung
Eingabe bearbeiten
Diffchecker Desktop
Der sicherste Weg, Diffchecker zu nutzen. Hol dir die Desktop-App: Deine Diffs verlassen nie deinen Computer!
Desktop holen
auraBal
Erstellt
vor 4 Jahren
Diff läuft nie ab
Löschen
Exportieren
Teilen
Die beiden Texte sind identisch
Es gibt keinen Unterschied zwischen diesen beiden Texten
0 Entfernungen
Zeilen
Gesamt
Entfernt
Zeichen
Gesamt
Entfernt
Um diese Funktion weiterhin zu nutzen, aktualisiere auf
Diff
checker
Pro
Preise anzeigen
278 Zeilen
Kopieren
0 Hinzufügungen
Zeilen
Gesamt
Hinzugefügt
Zeichen
Gesamt
Hinzugefügt
Um diese Funktion weiterhin zu nutzen, aktualisiere auf
Diff
checker
Pro
Preise anzeigen
278 Zeilen
Kopieren
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;
}
}
}
}
}
}
}
}
Gespeicherte Diffs
Originaltext
Datei öffnen
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; } } } }
Bearbeitung
Datei öffnen
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; } } } }
Unterschied finden