编译器
0.8.15+commit.e14f2714
文件 1 的 20:AggregatorV2V3Interface.sol
pragma solidity ^0.8.0;
interface AggregatorInterface {
function latestAnswer() external view returns (int256);
function latestTimestamp() external view returns (uint256);
function latestRound() external view returns (uint256);
function getAnswer(uint256 roundId) external view returns (int256);
function getTimestamp(uint256 roundId) external view returns (uint256);
event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt);
event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);
}
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(uint80 _roundId)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}
interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface {}
文件 2 的 20:BLREG.v1.sol
pragma solidity 0.8.15;
import "src/Kernel.sol";
abstract contract BLREGv1 is Module {
event VaultAdded(address indexed vault);
event VaultRemoved(address indexed vault);
uint256 public activeVaultCount;
address[] public activeVaults;
function addVault(address vault_) external virtual;
function removeVault(address vault_) external virtual;
}
文件 3 的 20:BLVaultLido.sol
pragma solidity 0.8.15;
import {IBLVaultLido, RewardsData} from "policies/BoostedLiquidity/interfaces/IBLVaultLido.sol";
import {IBLVaultManagerLido} from "policies/BoostedLiquidity/interfaces/IBLVaultManagerLido.sol";
import {BLVaultManagerLido} from "policies/BoostedLiquidity/BLVaultManagerLido.sol";
import {JoinPoolRequest, ExitPoolRequest, IVault, IBasePool} from "policies/BoostedLiquidity/interfaces/IBalancer.sol";
import {IAuraBooster, IAuraRewardPool, IAuraMiningLib, ISTASHToken} from "policies/BoostedLiquidity/interfaces/IAura.sol";
import {OlympusERC20Token} from "src/external/OlympusERC20.sol";
import {ERC20} from "solmate/tokens/ERC20.sol";
import {Clone} from "clones/Clone.sol";
import {TransferHelper} from "libraries/TransferHelper.sol";
import {FullMath} from "libraries/FullMath.sol";
contract BLVaultLido is IBLVaultLido, Clone {
using TransferHelper for ERC20;
using FullMath for uint256;
error BLVaultLido_AlreadyInitialized();
error BLVaultLido_OnlyOwner();
error BLVaultLido_Active();
error BLVaultLido_Inactive();
error BLVaultLido_Reentrancy();
error BLVaultLido_AuraDepositFailed();
error BLVaultLido_AuraWithdrawalFailed();
error BLVaultLido_WithdrawFailedPriceImbalance();
error BLVaultLido_WithdrawalDelay();
event Deposit(uint256 ohmAmount, uint256 wstethAmount);
event Withdraw(uint256 ohmAmount, uint256 wstethAmount);
event RewardsClaimed(address indexed rewardsToken, uint256 amount);
uint256 public lastDeposit;
uint256 private constant _OHM_DECIMALS = 1e9;
uint256 private constant _WSTETH_DECIMALS = 1e18;
uint256 private _reentrancyStatus;
constructor() {}
function initializeClone() external {
if (_reentrancyStatus != 0) revert BLVaultLido_AlreadyInitialized();
_reentrancyStatus = 1;
}
function owner() public pure returns (address) {
return _getArgAddress(0);
}
function manager() public pure returns (BLVaultManagerLido) {
return BLVaultManagerLido(_getArgAddress(20));
}
function TRSRY() public pure returns (address) {
return _getArgAddress(40);
}
function MINTR() public pure returns (address) {
return _getArgAddress(60);
}
function ohm() public pure returns (OlympusERC20Token) {
return OlympusERC20Token(_getArgAddress(80));
}
function wsteth() public pure returns (ERC20) {
return ERC20(_getArgAddress(100));
}
function aura() public pure returns (ERC20) {
return ERC20(_getArgAddress(120));
}
function bal() public pure returns (ERC20) {
return ERC20(_getArgAddress(140));
}
function vault() public pure returns (IVault) {
return IVault(_getArgAddress(160));
}
function liquidityPool() public pure returns (IBasePool) {
return IBasePool(_getArgAddress(180));
}
function pid() public pure returns (uint256) {
return _getArgUint256(200);
}
function auraBooster() public pure returns (IAuraBooster) {
return IAuraBooster(_getArgAddress(232));
}
function auraRewardPool() public pure returns (IAuraRewardPool) {
return IAuraRewardPool(_getArgAddress(252));
}
function fee() public pure returns (uint64) {
return _getArgUint64(272);
}
modifier onlyOwner() {
if (msg.sender != owner()) revert BLVaultLido_OnlyOwner();
_;
}
modifier onlyWhileActive() {
if (!manager().isLidoBLVaultActive()) revert BLVaultLido_Inactive();
_;
}
modifier onlyWhileInactive() {
if (manager().isLidoBLVaultActive()) revert BLVaultLido_Active();
_;
}
modifier nonReentrant() {
if (_reentrancyStatus != 1) revert BLVaultLido_Reentrancy();
_reentrancyStatus = 2;
_;
_reentrancyStatus = 1;
}
function deposit(uint256 amount_, uint256 minLpAmount_)
external
override
onlyWhileActive
onlyOwner
nonReentrant
returns (uint256 lpAmountOut)
{
IBLVaultManagerLido manager = manager();
OlympusERC20Token ohm = ohm();
ERC20 wsteth = wsteth();
IBasePool liquidityPool = liquidityPool();
IAuraBooster auraBooster = auraBooster();
uint256 ohmMintAmount;
lastDeposit = block.timestamp;
{
uint256 ohmWstethOraclePrice = manager.getOhmTknPrice();
uint256 ohmWstethPoolPrice = manager.getOhmTknPoolPrice();
uint256 ohmWstethPrice = ohmWstethOraclePrice < ohmWstethPoolPrice
? ohmWstethOraclePrice
: ohmWstethPoolPrice;
ohmMintAmount = (amount_ * ohmWstethPrice) / _WSTETH_DECIMALS;
}
{
uint256 bptBefore = liquidityPool.balanceOf(address(this));
wsteth.safeTransferFrom(msg.sender, address(this), amount_);
manager.mintOhmToVault(ohmMintAmount);
_joinBalancerPool(ohmMintAmount, amount_, minLpAmount_);
lpAmountOut = liquidityPool.balanceOf(address(this)) - bptBefore;
manager.increaseTotalLp(lpAmountOut);
liquidityPool.approve(address(auraBooster), lpAmountOut);
bool depositSuccess = auraBooster.deposit(pid(), lpAmountOut, true);
if (!depositSuccess) revert BLVaultLido_AuraDepositFailed();
}
uint256 unusedOhm = ohm.balanceOf(address(this));
uint256 unusedWsteth = wsteth.balanceOf(address(this));
if (unusedOhm > 0) {
ohm.increaseAllowance(MINTR(), unusedOhm);
manager.burnOhmFromVault(unusedOhm);
}
if (unusedWsteth > 0) {
wsteth.safeTransfer(msg.sender, unusedWsteth);
}
emit Deposit(ohmMintAmount - unusedOhm, amount_ - unusedWsteth);
return lpAmountOut;
}
function withdraw(
uint256 lpAmount_,
uint256[] calldata minTokenAmountsBalancer_,
uint256 minTokenAmountUser_,
bool claim_
) external override onlyOwner nonReentrant returns (uint256, uint256) {
OlympusERC20Token ohm = ohm();
ERC20 wsteth = wsteth();
IBLVaultManagerLido manager = manager();
if (block.timestamp - lastDeposit < manager.minWithdrawalDelay())
revert BLVaultLido_WithdrawalDelay();
uint256 ohmBefore = ohm.balanceOf(address(this));
uint256 wstethBefore = wsteth.balanceOf(address(this));
manager.decreaseTotalLp(lpAmount_);
bool withdrawalSuccess = auraRewardPool().withdrawAndUnwrap(lpAmount_, claim_);
if (!withdrawalSuccess) revert BLVaultLido_AuraWithdrawalFailed();
_exitBalancerPool(lpAmount_, minTokenAmountsBalancer_);
uint256 ohmAmountOut = ohm.balanceOf(address(this)) - ohmBefore;
uint256 wstethAmountOut = wsteth.balanceOf(address(this)) - wstethBefore;
uint256 wstethOhmPrice = manager.getTknOhmPrice();
uint256 expectedWstethAmountOut = (ohmAmountOut * wstethOhmPrice) / _OHM_DECIMALS;
uint256 wstethToReturn = wstethAmountOut > expectedWstethAmountOut
? expectedWstethAmountOut
: wstethAmountOut;
if (wstethToReturn < minTokenAmountUser_) revert BLVaultLido_WithdrawFailedPriceImbalance();
if (wstethAmountOut > wstethToReturn)
wsteth.safeTransfer(TRSRY(), wstethAmountOut - wstethToReturn);
ohm.increaseAllowance(MINTR(), ohmAmountOut);
manager.burnOhmFromVault(ohmAmountOut);
wsteth.safeTransfer(msg.sender, wstethToReturn);
if (claim_) _sendRewards();
emit Withdraw(ohmAmountOut, wstethToReturn);
return (ohmAmountOut, wstethToReturn);
}
function emergencyWithdraw(uint256 lpAmount_, uint256[] calldata minTokenAmounts_)
external
override
onlyWhileInactive
onlyOwner
nonReentrant
returns (uint256, uint256)
{
OlympusERC20Token ohm = ohm();
ERC20 wsteth = wsteth();
uint256 ohmBefore = ohm.balanceOf(address(this));
uint256 wstethBefore = wsteth.balanceOf(address(this));
auraRewardPool().withdrawAndUnwrap(lpAmount_, false);
_exitBalancerPool(lpAmount_, minTokenAmounts_);
uint256 ohmAmountOut = ohm.balanceOf(address(this)) - ohmBefore;
uint256 wstethAmountOut = wsteth.balanceOf(address(this)) - wstethBefore;
wsteth.safeTransfer(msg.sender, wstethAmountOut);
ohm.transfer(address(manager()), ohmAmountOut);
return (ohmAmountOut, wstethAmountOut);
}
function claimRewards() external override onlyWhileActive onlyOwner nonReentrant {
auraRewardPool().getReward(address(this), true);
_sendRewards();
}
function canWithdraw() external view override returns (bool) {
return block.timestamp - lastDeposit >= manager().minWithdrawalDelay();
}
function getLpBalance() public view override returns (uint256) {
return auraRewardPool().balanceOf(address(this));
}
function getUserPairShare() public view override returns (uint256) {
if (liquidityPool().totalSupply() == 0) return 0;
uint256 userLpBalance = getLpBalance();
(, uint256[] memory balances, ) = vault().getPoolTokens(liquidityPool().getPoolId());
uint256 userWstethShare = (userLpBalance * balances[1]) / liquidityPool().totalSupply();
uint256 wstethOhmPrice = manager().getTknOhmPrice();
uint256 expectedWstethShare = (userLpBalance * balances[0] * wstethOhmPrice) /
(liquidityPool().totalSupply() * _OHM_DECIMALS);
return userWstethShare > expectedWstethShare ? expectedWstethShare : userWstethShare;
}
function getOutstandingRewards() public view override returns (RewardsData[] memory) {
uint256 numExtraRewards = auraRewardPool().extraRewardsLength();
RewardsData[] memory rewards = new RewardsData[](numExtraRewards + 2);
uint256 balRewards = auraRewardPool().earned(address(this));
rewards[0] = RewardsData({rewardToken: address(bal()), outstandingRewards: balRewards});
uint256 auraRewards = manager().auraMiningLib().convertCrvToCvx(balRewards);
rewards[1] = RewardsData({rewardToken: address(aura()), outstandingRewards: auraRewards});
for (uint256 i; i < numExtraRewards; ) {
IAuraRewardPool extraRewardPool = IAuraRewardPool(auraRewardPool().extraRewards(i));
address extraRewardToken = ISTASHToken(extraRewardPool.rewardToken()).baseToken();
uint256 extraRewardAmount = extraRewardPool.earned(address(this));
rewards[i + 2] = RewardsData({
rewardToken: extraRewardToken,
outstandingRewards: extraRewardAmount
});
unchecked {
++i;
}
}
return rewards;
}
function _joinBalancerPool(
uint256 ohmAmount_,
uint256 wstethAmount_,
uint256 minLpAmount_
) internal {
OlympusERC20Token ohm = ohm();
ERC20 wsteth = wsteth();
IVault vault = vault();
address[] memory assets = new address[](2);
assets[0] = address(ohm);
assets[1] = address(wsteth);
uint256[] memory maxAmountsIn = new uint256[](2);
maxAmountsIn[0] = ohmAmount_;
maxAmountsIn[1] = wstethAmount_;
JoinPoolRequest memory joinPoolRequest = JoinPoolRequest({
assets: assets,
maxAmountsIn: maxAmountsIn,
userData: abi.encode(1, maxAmountsIn, minLpAmount_),
fromInternalBalance: false
});
ohm.increaseAllowance(address(vault), ohmAmount_);
wsteth.approve(address(vault), wstethAmount_);
vault.joinPool(liquidityPool().getPoolId(), address(this), address(this), joinPoolRequest);
}
function _exitBalancerPool(uint256 lpAmount_, uint256[] calldata minTokenAmounts_) internal {
OlympusERC20Token ohm = ohm();
ERC20 wsteth = wsteth();
IBasePool liquidityPool = liquidityPool();
IVault vault = vault();
address[] memory assets = new address[](2);
assets[0] = address(ohm);
assets[1] = address(wsteth);
ExitPoolRequest memory exitPoolRequest = ExitPoolRequest({
assets: assets,
minAmountsOut: minTokenAmounts_,
userData: abi.encode(1, lpAmount_),
toInternalBalance: false
});
liquidityPool.approve(address(vault), lpAmount_);
vault.exitPool(
liquidityPool.getPoolId(),
address(this),
payable(address(this)),
exitPoolRequest
);
}
function _sendRewards() internal {
{
uint256 balRewards = bal().balanceOf(address(this));
uint256 balFee = (balRewards * fee()) / 10_000;
if (balRewards - balFee > 0) {
bal().safeTransfer(owner(), balRewards - balFee);
emit RewardsClaimed(address(bal()), balRewards - balFee);
}
if (balFee > 0) bal().safeTransfer(TRSRY(), balFee);
}
{
uint256 auraRewards = aura().balanceOf(address(this));
uint256 auraFee = (auraRewards * fee()) / 10_000;
if (auraRewards - auraFee > 0) {
aura().safeTransfer(owner(), auraRewards - auraFee);
emit RewardsClaimed(address(aura()), auraRewards - auraFee);
}
if (auraFee > 0) aura().safeTransfer(TRSRY(), auraFee);
}
{
uint256 numExtraRewards = auraRewardPool().extraRewardsLength();
for (uint256 i; i < numExtraRewards; ) {
IAuraRewardPool extraRewardPool = IAuraRewardPool(auraRewardPool().extraRewards(i));
ERC20 extraRewardToken = ERC20(
ISTASHToken(extraRewardPool.rewardToken()).baseToken()
);
uint256 extraRewardAmount = extraRewardToken.balanceOf(address(this));
uint256 extraRewardFee = (extraRewardAmount * fee()) / 10_000;
if (extraRewardAmount - extraRewardFee > 0) {
extraRewardToken.safeTransfer(owner(), extraRewardAmount - extraRewardFee);
emit RewardsClaimed(
address(extraRewardToken),
extraRewardAmount - extraRewardFee
);
}
if (extraRewardFee > 0) extraRewardToken.safeTransfer(TRSRY(), extraRewardFee);
unchecked {
++i;
}
}
}
}
}
文件 4 的 20:BLVaultManagerLido.sol
pragma solidity 0.8.15;
import {MINTRv1} from "src/modules/MINTR/MINTR.v1.sol";
import {ROLESv1, RolesConsumer} from "src/modules/ROLES/OlympusRoles.sol";
import {TRSRYv1} from "src/modules/TRSRY/TRSRY.v1.sol";
import {BLREGv1} from "src/modules/BLREG/BLREG.v1.sol";
import "src/Kernel.sol";
import {AggregatorV3Interface} from "interfaces/AggregatorV2V3Interface.sol";
import {IAuraRewardPool, IAuraMiningLib, ISTASHToken} from "policies/BoostedLiquidity/interfaces/IAura.sol";
import {JoinPoolRequest, ExitPoolRequest, IVault, IBasePool, IBalancerHelper} from "policies/BoostedLiquidity/interfaces/IBalancer.sol";
import {IWsteth} from "policies/BoostedLiquidity/interfaces/ILido.sol";
import {RewardsData} from "policies/BoostedLiquidity/interfaces/IBLVaultLido.sol";
import {IBLVaultManagerLido} from "policies/BoostedLiquidity/interfaces/IBLVaultManagerLido.sol";
import {BLVaultLido} from "policies/BoostedLiquidity/BLVaultLido.sol";
import {OlympusERC20Token} from "src/external/OlympusERC20.sol";
import {ClonesWithImmutableArgs} from "clones/ClonesWithImmutableArgs.sol";
contract BLVaultManagerLido is Policy, IBLVaultManagerLido, RolesConsumer {
using ClonesWithImmutableArgs for address;
error BLManagerLido_AlreadyActive();
error BLManagerLido_AlreadyInactive();
error BLManagerLido_Inactive();
error BLManagerLido_InvalidVault();
error BLManagerLido_LimitViolation();
error BLManagerLido_InvalidLpAmount();
error BLManagerLido_InvalidLimit();
error BLManagerLido_InvalidFee();
error BLManagerLido_BadPriceFeed();
error BLManagerLido_VaultAlreadyExists();
error BLManagerLido_NoUserVault();
event VaultDeployed(address vault, address owner, uint64 fee);
MINTRv1 public MINTR;
TRSRYv1 public TRSRY;
BLREGv1 public BLREG;
address public ohm;
address public pairToken;
address public aura;
address public bal;
string public exchangeName;
BalancerData public balancerData;
AuraData public auraData;
IAuraMiningLib public auraMiningLib;
OracleFeed public ohmEthPriceFeed;
OracleFeed public ethUsdPriceFeed;
OracleFeed public stethUsdPriceFeed;
BLVaultLido public implementation;
mapping(BLVaultLido => address) public vaultOwners;
mapping(address => BLVaultLido) public userVaults;
uint256 public totalLp;
uint256 public deployedOhm;
uint256 public circulatingOhmBurned;
uint256 public ohmLimit;
uint64 public currentFee;
uint48 public minWithdrawalDelay;
bool public isLidoBLVaultActive;
uint32 public constant MAX_FEE = 10_000;
constructor(
Kernel kernel_,
TokenData memory tokenData_,
BalancerData memory balancerData_,
AuraData memory auraData_,
address auraMiningLib_,
OracleFeed memory ohmEthPriceFeed_,
OracleFeed memory ethUsdPriceFeed_,
OracleFeed memory stethUsdPriceFeed_,
address implementation_,
uint256 ohmLimit_,
uint64 fee_,
uint48 minWithdrawalDelay_
) Policy(kernel_) {
{
exchangeName = "Balancer";
}
{
ohm = tokenData_.ohm;
pairToken = tokenData_.pairToken;
aura = tokenData_.aura;
bal = tokenData_.bal;
}
{
balancerData = balancerData_;
}
{
auraData = auraData_;
auraMiningLib = IAuraMiningLib(auraMiningLib_);
}
{
ohmEthPriceFeed = ohmEthPriceFeed_;
ethUsdPriceFeed = ethUsdPriceFeed_;
stethUsdPriceFeed = stethUsdPriceFeed_;
}
{
implementation = BLVaultLido(implementation_);
}
{
ohmLimit = ohmLimit_;
currentFee = fee_;
minWithdrawalDelay = minWithdrawalDelay_;
}
}
function configureDependencies() external override returns (Keycode[] memory dependencies) {
dependencies = new Keycode[](4);
dependencies[0] = toKeycode("MINTR");
dependencies[1] = toKeycode("TRSRY");
dependencies[2] = toKeycode("BLREG");
dependencies[3] = toKeycode("ROLES");
MINTR = MINTRv1(getModuleAddress(dependencies[0]));
TRSRY = TRSRYv1(getModuleAddress(dependencies[1]));
BLREG = BLREGv1(getModuleAddress(dependencies[2]));
ROLES = ROLESv1(getModuleAddress(dependencies[3]));
}
function requestPermissions()
external
view
override
returns (Permissions[] memory permissions)
{
Keycode mintrKeycode = MINTR.KEYCODE();
Keycode blregKeycode = BLREG.KEYCODE();
permissions = new Permissions[](5);
permissions[0] = Permissions(mintrKeycode, MINTR.mintOhm.selector);
permissions[1] = Permissions(mintrKeycode, MINTR.burnOhm.selector);
permissions[2] = Permissions(mintrKeycode, MINTR.increaseMintApproval.selector);
permissions[3] = Permissions(blregKeycode, BLREG.addVault.selector);
permissions[4] = Permissions(blregKeycode, BLREG.removeVault.selector);
}
modifier onlyWhileActive() {
if (!isLidoBLVaultActive) revert BLManagerLido_Inactive();
_;
}
modifier onlyVault() {
if (vaultOwners[BLVaultLido(msg.sender)] == address(0)) revert BLManagerLido_InvalidVault();
_;
}
function deployVault() external override onlyWhileActive returns (address vault) {
if (address(userVaults[msg.sender]) != address(0))
revert BLManagerLido_VaultAlreadyExists();
bytes memory data = abi.encodePacked(
msg.sender,
this,
address(TRSRY),
address(MINTR),
ohm,
pairToken,
aura,
bal,
balancerData.vault,
balancerData.liquidityPool,
auraData.pid,
auraData.auraBooster,
auraData.auraRewardPool,
currentFee
);
BLVaultLido clone = BLVaultLido(address(implementation).clone(data));
clone.initializeClone();
vaultOwners[clone] = msg.sender;
userVaults[msg.sender] = clone;
emit VaultDeployed(address(clone), msg.sender, currentFee);
return address(clone);
}
function mintOhmToVault(uint256 amount_) external override onlyWhileActive onlyVault {
if (deployedOhm + amount_ > ohmLimit + circulatingOhmBurned)
revert BLManagerLido_LimitViolation();
deployedOhm += amount_;
MINTR.increaseMintApproval(address(this), amount_);
MINTR.mintOhm(msg.sender, amount_);
}
function burnOhmFromVault(uint256 amount_) external override onlyWhileActive onlyVault {
if (amount_ > deployedOhm) {
circulatingOhmBurned += amount_ - deployedOhm;
deployedOhm = 0;
} else {
deployedOhm -= amount_;
}
MINTR.burnOhm(msg.sender, amount_);
}
function increaseTotalLp(uint256 amount_) external override onlyWhileActive onlyVault {
totalLp += amount_;
}
function decreaseTotalLp(uint256 amount_) external override onlyWhileActive onlyVault {
if (amount_ > totalLp) amount_ = totalLp;
totalLp -= amount_;
}
function canWithdraw(address user_) external view override returns (bool) {
if (address(userVaults[user_]) == address(0)) return false;
return userVaults[user_].canWithdraw();
}
function getLpBalance(address user_) external view override returns (uint256) {
if (address(userVaults[user_]) == address(0)) return 0;
return userVaults[user_].getLpBalance();
}
function getUserPairShare(address user_) external view override returns (uint256) {
if (address(userVaults[user_]) == address(0)) return 0;
return userVaults[user_].getUserPairShare();
}
function getOutstandingRewards(address user_)
external
view
override
returns (RewardsData[] memory)
{
BLVaultLido vault = userVaults[user_];
if (address(vault) == address(0)) return new RewardsData[](0);
RewardsData[] memory rewards = vault.getOutstandingRewards();
return rewards;
}
function getMaxDeposit() external view override returns (uint256) {
uint256 maxOhmAmount = ohmLimit + circulatingOhmBurned - deployedOhm;
uint256 ohmTknPrice = getOhmTknPrice();
uint256 maxTknAmount = (maxOhmAmount * 1e18) / ohmTknPrice;
return maxTknAmount;
}
function getExpectedLpAmount(uint256 amount_) external override returns (uint256 bptAmount) {
IBasePool pool = IBasePool(balancerData.liquidityPool);
IBalancerHelper balancerHelper = IBalancerHelper(balancerData.balancerHelper);
uint256 ohmTknOraclePrice = getOhmTknPrice();
uint256 ohmTknPoolPrice = getOhmTknPoolPrice();
uint256 ohmTknPrice = ohmTknOraclePrice < ohmTknPoolPrice
? ohmTknOraclePrice
: ohmTknPoolPrice;
uint256 ohmMintAmount = (amount_ * ohmTknPrice) / 1e18;
address[] memory assets = new address[](2);
assets[0] = ohm;
assets[1] = pairToken;
uint256[] memory maxAmountsIn = new uint256[](2);
maxAmountsIn[0] = ohmMintAmount;
maxAmountsIn[1] = amount_;
JoinPoolRequest memory joinPoolRequest = JoinPoolRequest({
assets: assets,
maxAmountsIn: maxAmountsIn,
userData: abi.encode(1, maxAmountsIn, 0),
fromInternalBalance: false
});
(bptAmount, ) = balancerHelper.queryJoin(
pool.getPoolId(),
address(this),
address(this),
joinPoolRequest
);
}
function getExpectedTokensOutProtocol(uint256 lpAmount_)
external
override
returns (uint256[] memory expectedTokenAmounts)
{
IBasePool pool = IBasePool(balancerData.liquidityPool);
IBalancerHelper balancerHelper = IBalancerHelper(balancerData.balancerHelper);
address[] memory assets = new address[](2);
assets[0] = ohm;
assets[1] = pairToken;
uint256[] memory minAmountsOut = new uint256[](2);
minAmountsOut[0] = 0;
minAmountsOut[1] = 0;
ExitPoolRequest memory exitPoolRequest = ExitPoolRequest({
assets: assets,
minAmountsOut: minAmountsOut,
userData: abi.encode(1, lpAmount_),
toInternalBalance: false
});
(, expectedTokenAmounts) = balancerHelper.queryExit(
pool.getPoolId(),
address(this),
address(this),
exitPoolRequest
);
}
function getExpectedPairTokenOutUser(uint256 lpAmount_)
external
override
returns (uint256 expectedTknAmount)
{
IBasePool pool = IBasePool(balancerData.liquidityPool);
IBalancerHelper balancerHelper = IBalancerHelper(balancerData.balancerHelper);
address[] memory assets = new address[](2);
assets[0] = ohm;
assets[1] = pairToken;
uint256[] memory minAmountsOut = new uint256[](2);
minAmountsOut[0] = 0;
minAmountsOut[1] = 0;
ExitPoolRequest memory exitPoolRequest = ExitPoolRequest({
assets: assets,
minAmountsOut: minAmountsOut,
userData: abi.encode(1, lpAmount_),
toInternalBalance: false
});
(, uint256[] memory expectedTokenAmounts) = balancerHelper.queryExit(
pool.getPoolId(),
address(this),
address(this),
exitPoolRequest
);
uint256 tknOhmPrice = getTknOhmPrice();
uint256 expectedTknAmountOut = (expectedTokenAmounts[0] * tknOhmPrice) / 1e9;
expectedTknAmount = expectedTokenAmounts[1] > expectedTknAmountOut
? expectedTknAmountOut
: expectedTokenAmounts[1];
}
function getRewardTokens() external view override returns (address[] memory) {
IAuraRewardPool auraPool = IAuraRewardPool(auraData.auraRewardPool);
uint256 numExtraRewards = auraPool.extraRewardsLength();
address[] memory rewardTokens = new address[](numExtraRewards + 2);
rewardTokens[0] = aura;
rewardTokens[1] = auraPool.rewardToken();
for (uint256 i; i < numExtraRewards; ) {
IAuraRewardPool extraRewardPool = IAuraRewardPool(auraPool.extraRewards(i));
rewardTokens[i + 2] = ISTASHToken(extraRewardPool.rewardToken()).baseToken();
unchecked {
++i;
}
}
return rewardTokens;
}
function getRewardRate(address rewardToken_)
external
view
override
returns (uint256 rewardRate)
{
IAuraRewardPool auraPool = IAuraRewardPool(auraData.auraRewardPool);
if (rewardToken_ == bal) {
rewardRate = auraPool.rewardRate();
} else if (rewardToken_ == aura) {
uint256 balRewardRate = auraPool.rewardRate();
rewardRate = auraMiningLib.convertCrvToCvx(balRewardRate);
} else {
uint256 numExtraRewards = auraPool.extraRewardsLength();
for (uint256 i; i < numExtraRewards; ) {
IAuraRewardPool extraRewardPool = IAuraRewardPool(auraPool.extraRewards(i));
if (rewardToken_ == ISTASHToken(extraRewardPool.rewardToken()).baseToken()) {
rewardRate = extraRewardPool.rewardRate();
break;
}
unchecked {
++i;
}
}
}
}
function getPoolOhmShare() public view override returns (uint256) {
IVault vault = IVault(balancerData.vault);
IBasePool pool = IBasePool(balancerData.liquidityPool);
uint256 poolTotalSupply = pool.totalSupply();
(, uint256[] memory balances_, ) = vault.getPoolTokens(pool.getPoolId());
if (poolTotalSupply == 0) return 0;
else return (balances_[0] * totalLp) / poolTotalSupply;
}
function getOhmSupplyChangeData()
external
view
override
returns (
uint256 poolOhmShare,
uint256 mintedOhm,
uint256 netBurnedOhm
)
{
uint256 poolOhmShare = getPoolOhmShare();
mintedOhm = deployedOhm;
netBurnedOhm = circulatingOhmBurned;
}
function getOhmTknPrice() public view override returns (uint256) {
uint256 stethPerWsteth = IWsteth(pairToken).stEthPerToken();
uint256 ethPerOhm = _validatePrice(ohmEthPriceFeed.feed, ohmEthPriceFeed.updateThreshold);
uint256 usdPerEth = _validatePrice(ethUsdPriceFeed.feed, ethUsdPriceFeed.updateThreshold);
uint256 usdPerSteth = _validatePrice(
stethUsdPriceFeed.feed,
stethUsdPriceFeed.updateThreshold
);
return (stethPerWsteth * usdPerSteth * 1e9) / (ethPerOhm * usdPerEth);
}
function getTknOhmPrice() public view override returns (uint256) {
uint256 stethPerWsteth = IWsteth(pairToken).stEthPerToken();
uint256 ethPerOhm = _validatePrice(ohmEthPriceFeed.feed, ohmEthPriceFeed.updateThreshold);
uint256 usdPerEth = _validatePrice(ethUsdPriceFeed.feed, ethUsdPriceFeed.updateThreshold);
uint256 usdPerSteth = _validatePrice(
stethUsdPriceFeed.feed,
stethUsdPriceFeed.updateThreshold
);
return (ethPerOhm * usdPerEth * 1e18) / (stethPerWsteth * usdPerSteth);
}
function getOhmTknPoolPrice() public view override returns (uint256) {
IBasePool pool = IBasePool(balancerData.liquidityPool);
IVault vault = IVault(balancerData.vault);
(, uint256[] memory balances, ) = vault.getPoolTokens(pool.getPoolId());
if (balances[1] == 0) return 0;
else return (balances[0] * 1e18) / balances[1];
}
function emergencyBurnOhm(uint256 amount_) external override onlyRole("liquidityvault_admin") {
OlympusERC20Token(ohm).increaseAllowance(address(MINTR), amount_);
MINTR.burnOhm(address(this), amount_);
}
function setLimit(uint256 newLimit_) external override onlyRole("liquidityvault_admin") {
if (newLimit_ + circulatingOhmBurned < deployedOhm) revert BLManagerLido_InvalidLimit();
ohmLimit = newLimit_;
}
function setFee(uint64 newFee_) external override onlyRole("liquidityvault_admin") {
if (newFee_ > MAX_FEE) revert BLManagerLido_InvalidFee();
currentFee = newFee_;
}
function setWithdrawalDelay(uint48 newDelay_)
external
override
onlyRole("liquidityvault_admin")
{
minWithdrawalDelay = newDelay_;
}
function changeUpdateThresholds(
uint48 ohmEthUpdateThreshold_,
uint48 ethUsdUpdateThreshold_,
uint48 stethUsdUpdateThreshold_
) external onlyRole("liquidityvault_admin") {
ohmEthPriceFeed.updateThreshold = ohmEthUpdateThreshold_;
ethUsdPriceFeed.updateThreshold = ethUsdUpdateThreshold_;
stethUsdPriceFeed.updateThreshold = stethUsdUpdateThreshold_;
}
function activate() external override onlyRole("liquidityvault_admin") {
if (isLidoBLVaultActive) revert BLManagerLido_AlreadyActive();
isLidoBLVaultActive = true;
BLREG.addVault(address(this));
}
function deactivate() external override onlyRole("emergency_admin") {
if (!isLidoBLVaultActive) revert BLManagerLido_AlreadyInactive();
isLidoBLVaultActive = false;
BLREG.removeVault(address(this));
}
function _validatePrice(AggregatorV3Interface priceFeed_, uint48 updateThreshold_)
internal
view
returns (uint256)
{
(uint80 roundId, int256 priceInt, , uint256 updatedAt, uint80 answeredInRound) = priceFeed_
.latestRoundData();
if (
priceInt <= 0 ||
updatedAt < block.timestamp - updateThreshold_ ||
answeredInRound != roundId
) revert BLManagerLido_BadPriceFeed();
return uint256(priceInt);
}
}
文件 5 的 20:Clone.sol
pragma solidity ^0.8.4;
contract Clone {
function _getArgAddress(uint256 argOffset)
internal
pure
returns (address arg)
{
uint256 offset = _getImmutableArgsOffset();
assembly {
arg := shr(0x60, calldataload(add(offset, argOffset)))
}
}
function _getArgUint256(uint256 argOffset)
internal
pure
returns (uint256 arg)
{
uint256 offset = _getImmutableArgsOffset();
assembly {
arg := calldataload(add(offset, argOffset))
}
}
function _getArgUint64(uint256 argOffset)
internal
pure
returns (uint64 arg)
{
uint256 offset = _getImmutableArgsOffset();
assembly {
arg := shr(0xc0, calldataload(add(offset, argOffset)))
}
}
function _getArgUint8(uint256 argOffset) internal pure returns (uint8 arg) {
uint256 offset = _getImmutableArgsOffset();
assembly {
arg := shr(0xf8, calldataload(add(offset, argOffset)))
}
}
function _getImmutableArgsOffset() internal pure returns (uint256 offset) {
assembly {
offset := sub(
calldatasize(),
add(shr(240, calldataload(sub(calldatasize(), 2))), 2)
)
}
}
}
文件 6 的 20:ClonesWithImmutableArgs.sol
pragma solidity ^0.8.4;
library ClonesWithImmutableArgs {
error CreateFail();
function clone(address implementation, bytes memory data)
internal
returns (address instance)
{
unchecked {
uint256 extraLength = data.length + 2;
uint256 creationSize = 0x43 + extraLength;
uint256 runSize = creationSize - 11;
uint256 dataPtr;
uint256 ptr;
assembly {
ptr := mload(0x40)
mstore(
ptr,
0x3d61000000000000000000000000000000000000000000000000000000000000
)
mstore(add(ptr, 0x02), shl(240, runSize))
mstore(
add(ptr, 0x04),
0x80600b3d3981f300000000000000000000000000000000000000000000000000
)
mstore(
add(ptr, 0x0b),
0x363d3d3761000000000000000000000000000000000000000000000000000000
)
mstore(add(ptr, 0x10), shl(240, extraLength))
mstore(
add(ptr, 0x12),
0x603836393d3d3d36610000000000000000000000000000000000000000000000
)
mstore(add(ptr, 0x1b), shl(240, extraLength))
mstore(
add(ptr, 0x1d),
0x013d730000000000000000000000000000000000000000000000000000000000
)
mstore(add(ptr, 0x20), shl(0x60, implementation))
mstore(
add(ptr, 0x34),
0x5af43d82803e903d91603657fd5bf30000000000000000000000000000000000
)
}
extraLength -= 2;
uint256 counter = extraLength;
uint256 copyPtr = ptr + 0x43;
assembly {
dataPtr := add(data, 32)
}
for (; counter >= 32; counter -= 32) {
assembly {
mstore(copyPtr, mload(dataPtr))
}
copyPtr += 32;
dataPtr += 32;
}
uint256 mask = ~(256**(32 - counter) - 1);
assembly {
mstore(copyPtr, and(mload(dataPtr), mask))
}
copyPtr += counter;
assembly {
mstore(copyPtr, shl(240, extraLength))
}
assembly {
instance := create(0, ptr, creationSize)
}
if (instance == address(0)) {
revert CreateFail();
}
}
}
}
文件 7 的 20:ERC20.sol
pragma solidity >=0.8.0;
abstract contract ERC20 {
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
string public name;
string public symbol;
uint8 public immutable decimals;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender];
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}
文件 8 的 20:FullMath.sol
pragma solidity >=0.8.0;
library FullMath {
function mulDiv(
uint256 a,
uint256 b,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
uint256 prod0;
uint256 prod1;
assembly {
let mm := mulmod(a, b, not(0))
prod0 := mul(a, b)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
require(denominator > 0);
assembly {
result := div(prod0, denominator)
}
return result;
}
require(denominator > prod1);
uint256 remainder;
assembly {
remainder := mulmod(a, b, denominator)
}
assembly {
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = (type(uint256).max - denominator + 1) & denominator;
assembly {
denominator := div(denominator, twos)
}
assembly {
prod0 := div(prod0, twos)
}
assembly {
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inv = (3 * denominator) ^ 2;
inv *= 2 - denominator * inv;
inv *= 2 - denominator * inv;
inv *= 2 - denominator * inv;
inv *= 2 - denominator * inv;
inv *= 2 - denominator * inv;
inv *= 2 - denominator * inv;
result = prod0 * inv;
return result;
}
}
function mulDivUp(
uint256 a,
uint256 b,
uint256 denominator
) internal pure returns (uint256 result) {
result = mulDiv(a, b, denominator);
unchecked {
if (mulmod(a, b, denominator) > 0) {
require(result < type(uint256).max);
result++;
}
}
}
}
文件 9 的 20:IAura.sol
pragma solidity >=0.8.0;
interface IAuraBooster {
function deposit(
uint256 pid_,
uint256 amount_,
bool stake_
) external returns (bool);
}
interface IAuraRewardPool {
function balanceOf(address account_) external view returns (uint256);
function earned(address account_) external view returns (uint256);
function rewardRate() external view returns (uint256);
function rewardToken() external view returns (address);
function extraRewardsLength() external view returns (uint256);
function extraRewards(uint256 index) external view returns (address);
function deposit(uint256 assets_, address receiver_) external;
function getReward(address account_, bool claimExtras_) external;
function withdrawAndUnwrap(uint256 amount_, bool claim_) external returns (bool);
}
interface IAuraMiningLib {
function convertCrvToCvx(uint256 amount_) external view returns (uint256);
}
interface ISTASHToken {
function baseToken() external view returns (address);
}
文件 10 的 20:IBLVaultLido.sol
pragma solidity >=0.8.0;
struct RewardsData {
address rewardToken;
uint256 outstandingRewards;
}
interface IBLVaultLido {
function deposit(uint256 amount_, uint256 minLpAmount_) external returns (uint256 lpAmountOut);
function withdraw(
uint256 lpAmount_,
uint256[] calldata minTokenAmountsBalancer_,
uint256 minTokenAmountUser_,
bool claim_
) external returns (uint256, uint256);
function emergencyWithdraw(uint256 lpAmount_, uint256[] calldata minTokenAmounts_)
external
returns (uint256, uint256);
function claimRewards() external;
function canWithdraw() external view returns (bool);
function getLpBalance() external view returns (uint256);
function getUserPairShare() external view returns (uint256);
function getOutstandingRewards() external view returns (RewardsData[] memory);
}
文件 11 的 20:IBLVaultManagerLido.sol
pragma solidity >=0.8.0;
import {MINTRv1} from "src/modules/MINTR/MINTR.v1.sol";
import {ROLESv1} from "src/modules/ROLES/ROLES.v1.sol";
import {TRSRYv1} from "src/modules/TRSRY/TRSRY.v1.sol";
import {AggregatorV3Interface} from "interfaces/AggregatorV2V3Interface.sol";
import {IAuraMiningLib} from "policies/BoostedLiquidity/interfaces/IAura.sol";
import {IBLVaultLido, RewardsData} from "policies/BoostedLiquidity/interfaces/IBLVaultLido.sol";
interface IBLVaultManagerLido {
struct TokenData {
address ohm;
address pairToken;
address aura;
address bal;
}
struct BalancerData {
address vault;
address liquidityPool;
address balancerHelper;
}
struct AuraData {
uint256 pid;
address auraBooster;
address auraRewardPool;
}
struct OracleFeed {
AggregatorV3Interface feed;
uint48 updateThreshold;
}
function minWithdrawalDelay() external returns (uint48);
function deployVault() external returns (address);
function mintOhmToVault(uint256 amount_) external;
function burnOhmFromVault(uint256 amount_) external;
function increaseTotalLp(uint256 amount_) external;
function decreaseTotalLp(uint256 amount_) external;
function canWithdraw(address user_) external view returns (bool);
function getLpBalance(address user_) external view returns (uint256);
function getUserPairShare(address user_) external view returns (uint256);
function getOutstandingRewards(address user_) external view returns (RewardsData[] memory);
function getMaxDeposit() external view returns (uint256);
function getExpectedLpAmount(uint256 amount_) external returns (uint256);
function getExpectedTokensOutProtocol(uint256 lpAmount_)
external
returns (uint256[] memory expectedTokenAmounts);
function getExpectedPairTokenOutUser(uint256 lpAmount_)
external
returns (uint256 expectedTknAmount);
function getRewardTokens() external view returns (address[] memory);
function getRewardRate(address rewardToken_) external view returns (uint256);
function getPoolOhmShare() external view returns (uint256);
function getOhmSupplyChangeData()
external
view
returns (
uint256,
uint256,
uint256
);
function getOhmTknPrice() external view returns (uint256);
function getTknOhmPrice() external view returns (uint256);
function getOhmTknPoolPrice() external view returns (uint256);
function emergencyBurnOhm(uint256 amount_) external;
function setLimit(uint256 newLimit_) external;
function setFee(uint64 newFee_) external;
function setWithdrawalDelay(uint48 newDelay_) external;
function changeUpdateThresholds(
uint48 ohmEthUpdateThreshold_,
uint48 ethUsdUpdateThreshold_,
uint48 stethUsdUpdateThreshold_
) external;
function activate() external;
function deactivate() external;
}
文件 12 的 20:IBalancer.sol
pragma solidity >=0.8.0;
import {ERC20} from "solmate/tokens/ERC20.sol";
struct JoinPoolRequest {
address[] assets;
uint256[] maxAmountsIn;
bytes userData;
bool fromInternalBalance;
}
struct ExitPoolRequest {
address[] assets;
uint256[] minAmountsOut;
bytes userData;
bool toInternalBalance;
}
interface IVault {
function joinPool(
bytes32 poolId,
address sender,
address recipient,
JoinPoolRequest memory request
) external payable;
function exitPool(
bytes32 poolId,
address sender,
address payable recipient,
ExitPoolRequest memory request
) external;
function getPoolTokens(bytes32 poolId)
external
view
returns (
address[] memory,
uint256[] memory,
uint256
);
}
interface IBasePool {
function getPoolId() external view returns (bytes32);
function balanceOf(address user_) external view returns (uint256);
function totalSupply() external view returns (uint256);
function approve(address spender_, uint256 amount_) external returns (bool);
}
interface IFactory {
function create(
string memory name,
string memory symbol,
ERC20[] memory tokens,
uint256[] memory weights,
uint256 swapFeePercentage,
address owner
) external returns (address);
}
interface IBalancerHelper {
function queryJoin(
bytes32 poolId,
address sender,
address recipient,
JoinPoolRequest memory request
) external returns (uint256 bptOut, uint256[] memory amountsIn);
function queryExit(
bytes32 poolId,
address sender,
address recipient,
ExitPoolRequest memory request
) external returns (uint256 bptIn, uint256[] memory amountsOut);
}
文件 13 的 20:ILido.sol
pragma solidity >=0.8.0;
interface IWsteth {
function stEthPerToken() external view returns (uint256);
}
文件 14 的 20:Kernel.sol
pragma solidity 0.8.15;
enum Actions {
InstallModule,
UpgradeModule,
ActivatePolicy,
DeactivatePolicy,
ChangeExecutor,
MigrateKernel
}
struct Instruction {
Actions action;
address target;
}
struct Permissions {
Keycode keycode;
bytes4 funcSelector;
}
type Keycode is bytes5;
error TargetNotAContract(address target_);
error InvalidKeycode(Keycode keycode_);
function toKeycode(bytes5 keycode_) pure returns (Keycode) {
return Keycode.wrap(keycode_);
}
function fromKeycode(Keycode keycode_) pure returns (bytes5) {
return Keycode.unwrap(keycode_);
}
function ensureContract(address target_) view {
if (target_.code.length == 0) revert TargetNotAContract(target_);
}
function ensureValidKeycode(Keycode keycode_) pure {
bytes5 unwrapped = Keycode.unwrap(keycode_);
for (uint256 i = 0; i < 5; ) {
bytes1 char = unwrapped[i];
if (char < 0x41 || char > 0x5A) revert InvalidKeycode(keycode_);
unchecked {
i++;
}
}
}
abstract contract KernelAdapter {
error KernelAdapter_OnlyKernel(address caller_);
Kernel public kernel;
constructor(Kernel kernel_) {
kernel = kernel_;
}
modifier onlyKernel() {
if (msg.sender != address(kernel)) revert KernelAdapter_OnlyKernel(msg.sender);
_;
}
function changeKernel(Kernel newKernel_) external onlyKernel {
kernel = newKernel_;
}
}
abstract contract Module is KernelAdapter {
error Module_PolicyNotPermitted(address policy_);
constructor(Kernel kernel_) KernelAdapter(kernel_) {}
modifier permissioned() {
if (!kernel.modulePermissions(KEYCODE(), Policy(msg.sender), msg.sig))
revert Module_PolicyNotPermitted(msg.sender);
_;
}
function KEYCODE() public pure virtual returns (Keycode) {}
function VERSION() external pure virtual returns (uint8 major, uint8 minor) {}
function INIT() external virtual onlyKernel {}
}
abstract contract Policy is KernelAdapter {
error Policy_ModuleDoesNotExist(Keycode keycode_);
constructor(Kernel kernel_) KernelAdapter(kernel_) {}
function isActive() external view returns (bool) {
return kernel.isPolicyActive(this);
}
function getModuleAddress(Keycode keycode_) internal view returns (address) {
address moduleForKeycode = address(kernel.getModuleForKeycode(keycode_));
if (moduleForKeycode == address(0)) revert Policy_ModuleDoesNotExist(keycode_);
return moduleForKeycode;
}
function configureDependencies() external virtual returns (Keycode[] memory dependencies) {}
function requestPermissions() external view virtual returns (Permissions[] memory requests) {}
}
contract Kernel {
event PermissionsUpdated(
Keycode indexed keycode_,
Policy indexed policy_,
bytes4 funcSelector_,
bool granted_
);
event ActionExecuted(Actions indexed action_, address indexed target_);
error Kernel_OnlyExecutor(address caller_);
error Kernel_ModuleAlreadyInstalled(Keycode module_);
error Kernel_InvalidModuleUpgrade(Keycode module_);
error Kernel_PolicyAlreadyActivated(address policy_);
error Kernel_PolicyNotActivated(address policy_);
address public executor;
Keycode[] public allKeycodes;
mapping(Keycode => Module) public getModuleForKeycode;
mapping(Module => Keycode) public getKeycodeForModule;
mapping(Keycode => Policy[]) public moduleDependents;
mapping(Keycode => mapping(Policy => uint256)) public getDependentIndex;
mapping(Keycode => mapping(Policy => mapping(bytes4 => bool))) public modulePermissions;
Policy[] public activePolicies;
mapping(Policy => uint256) public getPolicyIndex;
constructor() {
executor = msg.sender;
}
modifier onlyExecutor() {
if (msg.sender != executor) revert Kernel_OnlyExecutor(msg.sender);
_;
}
function isPolicyActive(Policy policy_) public view returns (bool) {
return activePolicies.length > 0 && activePolicies[getPolicyIndex[policy_]] == policy_;
}
function executeAction(Actions action_, address target_) external onlyExecutor {
if (action_ == Actions.InstallModule) {
ensureContract(target_);
ensureValidKeycode(Module(target_).KEYCODE());
_installModule(Module(target_));
} else if (action_ == Actions.UpgradeModule) {
ensureContract(target_);
ensureValidKeycode(Module(target_).KEYCODE());
_upgradeModule(Module(target_));
} else if (action_ == Actions.ActivatePolicy) {
ensureContract(target_);
_activatePolicy(Policy(target_));
} else if (action_ == Actions.DeactivatePolicy) {
ensureContract(target_);
_deactivatePolicy(Policy(target_));
} else if (action_ == Actions.ChangeExecutor) {
executor = target_;
} else if (action_ == Actions.MigrateKernel) {
ensureContract(target_);
_migrateKernel(Kernel(target_));
}
emit ActionExecuted(action_, target_);
}
function _installModule(Module newModule_) internal {
Keycode keycode = newModule_.KEYCODE();
if (address(getModuleForKeycode[keycode]) != address(0))
revert Kernel_ModuleAlreadyInstalled(keycode);
getModuleForKeycode[keycode] = newModule_;
getKeycodeForModule[newModule_] = keycode;
allKeycodes.push(keycode);
newModule_.INIT();
}
function _upgradeModule(Module newModule_) internal {
Keycode keycode = newModule_.KEYCODE();
Module oldModule = getModuleForKeycode[keycode];
if (address(oldModule) == address(0) || oldModule == newModule_)
revert Kernel_InvalidModuleUpgrade(keycode);
getKeycodeForModule[oldModule] = Keycode.wrap(bytes5(0));
getKeycodeForModule[newModule_] = keycode;
getModuleForKeycode[keycode] = newModule_;
newModule_.INIT();
_reconfigurePolicies(keycode);
}
function _activatePolicy(Policy policy_) internal {
if (isPolicyActive(policy_)) revert Kernel_PolicyAlreadyActivated(address(policy_));
activePolicies.push(policy_);
getPolicyIndex[policy_] = activePolicies.length - 1;
Keycode[] memory dependencies = policy_.configureDependencies();
uint256 depLength = dependencies.length;
for (uint256 i; i < depLength; ) {
Keycode keycode = dependencies[i];
moduleDependents[keycode].push(policy_);
getDependentIndex[keycode][policy_] = moduleDependents[keycode].length - 1;
unchecked {
++i;
}
}
Permissions[] memory requests = policy_.requestPermissions();
_setPolicyPermissions(policy_, requests, true);
}
function _deactivatePolicy(Policy policy_) internal {
if (!isPolicyActive(policy_)) revert Kernel_PolicyNotActivated(address(policy_));
Permissions[] memory requests = policy_.requestPermissions();
_setPolicyPermissions(policy_, requests, false);
uint256 idx = getPolicyIndex[policy_];
Policy lastPolicy = activePolicies[activePolicies.length - 1];
activePolicies[idx] = lastPolicy;
activePolicies.pop();
getPolicyIndex[lastPolicy] = idx;
delete getPolicyIndex[policy_];
_pruneFromDependents(policy_);
}
function _migrateKernel(Kernel newKernel_) internal {
uint256 keycodeLen = allKeycodes.length;
for (uint256 i; i < keycodeLen; ) {
Module module = Module(getModuleForKeycode[allKeycodes[i]]);
module.changeKernel(newKernel_);
unchecked {
++i;
}
}
uint256 policiesLen = activePolicies.length;
for (uint256 j; j < policiesLen; ) {
Policy policy = activePolicies[j];
policy.changeKernel(newKernel_);
unchecked {
++j;
}
}
}
function _reconfigurePolicies(Keycode keycode_) internal {
Policy[] memory dependents = moduleDependents[keycode_];
uint256 depLength = dependents.length;
for (uint256 i; i < depLength; ) {
dependents[i].configureDependencies();
unchecked {
++i;
}
}
}
function _setPolicyPermissions(
Policy policy_,
Permissions[] memory requests_,
bool grant_
) internal {
uint256 reqLength = requests_.length;
for (uint256 i = 0; i < reqLength; ) {
Permissions memory request = requests_[i];
modulePermissions[request.keycode][policy_][request.funcSelector] = grant_;
emit PermissionsUpdated(request.keycode, policy_, request.funcSelector, grant_);
unchecked {
++i;
}
}
}
function _pruneFromDependents(Policy policy_) internal {
Keycode[] memory dependencies = policy_.configureDependencies();
uint256 depcLength = dependencies.length;
for (uint256 i; i < depcLength; ) {
Keycode keycode = dependencies[i];
Policy[] storage dependents = moduleDependents[keycode];
uint256 origIndex = getDependentIndex[keycode][policy_];
Policy lastPolicy = dependents[dependents.length - 1];
dependents[origIndex] = lastPolicy;
dependents.pop();
getDependentIndex[keycode][lastPolicy] = origIndex;
delete getDependentIndex[keycode][policy_];
unchecked {
++i;
}
}
}
}
文件 15 的 20:MINTR.v1.sol
pragma solidity 0.8.15;
import {OlympusERC20Token as OHM} from "src/external/OlympusERC20.sol";
import "src/Kernel.sol";
abstract contract MINTRv1 is Module {
event IncreaseMintApproval(address indexed policy_, uint256 newAmount_);
event DecreaseMintApproval(address indexed policy_, uint256 newAmount_);
event Mint(address indexed policy_, address indexed to_, uint256 amount_);
event Burn(address indexed policy_, address indexed from_, uint256 amount_);
error MINTR_NotApproved();
error MINTR_ZeroAmount();
error MINTR_NotActive();
OHM public ohm;
bool public active;
mapping(address => uint256) public mintApproval;
modifier onlyWhileActive() {
if (!active) revert MINTR_NotActive();
_;
}
function mintOhm(address to_, uint256 amount_) external virtual;
function burnOhm(address from_, uint256 amount_) external virtual;
function increaseMintApproval(address policy_, uint256 amount_) external virtual;
function decreaseMintApproval(address policy_, uint256 amount_) external virtual;
function deactivate() external virtual;
function activate() external virtual;
}
文件 16 的 20:OlympusERC20.sol
pragma solidity >=0.7.5;
interface IOlympusAuthority {
event GovernorPushed(address indexed from, address indexed to, bool _effectiveImmediately);
event GuardianPushed(address indexed from, address indexed to, bool _effectiveImmediately);
event PolicyPushed(address indexed from, address indexed to, bool _effectiveImmediately);
event VaultPushed(address indexed from, address indexed to, bool _effectiveImmediately);
event GovernorPulled(address indexed from, address indexed to);
event GuardianPulled(address indexed from, address indexed to);
event PolicyPulled(address indexed from, address indexed to);
event VaultPulled(address indexed from, address indexed to);
function governor() external view returns (address);
function guardian() external view returns (address);
function policy() external view returns (address);
function vault() external view returns (address);
}
abstract contract OlympusAccessControlled {
event AuthorityUpdated(IOlympusAuthority indexed authority);
string internal UNAUTHORIZED = "UNAUTHORIZED";
IOlympusAuthority public authority;
constructor(IOlympusAuthority _authority) {
authority = _authority;
emit AuthorityUpdated(_authority);
}
modifier onlyGovernor() {
require(msg.sender == authority.governor(), UNAUTHORIZED);
_;
}
modifier onlyGuardian() {
require(msg.sender == authority.guardian(), UNAUTHORIZED);
_;
}
modifier onlyPermitted() {
require(msg.sender == authority.policy(), UNAUTHORIZED);
_;
}
modifier onlyVault() {
require(msg.sender == authority.vault(), UNAUTHORIZED);
_;
}
function setAuthority(IOlympusAuthority _newAuthority) external onlyGovernor {
authority = _newAuthority;
emit AuthorityUpdated(_newAuthority);
}
}
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return;
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
} else if (error == RecoverError.InvalidSignatureV) {
revert("ECDSA: invalid signature 'v' value");
}
}
function tryRecover(bytes32 hash, bytes memory signature)
internal
pure
returns (address, RecoverError)
{
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else if (signature.length == 64) {
bytes32 r;
bytes32 vs;
assembly {
r := mload(add(signature, 0x20))
vs := mload(add(signature, 0x40))
}
return tryRecover(hash, r, vs);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address, RecoverError) {
bytes32 s;
uint8 v;
assembly {
s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
v := add(shr(255, vs), 27)
}
return tryRecover(hash, v, r, s);
}
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError) {
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
if (v != 27 && v != 28) {
return (address(0), RecoverError.InvalidSignatureV);
}
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash)
internal
pure
returns (bytes32)
{
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}
abstract contract EIP712 {
bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
uint256 private immutable _CACHED_CHAIN_ID;
bytes32 private immutable _HASHED_NAME;
bytes32 private immutable _HASHED_VERSION;
bytes32 private immutable _TYPE_HASH;
constructor(string memory name, string memory version) {
uint256 chainID;
assembly {
chainID := chainid()
}
bytes32 hashedName = keccak256(bytes(name));
bytes32 hashedVersion = keccak256(bytes(version));
bytes32 typeHash = keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
_HASHED_NAME = hashedName;
_HASHED_VERSION = hashedVersion;
_CACHED_CHAIN_ID = chainID;
_CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
_TYPE_HASH = typeHash;
}
function _domainSeparatorV4() internal view returns (bytes32) {
uint256 chainID;
assembly {
chainID := chainid()
}
if (chainID == _CACHED_CHAIN_ID) {
return _CACHED_DOMAIN_SEPARATOR;
} else {
return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
}
}
function _buildDomainSeparator(
bytes32 typeHash,
bytes32 nameHash,
bytes32 versionHash
) private view returns (bytes32) {
uint256 chainID;
assembly {
chainID := chainid()
}
return keccak256(abi.encode(typeHash, nameHash, versionHash, chainID, address(this)));
}
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
}
}
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
interface IOHM is IERC20 {
function mint(address account_, uint256 amount_) external;
function burn(uint256 amount) external;
function burnFrom(address account_, uint256 amount_) external;
}
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
assert(a == b * c + (a % b));
return c;
}
function sqrrt(uint256 a) internal pure returns (uint256 c) {
if (a > 3) {
c = a;
uint256 b = add(div(a, 2), 1);
while (b < c) {
c = b;
b = div(add(div(a, b), b), 2);
}
} else if (a != 0) {
c = 1;
}
}
}
library Counters {
using SafeMath for uint256;
struct Counter {
uint256 _value;
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
counter._value += 1;
}
function decrement(Counter storage counter) internal {
counter._value = counter._value.sub(1);
}
}
abstract contract ERC20 is IERC20 {
using SafeMath for uint256;
bytes32 private constant ERC20TOKEN_ERC1820_INTERFACE_ID = keccak256("ERC20Token");
mapping(address => uint256) internal _balances;
mapping(address => mapping(address => uint256)) internal _allowances;
uint256 internal _totalSupply;
string internal _name;
string internal _symbol;
uint8 internal immutable _decimals;
constructor(
string memory name_,
string memory symbol_,
uint8 decimals_
) {
_name = name_;
_symbol = symbol_;
_decimals = decimals_;
}
function name() public view returns (string memory) {
return _name;
}
function symbol() public view returns (string memory) {
return _symbol;
}
function decimals() public view virtual returns (uint8) {
return _decimals;
}
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(msg.sender, recipient, amount);
return true;
}
function allowance(address owner, address spender)
public
view
virtual
override
returns (uint256)
{
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
function transferFrom(
address sender,
address recipient,
uint256 amount
) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
_approve(
sender,
msg.sender,
_allowances[sender][msg.sender].sub(amount, "ERC20: transfer amount exceeds allowance")
);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue));
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue)
public
virtual
returns (bool)
{
_approve(
msg.sender,
spender,
_allowances[msg.sender][spender].sub(
subtractedValue,
"ERC20: decreased allowance below zero"
)
);
return true;
}
function _transfer(
address sender,
address recipient,
uint256 amount
) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
_balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
_totalSupply = _totalSupply.sub(amount);
emit Transfer(account, address(0), amount);
}
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _beforeTokenTransfer(
address from_,
address to_,
uint256 amount_
) internal virtual {}
}
abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {
using Counters for Counters.Counter;
mapping(address => Counters.Counter) private _nonces;
bytes32 private immutable _PERMIT_TYPEHASH =
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
);
constructor(string memory name) EIP712(name, "1") {}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual override {
require(block.timestamp <= deadline, "ERC20Permit: expired deadline");
bytes32 structHash = keccak256(
abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline)
);
bytes32 hash = _hashTypedDataV4(structHash);
address signer = ECDSA.recover(hash, v, r, s);
require(signer == owner, "ERC20Permit: invalid signature");
_approve(owner, spender, value);
}
function nonces(address owner) public view virtual override returns (uint256) {
return _nonces[owner].current();
}
function DOMAIN_SEPARATOR() external view override returns (bytes32) {
return _domainSeparatorV4();
}
function _useNonce(address owner) internal virtual returns (uint256 current) {
Counters.Counter storage nonce = _nonces[owner];
current = nonce.current();
nonce.increment();
}
}
contract OlympusERC20Token is ERC20Permit, IOHM, OlympusAccessControlled {
using SafeMath for uint256;
constructor(address _authority)
ERC20("Olympus", "OHM", 9)
ERC20Permit("Olympus")
OlympusAccessControlled(IOlympusAuthority(_authority))
{}
function mint(address account_, uint256 amount_) external override onlyVault {
_mint(account_, amount_);
}
function burn(uint256 amount) external override {
_burn(msg.sender, amount);
}
function burnFrom(address account_, uint256 amount_) external override {
_burnFrom(account_, amount_);
}
function _burnFrom(address account_, uint256 amount_) internal {
uint256 decreasedAllowance_ = allowance(account_, msg.sender).sub(
amount_,
"ERC20: burn amount exceeds allowance"
);
_approve(account_, msg.sender, decreasedAllowance_);
_burn(account_, amount_);
}
}
文件 17 的 20:OlympusRoles.sol
pragma solidity 0.8.15;
import {ROLESv1} from "src/modules/ROLES/ROLES.v1.sol";
import "src/Kernel.sol";
abstract contract RolesConsumer {
ROLESv1 public ROLES;
modifier onlyRole(bytes32 role_) {
ROLES.requireRole(role_, msg.sender);
_;
}
}
contract OlympusRoles is ROLESv1 {
constructor(Kernel kernel_) Module(kernel_) {}
function KEYCODE() public pure override returns (Keycode) {
return toKeycode("ROLES");
}
function VERSION() external pure override returns (uint8 major, uint8 minor) {
major = 1;
minor = 0;
}
function saveRole(bytes32 role_, address addr_) external override permissioned {
if (hasRole[addr_][role_]) revert ROLES_AddressAlreadyHasRole(addr_, role_);
ensureValidRole(role_);
hasRole[addr_][role_] = true;
emit RoleGranted(role_, addr_);
}
function removeRole(bytes32 role_, address addr_) external override permissioned {
if (!hasRole[addr_][role_]) revert ROLES_AddressDoesNotHaveRole(addr_, role_);
hasRole[addr_][role_] = false;
emit RoleRevoked(role_, addr_);
}
function requireRole(bytes32 role_, address caller_) external view override {
if (!hasRole[caller_][role_]) revert ROLES_RequireRole(role_);
}
function ensureValidRole(bytes32 role_) public pure override {
for (uint256 i = 0; i < 32; ) {
bytes1 char = role_[i];
if ((char < 0x61 || char > 0x7A) && char != 0x5f && char != 0x00) {
revert ROLES_InvalidRole(role_);
}
unchecked {
i++;
}
}
}
}
文件 18 的 20:ROLES.v1.sol
pragma solidity 0.8.15;
import "src/Kernel.sol";
abstract contract ROLESv1 is Module {
event RoleGranted(bytes32 indexed role_, address indexed addr_);
event RoleRevoked(bytes32 indexed role_, address indexed addr_);
error ROLES_InvalidRole(bytes32 role_);
error ROLES_RequireRole(bytes32 role_);
error ROLES_AddressAlreadyHasRole(address addr_, bytes32 role_);
error ROLES_AddressDoesNotHaveRole(address addr_, bytes32 role_);
error ROLES_RoleDoesNotExist(bytes32 role_);
mapping(address => mapping(bytes32 => bool)) public hasRole;
function saveRole(bytes32 role_, address addr_) external virtual;
function removeRole(bytes32 role_, address addr_) external virtual;
function requireRole(bytes32 role_, address caller_) external virtual;
function ensureValidRole(bytes32 role_) external pure virtual;
}
文件 19 的 20:TRSRY.v1.sol
pragma solidity 0.8.15;
import {ERC20} from "solmate/tokens/ERC20.sol";
import "src/Kernel.sol";
abstract contract TRSRYv1 is Module {
event IncreaseWithdrawApproval(
address indexed withdrawer_,
ERC20 indexed token_,
uint256 newAmount_
);
event DecreaseWithdrawApproval(
address indexed withdrawer_,
ERC20 indexed token_,
uint256 newAmount_
);
event Withdrawal(
address indexed policy_,
address indexed withdrawer_,
ERC20 indexed token_,
uint256 amount_
);
event IncreaseDebtorApproval(address indexed debtor_, ERC20 indexed token_, uint256 newAmount_);
event DecreaseDebtorApproval(address indexed debtor_, ERC20 indexed token_, uint256 newAmount_);
event DebtIncurred(ERC20 indexed token_, address indexed policy_, uint256 amount_);
event DebtRepaid(ERC20 indexed token_, address indexed policy_, uint256 amount_);
event DebtSet(ERC20 indexed token_, address indexed policy_, uint256 amount_);
error TRSRY_NoDebtOutstanding();
error TRSRY_NotActive();
bool public active;
mapping(address => mapping(ERC20 => uint256)) public withdrawApproval;
mapping(address => mapping(ERC20 => uint256)) public debtApproval;
mapping(ERC20 => uint256) public totalDebt;
mapping(ERC20 => mapping(address => uint256)) public reserveDebt;
modifier onlyWhileActive() {
if (!active) revert TRSRY_NotActive();
_;
}
function increaseWithdrawApproval(
address withdrawer_,
ERC20 token_,
uint256 amount_
) external virtual;
function decreaseWithdrawApproval(
address withdrawer_,
ERC20 token_,
uint256 amount_
) external virtual;
function withdrawReserves(
address to_,
ERC20 token_,
uint256 amount_
) external virtual;
function increaseDebtorApproval(
address debtor_,
ERC20 token_,
uint256 amount_
) external virtual;
function decreaseDebtorApproval(
address debtor_,
ERC20 token_,
uint256 amount_
) external virtual;
function incurDebt(ERC20 token_, uint256 amount_) external virtual;
function repayDebt(
address debtor_,
ERC20 token_,
uint256 amount_
) external virtual;
function setDebt(
address debtor_,
ERC20 token_,
uint256 amount_
) external virtual;
function getReserveBalance(ERC20 token_) external view virtual returns (uint256);
function deactivate() external virtual;
function activate() external virtual;
}
文件 20 的 20:TransferHelper.sol
pragma solidity >=0.8.0;
import {ERC20} from "solmate/tokens/ERC20.sol";
library TransferHelper {
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 amount
) internal {
(bool success, bytes memory data) = address(token).call(
abi.encodeWithSelector(ERC20.transferFrom.selector, from, to, amount)
);
require(success && (data.length == 0 || abi.decode(data, (bool))), "TRANSFER_FROM_FAILED");
}
function safeTransfer(
ERC20 token,
address to,
uint256 amount
) internal {
(bool success, bytes memory data) = address(token).call(
abi.encodeWithSelector(ERC20.transfer.selector, to, amount)
);
require(success && (data.length == 0 || abi.decode(data, (bool))), "TRANSFER_FAILED");
}
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
(bool success, bytes memory data) = address(token).call(
abi.encodeWithSelector(ERC20.approve.selector, to, amount)
);
require(success && (data.length == 0 || abi.decode(data, (bool))), "APPROVE_FAILED");
}
}
{
"compilationTarget": {
"src/policies/BoostedLiquidity/BLVaultManagerLido.sol": "BLVaultManagerLido"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 10
},
"remappings": [
":balancer-v2/=lib/balancer-v2/",
":bonds/=lib/bonds/src/",
":clones-with-immutable-args/=lib/clones-with-immutable-args/src/",
":clones/=lib/clones-with-immutable-args/src/",
":ds-test/=lib/ds-test/src/",
":forge-std/=lib/forge-std/src/",
":interfaces/=src/interfaces/",
":libraries/=src/libraries/",
":modules/=src/modules/",
":policies/=src/policies/",
":solmate/=lib/solmate/src/",
":test/=src/test/"
]
}
[{"inputs":[{"internalType":"contract Kernel","name":"kernel_","type":"address"},{"components":[{"internalType":"address","name":"ohm","type":"address"},{"internalType":"address","name":"pairToken","type":"address"},{"internalType":"address","name":"aura","type":"address"},{"internalType":"address","name":"bal","type":"address"}],"internalType":"struct IBLVaultManagerLido.TokenData","name":"tokenData_","type":"tuple"},{"components":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"liquidityPool","type":"address"},{"internalType":"address","name":"balancerHelper","type":"address"}],"internalType":"struct IBLVaultManagerLido.BalancerData","name":"balancerData_","type":"tuple"},{"components":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"address","name":"auraBooster","type":"address"},{"internalType":"address","name":"auraRewardPool","type":"address"}],"internalType":"struct IBLVaultManagerLido.AuraData","name":"auraData_","type":"tuple"},{"internalType":"address","name":"auraMiningLib_","type":"address"},{"components":[{"internalType":"contract AggregatorV3Interface","name":"feed","type":"address"},{"internalType":"uint48","name":"updateThreshold","type":"uint48"}],"internalType":"struct IBLVaultManagerLido.OracleFeed","name":"ohmEthPriceFeed_","type":"tuple"},{"components":[{"internalType":"contract AggregatorV3Interface","name":"feed","type":"address"},{"internalType":"uint48","name":"updateThreshold","type":"uint48"}],"internalType":"struct IBLVaultManagerLido.OracleFeed","name":"ethUsdPriceFeed_","type":"tuple"},{"components":[{"internalType":"contract AggregatorV3Interface","name":"feed","type":"address"},{"internalType":"uint48","name":"updateThreshold","type":"uint48"}],"internalType":"struct IBLVaultManagerLido.OracleFeed","name":"stethUsdPriceFeed_","type":"tuple"},{"internalType":"address","name":"implementation_","type":"address"},{"internalType":"uint256","name":"ohmLimit_","type":"uint256"},{"internalType":"uint64","name":"fee_","type":"uint64"},{"internalType":"uint48","name":"minWithdrawalDelay_","type":"uint48"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BLManagerLido_AlreadyActive","type":"error"},{"inputs":[],"name":"BLManagerLido_AlreadyInactive","type":"error"},{"inputs":[],"name":"BLManagerLido_BadPriceFeed","type":"error"},{"inputs":[],"name":"BLManagerLido_Inactive","type":"error"},{"inputs":[],"name":"BLManagerLido_InvalidFee","type":"error"},{"inputs":[],"name":"BLManagerLido_InvalidLimit","type":"error"},{"inputs":[],"name":"BLManagerLido_InvalidLpAmount","type":"error"},{"inputs":[],"name":"BLManagerLido_InvalidVault","type":"error"},{"inputs":[],"name":"BLManagerLido_LimitViolation","type":"error"},{"inputs":[],"name":"BLManagerLido_NoUserVault","type":"error"},{"inputs":[],"name":"BLManagerLido_VaultAlreadyExists","type":"error"},{"inputs":[],"name":"CreateFail","type":"error"},{"inputs":[{"internalType":"address","name":"caller_","type":"address"}],"name":"KernelAdapter_OnlyKernel","type":"error"},{"inputs":[{"internalType":"Keycode","name":"keycode_","type":"bytes5"}],"name":"Policy_ModuleDoesNotExist","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint64","name":"fee","type":"uint64"}],"name":"VaultDeployed","type":"event"},{"inputs":[],"name":"BLREG","outputs":[{"internalType":"contract BLREGv1","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FEE","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTR","outputs":[{"internalType":"contract MINTRv1","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROLES","outputs":[{"internalType":"contract ROLESv1","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TRSRY","outputs":[{"internalType":"contract TRSRYv1","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"activate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"aura","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auraData","outputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"address","name":"auraBooster","type":"address"},{"internalType":"address","name":"auraRewardPool","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auraMiningLib","outputs":[{"internalType":"contract IAuraMiningLib","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bal","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balancerData","outputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"liquidityPool","type":"address"},{"internalType":"address","name":"balancerHelper","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"burnOhmFromVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user_","type":"address"}],"name":"canWithdraw","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Kernel","name":"newKernel_","type":"address"}],"name":"changeKernel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint48","name":"ohmEthUpdateThreshold_","type":"uint48"},{"internalType":"uint48","name":"ethUsdUpdateThreshold_","type":"uint48"},{"internalType":"uint48","name":"stethUsdUpdateThreshold_","type":"uint48"}],"name":"changeUpdateThresholds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"circulatingOhmBurned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"configureDependencies","outputs":[{"internalType":"Keycode[]","name":"dependencies","type":"bytes5[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentFee","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deactivate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"decreaseTotalLp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployVault","outputs":[{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployedOhm","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"emergencyBurnOhm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ethUsdPriceFeed","outputs":[{"internalType":"contract AggregatorV3Interface","name":"feed","type":"address"},{"internalType":"uint48","name":"updateThreshold","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchangeName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"getExpectedLpAmount","outputs":[{"internalType":"uint256","name":"bptAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"lpAmount_","type":"uint256"}],"name":"getExpectedPairTokenOutUser","outputs":[{"internalType":"uint256","name":"expectedTknAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"lpAmount_","type":"uint256"}],"name":"getExpectedTokensOutProtocol","outputs":[{"internalType":"uint256[]","name":"expectedTokenAmounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user_","type":"address"}],"name":"getLpBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOhmSupplyChangeData","outputs":[{"internalType":"uint256","name":"poolOhmShare","type":"uint256"},{"internalType":"uint256","name":"mintedOhm","type":"uint256"},{"internalType":"uint256","name":"netBurnedOhm","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOhmTknPoolPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOhmTknPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user_","type":"address"}],"name":"getOutstandingRewards","outputs":[{"components":[{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"uint256","name":"outstandingRewards","type":"uint256"}],"internalType":"struct RewardsData[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPoolOhmShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"rewardToken_","type":"address"}],"name":"getRewardRate","outputs":[{"internalType":"uint256","name":"rewardRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTknOhmPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user_","type":"address"}],"name":"getUserPairShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"contract BLVaultLido","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"increaseTotalLp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isLidoBLVaultActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"kernel","outputs":[{"internalType":"contract Kernel","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minWithdrawalDelay","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"mintOhmToVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ohm","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ohmEthPriceFeed","outputs":[{"internalType":"contract AggregatorV3Interface","name":"feed","type":"address"},{"internalType":"uint48","name":"updateThreshold","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ohmLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pairToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"requestPermissions","outputs":[{"components":[{"internalType":"Keycode","name":"keycode","type":"bytes5"},{"internalType":"bytes4","name":"funcSelector","type":"bytes4"}],"internalType":"struct Permissions[]","name":"permissions","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"newFee_","type":"uint64"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newLimit_","type":"uint256"}],"name":"setLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint48","name":"newDelay_","type":"uint48"}],"name":"setWithdrawalDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stethUsdPriceFeed","outputs":[{"internalType":"contract AggregatorV3Interface","name":"feed","type":"address"},{"internalType":"uint48","name":"updateThreshold","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalLp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userVaults","outputs":[{"internalType":"contract BLVaultLido","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract BLVaultLido","name":"","type":"address"}],"name":"vaultOwners","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]