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; } } } }
查找差异