Diff
checker
文本
文本
圖像
文檔
Excel
文件夾
Legal
Enterprise
桌面版
定價
登入
下載 Diffchecker 桌面版
比較文本
尋找兩個文字檔案之間的差異
工具
歷史
即時編輯器
摺疊未變更行
關閉換行
檢視
拆分
統一
比對精度
智能
單詞
字符
語法突出顯示
選擇語法
忽略
文字轉換
前往第一個差異
編輯輸入
Diffchecker Desktop
執行Diffchecker最安全的方式。取得Diffchecker桌面應用程式:您的差異永遠不會離開您的電腦!
取得桌面版
auraBal
建立於
4 年前
差異永不過期
清除
匯出
分享
兩個文本完全相同
這兩個文本之間沒有差異
0 刪除
行
總計
刪除
字符
總計
刪除
要繼續使用此功能,請升級到
Diff
checker
Pro
查看價格
278 行
全部複製
0 新增
行
總計
新增
字符
總計
新增
要繼續使用此功能,請升級到
Diff
checker
Pro
查看價格
278 行
全部複製
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;
}
}
}
}
}
}
}
}
已保存差異
原始文本
開啟檔案
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; } } } }
更改後文本
開啟檔案
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; } } } }
尋找差異