编译器
0.8.17+commit.8df45f5f
文件 1 的 54:AccessControl.sol
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(account),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}
文件 2 的 54:AggregateVault.sol
pragma solidity 0.8.17;
import { IGlpRebalanceRouter } from "../interfaces/IGlpRebalanceRouter.sol";
import { INettedPositionTracker } from "../interfaces/INettedPositionTracker.sol";
import { PositionManagerRouter, WhitelistedTokenRegistry } from "../handlers/hedgeManagers/PositionManagerRouter.sol";
import { AccessControl } from "@openzeppelin/contracts/access/AccessControl.sol";
import { Pausable } from "@openzeppelin/contracts/security/Pausable.sol";
import { ERC20 } from "solmate/tokens/ERC20.sol";
import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol";
import { IRewardRouterV2 } from "../interfaces/IRewardRouterV2.sol";
import { IAssetVault } from "../interfaces/IAssetVault.sol";
import { IFeeEscrow } from "../interfaces/IFeeEscrow.sol";
import { IVaultFeesAndHooks } from "../interfaces/IVaultFeesAndHooks.sol";
import { AggregateVaultStorage } from "../storage/AggregateVaultStorage.sol";
import { NettingMath } from "../libraries/NettingMath.sol";
import { Solarray } from "../libraries/Solarray.sol";
import { Auth, GlobalACL, KEEPER_ROLE, SWAP_KEEPER } from "../Auth.sol";
import {
UMAMI_TOTAL_VAULTS,
GMX_FEE_STAKED_GLP,
GMX_GLP_MANAGER,
GMX_GLP_REWARD_ROUTER,
GMX_FEE_STAKED_GLP,
GMX_GLP_CLAIM_REWARDS,
UNISWAP_SWAP_ROUTER
} from "../constants.sol";
import { AssetVault } from "./AssetVault.sol";
import { GlpHandler } from "../handlers/GlpHandler.sol";
import { IPositionManager } from "../interfaces/IPositionManager.sol";
import { Whitelist } from "../peripheral/Whitelist.sol";
import { AggregateVaultHelper } from "../peripheral/AggregateVaultHelper.sol";
import { Multicall } from "../libraries/Multicall.sol";
import { ISwapManager } from "../interfaces/ISwapManager.sol";
enum Peripheral {
FeeHookHelper,
RebalanceRouter,
NettedPositionTracker,
GlpHandler,
GlpYieldRewardRouter,
Whitelist,
AggregateVaultHelper,
NettingMath,
UniV3SwapManager
}
contract AggregateVault is GlobalACL, PositionManagerRouter, AggregateVaultStorage, Multicall {
using SafeTransferLib for ERC20;
event CollectVaultFees(
uint256 totalVaultFee,
uint256 performanceFeeInAsset,
uint256 managementFeeInAsset,
uint256 timelockYieldMintAmount,
address _assetVault
);
event OpenRebalance(
uint256 timestamp, uint256[5] nextVaultGlpAlloc, uint256[5] nextGlpComp, int256[5] adjustedPositions
);
event CloseRebalance(uint256 _timestamp);
ERC20 public constant fsGLP = ERC20(GMX_FEE_STAKED_GLP);
constructor(
Auth _auth,
GlpHandler _glpHandler,
uint256 _nettingPriceTolerance,
uint256 _zeroSumPnlThreshold,
WhitelistedTokenRegistry _registry
) GlobalACL(_auth) PositionManagerRouter(_registry) {
AVStorage storage _storage = _getStorage();
_storage.glpHandler = _glpHandler;
_storage.glpRewardClaimAddr = GMX_GLP_CLAIM_REWARDS;
_storage.shouldCheckNetting = true;
_storage.nettedThreshold = 10;
_storage.glpRebalanceTolerance = 500;
_storage.nettingPriceTolerance = _nettingPriceTolerance;
_storage.zeroSumPnlThreshold = _zeroSumPnlThreshold;
}
function handleDeposit(ERC20 asset, uint256 _amount, address _account) external onlyAssetVault returns (uint256) {
require(_amount > 0, "AggregateVault: deposit amount must be greater than 0");
require(_account != address(0), "AggregateVault: deposit account must be non-zero address");
uint256 vaultId = getVaultIndex(address(asset));
require(vaultId < 5, "AggregateVault: invalid vaultId");
AssetVaultEntry storage vault = _getAssetVaultEntries()[vaultId];
uint256 amountSansFee = _amount - _collectDepositFee(vault, _amount);
vault.epochDelta += int256(amountSansFee);
return amountSansFee;
}
function handleWithdraw(ERC20 asset, uint256 _amount, address _account) external onlyAssetVault returns (uint256) {
require(_amount > 0, "AggregateVault: withdraw amount must be greater than 0");
require(_account != address(0), "AggregateVault: withdraw account must be non-zero address");
uint256 vaultId = getVaultIndex(address(asset));
require(vaultId < 5, "AggregateVault: invalid vaultId");
AssetVaultEntry storage vault = _getAssetVaultEntries()[vaultId];
uint256 amountSansFee = _amount - _collectWithdrawalFee(vault, _amount);
require(asset.balanceOf(address(this)) >= amountSansFee, "AggregateVault: buffer exhausted");
_transferAsset(address(asset), _account, amountSansFee);
vault.epochDelta -= int256(amountSansFee);
return amountSansFee;
}
function whitelistedDeposit(ERC20 _asset, address _account, uint256 _amount, bytes32[] memory merkleProof)
public
onlyAssetVault
{
Whitelist whitelist = _getWhitelist();
require(whitelist.isWhitelisted(address(_asset), _account, merkleProof), "AggregateVault: not whitelisted");
if (whitelist.isWhitelistedPriority(address(_asset), _account)) {
whitelist.whitelistDeposit(address(_asset), _account, _amount);
} else {
whitelist.whitelistDepositMerkle(address(_asset), _account, _amount, merkleProof);
}
}
function openRebalancePeriod(
uint256[5] memory nextVaultGlpAlloc,
uint256[5] memory nextGlpComp,
int256[5][5] memory nextHedgeMatrix,
int256[5] memory adjustedPositions,
int256[5][5] memory adjustedNettedHedgeMatrix,
bytes memory _hook
) external onlyRole(KEEPER_ROLE) {
_delegatecall(_getFeeHookHelper(), abi.encodeCall(IVaultFeesAndHooks.beforeOpenRebalancePeriod, _hook));
VaultState storage vaultState = _getVaultState();
require(!vaultState.rebalanceOpen, "AggregateVault: rebalance period already open");
checkNettingConstraint(nextVaultGlpAlloc, nextGlpComp, nextHedgeMatrix, adjustedPositions);
pauseDeposits();
RebalanceState storage rebalanceState = _getRebalanceState();
rebalanceState.glpAllocation = nextVaultGlpAlloc;
rebalanceState.glpComposition = nextGlpComp;
rebalanceState.externalPositions = nextHedgeMatrix;
rebalanceState.aggregatePositions = adjustedPositions;
rebalanceState.epoch = vaultState.epoch;
rebalanceState.adjustedExternalPositions = adjustedNettedHedgeMatrix;
_setRebalancePPS(vaultState.rebalancePPS);
vaultState.rebalanceOpen = true;
emit OpenRebalance(block.timestamp, nextVaultGlpAlloc, nextGlpComp, adjustedPositions);
}
function closeRebalancePeriod(uint256 _glpPrice, bytes memory _hook) external onlyRole(KEEPER_ROLE) {
VaultState storage vaultState = _getVaultState();
require(vaultState.rebalanceOpen, "AggregateVault: no open rebalance period");
uint256[5] memory dollarGlpBalance = _glpToDollarArray(_glpPrice);
RebalanceState storage rebalanceState = _getRebalanceState();
checkNettingConstraint(
dollarGlpBalance,
rebalanceState.glpComposition,
rebalanceState.externalPositions,
rebalanceState.aggregatePositions
);
_resetEpochDeltas();
vaultState.rebalanceOpen = false;
vaultState.glpAllocation = rebalanceState.glpAllocation;
vaultState.aggregatePositions = rebalanceState.aggregatePositions;
int256[5][5] memory exposureMatrix;
int256[5][5] memory _nettedPositions;
(_nettedPositions, exposureMatrix) = _getNettingMath().calculateNettedPositions(
rebalanceState.adjustedExternalPositions, rebalanceState.glpComposition, rebalanceState.glpAllocation
);
_setNettedPositions(_nettedPositions);
_setStateExternalPositions(rebalanceState);
AssetVaultEntry[5] storage assetVaults = _getAssetVaultEntries();
for (uint256 i = 0; i < 5; i++) {
_collectVaultRebalanceFees(assetVaults[i]);
}
_setCheckpointTvls();
unpauseDeposits();
vaultState.epoch += 1;
vaultState.lastRebalanceTime = block.timestamp;
_delegatecall(_getFeeHookHelper(), abi.encodeCall(IVaultFeesAndHooks.afterCloseRebalancePeriod, _hook));
emit CloseRebalance(block.timestamp);
}
function cycle(uint256[5] memory, uint256 ) external onlyRole(KEEPER_ROLE) {
(bytes memory ret) = _forwardToHelper(msg.data);
_return(ret);
}
function multicall(bytes[] calldata data)
external
payable
onlyRole(KEEPER_ROLE)
returns (bytes[] memory results, uint256[] memory gasEstimates)
{
(results, gasEstimates) = _multicall(data);
}
function checkNettingConstraint(
uint256[5] memory vaultGlpAlloc,
uint256[5] memory glpComp,
int256[5][5] memory hedgeMatrix,
int256[5] memory aggregatePositions
) public view {
NettingMath.NettedState memory nettingState =
NettingMath.NettedState({ glpHeld: vaultGlpAlloc, externalPositions: aggregatePositions });
NettingMath.NettedParams memory nettingParams = NettingMath.NettedParams({
vaultCumulativeGlpTvl: Solarray.arraySum(vaultGlpAlloc),
glpComposition: glpComp,
nettedThreshold: _getNettedThreshold()
});
if (_getStorage().shouldCheckNetting) {
require(
_getNettingMath().isNetted(nettingState, nettingParams, hedgeMatrix),
"AggregateVault: netting constraint not satisfied"
);
}
}
function previewDepositFee(uint256 size) public returns (uint256 totalDepositFee) {
(bytes memory ret) = _forwardToFeeHookHelper(abi.encodeCall(IVaultFeesAndHooks.getDepositFee, (size)));
(totalDepositFee) = abi.decode(ret, (uint256));
}
function previewWithdrawalFee(address token, uint256 size) public returns (uint256 totalWithdrawalFee) {
(bytes memory ret) = _forwardToFeeHookHelper(abi.encodeCall(IVaultFeesAndHooks.getWithdrawalFee, (token, size)));
(totalWithdrawalFee) = abi.decode(ret, (uint256));
}
function getVaultIndex(address _asset) public view returns (uint256 idx) {
mapping(address => uint256) storage tokenToAssetVaultIndex = _getTokenToAssetVaultIndex();
idx = tokenToAssetVaultIndex[_asset];
AssetVaultEntry[5] storage assetVaults = _getAssetVaultEntries();
require(assetVaults[idx].token == _asset, "AggregateVault: asset vault not found");
}
function getVaultPPS(address _assetVault) public returns (uint256 _pps) {
(bytes memory ret) = _forwardToHelper(abi.encodeCall(this.getVaultPPS, (_assetVault)));
(_pps) = abi.decode(ret, (uint256));
}
function getVaultTVL(address _assetVault) public returns (uint256 _tvl) {
(bytes memory ret) = _forwardToHelper(abi.encodeCall(this.getVaultTVL, (_assetVault)));
(_tvl) = abi.decode(ret, (uint256));
}
function previewVaultCap(address _asset) public view returns (uint256) {
uint256 vidx = getVaultIndex(_asset);
VaultState memory state = _getVaultState();
return state.vaultCaps[vidx];
}
function whitelistEnabled() public view returns (bool) {
Whitelist whitelist = _getWhitelist();
if (address(whitelist) != address(0)) return whitelist.whitelistEnabled();
return false;
}
function rebalanceOpen() public view returns (bool) {
VaultState storage vaultState = _getVaultState();
return vaultState.rebalanceOpen;
}
function setPeripheral(Peripheral _peripheral, address _addr) external onlyConfigurator {
AVStorage storage _storage = _getStorage();
if (_peripheral == Peripheral.FeeHookHelper) {
_storage.feeAndHookHelper = _addr;
} else if (_peripheral == Peripheral.RebalanceRouter) {
_storage.glpRebalanceRouter = IGlpRebalanceRouter(_addr);
} else if (_peripheral == Peripheral.NettedPositionTracker) {
_storage.nettedPositionTracker = INettedPositionTracker(_addr);
} else if (_peripheral == Peripheral.GlpHandler) {
_storage.glpHandler = GlpHandler(_addr);
} else if (_peripheral == Peripheral.GlpYieldRewardRouter) {
_storage.glpRewardClaimAddr = _addr;
} else if (_peripheral == Peripheral.Whitelist) {
_storage.whitelist = Whitelist(_addr);
} else if (_peripheral == Peripheral.AggregateVaultHelper) {
_storage.aggregateVaultHelper = _addr;
} else if (_peripheral == Peripheral.NettingMath) {
_storage.nettingMath = NettingMath(_addr);
} else if (_peripheral == Peripheral.UniV3SwapManager) {
_storage.uniV3SwapManager = ISwapManager(_addr);
}
}
function addPositionManager(IPositionManager _manager) external onlyConfigurator {
IPositionManager[] storage positionManagers = _getPositionManagers();
positionManagers.push(_manager);
}
function setVaultFees(
uint256 _performanceFee,
uint256 _managementFee,
uint256 _withdrawalFee,
uint256 _depositFee,
uint256 _timelockBoostPercent
) external onlyConfigurator {
_getStorage().vaultFees = VaultFees({
performanceFee: _performanceFee,
managementFee: _managementFee,
withdrawalFee: _withdrawalFee,
depositFee: _depositFee,
timelockBoostAmount: _timelockBoostPercent
});
}
function setFeeWatermarks(uint256[5] memory _newWatermarks) external onlyConfigurator {
AssetVaultEntry[5] storage assetVaults = _getAssetVaultEntries();
for (uint256 i = 0; i < 5; i++) {
assetVaults[i].feeWatermarkPPS = _newWatermarks[i];
assetVaults[i].feeWatermarkDate = block.timestamp;
}
}
function updateFeeWatermarkVault(uint256 _vaultId, uint256 _feeWatermarkPPS) external onlyConfigurator {
AssetVaultEntry[5] storage assetVaults = _getAssetVaultEntries();
assetVaults[_vaultId].feeWatermarkDate = block.timestamp;
assetVaults[_vaultId].feeWatermarkPPS = _feeWatermarkPPS;
}
function setShouldCheckNetting(bool _newVal) external onlyConfigurator {
AVStorage storage _storage = _getStorage();
_storage.shouldCheckNetting = _newVal;
}
function setNettedThreshold(uint256 _newNettedThreshold) external onlyConfigurator {
AVStorage storage _storage = _getStorage();
_storage.nettedThreshold = _newNettedThreshold;
}
function setZeroSumPnlThreshold(uint256 _zeroSumPnlThreshold) external onlyConfigurator {
require(_zeroSumPnlThreshold > 0, "AggregateVault: _zeroSumPnlThreshold must be > 0");
require(_zeroSumPnlThreshold < 1e18, "AggregateVault: _zeroSumPnlThreshold must be < 1e18");
AVStorage storage _storage = _getStorage();
_storage.zeroSumPnlThreshold = _zeroSumPnlThreshold;
}
function setAssetVaults(AssetVaultEntry[5] calldata _assetVaults) external onlyConfigurator {
AssetVaultEntry[5] storage assetVaults = _getAssetVaultEntries();
mapping(address => uint256) storage tokenToAssetVaultIndex = _getTokenToAssetVaultIndex();
mapping(address => uint256) storage vaultToAssetVaultIndex = _getVaultToAssetVaultIndex();
for (uint256 i = 0; i < _assetVaults.length; i++) {
assetVaults[i] = _assetVaults[i];
tokenToAssetVaultIndex[_assetVaults[i].token] = i;
vaultToAssetVaultIndex[_assetVaults[i].vault] = i;
}
}
function setVaultCaps(uint256[5] memory _newCaps) external onlyConfigurator {
VaultState storage state = _getVaultState();
state.vaultCaps = _newCaps;
}
function setFeeRecipient(address _recipient, address _depositFeeEscrow, address _withdrawalFeeEscrow)
external
onlyConfigurator
{
require(_recipient != address(0), "AggregateVault: !address(0)");
require(_depositFeeEscrow != address(0), "AggregateVault: !address(0)");
VaultState storage state = _getVaultState();
state.feeRecipient = _recipient;
state.depositFeeEscrow = _depositFeeEscrow;
state.withdrawalFeeEscrow = _withdrawalFeeEscrow;
}
function _collectVaultRebalanceFees(AssetVaultEntry memory assetVault) internal {
uint256 performanceFeeInAsset;
uint256 managementFeeInAsset;
uint256 timelockYieldMintAmount;
uint256 totalVaultFee;
VaultState storage vaultState = _getVaultState();
(bytes memory ret) = _forwardToFeeHookHelper(
abi.encodeCall(IVaultFeesAndHooks.getVaultRebalanceFees, (assetVault.token, vaultState.lastRebalanceTime))
);
(performanceFeeInAsset, managementFeeInAsset, timelockYieldMintAmount, totalVaultFee) =
abi.decode(ret, (uint256, uint256, uint256, uint256));
if (totalVaultFee > 0) {
_transferAsset(assetVault.token, vaultState.feeRecipient, totalVaultFee);
}
if (timelockYieldMintAmount > 0 && assetVault.timelockYieldBoost != address(0)) {
AssetVault(assetVault.vault).mintTimelockBoost(timelockYieldMintAmount, assetVault.timelockYieldBoost);
}
emit CollectVaultFees(
totalVaultFee, performanceFeeInAsset, managementFeeInAsset, timelockYieldMintAmount, assetVault.vault
);
}
function _collectWithdrawalFee(AssetVaultEntry memory assetVault, uint256 size) internal returns (uint256) {
uint256 totalWithdrawalFee;
(bytes memory ret) =
_forwardToFeeHookHelper(abi.encodeCall(IVaultFeesAndHooks.getWithdrawalFee, (assetVault.token, size)));
(totalWithdrawalFee) = abi.decode(ret, (uint256));
VaultState memory vaultState = _getVaultState();
if (totalWithdrawalFee > 0) {
_transferAsset(assetVault.token, vaultState.withdrawalFeeEscrow, totalWithdrawalFee);
}
return totalWithdrawalFee;
}
function _collectDepositFee(AssetVaultEntry memory assetVault, uint256 size) internal returns (uint256) {
uint256 totalDepositFee;
(bytes memory ret) = _forwardToFeeHookHelper(abi.encodeCall(IVaultFeesAndHooks.getDepositFee, (size)));
(totalDepositFee) = abi.decode(ret, (uint256));
VaultState storage vaultState = _getVaultState();
if (totalDepositFee > 0) {
_transferAsset(assetVault.token, vaultState.depositFeeEscrow, totalDepositFee);
}
return totalDepositFee;
}
function _resetEpochDeltas() internal {
AssetVaultEntry[5] storage assetVaults = _getAssetVaultEntries();
for (uint256 i = 0; i < 5; i++) {
assetVaults[i].epochDelta = int256(0);
}
}
function _setCheckpointTvls() internal {
AssetVaultEntry[5] storage assetVaults = _getAssetVaultEntries();
for (uint256 i = 0; i < 5; i++) {
assetVaults[i].lastCheckpointTvl = getVaultTVL(assetVaults[i].vault);
}
}
function _setRebalancePPS(uint256[5] storage rebalancePps) internal {
AssetVaultEntry[5] storage assetVaults = _getAssetVaultEntries();
for (uint256 i = 0; i < 5; i++) {
rebalancePps[i] = getVaultPPS(assetVaults[i].vault);
}
}
function _glpToDollarArray(uint256 _glpPrice) internal view returns (uint256[5] memory glpAsDollars) {
uint256[5] memory _vaultGlpAttribution = _getVaultGlpAttribution();
uint256 totalGlpAttribution = Solarray.arraySum(_vaultGlpAttribution);
uint256 totalGlpBalance = fsGLP.balanceOf(address(this));
for (uint256 i = 0; i < 5; i++) {
uint256 glpBalance = totalGlpBalance * _vaultGlpAttribution[i] / totalGlpAttribution;
glpAsDollars[i] = _glpPrice * glpBalance / 1e18;
}
}
function pauseDeposits() public onlyRole(KEEPER_ROLE) {
AssetVaultEntry[5] storage assetVaults = _getAssetVaultEntries();
for (uint256 i = 0; i < assetVaults.length; i++) {
IAssetVault(assetVaults[i].vault).pauseDepositWithdraw();
}
}
function unpauseDeposits() public onlyRole(KEEPER_ROLE) {
AssetVaultEntry[5] storage assetVaults = _getAssetVaultEntries();
for (uint256 i = 0; i < assetVaults.length; i++) {
IAssetVault(assetVaults[i].vault).unpauseDepositWithdraw();
}
}
function delegateview(address _target, bytes calldata _data) external returns (bool _success, bytes memory _ret) {
(bool success, bytes memory ret) = address(this).call(abi.encodeCall(this.delegateviewRevert, (_target, _data)));
require(!success, "AggregateVault: delegateViewRevert didn't revert");
(_success, _ret) = abi.decode(ret, (bool, bytes));
}
function delegateviewRevert(address _target, bytes memory _data) external {
(bool success, bytes memory ret) = _target.delegatecall(_data);
bytes memory encoded = abi.encode(success, ret);
assembly {
revert(add(encoded, 0x20), mload(encoded))
}
}
function _forwardToHelper(bytes memory _calldata) internal returns (bytes memory ret) {
address aggregateVaultHelper = _getAggregateVaultHelper();
ret = _delegatecall(aggregateVaultHelper, _calldata);
}
function _forwardToFeeHookHelper(bytes memory _calldata) internal returns (bytes memory ret) {
address feeHookHelper = _getFeeHookHelper();
ret = _delegatecall(feeHookHelper, _calldata);
}
function _return(bytes memory _ret) internal pure {
assembly {
let length := mload(_ret)
return(add(_ret, 0x20), length)
}
}
function _onlyConfigurator() internal override onlyConfigurator { }
function _onlySwapIssuer() internal override onlyRole(SWAP_KEEPER) { }
function _validateExecuteCallAuth() internal override onlyRole(KEEPER_ROLE) { }
function _transferAsset(address asset, address recipient, uint256 amount) internal {
ERC20(asset).safeTransfer(recipient, amount);
}
modifier onlyAssetVault() {
AssetVaultEntry[5] storage assetVaults = _getAssetVaultEntries();
for (uint256 i = 0; i < UMAMI_TOTAL_VAULTS; ++i) {
if (msg.sender == assetVaults[i].vault) {
_;
return;
}
}
revert("AggregateVault: not asset vault");
}
}
文件 3 的 54:AggregateVaultHelper.sol
pragma solidity 0.8.17;
import { AggregateVaultStorage } from "../storage/AggregateVaultStorage.sol";
import {
UMAMI_TOTAL_VAULTS,
GMX_FEE_STAKED_GLP,
GMX_GLP_REWARD_ROUTER,
GMX_GLP_MANAGER,
TOKEN_USDC,
TOKEN_WETH,
TOKEN_WBTC,
TOKEN_LINK,
TOKEN_UNI,
UNISWAP_SWAP_ROUTER
} from "../constants.sol";
import { ERC20 } from "solmate/tokens/ERC20.sol";
import { Solarray } from "../libraries/Solarray.sol";
import { AssetVault } from "../vaults/AssetVault.sol";
import { IPositionManager } from "../interfaces/IPositionManager.sol";
import { GlpHandler } from "../handlers/GlpHandler.sol";
import { BaseHandler } from "../handlers/BaseHandler.sol";
import { INettedPositionTracker } from "../interfaces/INettedPositionTracker.sol";
import { VaultMath } from "../libraries/VaultMath.sol";
import { IRewardRouterV2 } from "../interfaces/IRewardRouterV2.sol";
import { Multicall } from "../libraries/Multicall.sol";
import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol";
import { Solarray } from "../libraries/Solarray.sol";
import { PositionManagerRouter } from "../handlers/hedgeManagers/PositionManagerRouter.sol";
import { FeeEscrow } from "./FeeEscrow.sol";
import { LibRebalance } from "../libraries/LibRebalance.sol";
import { LibAggregateVaultUtils } from "../libraries/LibAggregateVaultUtils.sol";
ERC20 constant fsGLP = ERC20(GMX_FEE_STAKED_GLP);
uint256 constant BIPS = 10_000;
contract AggregateVaultViews is AggregateVaultStorage {
error RebalanceGlpAccountingError();
function getAssetVaultEntries() public view returns (AssetVaultEntry[5] memory _assetVaultEntry) {
_assetVaultEntry = _getStorage().assetVaults;
}
function tokenToAssetVaultIndex(address _token) public view returns (uint256 _idx) {
_idx = _getStorage().tokenToAssetVaultIndex[_token];
}
function vaultToAssetVaultIndex(address _vault) public view returns (uint256 _idx) {
_idx = _getStorage().vaultToAssetVaultIndex[_vault];
}
function getVaultState() public view returns (VaultState memory _vaultState) {
_vaultState = _getStorage().vaultState;
}
function getRebalanceState() public view returns (RebalanceState memory _rebalanceState) {
_rebalanceState = _getStorage().rebalanceState;
}
function getVaultGlpAttribution() public view returns (uint256[5] memory _glpAttribution) {
_glpAttribution = _getStorage().vaultGlpAttribution;
}
function getLastNettedPrice(uint256 _epoch)
public
view
returns (INettedPositionTracker.NettedPrices memory _nettedPrices)
{
_nettedPrices = _getStorage().lastNettedPrices[_epoch];
}
function getPositionManagers() public view returns (IPositionManager[] memory _positionManagers) {
_positionManagers = _getStorage().positionManagers;
}
function getActiveAggregatePositions() public view returns (int256[4] memory _activeAggregatePositions) {
_activeAggregatePositions = _getStorage().activeAggregatePositions;
}
function getNettedPositions() public view returns (int256[5][5] memory _nettedPositions) {
_nettedPositions = _getStorage().nettedPositions;
}
function getActiveExternalPositions() public view returns (int256[5][5] memory _activeExternalPositions) {
_activeExternalPositions = _getStorage().activeExternalPositions;
}
function getLastGlpComposition() public view returns (uint256[5] memory _glpComposition) {
_glpComposition = _getStorage().lastGlpComposition;
}
}
contract AggregateVaultHelper is AggregateVaultViews, BaseHandler, Multicall {
using SafeTransferLib for ERC20;
event SettleNettedPositionPnl(
uint256[5] previousGlpAmount,
uint256[5] settledGlpAmount,
int256[5] glpPnl,
int256[5] dollarPnl,
int256[5] percentPriceChange
);
event UpdateNettingCheckpointPrice(
INettedPositionTracker.NettedPrices oldPrices, INettedPositionTracker.NettedPrices newPrices
);
event CompoundDistributeYield(uint256[5] glpYieldPerVault);
event RebalanceGlpPosition(
uint256[5] vaultGlpAttributionBefore,
uint256[5] vaultGlpAttributionAfter,
uint256[5] targetGlpAllocation,
int256[5] totalVaultGlpDelta,
int256[5] feeAmounts
);
event GlpRewardClaimed(uint256 _amount);
event Cycle(uint256 timestamp, uint256 round);
function getVaultPPS(address _assetVault) public onlyDelegateCall returns (uint256 _pps) {
VaultState memory vaultState = _getVaultState();
if (vaultState.rebalanceOpen) {
mapping(address => uint256) storage vaultToAssetVaultIndex = _getVaultToAssetVaultIndex();
return vaultState.rebalancePPS[vaultToAssetVaultIndex[_assetVault]];
}
uint256 idx = _getVaultToAssetVaultIndex()[_assetVault];
AssetVaultEntry storage assetVault = _getAssetVaultEntry(idx);
(uint256 tvl,,,) = _getAssetVaultTvl(assetVault);
uint256 oneShare = 10 ** ERC20(assetVault.vault).decimals();
uint256 totalSupply = ERC20(assetVault.vault).totalSupply();
if (totalSupply == 0) return oneShare;
_pps = (tvl * oneShare) / totalSupply;
}
function getVaultsGlp() public view returns (uint256[5] memory _vaultsGlp) {
_vaultsGlp = LibAggregateVaultUtils.getVaultsGlp(_getStorage());
}
function getVaultsGlpNoPnl() public view returns (uint256[5] memory _vaultsGlpNoPnl) {
_vaultsGlpNoPnl = LibAggregateVaultUtils.getVaultsGlpNoPnl(_getStorage());
}
function getVaultTVL(address _assetVault) public onlyDelegateCall returns (uint256 _tvl) {
uint256 idx = _getVaultToAssetVaultIndex()[_assetVault];
AssetVaultEntry storage assetVault = _getAssetVaultEntry(idx);
(_tvl,,,) = _getAssetVaultTvl(assetVault);
}
function getVaultTVLBreakdown(address _assetVault)
public
onlyDelegateCall
returns (uint256 _total, uint256 _buffer, uint256 _glp, uint256 _hedges)
{
(_total, _buffer, _glp, _hedges) =
_getAssetVaultTvl(_getAssetVaultEntry(_getVaultToAssetVaultIndex()[_assetVault]));
}
function setTimelockYieldBoost(address newTimelockYieldBoost, uint256 vaultIdx) public onlyDelegateCall {
AssetVaultEntry[5] storage assetVaults = _getAssetVaultEntries();
assetVaults[vaultIdx].timelockYieldBoost = newTimelockYieldBoost;
}
function setNettedPositions(int256[5][5] memory _nettedPositions) public onlyDelegateCall {
_setNettedPositions(_nettedPositions);
}
function setKeeperShareConfig(address _newKeeper, uint256 _newBps) public onlyDelegateCall {
require(_newKeeper != address(0), "Invalid keeper address");
require(_newBps <= 5000, "More than max allowed");
_getStorage().keeper = _newKeeper;
_getStorage().keeperShareBps = _newBps;
}
function setSwapTolerance(uint256 _newSwapTolerance) public onlyDelegateCall {
require(_newSwapTolerance <= 10_000, "Invalid BPS");
_getStorage().swapToleranceBps = _newSwapTolerance;
}
function settleInternalPnl(uint256[5] memory assetPrices, uint256 glpPrice) external onlyDelegateCall {
_settleInternalPnl(assetPrices, glpPrice);
}
function setVaultGlpAttribution(uint256[5] memory _newVals) public onlyDelegateCall {
uint256[5] storage _vaultGlpAttribution = _getVaultGlpAttribution();
for (uint256 i = 0; i < _vaultGlpAttribution.length; ++i) {
_vaultGlpAttribution[i] = _newVals[i];
}
}
function setNettingPriceTolerance(uint256 _tolerance) external onlyDelegateCall {
require(_tolerance <= BIPS, "AggregateVaultHelper: tolerance too high");
_getStorage().nettingPriceTolerance = _tolerance;
}
function setGlpRebalanceTolerance(uint256 _tolerance) external onlyDelegateCall {
require(_tolerance <= BIPS, "AggregateVaultHelper: tolerance too high");
_getStorage().glpRebalanceTolerance = _tolerance;
}
function setRebalanceState(RebalanceState memory _rebalanceState) external onlyDelegateCall {
RebalanceState storage rebalanceState = _getRebalanceState();
rebalanceState.glpAllocation = _rebalanceState.glpAllocation;
rebalanceState.glpComposition = _rebalanceState.glpComposition;
rebalanceState.aggregatePositions = _rebalanceState.aggregatePositions;
rebalanceState.epoch = _rebalanceState.epoch;
for (uint256 i = 0; i < UMAMI_TOTAL_VAULTS; ++i) {
for (uint256 j = 0; j < UMAMI_TOTAL_VAULTS; ++j) {
rebalanceState.externalPositions[i][j] = _rebalanceState.externalPositions[i][j];
rebalanceState.adjustedExternalPositions[i][j] = _rebalanceState.adjustedExternalPositions[i][j];
}
}
}
function setGlpMintBurnSlippageTolerance(uint256 _newTolerance) external onlyDelegateCall {
_getStorage().glpMintBurnSlippageTolerance = _newTolerance;
}
function updateNettingCheckpointPrice(INettedPositionTracker.NettedPrices memory assetPrices, uint256 epochId)
external
onlyDelegateCall
{
_updateNettingCheckpointPrice(assetPrices, epochId);
}
function removePositionManagerAt(address _addr, uint256 idx) external onlyDelegateCall {
IPositionManager[] storage positionManagers = _getPositionManagers();
require(positionManagers[idx] == IPositionManager(_addr), "invalid idx");
positionManagers[idx] = positionManagers[positionManagers.length - 1];
positionManagers.pop();
}
function updateEpoch(uint256 _epoch) public onlyDelegateCall {
_getStorage().vaultState.epoch = _epoch;
}
function cycle(uint256[5] memory assetPrices, uint256 glpPrice) external onlyDelegateCall {
_cycle(assetPrices, glpPrice);
VaultState storage vaultState = _getVaultState();
emit Cycle(block.timestamp, vaultState.epoch);
}
function handleGlpRewards(bool compound) public onlyDelegateCall {
uint256 priorBalance = ERC20(TOKEN_WETH).balanceOf(address(this));
_getFeeClaimRewardRouter().handleRewards(true, true, true, true, true, true, false);
uint256 rewardAmount = ERC20(TOKEN_WETH).balanceOf(address(this)) - priorBalance;
emit GlpRewardClaimed(rewardAmount);
if (compound) {
_compoundDistributeYield(rewardAmount);
} else {
_bufferDistributeYield(rewardAmount);
}
}
function rebalanceGlpPosition(uint256[5] memory _nextGlpAllocation, uint256 _glpPrice) external onlyDelegateCall {
LibRebalance.rebalanceGlpPosition(_getStorage(), _nextGlpAllocation, _glpPrice);
}
function _getAssetVaultEntry(uint256 _idx) internal view returns (AssetVaultEntry storage _assetVault) {
_assetVault = _getAssetVaultEntries()[_idx];
}
function _getAssetVaultIdxFromVault(address _vault) internal view returns (uint256 _idx) {
AssetVaultEntry[5] storage assetVaults = _getAssetVaultEntries();
for (uint256 i = 0; i < UMAMI_TOTAL_VAULTS; ++i) {
if (assetVaults[i].vault == _vault) {
return i;
}
}
revert("AggregateVault: unknown asset vault");
}
function _getAssetVaultTvl(AssetVaultEntry storage _assetVault)
internal
returns (uint256 _totalTvl, uint256 _bufferTvl, uint256 _glpTvl, uint256 _hedgesTvl)
{
uint256 assetVaultIdx = _getAssetVaultIdxFromVault(_assetVault.vault);
_bufferTvl = ERC20(_assetVault.token).balanceOf(address(this));
_glpTvl = _assetVaultGlpToken(assetVaultIdx);
_hedgesTvl = _getAssetVaultHedgesInNativeToken(assetVaultIdx);
_totalTvl = _bufferTvl + _glpTvl + _hedgesTvl;
}
function _getAssetVaultHedgesInUsd(uint256 _vaultIdx) internal returns (uint256 _hedgesUsd) {
AssetVaultEntry[5] storage assetVaults = _getAssetVaultEntries();
VaultState storage vaultState = _getVaultState();
for (uint256 i = 1; i < UMAMI_TOTAL_VAULTS; ++i) {
address token = assetVaults[i].token;
uint256 totalNotional = _getTotalNotionalInExternalPositions(i);
uint256 notional = vaultState.externalPositions[_vaultIdx][i] > 0
? uint256(vaultState.externalPositions[_vaultIdx][i])
: uint256(-vaultState.externalPositions[_vaultIdx][i]);
(uint256 totalMargin,) = _getTotalMargin(token);
if (totalNotional > 0) {
_hedgesUsd += (totalMargin * notional) / totalNotional;
}
}
}
function _getAssetVaultHedgesInNativeToken(uint256 _vaultIdx) internal returns (uint256 _hedgesToken) {
uint256 hedgesUsd = _getAssetVaultHedgesInUsd(_vaultIdx);
GlpHandler glpHandler = _getGlpHandler();
AssetVaultEntry storage assetVault = _getAssetVaultEntries()[_vaultIdx];
_hedgesToken = glpHandler.getUsdToToken(hedgesUsd, 30, assetVault.token);
}
function _getTotalNotionalInExternalPositions(uint256 _idx) internal view returns (uint256 _totalNotional) {
VaultState storage vaultState = _getVaultState();
for (uint256 i = 0; i < UMAMI_TOTAL_VAULTS; ++i) {
int256 externalPosition = vaultState.externalPositions[i][_idx];
uint256 absoluteExternalPosition =
externalPosition > 0 ? uint256(externalPosition) : uint256(-externalPosition);
_totalNotional += absoluteExternalPosition;
}
}
function _getAllAssetVaultsHedgeAtribution() external returns (uint256[4][5] memory hedgeAttribution) {
AssetVaultEntry[5] storage assetVaults = _getAssetVaultEntries();
for (uint256 i = 0; i < assetVaults.length; ++i) {
hedgeAttribution[i] = _getAssetVaultHedgeAttribution(assetVaults[i].vault);
}
return hedgeAttribution;
}
function _getTotalNotional(address _token) public returns (uint256 _totalNotional, bool _isLong) {
IPositionManager[] storage positionManagers = _getPositionManagers();
uint256 length = positionManagers.length;
bool unset = true;
_isLong = false;
for (uint256 i = 0; i < length; ++i) {
bytes memory ret = _delegatecall(
address(positionManagers[i]), abi.encodeWithSignature("positionNotional(address)", _token)
);
(uint256 notional, bool isLong_) = abi.decode(ret, (uint256, bool));
if (notional > 0) {
if (unset) {
_isLong = isLong_;
unset = false;
} else {
require(_isLong == isLong_, "AggregateVaultHelper: mixed long/short");
}
}
_totalNotional += notional;
}
}
function _getTotalMargin(address _token) public returns (uint256 _totalMargin, bool _isLong) {
IPositionManager[] storage positionManagers = _getPositionManagers();
uint256 length = positionManagers.length;
bool unset = true;
_isLong = false;
for (uint256 i = 0; i < length; ++i) {
bytes memory ret =
_delegatecall(address(positionManagers[i]), abi.encodeWithSignature("positionMargin(address)", _token));
(uint256 margin, bool isLong_) = abi.decode(ret, (uint256, bool));
if (margin > 0) {
if (unset) {
_isLong = isLong_;
unset = false;
} else {
require(_isLong == isLong_, "AggregateVaultHelper: mixed long/short");
}
}
_totalMargin += margin;
}
}
function _getCurrentPrices() public view returns (INettedPositionTracker.NettedPrices memory _prices) {
_prices = LibAggregateVaultUtils.getCurrentPrices(_getStorage());
}
function _getAssetVaultHedgeAttribution(address _vault)
internal
returns (uint256[4] memory _vaultMarginAttribution)
{
uint256 assetVaultIdx = _getAssetVaultIdxFromVault(_vault);
AssetVaultEntry[5] storage assetVaults = _getAssetVaultEntries();
VaultState storage vaultState = _getVaultState();
for (uint256 i = 1; i < UMAMI_TOTAL_VAULTS; ++i) {
address token = assetVaults[i].token;
uint256 totalNotional = _getTotalNotionalInExternalPositions(i);
uint256 notional = vaultState.externalPositions[assetVaultIdx][i] > 0
? uint256(vaultState.externalPositions[assetVaultIdx][i])
: uint256(-vaultState.externalPositions[assetVaultIdx][i]);
(uint256 actualNotional,) = _getTotalNotional(token);
if (totalNotional > 0) {
_vaultMarginAttribution[i - 1] = (actualNotional * notional) / totalNotional;
}
}
return _vaultMarginAttribution;
}
function _updateNettingCheckpointPrice(INettedPositionTracker.NettedPrices memory assetPrices, uint256 epochId)
internal
{
INettedPositionTracker.NettedPrices storage nettedPrice = _getEpochNettedPrice(epochId);
require(nettedPrice.stable == 0, "AggregateVault: lastNettedPrices already inited for given epoch");
_checkNettingCheckpointPrice(assetPrices);
mapping(uint256 => INettedPositionTracker.NettedPrices) storage lastNettedPrices = _getLastNettedPrices();
lastNettedPrices[epochId] = assetPrices;
emit UpdateNettingCheckpointPrice(lastNettedPrices[epochId - 1], assetPrices);
}
function _cycle(uint256[5] memory assetPrices, uint256 glpPrice) internal {
VaultState storage vaultState = _getVaultState();
if (vaultState.epoch > 0) {
_settleInternalPnl(assetPrices, glpPrice);
}
_updateNettingCheckpointPrice(
INettedPositionTracker.NettedPrices({
stable: assetPrices[0],
eth: assetPrices[1],
btc: assetPrices[2],
link: assetPrices[3],
uni: assetPrices[4]
}),
vaultState.epoch + 1
);
RebalanceState storage rebalanceState = _getRebalanceState();
LibRebalance.rebalanceGlpPosition(_getStorage(), rebalanceState.glpAllocation, glpPrice);
}
function _settleInternalPnl(uint256[5] memory assetPrices, uint256 glpPrice) internal {
uint256[5] memory settledVaultGlpAmount;
int256[5] memory nettedPnl;
int256[5] memory glpPnl;
int256[5] memory percentPriceChange;
INettedPositionTracker.NettedPrices memory nettedPrices = INettedPositionTracker.NettedPrices({
stable: assetPrices[0],
eth: assetPrices[1],
btc: assetPrices[2],
link: assetPrices[3],
uni: assetPrices[4]
});
VaultState storage vaultState = _getVaultState();
uint256[5] memory vaultGlpAmount = LibAggregateVaultUtils.getVaultsGlpNoPnl(_getStorage());
(settledVaultGlpAmount, nettedPnl, glpPnl, percentPriceChange) = _getNettedPositionTracker()
.settleNettingPositionPnl(
_getNettedPositions(),
nettedPrices,
_getEpochNettedPrice(vaultState.epoch),
vaultGlpAmount,
glpPrice,
_getZeroSumPnlThreshold()
);
setVaultGlpAttribution(settledVaultGlpAmount);
emit SettleNettedPositionPnl(vaultGlpAmount, settledVaultGlpAmount, glpPnl, nettedPnl, percentPriceChange);
}
function _bufferDistributeYield(uint256 _rewardAmount) internal {
require(_rewardAmount > 0, "AggregateVault: _rewardAmount 0");
AssetVaultEntry[5] storage assetVaults = _getAssetVaultEntries();
uint256 swapInput;
GlpHandler handler = _getGlpHandler();
for (uint256 i = 0; i < assetVaults.length; i++) {
if (assetVaults[i].token != TOKEN_WETH) {
swapInput = _rewardAmount * _getVaultGlpAttributeProportion(i) / 1e18;
PositionManagerRouter(payable(address(this))).executeSwap(
_getUniV3SwapManager(),
TOKEN_WETH,
assetVaults[i].token,
swapInput,
handler.tokenToToken(TOKEN_WETH, assetVaults[i].token, swapInput),
bytes("")
);
}
}
}
function _compoundDistributeYield(uint256 _rewardAmount) internal {
if (_rewardAmount > 0) {
ERC20(TOKEN_WETH).safeApprove(GMX_GLP_MANAGER, _rewardAmount);
uint256 amountWithSlippage =
VaultMath.getSlippageAdjustedAmount(_rewardAmount, _getStorage().glpMintBurnSlippageTolerance);
uint256 glpMinted =
IRewardRouterV2(GMX_GLP_REWARD_ROUTER).mintAndStakeGlp(TOKEN_WETH, _rewardAmount, amountWithSlippage, 0);
AssetVaultEntry[5] storage assetVaults = _getAssetVaultEntries();
uint256[5] storage _vaultGlpAttribution = _getVaultGlpAttribution();
uint256[5] memory increments;
for (uint256 i = 0; i < assetVaults.length; i++) {
increments[i] = (glpMinted * _getVaultGlpAttributeProportion(i)) / 1e18;
}
for (uint256 i = 0; i < assetVaults.length; i++) {
_vaultGlpAttribution[i] += increments[i];
}
emit CompoundDistributeYield(increments);
}
}
function _assetVaultGlpToken(uint256 _vaultIdx) internal view returns (uint256 _glpToken) {
uint256 currentEpoch = _getVaultState().epoch;
uint256 vaultGlp = LibAggregateVaultUtils.getVaultGlp(_getStorage(), _vaultIdx, currentEpoch);
AssetVaultEntry storage assetVault = _getAssetVaultEntries()[_vaultIdx];
GlpHandler glpHandler = _getGlpHandler();
_glpToken = glpHandler.previewGlpMintBurn(assetVault.token, vaultGlp);
}
function _getVaultGlpAttributeProportion(uint256 _vaultIdx) internal view returns (uint256 _proportion) {
uint256[5] memory _vaultGlpAttribution = _getVaultGlpAttribution();
uint256 totalGlpAttribution = Solarray.arraySum(_vaultGlpAttribution);
if (totalGlpAttribution == 0) return 0;
return (_vaultGlpAttribution[_vaultIdx] * 1e18) / totalGlpAttribution;
}
function resetCheckpointPrices(uint256 _noOfEpochs) public onlyDelegateCall {
INettedPositionTracker.NettedPrices memory assetPrices =
INettedPositionTracker.NettedPrices({ stable: 0, eth: 0, btc: 0, link: 0, uni: 0 });
mapping(uint256 => INettedPositionTracker.NettedPrices) storage lastNettedPrices = _getLastNettedPrices();
for (uint256 i = 0; i < _noOfEpochs; ++i) {
lastNettedPrices[i] = assetPrices;
}
}
function _checkNettingCheckpointPrice(INettedPositionTracker.NettedPrices memory _assetPrices) internal view {
INettedPositionTracker.NettedPrices memory currentPrices =
LibAggregateVaultUtils.getCurrentPrices(_getStorage());
uint256 tolerance = _getNettingPriceTolerance();
_assertWithinTolerance(_assetPrices.stable, currentPrices.stable, tolerance);
_assertWithinTolerance(_assetPrices.eth, currentPrices.eth, tolerance);
_assertWithinTolerance(_assetPrices.btc, currentPrices.btc, tolerance);
_assertWithinTolerance(_assetPrices.link, currentPrices.link, tolerance);
_assertWithinTolerance(_assetPrices.uni, currentPrices.uni, tolerance);
}
function _assertWithinTolerance(uint256 _actual, uint256 _target, uint256 _toleranceBps) internal pure {
require(_toleranceBps <= BIPS, "tolerance must be <= 100%");
uint256 lower = (_target * (BIPS - _toleranceBps)) / BIPS;
uint256 higher = (_target * (BIPS + _toleranceBps)) / BIPS;
require(_actual >= lower && _actual <= higher, "not within tolerance");
}
function _delegatecall(address _target, bytes memory _data) internal returns (bytes memory ret) {
bool success;
(success, ret) = _target.delegatecall(_data);
if (!success) {
assembly {
let length := mload(ret)
let start := add(ret, 0x20)
revert(start, length)
}
}
return ret;
}
function callbackSigs() external pure returns (bytes4[] memory _ret) {
_ret = new bytes4[](0);
}
}
文件 4 的 54:AggregateVaultStorage.sol
pragma solidity 0.8.17;
import { Whitelist } from "../peripheral/Whitelist.sol";
import { NettingMath } from "../libraries/NettingMath.sol";
import { IGlpRebalanceRouter } from "../interfaces/IGlpRebalanceRouter.sol";
import { INettedPositionTracker } from "../interfaces/INettedPositionTracker.sol";
import { IVaultFeesAndHooks } from "../interfaces/IVaultFeesAndHooks.sol";
import { GlpHandler } from "../handlers/GlpHandler.sol";
import { IPositionManager } from "../interfaces/IPositionManager.sol";
import { IRewardRouterV2 } from "../interfaces/IRewardRouterV2.sol";
import { UMAMI_TOTAL_VAULTS } from "../constants.sol";
import { ISwapManager } from "../interfaces/ISwapManager.sol";
abstract contract AggregateVaultStorage {
bytes32 public constant STORAGE_SLOT = keccak256("AggregateVault.storage");
struct AssetVaultEntry {
address vault;
address token;
uint256 feeWatermarkPPS;
uint256 feeWatermarkDate;
int256 epochDelta;
uint256 lastCheckpointTvl;
address timelockYieldBoost;
}
struct VaultState {
uint256 epoch;
bool rebalanceOpen;
uint256 lastRebalanceTime;
uint256[5] glpAllocation;
int256[5] aggregatePositions;
int256[5][5] externalPositions;
address feeRecipient;
address depositFeeEscrow;
address withdrawalFeeEscrow;
uint256[5] vaultCaps;
uint256[5] rebalancePPS;
}
struct RebalanceState {
uint256[5] glpAllocation;
uint256[5] glpComposition;
int256[5][5] externalPositions;
int256[5] aggregatePositions;
uint256 epoch;
int256[5][5] adjustedExternalPositions;
}
struct VaultFees {
uint256 performanceFee;
uint256 managementFee;
uint256 withdrawalFee;
uint256 depositFee;
uint256 timelockBoostAmount;
}
struct VaultFeeParams {
uint256 performanceFeePercent;
uint256 managementFeePercent;
uint256 withdrawalFeePercent;
uint256 depositFeePercent;
}
struct AVStorage {
AssetVaultEntry[5] assetVaults;
mapping(address => uint256) tokenToAssetVaultIndex;
mapping(address => uint256) vaultToAssetVaultIndex;
address glpRewardClaimAddr;
VaultState vaultState;
RebalanceState rebalanceState;
VaultFees vaultFees;
uint256[5] vaultGlpAttribution;
IGlpRebalanceRouter glpRebalanceRouter;
INettedPositionTracker nettedPositionTracker;
address feeAndHookHelper;
mapping(uint256 => INettedPositionTracker.NettedPrices) lastNettedPrices;
GlpHandler glpHandler;
IPositionManager[] positionManagers;
bool shouldCheckNetting;
Whitelist whitelist;
address aggregateVaultHelper;
int256[4] activeAggregatePositions;
int256[5][5] nettedPositions;
int256[5][5] activeExternalPositions;
uint256[5] lastGlpComposition;
NettingMath nettingMath;
uint256 nettedThreshold;
uint256 nettingPriceTolerance;
uint256 glpRebalanceTolerance;
uint256 zeroSumPnlThreshold;
ISwapManager uniV3SwapManager;
uint256 glpMintBurnSlippageTolerance;
address hookHelper;
uint256 keeperShareBps;
address keeper;
uint256 swapToleranceBps;
}
function _getStorage() internal pure returns (AVStorage storage _storage) {
bytes32 slot = STORAGE_SLOT;
assembly {
_storage.slot := slot
}
}
function _getRebalanceState() internal view returns (RebalanceState storage _rebalanceState) {
_rebalanceState = _getStorage().rebalanceState;
}
function _getAssetVaultEntries() internal view returns (AssetVaultEntry[5] storage _assetVaults) {
_assetVaults = _getStorage().assetVaults;
}
function _getVaultState() internal view returns (VaultState storage _vaultState) {
_vaultState = _getStorage().vaultState;
}
function _getPositionManagers() internal view returns (IPositionManager[] storage _positionManagers) {
_positionManagers = _getStorage().positionManagers;
}
function _getGlpHandler() internal view returns (GlpHandler _glpHandler) {
_glpHandler = _getStorage().glpHandler;
}
function _getVaultToAssetVaultIndex()
internal
view
returns (mapping(address => uint256) storage _vaultToAssetVaultIndex)
{
_vaultToAssetVaultIndex = _getStorage().vaultToAssetVaultIndex;
}
function _getFeeClaimRewardRouter() internal view returns (IRewardRouterV2 _rewardRouter) {
_rewardRouter = IRewardRouterV2(_getStorage().glpRewardClaimAddr);
}
function _getVaultGlpAttribution() internal view returns (uint256[5] storage _vaultGlpAttribution) {
_vaultGlpAttribution = _getStorage().vaultGlpAttribution;
}
function _getNettedPositions() internal view returns (int256[5][5] storage _nettedPositions) {
_nettedPositions = _getStorage().nettedPositions;
}
function _getRebalanceRouter() internal view returns (IGlpRebalanceRouter _rebalanceRouter) {
_rebalanceRouter = _getStorage().glpRebalanceRouter;
}
function _getNettedPositionTracker() internal view returns (INettedPositionTracker _nettedPositionTracker) {
_nettedPositionTracker = _getStorage().nettedPositionTracker;
}
function _getLastNettedPrices()
internal
view
returns (mapping(uint256 => INettedPositionTracker.NettedPrices) storage _lastNettedPrices)
{
_lastNettedPrices = _getStorage().lastNettedPrices;
}
function _getEpochNettedPrice(uint256 _epoch)
internal
view
returns (INettedPositionTracker.NettedPrices storage _nettedPrices)
{
_nettedPrices = _getLastNettedPrices()[_epoch];
}
function _getFeeHookHelper() internal view returns (address _feeAndHookHelper) {
_feeAndHookHelper = _getStorage().feeAndHookHelper;
}
function _getVaultFees() internal view returns (VaultFees storage _vaultFees) {
_vaultFees = _getStorage().vaultFees;
}
function _getTokenToAssetVaultIndex()
internal
view
returns (mapping(address => uint256) storage _tokenToAssetVaultIndex)
{
_tokenToAssetVaultIndex = _getStorage().tokenToAssetVaultIndex;
}
function _getWhitelist() internal view returns (Whitelist _whitelist) {
_whitelist = _getStorage().whitelist;
}
function _getNettingMath() internal view returns (NettingMath _nettingMath) {
_nettingMath = _getStorage().nettingMath;
}
function _getAggregateVaultHelper() internal view returns (address _aggregateVaultHelper) {
_aggregateVaultHelper = _getStorage().aggregateVaultHelper;
}
function _getNettedThreshold() internal view returns (uint256 _nettedThreshold) {
_nettedThreshold = _getStorage().nettedThreshold;
}
function _setNettedPositions(int256[5][5] memory _nettedPositions) internal {
int256[5][5] storage nettedPositions = _getNettedPositions();
for (uint256 i = 0; i < 5; ++i) {
for (uint256 j = 0; j < 5; ++j) {
nettedPositions[i][j] = _nettedPositions[i][j];
}
}
}
function _setVaultGlpAttribution(uint256[5] memory _vaultGlpAttribution) internal {
uint256[5] storage __vaultGlpAttribution = _getVaultGlpAttribution();
for (uint256 i = 0; i < 5; ++i) {
__vaultGlpAttribution[i] = _vaultGlpAttribution[i];
}
}
function getVaultFromAsset(address _asset) public view returns (AssetVaultEntry memory vault) {
AssetVaultEntry[5] storage assetVaults = _getAssetVaultEntries();
for (uint256 i = 0; i < 5; i++) {
if (assetVaults[i].token == _asset) {
return assetVaults[i];
}
}
return vault;
}
function _getNettingPriceTolerance() internal view returns (uint256 _tolerance) {
_tolerance = _getStorage().nettingPriceTolerance;
}
function _getZeroSumPnlThreshold() internal view returns (uint256 _zeroSumPnlThreshold) {
_zeroSumPnlThreshold = _getStorage().zeroSumPnlThreshold;
}
function _setStateExternalPositions(RebalanceState storage _rebalanceStorage) internal {
VaultState storage vaultState = _getVaultState();
for (uint256 i = 0; i < UMAMI_TOTAL_VAULTS; ++i) {
for (uint256 j = 0; j < UMAMI_TOTAL_VAULTS; ++j) {
vaultState.externalPositions[i][j] = _rebalanceStorage.adjustedExternalPositions[i][j];
}
}
}
function _getUniV3SwapManager() internal view returns (ISwapManager _swapManager) {
_swapManager = _getStorage().uniV3SwapManager;
}
}
文件 5 的 54:AssetVault.sol
pragma solidity 0.8.17;
import { ERC4626 } from "solmate/mixins/ERC4626.sol";
import { ERC20 } from "solmate/tokens/ERC20.sol";
import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol";
import { ShareMath } from "../libraries/ShareMath.sol";
import { IAggregateVault } from "../interfaces/IAggregateVault.sol";
import { AggregateVault } from "./AggregateVault.sol";
import { GlobalACL } from "../Auth.sol";
import { PausableVault } from "../PausableVault.sol";
contract AssetVault is ERC4626, PausableVault, GlobalACL {
using SafeTransferLib for ERC20;
AggregateVault public aggregateVault;
constructor(ERC20 _asset, string memory _name, string memory _symbol, address _aggregateVault)
ERC4626(_asset, _name, _symbol)
GlobalACL(AggregateVault(payable(_aggregateVault)).AUTH())
{
aggregateVault = AggregateVault(payable(_aggregateVault));
}
function deposit(uint256 assets, address receiver)
public
override
whitelistDisabled
whenDepositNotPaused
returns (uint256 shares)
{
require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES");
require(tvl() + assets <= previewVaultCap(), "AssetVault: over vault cap");
uint256 depositPPS = pps();
asset.safeTransferFrom(msg.sender, address(aggregateVault), assets);
assets = aggregateVault.handleDeposit(asset, assets, msg.sender);
shares = ShareMath.assetToShares(assets, depositPPS, decimals);
_mint(receiver, shares);
emit Deposit(msg.sender, receiver, assets, shares);
afterDeposit(assets, shares);
}
function mint(uint256 shares, address receiver)
public
override
whitelistDisabled
whenDepositNotPaused
returns (uint256 assets)
{
assets = previewMint(shares);
require(tvl() + assets <= previewVaultCap(), "AssetVault: over vault cap");
uint256 depositPPS = pps();
asset.safeTransferFrom(msg.sender, address(aggregateVault), assets);
assets = aggregateVault.handleDeposit(asset, assets, receiver);
shares = ShareMath.assetToShares(assets, depositPPS, decimals);
_mint(receiver, shares);
emit Deposit(msg.sender, receiver, assets, shares);
afterDeposit(assets, shares);
}
function withdraw(uint256 assets, address receiver, address owner)
public
override
whenWithdrawalNotPaused
returns (uint256 shares)
{
assets += previewWithdrawalFee(assets);
shares = ShareMath.assetToShares(assets, pps(), decimals);
require(shares > 0, "AssetVault: !shares > 0");
if (msg.sender != owner) {
_checkAllowance(owner, shares);
}
beforeWithdraw(assets, shares);
_burn(owner, shares);
assets = aggregateVault.handleWithdraw(asset, assets, receiver);
emit Withdraw(msg.sender, receiver, owner, assets, shares);
}
function redeem(uint256 shares, address receiver, address owner)
public
override
whenWithdrawalNotPaused
returns (uint256 assets)
{
require(shares > 0, "AssetVault: !shares > 0");
assets = totalSupply == 0 ? shares : ShareMath.sharesToAsset(shares, pps(), decimals);
if (msg.sender != owner) {
_checkAllowance(owner, shares);
}
require(previewRedeem(shares) != 0, "ZERO_ASSETS");
beforeWithdraw(assets, shares);
_burn(owner, shares);
assets = aggregateVault.handleWithdraw(asset, assets, receiver);
emit Withdraw(msg.sender, receiver, owner, assets, shares);
}
function whitelistDeposit(uint256 assets, address receiver, bytes32[] memory merkleProof)
public
whitelistEnabled
whenDepositNotPaused
returns (uint256 shares)
{
require(tvl() + assets <= previewVaultCap(), "AssetVault: over vault cap");
require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES");
aggregateVault.whitelistedDeposit(asset, msg.sender, assets, merkleProof);
uint256 depositPPS = pps();
asset.safeTransferFrom(msg.sender, address(aggregateVault), assets);
assets = aggregateVault.handleDeposit(asset, assets, msg.sender);
shares = ShareMath.assetToShares(assets, depositPPS, decimals);
_mint(receiver, shares);
emit Deposit(msg.sender, receiver, assets, shares);
afterDeposit(assets, shares);
}
function totalAssets() public view override returns (uint256) {
return ShareMath.sharesToAsset(totalSupply, pps(), decimals);
}
function convertToShares(uint256 assets) public view override returns (uint256) {
return totalSupply == 0 ? assets : ShareMath.assetToShares(assets, pps(), decimals);
}
function convertToAssets(uint256 shares) public view override returns (uint256) {
return totalSupply == 0 ? shares : ShareMath.sharesToAsset(shares, pps(), decimals);
}
function previewDeposit(uint256 assets) public view override returns (uint256) {
uint256 assetFee = previewDepositFee(assets);
if (assetFee >= assets) return 0;
return convertToShares(assets - assetFee);
}
function previewMint(uint256 shares) public view override returns (uint256 _mintAmount) {
_mintAmount = totalSupply == 0 ? shares : ShareMath.sharesToAsset(shares, pps(), decimals);
_mintAmount = _mintAmount + previewDepositFee(_mintAmount);
}
function previewWithdraw(uint256 assets) public view override returns (uint256 _withdrawAmount) {
uint256 assetFee = previewWithdrawalFee(assets);
if (assetFee >= assets) return 0;
_withdrawAmount = totalSupply == 0 ? assets : ShareMath.assetToShares(assets - assetFee, pps(), decimals);
}
function previewRedeem(uint256 shares) public view override returns (uint256) {
uint256 assets = ShareMath.sharesToAsset(shares, pps(), decimals);
uint256 assetFee = previewWithdrawalFee(assets);
if (assetFee >= assets) return 0;
return assets - assetFee;
}
function maxDeposit(address) public view override returns (uint256) {
uint256 cap = previewVaultCap();
uint256 tvl = tvl();
return cap > tvl ? cap - tvl : 0;
}
function maxMint(address) public view override returns (uint256) {
uint256 cap = previewVaultCap();
uint256 tvl = tvl();
return cap > tvl ? convertToShares(cap - tvl) : 0;
}
function maxWithdraw(address owner) public view override returns (uint256) {
uint256 aggBalance = asset.balanceOf(address(aggregateVault));
uint256 userMaxAssets = convertToAssets(balanceOf[owner]);
return aggBalance > userMaxAssets ? userMaxAssets : aggBalance;
}
function maxRedeem(address owner) public view override returns (uint256) {
uint256 aggBalance = convertToShares(asset.balanceOf(address(aggregateVault)));
return aggBalance > balanceOf[owner] ? balanceOf[owner] : aggBalance;
}
function pauseDepositWithdraw() external onlyAggregateVault {
_pause();
}
function unpauseDepositWithdraw() external onlyAggregateVault {
_unpause();
}
function pauseDeposits() external onlyConfigurator {
_pauseDeposit();
}
function unpauseDeposits() external onlyConfigurator {
_unpauseDeposit();
}
function pauseWithdrawals() external onlyConfigurator {
_pauseWithdrawal();
}
function unpauseWithdrawals() external onlyConfigurator {
_unpauseWithdrawal();
}
function pps() public view returns (uint256 pricePerShare) {
(bool success, bytes memory ret) =
address(aggregateVault).staticcall(abi.encodeCall(AggregateVault.getVaultPPS, address(this)));
if (!success) {
assembly {
let length := mload(ret)
revert(add(32, ret), length)
}
}
pricePerShare = abi.decode(ret, (uint256));
}
function tvl() public view returns (uint256 totalValueLocked) {
(bool success, bytes memory ret) =
address(aggregateVault).staticcall(abi.encodeCall(AggregateVault.getVaultTVL, address(this)));
if (!success) {
assembly {
let length := mload(ret)
revert(add(32, ret), length)
}
}
totalValueLocked = abi.decode(ret, (uint256));
}
function updateAggregateVault(AggregateVault _newAggregateVault) external onlyConfigurator {
aggregateVault = _newAggregateVault;
}
function mintTimelockBoost(uint256 _mintAmount, address _timelockContract) external onlyAggregateVault {
_mint(_timelockContract, _mintAmount);
}
function previewDepositFee(uint256 size) public view returns (uint256 totalDepositFee) {
(bool success, bytes memory ret) =
address(aggregateVault).staticcall(abi.encodeCall(AggregateVault.previewDepositFee, (size)));
if (!success) {
assembly {
let length := mload(ret)
revert(add(32, ret), length)
}
}
totalDepositFee = abi.decode(ret, (uint256));
}
function previewWithdrawalFee(uint256 size) public view returns (uint256 totalWithdrawalFee) {
(bool success, bytes memory ret) = address(aggregateVault).staticcall(
abi.encodeCall(AggregateVault.previewWithdrawalFee, (address(asset), size))
);
if (!success) {
assembly {
let length := mload(ret)
revert(add(32, ret), length)
}
}
totalWithdrawalFee = abi.decode(ret, (uint256));
}
function previewVaultCap() public view returns (uint256) {
return aggregateVault.previewVaultCap(address(asset));
}
function _checkAllowance(address owner, uint256 shares) internal {
uint256 allowed = allowance[owner][msg.sender];
if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;
}
modifier onlyAggregateVault() {
require(msg.sender == address(aggregateVault), "AssetVault: Caller is not AggregateVault");
_;
}
modifier whitelistEnabled() {
require(aggregateVault.whitelistEnabled());
_;
}
modifier whitelistDisabled() {
require(!aggregateVault.whitelistEnabled());
_;
}
}
文件 6 的 54:Auth.sol
pragma solidity 0.8.17;
bytes32 constant CONFIGURATOR_ROLE = keccak256("CONFIGURATOR");
bytes32 constant KEEPER_ROLE = keccak256("KEEPER_ROLE");
bytes32 constant SWAP_KEEPER = keccak256("SWAP_KEEPER");
contract Auth {
error NotAuthorized(bytes32 _role, address _user);
event RoleUpdated(bytes32 indexed role, address indexed user, bool authorized);
bytes32 public constant AUTH_MANAGER_ROLE = keccak256("AUTH_MANAGER");
mapping(bytes32 => mapping(address => bool)) public hasRole;
constructor() {
_updateRole(msg.sender, AUTH_MANAGER_ROLE, true);
}
function updateRole(address _user, bytes32 _role, bool _authorized) external {
onlyRole(AUTH_MANAGER_ROLE, msg.sender);
_updateRole(_user, _role, _authorized);
}
function onlyRole(bytes32 _role, address _user) public view {
if (!hasRole[_role][_user]) {
revert NotAuthorized(_role, _user);
}
}
function _updateRole(address _user, bytes32 _role, bool _authorized) internal {
hasRole[_role][_user] = _authorized;
emit RoleUpdated(_role, _user, _authorized);
}
}
abstract contract GlobalACL {
Auth public immutable AUTH;
constructor(Auth _auth) {
require(address(_auth) != address(0), "GlobalACL: zero address");
AUTH = _auth;
}
modifier onlyConfigurator() {
AUTH.onlyRole(CONFIGURATOR_ROLE, msg.sender);
_;
}
modifier onlyRole(bytes32 _role) {
AUTH.onlyRole(_role, msg.sender);
_;
}
}
文件 7 的 54:BaseHandler.sol
pragma solidity 0.8.17;
import { IHandlerContract } from "../interfaces/IHandlerContract.sol";
abstract contract BaseHandler is IHandlerContract {
address immutable SELF;
error OnlyDelegateCall();
constructor() {
SELF = address(this);
}
modifier onlyDelegateCall() {
if (address(this) == SELF) {
revert OnlyDelegateCall();
}
_;
}
}
文件 8 的 54:BaseSwapManager.sol
pragma solidity 0.8.17;
import { BaseHandler } from "../BaseHandler.sol";
import { ISwapManager } from "../../interfaces/ISwapManager.sol";
import { IHandlerContract } from "../../interfaces/IHandlerContract.sol";
import { ERC20 } from "solmate/tokens/ERC20.sol";
abstract contract BaseSwapManager is BaseHandler, ISwapManager {
error InsufficientOutput();
error InsufficientInput();
error InvalidInput();
function callbackSigs() external pure returns (bytes4[] memory _ret) {
_ret = new bytes4[](0);
}
modifier swapChecks(address _tokenIn, address _tokenOut, uint256 _amountIn, uint256 _minOut) {
uint256 tokenInBalance = ERC20(_tokenIn).balanceOf(address(this));
if (tokenInBalance < _amountIn) revert InsufficientInput();
uint256 tokenOutBalanceBefore = ERC20(_tokenOut).balanceOf(address(this));
_;
uint256 tokenOutBalanceAfter = ERC20(_tokenOut).balanceOf(address(this));
uint256 actualOut = tokenOutBalanceAfter - tokenOutBalanceBefore;
if (actualOut < _minOut) revert InsufficientOutput();
}
}
文件 9 的 54:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 10 的 54:ERC165.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 11 的 54: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);
}
}
文件 12 的 54:ERC4626.sol
pragma solidity >=0.8.0;
import {ERC20} from "../tokens/ERC20.sol";
import {SafeTransferLib} from "../utils/SafeTransferLib.sol";
import {FixedPointMathLib} from "../utils/FixedPointMathLib.sol";
abstract contract ERC4626 is ERC20 {
using SafeTransferLib for ERC20;
using FixedPointMathLib for uint256;
event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed caller,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
ERC20 public immutable asset;
constructor(
ERC20 _asset,
string memory _name,
string memory _symbol
) ERC20(_name, _symbol, _asset.decimals()) {
asset = _asset;
}
function deposit(uint256 assets, address receiver) public virtual returns (uint256 shares) {
require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES");
asset.safeTransferFrom(msg.sender, address(this), assets);
_mint(receiver, shares);
emit Deposit(msg.sender, receiver, assets, shares);
afterDeposit(assets, shares);
}
function mint(uint256 shares, address receiver) public virtual returns (uint256 assets) {
assets = previewMint(shares);
asset.safeTransferFrom(msg.sender, address(this), assets);
_mint(receiver, shares);
emit Deposit(msg.sender, receiver, assets, shares);
afterDeposit(assets, shares);
}
function withdraw(
uint256 assets,
address receiver,
address owner
) public virtual returns (uint256 shares) {
shares = previewWithdraw(assets);
if (msg.sender != owner) {
uint256 allowed = allowance[owner][msg.sender];
if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;
}
beforeWithdraw(assets, shares);
_burn(owner, shares);
emit Withdraw(msg.sender, receiver, owner, assets, shares);
asset.safeTransfer(receiver, assets);
}
function redeem(
uint256 shares,
address receiver,
address owner
) public virtual returns (uint256 assets) {
if (msg.sender != owner) {
uint256 allowed = allowance[owner][msg.sender];
if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;
}
require((assets = previewRedeem(shares)) != 0, "ZERO_ASSETS");
beforeWithdraw(assets, shares);
_burn(owner, shares);
emit Withdraw(msg.sender, receiver, owner, assets, shares);
asset.safeTransfer(receiver, assets);
}
function totalAssets() public view virtual returns (uint256);
function convertToShares(uint256 assets) public view virtual returns (uint256) {
uint256 supply = totalSupply;
return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets());
}
function convertToAssets(uint256 shares) public view virtual returns (uint256) {
uint256 supply = totalSupply;
return supply == 0 ? shares : shares.mulDivDown(totalAssets(), supply);
}
function previewDeposit(uint256 assets) public view virtual returns (uint256) {
return convertToShares(assets);
}
function previewMint(uint256 shares) public view virtual returns (uint256) {
uint256 supply = totalSupply;
return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply);
}
function previewWithdraw(uint256 assets) public view virtual returns (uint256) {
uint256 supply = totalSupply;
return supply == 0 ? assets : assets.mulDivUp(supply, totalAssets());
}
function previewRedeem(uint256 shares) public view virtual returns (uint256) {
return convertToAssets(shares);
}
function maxDeposit(address) public view virtual returns (uint256) {
return type(uint256).max;
}
function maxMint(address) public view virtual returns (uint256) {
return type(uint256).max;
}
function maxWithdraw(address owner) public view virtual returns (uint256) {
return convertToAssets(balanceOf[owner]);
}
function maxRedeem(address owner) public view virtual returns (uint256) {
return balanceOf[owner];
}
function beforeWithdraw(uint256 assets, uint256 shares) internal virtual {}
function afterDeposit(uint256 assets, uint256 shares) internal virtual {}
}
文件 13 的 54:FeeEscrow.sol
pragma solidity 0.8.17;
import { ERC20 } from "solmate/tokens/ERC20.sol";
import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol";
import { Vester } from "./Vester.sol";
uint256 constant TOTAL_BPS = 10_000;
contract FeeEscrow {
using SafeTransferLib for ERC20;
event ReimburseAndVest(uint256[5] feeAmounts, uint256[5] vestAmounts, uint256[5] keeperAmounts);
ERC20[5] public ASSETS;
address public immutable AGGREGATE_VAULT;
Vester public immutable VESTER;
constructor(ERC20[5] memory _assets, address _aggregateVault, address _vester) {
ASSETS = _assets;
AGGREGATE_VAULT = _aggregateVault;
VESTER = Vester(_vester);
}
function pullFeesAndVest(uint256[5] memory _feeAmounts, address keeper, uint256 keeperBps)
external
onlyAggregateVault
{
require(keeperBps <= TOTAL_BPS, "FeeEscrow: keeperBps > TOTAL_BPS");
uint256[5] memory reimbursedFeeAmounts;
uint256[5] memory vestAmounts;
uint256[5] memory keeperAmounts;
for (uint256 i = 0; i < 5; i++) {
uint256 balance = ASSETS[i].balanceOf(address(this));
uint256 feeAmount = _feeAmounts[i] > balance ? balance : _feeAmounts[i];
uint256 remainder = balance - feeAmount;
uint256 toKeeper = remainder * keeperBps / TOTAL_BPS;
uint256 toVest = remainder - toKeeper;
reimbursedFeeAmounts[i] = feeAmount;
vestAmounts[i] = toVest;
keeperAmounts[i] = toKeeper;
if (feeAmount > 0) {
ASSETS[i].safeTransfer(AGGREGATE_VAULT, feeAmount);
}
if (toKeeper > 0) {
ASSETS[i].safeTransfer(keeper, toKeeper);
}
if (toVest > 0) {
ASSETS[i].safeApprove(address(VESTER), toVest);
VESTER.addVest(address(ASSETS[i]), toVest);
}
}
}
modifier onlyAggregateVault() {
require(msg.sender == address(AGGREGATE_VAULT), "AssetVault: Caller is not AggregateVault");
_;
}
}
文件 14 的 54:FixedPointMathLib.sol
pragma solidity >=0.8.0;
library FixedPointMathLib {
uint256 internal constant MAX_UINT256 = 2**256 - 1;
uint256 internal constant WAD = 1e18;
function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, y, WAD);
}
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, y, WAD);
}
function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, WAD, y);
}
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, WAD, y);
}
function mulDivDown(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
assembly {
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
z := div(mul(x, y), denominator)
}
}
function mulDivUp(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
assembly {
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
}
}
function rpow(
uint256 x,
uint256 n,
uint256 scalar
) internal pure returns (uint256 z) {
assembly {
switch x
case 0 {
switch n
case 0 {
z := scalar
}
default {
z := 0
}
}
default {
switch mod(n, 2)
case 0 {
z := scalar
}
default {
z := x
}
let half := shr(1, scalar)
for {
n := shr(1, n)
} n {
n := shr(1, n)
} {
if shr(128, x) {
revert(0, 0)
}
let xx := mul(x, x)
let xxRound := add(xx, half)
if lt(xxRound, xx) {
revert(0, 0)
}
x := div(xxRound, scalar)
if mod(n, 2) {
let zx := mul(z, x)
if iszero(eq(div(zx, x), z)) {
if iszero(iszero(x)) {
revert(0, 0)
}
}
let zxRound := add(zx, half)
if lt(zxRound, zx) {
revert(0, 0)
}
z := div(zxRound, scalar)
}
}
}
}
}
function sqrt(uint256 x) internal pure returns (uint256 z) {
assembly {
let y := x
z := 181
if iszero(lt(y, 0x10000000000000000000000000000000000)) {
y := shr(128, y)
z := shl(64, z)
}
if iszero(lt(y, 0x1000000000000000000)) {
y := shr(64, y)
z := shl(32, z)
}
if iszero(lt(y, 0x10000000000)) {
y := shr(32, y)
z := shl(16, z)
}
if iszero(lt(y, 0x1000000)) {
y := shr(16, y)
z := shl(8, z)
}
z := shr(18, mul(z, add(y, 65536)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := sub(z, lt(div(x, z), z))
}
}
function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
z := mod(x, y)
}
}
function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
assembly {
r := div(x, y)
}
}
function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
z := add(gt(mod(x, y), 0), div(x, y))
}
}
}
文件 15 的 54:GlpHandler.sol
pragma solidity 0.8.17;
import { IHandlerContract } from "../interfaces/IHandlerContract.sol";
import { BaseHandler } from "./BaseHandler.sol";
import { GMX_GLP_REWARD_ROUTER, GMX_VAULT, TOKEN_FRAX } from "../constants.sol";
import { IGlpRewardRouter } from "../interfaces/gmx/IGlpRewardRouter.sol";
import { ERC20 } from "solmate/tokens/ERC20.sol";
import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol";
import { IVault } from "../interfaces/gmx/IVault.sol";
import { IGlpManager } from "../interfaces/gmx/IGlpManager.sol";
import { IPositionRouter } from "../interfaces/gmx/IPositionRouter.sol";
contract GlpHandler is BaseHandler {
using SafeTransferLib for ERC20;
error NotStableToken(address _token);
error NoMintCapacity();
struct CollateralUtilization {
address token;
uint256 poolAmount;
uint256 reservedAmount;
uint256 utilization;
}
bytes32 public constant GLP_HANDLER_CONFIG_SLOT = keccak256("handlers.glp.config");
IGlpRewardRouter public constant glpRewardRouter = IGlpRewardRouter(GMX_GLP_REWARD_ROUTER);
IVault public constant vault = IVault(GMX_VAULT);
uint256 public constant FUNDING_RATE_PRECISION = 1_000_000;
uint256 public constant USDG_DECIMALS = 18;
uint256 public constant BASIS_POINTS_DIVISOR = 10_000;
uint256 public constant FALLBACK_SWAP_SLIPPAGE = 1000;
IGlpManager public immutable glpManager;
IPositionRouter public immutable positionRouter;
constructor(IGlpManager _glpManager, IPositionRouter _positionRouter) {
glpManager = _glpManager;
positionRouter = _positionRouter;
}
function getGlpComposition(address[] calldata volatileTokens)
external
view
returns (uint256[] memory _composition)
{
uint256 precision = 1e18;
_composition = new uint[](volatileTokens.length + 1);
address[] memory stableTokens = _getUnderlyingGlpTokens(true);
uint256 totalStablesWorth;
for (uint256 i = 0; i < stableTokens.length; ++i) {
(, uint256 _usdgAmount) = _getPoolAmounts(stableTokens[i]);
totalStablesWorth += _usdgAmount;
}
uint256[] memory volatilesWorth = new uint[](volatileTokens.length);
uint256 totalVolatilesWorth;
for (uint256 i = 0; i < volatileTokens.length; ++i) {
(, uint256 _usdgAmount) = _getPoolAmounts(volatileTokens[i]);
volatilesWorth[i] = _usdgAmount;
totalVolatilesWorth += _usdgAmount;
}
uint256 totalGlpWorth = totalVolatilesWorth + totalStablesWorth;
uint256 totalVolatilesComposition;
for (uint256 i = 0; i < volatileTokens.length; ++i) {
_composition[i] = (volatilesWorth[i] * precision) / totalGlpWorth;
totalVolatilesComposition += _composition[i];
}
_composition[volatileTokens.length] = precision - totalVolatilesComposition;
}
function previewGlpMintBurn(address _tokenOut, uint256 _glpAmount, bool _mint)
public
view
returns (uint256 _amtOut)
{
uint256 priceMin = glpManager.getPrice(_mint);
uint256 usdgAmount = (_glpAmount * priceMin) / 1e30;
uint256 maxFees = vault.mintBurnFeeBasisPoints() + vault.taxBasisPoints();
uint256 usdgAmountFees = _mint ? (usdgAmount * (1e4 + maxFees)) / 1e4 : (usdgAmount * (1e4 - maxFees)) / 1e4;
uint256 tokenPrice = vault.getMaxPrice(_tokenOut);
uint256 tokenDecimals = ERC20(_tokenOut).decimals();
_amtOut = (usdgAmountFees * 1e30) / tokenPrice;
return (_amtOut * (10 ** tokenDecimals)) / (10 ** 18);
}
function previewGlpMintBurn(address _tokenOut, uint256 _glpAmount) external view returns (uint256 _amtOut) {
uint256 mintAmount = previewGlpMintBurn(_tokenOut, _glpAmount, true);
uint256 burnAmount = previewGlpMintBurn(_tokenOut, _glpAmount, false);
_amtOut = (mintAmount + burnAmount) / 2;
}
function getTokenPrice(address _token, uint256 decimals) public view returns (uint256 _price) {
uint256 maxPrice = vault.getMaxPrice(_token);
uint256 minPrice = vault.getMinPrice(_token);
uint256 price = (maxPrice + minPrice) / 2;
_price = (price * (10 ** decimals)) / 1e30;
}
function getTokenMinPrice(address _token, uint256 decimals) public view returns (uint256 _price) {
uint256 minPrice = vault.getMinPrice(_token);
_price = (minPrice * (10 ** decimals)) / 1e30;
}
function getUsdToToken(uint256 _usdAmount, uint256 _usdDecimals, address _token)
public
view
returns (uint256 _amountOut)
{
uint256 usdAmount = (_usdAmount * 1e30) / 10 ** _usdDecimals;
uint256 decimals = ERC20(_token).decimals();
uint256 price = getTokenPrice(_token, 30);
_amountOut = (usdAmount * (10 ** decimals)) / price;
}
function getTokenToUsd(address _token, uint256 _tokenAmount, uint256 _usdDecimals)
public
view
returns (uint256 _usdAmount)
{
uint256 decimals = ERC20(_token).decimals();
uint256 price = getTokenPrice(_token, 30);
_usdAmount = (_tokenAmount * price * 10 ** _usdDecimals) / ((10 ** decimals) * (10 ** 30));
}
function usdToGlp(uint256 _usdAmount, uint256 _usdDecimals, bool _max) external view returns (uint256 _glpAmount) {
uint256 usdAmount = (_usdAmount * 1e30) / 10 ** _usdDecimals;
uint256 glpPrice = glpManager.getPrice(_max);
_glpAmount = (usdAmount * 1e18) / glpPrice;
}
function getGlpPrice() external view returns (uint256 _price) {
uint256 maxPrice = glpManager.getPrice(true);
uint256 minPrice = glpManager.getPrice(false);
_price = (maxPrice + minPrice) / 2;
}
function getGlpPrice(bool _max) external view returns (uint256 _price) {
_price = glpManager.getPrice(_max);
}
function tokenToToken(address _tokenIn, address _tokenOut, uint256 _amountIn, uint256 _toleranceBps)
public
view
returns (uint256 minOut)
{
uint256 tokenInDecimals = ERC20(_tokenIn).decimals();
uint256 tokenOutDecimals = ERC20(_tokenOut).decimals();
uint256 tokenInDollars = _amountIn * getTokenPrice(_tokenIn, 30);
minOut = (tokenInDollars / getTokenPrice(_tokenOut, 30)) * ((BASIS_POINTS_DIVISOR - _toleranceBps))
/ BASIS_POINTS_DIVISOR;
minOut = minOut * 10 ** tokenOutDecimals / 10 ** tokenInDecimals;
}
function tokenToToken(address _tokenIn, address _tokenOut, uint256 _amountIn)
public
view
returns (uint256 minOut)
{
minOut = tokenToToken(_tokenIn, _tokenOut, _amountIn, FALLBACK_SWAP_SLIPPAGE);
}
function getAvailableLiquidityLong(address _indexToken)
external
view
returns (uint256 _notional, CollateralUtilization memory _util)
{
uint256 maxLongs = positionRouter.maxGlobalLongSizes(_indexToken);
uint256 existingLongs = vault.guaranteedUsd(_indexToken);
uint256 poolAmount = vault.poolAmounts(_indexToken);
uint256 reservedAmount = vault.reservedAmounts(_indexToken);
uint256 availableAmount = poolAmount - reservedAmount;
uint256 maxPrice = vault.getMaxPrice(_indexToken);
uint256 availableUsd = (availableAmount * maxPrice) / (10 ** ERC20(_indexToken).decimals());
_util.token = _indexToken;
_util.poolAmount = poolAmount;
_util.reservedAmount = reservedAmount;
_util.utilization = (reservedAmount * FUNDING_RATE_PRECISION) / poolAmount;
if (maxLongs > existingLongs) {
uint256 availableLongs = maxLongs - existingLongs;
_notional = availableLongs > availableUsd ? availableUsd : availableLongs;
} else {
_notional = 0;
}
}
function getAvailableLiquidityShort(address _indexToken, address[] calldata _collateralTokens)
external
view
returns (
uint256 _availableNotional,
uint256[] memory _availableStables,
CollateralUtilization[] memory _utilizations
)
{
_availableStables = new uint[](_collateralTokens.length);
_utilizations = new CollateralUtilization[](_collateralTokens.length);
uint256 maxShorts = positionRouter.maxGlobalShortSizes(_indexToken);
uint256 globalShorts = vault.globalShortSizes(_indexToken);
_availableNotional = maxShorts > globalShorts ? maxShorts - globalShorts : 0;
for (uint256 i = 0; i < _collateralTokens.length; ++i) {
address _collateralToken = _collateralTokens[i];
_validateStableToken(_collateralToken);
uint256 poolAmounts = vault.poolAmounts(_collateralToken);
uint256 reservedAmounts = vault.reservedAmounts(_collateralToken);
uint256 availableAmount = poolAmounts - reservedAmounts;
uint256 availableStableNotional = (availableAmount * 1e30) / (10 ** ERC20(_collateralToken).decimals());
_availableStables[i] =
_availableNotional > availableStableNotional ? availableStableNotional : _availableNotional;
_utilizations[i].token = _collateralToken;
_utilizations[i].poolAmount = poolAmounts;
_utilizations[i].reservedAmount = reservedAmounts;
_utilizations[i].utilization = (reservedAmounts * FUNDING_RATE_PRECISION) / poolAmounts;
}
}
function calculateTokenMintAmount(address _mintToken, uint256 _tokenAmount)
external
view
returns (uint256 increasedTokenAmount)
{
uint256 price = getTokenMinPrice(_mintToken, 30);
uint256 usdgAmount = _tokenAmount * price / 1e30;
uint256 feeBasisPoints = vault.getFeeBasisPoints(
_mintToken, usdgAmount, vault.mintBurnFeeBasisPoints(), vault.taxBasisPoints(), true
);
uint256 increasePoints = BASIS_POINTS_DIVISOR * 1e30 / (BASIS_POINTS_DIVISOR - feeBasisPoints);
increasedTokenAmount = increasePoints * _tokenAmount / 1e30;
}
function routeGlpMint(address _intendedMintAsset, uint256 _dollarMint, bool _onlyStables)
external
view
returns (address _mintToken, uint256 _minOut)
{
if (checkGlpMintCapacity(_intendedMintAsset, _dollarMint)) {
return (_intendedMintAsset, 0);
} else {
address[] memory possibleMintTokens = _getUnderlyingGlpTokens(_onlyStables);
for (uint256 i = 0; i < possibleMintTokens.length; ++i) {
if (checkGlpMintCapacity(possibleMintTokens[i], _dollarMint) && possibleMintTokens[i] != TOKEN_FRAX) {
return (
possibleMintTokens[i],
getUsdToToken(_dollarMint, 18, possibleMintTokens[i])
* (BASIS_POINTS_DIVISOR - FALLBACK_SWAP_SLIPPAGE) / BASIS_POINTS_DIVISOR
);
}
}
revert NoMintCapacity();
}
}
function checkGlpMintCapacity(address intendedMintAsset, uint256 dollarMint) public view returns (bool) {
uint256 tokenAmount = getUsdToToken(dollarMint, 18, intendedMintAsset);
uint256 price = vault.getMinPrice(intendedMintAsset);
uint256 usdgAmount = tokenAmount * price / 1e30;
usdgAmount = adjustForDecimals(usdgAmount, intendedMintAsset, vault.usdg());
require(usdgAmount > 0, "GlpHandler: !usdgAmount");
uint256 feeBasisPoints = vault.getFeeBasisPoints(
intendedMintAsset, usdgAmount, vault.mintBurnFeeBasisPoints(), vault.taxBasisPoints(), true
);
uint256 amountAfterFees = tokenAmount * (BASIS_POINTS_DIVISOR - feeBasisPoints) / BASIS_POINTS_DIVISOR;
uint256 mintAmount = amountAfterFees * price / 1e30;
mintAmount = adjustForDecimals(mintAmount, intendedMintAsset, vault.usdg());
uint256 currentUsdgAmount = vault.usdgAmounts(intendedMintAsset) + mintAmount;
return currentUsdgAmount <= vault.maxUsdgAmounts(intendedMintAsset);
}
function adjustForDecimals(uint256 _amount, address _tokenDiv, address _tokenMul) public view returns (uint256) {
uint256 decimalsDiv = _tokenDiv == vault.usdg() ? USDG_DECIMALS : ERC20(_tokenDiv).decimals();
uint256 decimalsMul = _tokenMul == vault.usdg() ? USDG_DECIMALS : ERC20(_tokenMul).decimals();
return _amount * 10 ** decimalsMul / 10 ** decimalsDiv;
}
function _getUnderlyingGlpTokens(bool onlyStables) internal view returns (address[] memory _tokens) {
address[] memory allWhitelistedTokens = _allWhitelistedTokens();
_tokens = new address[](allWhitelistedTokens.length);
uint256 foundTokens = 0;
for (uint256 i = 0; i < allWhitelistedTokens.length; ++i) {
bool isStable = vault.stableTokens(allWhitelistedTokens[i]);
if (onlyStables && isStable) {
_tokens[foundTokens++] = allWhitelistedTokens[i];
} else if (!onlyStables && !isStable) {
_tokens[foundTokens++] = allWhitelistedTokens[i];
}
}
assembly {
mstore(_tokens, foundTokens)
}
}
function _allWhitelistedTokens() internal view returns (address[] memory _tokens) {
_tokens = new address[](vault.allWhitelistedTokensLength());
for (uint256 i = 0; i < _tokens.length; ++i) {
_tokens[i] = vault.allWhitelistedTokens(i);
}
}
function _getPoolAmounts(address _token) internal view returns (uint256 _tokenAmount, uint256 _usdgAmount) {
_tokenAmount = vault.poolAmounts(_token);
uint256 maxPrice = vault.getMaxPrice(_token);
uint256 minPrice = vault.getMinPrice(_token);
uint256 tokenDecimals = vault.tokenDecimals(_token);
uint256 avgPrice = (minPrice + maxPrice) / 2;
_usdgAmount = (_tokenAmount * avgPrice) / 10 ** tokenDecimals;
}
function _getGlpStaticAum() internal view returns (uint256 _aum) {
address[] memory tokens = _allWhitelistedTokens();
for (uint256 i = 0; i < tokens.length; ++i) {
(, uint256 _usdgAmount) = _getPoolAmounts(tokens[i]);
_aum += _usdgAmount;
}
return _aum;
}
function _getGlpDynamicAum() internal view returns (uint256 _aum) {
uint256 maxAum = glpManager.getAum(true);
uint256 minAum = glpManager.getAum(false);
return (maxAum + minAum) / 2;
}
function _validateStableToken(address _token) internal view {
if (!vault.stableTokens(_token)) {
revert NotStableToken(_token);
}
}
function callbackSigs() external pure override returns (bytes4[] memory _ret) {
_ret = new bytes4[](0);
}
}
文件 16 的 54:IAccessControl.sol
pragma solidity ^0.8.0;
interface IAccessControl {
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address account) external;
}
文件 17 的 54:IAggregateVault.sol
pragma solidity 0.8.17;
import { ERC20 } from "solmate/tokens/ERC20.sol";
interface IAggregateVault {
function handleWithdraw(ERC20 asset, uint256 _amount, address _account) external;
function handleDeposit(ERC20 asset, uint256 _amount, address _account) external;
function getVaultPPS(address _assetVault) external view returns (uint256);
function previewWithdrawalFee(address token, uint256 _size) external view returns (uint256);
function previewDepositFee(uint256 _size) external view returns (uint256);
function rebalanceOpen() external view returns (bool);
}
文件 18 的 54:IAssetVault.sol
pragma solidity 0.8.17;
interface IAssetVault {
function asset() external returns (address);
function pauseDepositWithdraw() external;
function unpauseDepositWithdraw() external;
}
文件 19 的 54:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 20 的 54:IFeeEscrow.sol
pragma solidity ^0.8.17;
interface IFeeEscrow {
function returnDepositFees() external;
}
文件 21 的 54:IGlpManager.sol
pragma solidity 0.8.17;
interface IGlpManager {
function getPrice(bool _maximise) external view returns (uint256);
function getAum(bool maximise) external view returns (uint256);
function aumAddition() external view returns (uint256);
function aumDeduction() external view returns (uint256);
function shortsTracker() external view returns (address);
function shortsTrackerAveragePriceWeight() external view returns (uint256);
}
文件 22 的 54:IGlpRebalanceRouter.sol
pragma solidity 0.8.17;
interface IGlpRebalanceRouter {
function netGlpRebalance(uint256[5] memory lastAllocations, uint256[5] memory nextAllocations)
external
view
returns (int256[5] memory glpVaultDeltaExecute, int256[5] memory glpVaultDeltaAccount);
}
文件 23 的 54:IGlpRewardRouter.sol
pragma solidity 0.8.17;
interface IGlpRewardRouter {
function mintAndStakeGlp(address _token, uint256 _amount, uint256 _minUsdg, uint256 _minGlp)
external
returns (uint256);
function mintAndStakeGlpETH(uint256 _minUsdg, uint256 _minGlp) external payable returns (uint256);
}
文件 24 的 54:IHandlerContract.sol
pragma solidity 0.8.17;
interface IHandlerContract {
function callbackSigs() external pure returns (bytes4[] memory);
}
文件 25 的 54:INettedPositionTracker.sol
pragma solidity 0.8.17;
interface INettedPositionTracker {
struct NettedPrices {
uint256 stable;
uint256 eth;
uint256 btc;
uint256 link;
uint256 uni;
}
function settleNettingPositionPnl(
int256[5][5] memory internalPositions,
NettedPrices memory assetPrices,
NettedPrices memory lastAssetPrices,
uint256[5] memory vaultGlpAmount,
uint256 glpPrice,
uint256 pnlSumThreshold
)
external
view
returns (
uint256[5] memory settledVaultGlpAmount,
int256[5] memory nettedPnl,
int256[5] memory glpPnl,
int256[5] memory percentPriceChange
);
}
文件 26 的 54:IPositionManager.sol
pragma solidity 0.8.17;
import { IHandlerContract } from "./IHandlerContract.sol";
interface IPositionManager is IHandlerContract {
function positionMargin(address _indexToken, address _collateralToken, bool _isLong)
external
view
returns (uint256);
function positionNotional(address _indexToken, address _collateralToken, bool _isLong)
external
view
returns (uint256);
function positionNotional(address _indexToken) external view returns (uint256, bool);
function positionMargin(address _indexToken) external view returns (uint256, bool);
}
文件 27 的 54:IPositionRouter.sol
pragma solidity 0.8.17;
interface IPositionRouter {
struct IncreasePositionRequest {
address account;
address[] path;
address indexToken;
uint256 amountIn;
uint256 minOut;
uint256 sizeDelta;
bool isLong;
uint256 acceptablePrice;
uint256 executionFee;
uint256 blockNumber;
uint256 blockTime;
bool hasCollateralInETH;
address callbackTarget;
}
struct IncreasePositionRequestWithoutPath {
address account;
address indexToken;
uint256 amountIn;
uint256 minOut;
uint256 sizeDelta;
bool isLong;
uint256 acceptablePrice;
uint256 executionFee;
uint256 blockNumber;
uint256 blockTime;
bool hasCollateralInETH;
address callbackTarget;
}
struct DecreasePositionRequest {
address account;
address[] path;
address indexToken;
uint256 collateralDelta;
uint256 sizeDelta;
bool isLong;
address receiver;
uint256 acceptablePrice;
uint256 minOut;
uint256 executionFee;
uint256 blockNumber;
uint256 blockTime;
bool withdrawETH;
address callbackTarget;
}
struct DecreasePositionRequestWithoutPath {
address account;
address indexToken;
uint256 collateralDelta;
uint256 sizeDelta;
bool isLong;
address receiver;
uint256 acceptablePrice;
uint256 minOut;
uint256 executionFee;
uint256 blockNumber;
uint256 blockTime;
bool withdrawETH;
address callbackTarget;
}
function createIncreasePosition(
address[] memory _path,
address _indexToken,
uint256 _amountIn,
uint256 _minOut,
uint256 _sizeDelta,
bool _isLong,
uint256 _acceptablePrice,
uint256 _executionFee,
bytes32 _referralCode,
address _callbackTarget
) external payable returns (bytes32);
function createIncreasePositionETH(
address[] memory _path,
address _indexToken,
uint256 _minOut,
uint256 _sizeDelta,
bool _isLong,
uint256 _acceptablePrice,
uint256 _executionFee,
bytes32 _referralCode,
address _callbackTarget
) external payable returns (bytes32);
function createDecreasePosition(
address[] memory _path,
address _indexToken,
uint256 _collateralDelta,
uint256 _sizeDelta,
bool _isLong,
address _receiver,
uint256 _acceptablePrice,
uint256 _minOut,
uint256 _executionFee,
bool _withdrawETH,
address _callbackTarget
) external payable returns (bytes32);
function minExecutionFee() external view returns (uint256);
function maxGlobalLongSizes(address _token) external view returns (uint256);
function maxGlobalShortSizes(address _token) external view returns (uint256);
function getRequestQueueLengths()
external
view
returns (
uint256 increasePositionRequestKeysStart,
uint256 increasePositionRequestKeysLength,
uint256 decreasePositionRequestKeysStart,
uint256 decreasePositionRequestKeysLength
);
function admin() external view returns (address);
function setPositionKeeper(address _account, bool _isActive) external;
function executeIncreasePositions(uint256 _endIndex, address payable _executionFeeReceiver) external;
function executeDecreasePositions(uint256 _endIndex, address payable _executionFeeReceiver) external;
function increasePositionRequests(bytes32 _key) external view returns (IncreasePositionRequestWithoutPath memory);
function decreasePositionRequests(bytes32 _key) external view returns (DecreasePositionRequestWithoutPath memory);
function getIncreasePositionRequestPath(bytes32 _key) external view returns (address[] memory);
function getDecreasePositionRequestPath(bytes32 _key) external view returns (address[] memory);
}
文件 28 的 54:IRewardRouterV2.sol
pragma solidity 0.8.17;
interface IRewardRouterV2 {
function unstakeAndRedeemGlp(address _tokenOut, uint256 _glpAmount, uint256 _minOut, address _receiver)
external
returns (uint256);
function mintAndStakeGlp(address _token, uint256 _amount, uint256 _minUsdg, uint256 _minGlp)
external
returns (uint256);
function handleRewards(
bool _shouldClaimGmx,
bool _shouldStakeGmx,
bool _shouldClaimEsGmx,
bool _shouldStakeEsGmx,
bool _shouldStakeMultiplierPoints,
bool _shouldClaimWeth,
bool _shouldConvertWethToEth
) external;
function claimEsGmx() external;
function signalTransfer(address _receiver) external;
function acceptTransfer(address _sender) external;
}
文件 29 的 54:ISwapManager.sol
pragma solidity 0.8.17;
import { IHandlerContract } from "./IHandlerContract.sol";
interface ISwapManager is IHandlerContract {
function swap(address _tokenIn, address _tokenOut, uint256 _amountIn, uint256 _minOut, bytes calldata _data)
external
returns (uint256 _amountOut);
}
文件 30 的 54:ISwapRouter.sol
pragma solidity 0.8.17;
pragma abicoder v2;
interface ISwapRouter {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
struct ExactInputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
}
function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);
struct ExactOutputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
uint160 sqrtPriceLimitX96;
}
function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);
struct ExactOutputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
}
function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
}
文件 31 的 54:IUniswapV3Factory.sol
pragma solidity 0.8.17;
interface IUniswapV3Factory {
event OwnerChanged(address indexed oldOwner, address indexed newOwner);
event PoolCreated(
address indexed token0, address indexed token1, uint24 indexed fee, int24 tickSpacing, address pool
);
event FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing);
function owner() external view returns (address);
function feeAmountTickSpacing(uint24 fee) external view returns (int24);
function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool);
function createPool(address tokenA, address tokenB, uint24 fee) external returns (address pool);
function setOwner(address _owner) external;
function enableFeeAmount(uint24 fee, int24 tickSpacing) external;
}
文件 32 的 54:IUniswapV3Pool.sol
pragma solidity 0.8.17;
import { IUniswapV3PoolState } from "./IUniswapV3PoolState.sol";
interface IUniswapV3Pool is IUniswapV3PoolState {
function fee() external view returns (uint24);
function token0() external view returns (address);
function token1() external view returns (address);
}
文件 33 的 54:IUniswapV3PoolState.sol
pragma solidity 0.8.17;
interface IUniswapV3PoolState {
function slot0()
external
view
returns (
uint160 sqrtPriceX96,
int24 tick,
uint16 observationIndex,
uint16 observationCardinality,
uint16 observationCardinalityNext,
uint8 feeProtocol,
bool unlocked
);
function feeGrowthGlobal0X128() external view returns (uint256);
function feeGrowthGlobal1X128() external view returns (uint256);
function protocolFees() external view returns (uint128 token0, uint128 token1);
function liquidity() external view returns (uint128);
function ticks(int24 tick)
external
view
returns (
uint128 liquidityGross,
int128 liquidityNet,
uint256 feeGrowthOutside0X128,
uint256 feeGrowthOutside1X128,
int56 tickCumulativeOutside,
uint160 secondsPerLiquidityOutsideX128,
uint32 secondsOutside,
bool initialized
);
function tickBitmap(int16 wordPosition) external view returns (uint256);
function positions(bytes32 key)
external
view
returns (
uint128 _liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
uint128 tokensOwed0,
uint128 tokensOwed1
);
function observations(uint256 index)
external
view
returns (
uint32 blockTimestamp,
int56 tickCumulative,
uint160 secondsPerLiquidityCumulativeX128,
bool initialized
);
}
文件 34 的 54:IVault.sol
pragma solidity 0.8.17;
interface IVault {
struct Position {
uint256 size;
uint256 collateral;
uint256 averagePrice;
uint256 entryFundingRate;
uint256 reserveAmount;
int256 realisedPnl;
uint256 lastIncreasedTime;
}
function getFeeBasisPoints(
address _token,
uint256 _usdgDelta,
uint256 _feeBasisPoints,
uint256 _taxBasisPoints,
bool _increment
) external view returns (uint256);
function usdg() external view returns (address);
function usdgAmounts(address _token) external view returns (uint256);
function maxUsdgAmounts(address _token) external view returns (uint256);
function whitelistedTokens(address _token) external view returns (bool);
function stableTokens(address _token) external view returns (bool);
function shortableTokens(address _token) external view returns (bool);
function getMinPrice(address _token) external view returns (uint256);
function getMaxPrice(address _token) external view returns (uint256);
function getPositionDelta(address _account, address _collateralToken, address _indexToken, bool _isLong)
external
view
returns (bool, uint256);
function getPosition(address _account, address _collateralToken, address _indexToken, bool _isLong)
external
view
returns (
uint256 size,
uint256 collateral,
uint256 averagePrice,
uint256 entryFundingRate,
uint256 reserveAmount,
uint256 realisedPnl,
bool isProfit,
uint256 lastIncreasedTime
);
function poolAmounts(address _token) external view returns (uint256);
function reservedAmounts(address _token) external view returns (uint256);
function guaranteedUsd(address _token) external view returns (uint256);
function globalShortSizes(address _token) external view returns (uint256);
function positions(bytes32 _key)
external
view
returns (
uint256 _size,
uint256 _collateral,
uint256 _averagePrice,
uint256 _entryFundingRate,
uint256 _reserveAmount,
int256 _realisedPnl,
uint256 _lastIncreasedTime
);
function swap(address _tokenIn, address _tokenOut, address _receiver) external returns (uint256);
function getPositionFee(uint256 _sizeDelta) external view returns (uint256);
function getFundingFee(address _token, uint256 _size, uint256 _entryFundinRate) external view returns (uint256);
function cumulativeFundingRates(address _token) external view returns (uint256);
function getNextFundingRate(address _token) external view returns (uint256);
function getDelta(
address _indexToken,
uint256 _size,
uint256 _averagePrice,
bool _isLong,
uint256 _lastIncreasedTime
) external view returns (bool, uint256);
function allWhitelistedTokensLength() external view returns (uint256);
function allWhitelistedTokens(uint256) external view returns (address);
function tokenDecimals(address) external view returns (uint256);
function taxBasisPoints() external view returns (uint256);
function stableTaxBasisPoints() external view returns (uint256);
function mintBurnFeeBasisPoints() external view returns (uint256);
function globalShortAveragePrices(address) external view returns (uint256);
}
文件 35 的 54:IVaultFeesAndHooks.sol
pragma solidity ^0.8.17;
interface IVaultFeesAndHooks {
function getVaultRebalanceFees(address vault, uint256 lastRebalance)
external
pure
returns (uint256, uint256, uint256, uint256);
function getWithdrawalFee(address vault, uint256 size) external pure returns (uint256);
function getDepositFee(uint256 size) external pure returns (uint256);
function beforeOpenRebalancePeriod(bytes memory _calldata) external;
function afterCloseRebalancePeriod(bytes memory _calldata) external;
}
文件 36 的 54:LibAggregateVaultUtils.sol
pragma solidity 0.8.17;
import { ERC20 } from "solmate/tokens/ERC20.sol";
import { GMX_FEE_STAKED_GLP, TOKEN_USDC, TOKEN_WETH, TOKEN_WBTC, TOKEN_LINK, TOKEN_UNI } from "../constants.sol";
import { Solarray } from "./Solarray.sol";
import { AggregateVaultStorage } from "../storage/AggregateVaultStorage.sol";
import { INettedPositionTracker } from "../interfaces/INettedPositionTracker.sol";
import { GlpHandler } from "../handlers/GlpHandler.sol";
ERC20 constant fsGLP = ERC20(GMX_FEE_STAKED_GLP);
library LibAggregateVaultUtils {
function glpToDollarArray(AggregateVaultStorage.AVStorage storage _avStorage, uint256 _glpPrice)
internal
view
returns (uint256[5] memory glpAsDollars)
{
for (uint256 i = 0; i < 5; i++) {
glpAsDollars[i] = (_glpPrice * getVaultGlpAttributeBalance(_avStorage, i)) / 1e18;
}
}
function getVaultGlpAttributeBalance(AggregateVaultStorage.AVStorage storage _avStorage, uint256 _vaultIdx)
internal
view
returns (uint256 _balance)
{
uint256 totalGlpBalance = fsGLP.balanceOf(address(this));
uint256 proportion = getVaultGlpAttributeProportion(_avStorage, _vaultIdx);
return (totalGlpBalance * proportion) / 1e18;
}
function getVaultGlpAttributeProportion(AggregateVaultStorage.AVStorage storage _avStorage, uint256 _vaultIdx)
internal
view
returns (uint256 _proportion)
{
uint256[5] memory _vaultGlpAttribution = _avStorage.vaultGlpAttribution;
uint256 totalGlpAttribution = Solarray.arraySum(_vaultGlpAttribution);
if (totalGlpAttribution == 0) return 0;
return (_vaultGlpAttribution[_vaultIdx] * 1e18) / totalGlpAttribution;
}
function getVaultsGlpNoPnl(AggregateVaultStorage.AVStorage storage _avStorage)
internal
view
returns (uint256[5] memory _vaultsGlpNoPnl)
{
for (uint256 i = 0; i < 5; i++) {
_vaultsGlpNoPnl[i] = getVaultGlp(_avStorage, i, 0);
}
}
function getVaultsGlp(AggregateVaultStorage.AVStorage storage _avStorage)
internal
view
returns (uint256[5] memory _vaultsGlp)
{
uint256 currentEpoch = _avStorage.vaultState.epoch;
for (uint256 i = 0; i < 5; i++) {
_vaultsGlp[i] = getVaultGlp(_avStorage, i, currentEpoch);
}
}
function getVaultGlp(AggregateVaultStorage.AVStorage storage _avStorage, uint256 _vaultIdx, uint256 _currentEpoch)
internal
view
returns (uint256 _glpAmount)
{
uint256 totalGlpBalance = fsGLP.balanceOf(address(this));
uint256 ownedGlp = (totalGlpBalance * getVaultGlpAttributeProportion(_avStorage, _vaultIdx)) / 1e18;
_glpAmount = ownedGlp;
if (_currentEpoch > 0) {
(,, int256[5] memory glpPnl,) = _avStorage.nettedPositionTracker.settleNettingPositionPnl(
_avStorage.nettedPositions,
getCurrentPrices(_avStorage),
getEpochNettedPrice(_avStorage, _currentEpoch),
getVaultsGlpNoPnl(_avStorage),
(_getGlpPrice(_avStorage) * 1e18) / 1e30,
_avStorage.zeroSumPnlThreshold
);
int256 glpDelta = glpPnl[_vaultIdx];
if (glpPnl[_vaultIdx] < 0 && ownedGlp < uint256(-glpDelta)) {
_glpAmount = 0;
} else {
_glpAmount = uint256(int256(ownedGlp) + glpDelta);
}
}
}
function getCurrentPrices(AggregateVaultStorage.AVStorage storage _avStorage)
internal
view
returns (INettedPositionTracker.NettedPrices memory _prices)
{
GlpHandler glpHandler = _avStorage.glpHandler;
_prices = INettedPositionTracker.NettedPrices({
stable: glpHandler.getTokenPrice(TOKEN_USDC, 18),
eth: glpHandler.getTokenPrice(TOKEN_WETH, 18),
btc: glpHandler.getTokenPrice(TOKEN_WBTC, 18),
link: glpHandler.getTokenPrice(TOKEN_LINK, 18),
uni: glpHandler.getTokenPrice(TOKEN_UNI, 18)
});
}
function getEpochNettedPrice(AggregateVaultStorage.AVStorage storage _avStorage, uint256 _epoch)
internal
view
returns (INettedPositionTracker.NettedPrices storage _nettedPrices)
{
_nettedPrices = _avStorage.lastNettedPrices[_epoch];
}
function _getGlpPrice(AggregateVaultStorage.AVStorage storage _avStorage) internal view returns (uint256 _price) {
_price = _avStorage.glpHandler.getGlpPrice();
}
}
文件 37 的 54:LibRebalance.sol
pragma solidity 0.8.17;
import { AggregateVaultStorage } from "../storage/AggregateVaultStorage.sol";
import { FeeEscrow } from "../peripheral/FeeEscrow.sol";
import { VaultMath } from "./VaultMath.sol";
import { GlpHandler } from "../handlers/GlpHandler.sol";
import { ERC20 } from "solmate/tokens/ERC20.sol";
import { PositionManagerRouter } from "../handlers/hedgeManagers/PositionManagerRouter.sol";
import { GMX_GLP_MANAGER, GMX_GLP_REWARD_ROUTER, GMX_FEE_STAKED_GLP } from "../constants.sol";
import { IRewardRouterV2 } from "../interfaces/IRewardRouterV2.sol";
import { Solarray } from "./Solarray.sol";
import { LibAggregateVaultUtils } from "./LibAggregateVaultUtils.sol";
import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol";
import { UniswapV3SwapManager } from "../handlers/swapManagers/UniswapV3SwapManager.sol";
ERC20 constant fsGLP = ERC20(GMX_FEE_STAKED_GLP);
uint256 constant TOTAL_BPS = 10_000;
using SafeTransferLib for ERC20;
library LibRebalance {
event RebalanceGlpPosition(
uint256[5] vaultGlpAttributionBefore,
uint256[5] vaultGlpAttributionAfter,
uint256[5] targetGlpAllocation,
int256[5] totalVaultGlpDelta,
int256[5] feeAmounts
);
error RebalanceGlpAccountingError();
function pullFeeAmountsFromEscrow(AggregateVaultStorage.AVStorage storage _avStorage, int256[5] memory _feeAmounts)
public
{
AggregateVaultStorage.VaultState storage vaultState = _avStorage.vaultState;
FeeEscrow depositFeeEscrow = FeeEscrow(vaultState.depositFeeEscrow);
FeeEscrow withdrawFeeEscrow = FeeEscrow(vaultState.withdrawalFeeEscrow);
uint256[5] memory mintFees;
uint256[5] memory burnFees;
for (uint256 i = 0; i < _feeAmounts.length; i++) {
if (_feeAmounts[i] > 0) {
mintFees[i] = uint256(_feeAmounts[i]);
} else {
burnFees[i] = uint256(-_feeAmounts[i]);
}
}
uint256 keeperBps = _avStorage.keeperShareBps;
address keeper = _avStorage.keeper;
depositFeeEscrow.pullFeesAndVest(mintFees, keeper, keeperBps);
withdrawFeeEscrow.pullFeesAndVest(burnFees, keeper, keeperBps);
}
function increaseGlpPosition(
AggregateVaultStorage.AVStorage storage _avStorage,
uint256 glpAllocation,
address mintToken
) public returns (uint256, uint256) {
uint256 usdgMinAmount =
VaultMath.getSlippageAdjustedAmount(glpAllocation, _avStorage.glpMintBurnSlippageTolerance);
GlpHandler glpHandler = _avStorage.glpHandler;
(address derivedMintToken, uint256 minOut) = glpHandler.routeGlpMint(mintToken, glpAllocation, false);
if (derivedMintToken == mintToken) {
uint256 tokenAmount = glpHandler.getUsdToToken(glpAllocation, 18, mintToken);
uint256 feeAdjustedTokenAmount = glpHandler.calculateTokenMintAmount(mintToken, tokenAmount);
ERC20(mintToken).safeApprove(GMX_GLP_MANAGER, feeAdjustedTokenAmount);
uint256 glpMinted = IRewardRouterV2(GMX_GLP_REWARD_ROUTER).mintAndStakeGlp(
mintToken, feeAdjustedTokenAmount, usdgMinAmount, 0
);
uint256 feeAmount = feeAdjustedTokenAmount - tokenAmount;
return (glpMinted, feeAmount);
}
uint256 tokenAmount = glpHandler.getUsdToToken(glpAllocation, 18, mintToken);
uint256 tokenAmountDerivedMintToken = glpHandler.tokenToToken(mintToken, derivedMintToken, tokenAmount);
uint256 feeAdjustedDerivedMintTokenAmount =
glpHandler.calculateTokenMintAmount(derivedMintToken, tokenAmountDerivedMintToken);
AggregateVaultStorage.AVStorage storage __avStorage = _avStorage;
bytes memory ret = PositionManagerRouter(payable(address(this))).execute(
address(_avStorage.uniV3SwapManager),
abi.encodeCall(
UniswapV3SwapManager.exactOutputSwap,
(
mintToken,
derivedMintToken,
feeAdjustedDerivedMintTokenAmount,
tokenAmount * (TOTAL_BPS + __avStorage.swapToleranceBps) / TOTAL_BPS
)
)
);
(uint256 amountIn) = abi.decode(ret, (uint256));
ERC20(derivedMintToken).safeApprove(GMX_GLP_MANAGER, feeAdjustedDerivedMintTokenAmount);
uint256 glpMinted = IRewardRouterV2(GMX_GLP_REWARD_ROUTER).mintAndStakeGlp(
mintToken, feeAdjustedDerivedMintTokenAmount, usdgMinAmount, 0
);
uint256 feeAmount = amountIn - tokenAmount;
return (glpMinted, feeAmount);
}
function reduceGlpPosition(
AggregateVaultStorage.AVStorage storage _avStorage,
uint256 glpAllocation,
address tokenOut
) public returns (uint256 glpAmount, uint256 feeAmount) {
GlpHandler glpHandler = _avStorage.glpHandler;
glpAmount = glpHandler.usdToGlp(glpAllocation, 18, false);
uint256 amountOut =
IRewardRouterV2(GMX_GLP_REWARD_ROUTER).unstakeAndRedeemGlp(tokenOut, glpAmount, 0, address(this));
uint256 usdValueTokenOut = glpHandler.getTokenToUsd(tokenOut, amountOut, 18);
uint256 feeAmountUsd = glpAllocation > usdValueTokenOut ? glpAllocation - usdValueTokenOut : 0;
feeAmount = glpHandler.getUsdToToken(feeAmountUsd, 18, tokenOut);
}
function rebalanceGlpPosition(
AggregateVaultStorage.AVStorage storage _avStorage,
uint256[5] memory _nextGlpAllocation,
uint256 _glpPrice
) external returns (int256[5] memory feeAmounts) {
AggregateVaultStorage.VaultState storage vaultState = _avStorage.vaultState;
require(vaultState.rebalanceOpen, "rebalancing period not open yet");
uint256[5] memory glpAlloc = LibAggregateVaultUtils.glpToDollarArray(_avStorage, _glpPrice);
(, int256[5] memory vaultGlpDeltaAccount) =
_avStorage.glpRebalanceRouter.netGlpRebalance(glpAlloc, _nextGlpAllocation);
uint256[5] storage _vaultGlpAttribution = _avStorage.vaultGlpAttribution;
uint256[5] memory previousVaultGlp = LibAggregateVaultUtils.getVaultsGlpNoPnl(_avStorage);
AggregateVaultStorage.AssetVaultEntry[5] storage assetVaults = _avStorage.assetVaults;
uint256[5] memory vaultGlpPartial;
for (uint256 i = 0; i < 5; i++) {
if (vaultGlpDeltaAccount[i] > 0) {
(uint256 glpBurnt, uint256 feeAmount) =
reduceGlpPosition(_avStorage, uint256(vaultGlpDeltaAccount[i]), assetVaults[i].token);
vaultGlpPartial[i] = previousVaultGlp[i] - glpBurnt;
feeAmounts[i] = -int256(feeAmount);
} else if (vaultGlpDeltaAccount[i] < 0) {
(uint256 glpMinted, uint256 feeAmount) =
increaseGlpPosition(_avStorage, uint256(-vaultGlpDeltaAccount[i]), assetVaults[i].token);
vaultGlpPartial[i] = previousVaultGlp[i] + glpMinted;
feeAmounts[i] = int256(feeAmount);
} else {
vaultGlpPartial[i] = previousVaultGlp[i];
}
}
uint256 vaultGlpPartialSum = Solarray.arraySum(vaultGlpPartial);
{
uint256 tolerance = _avStorage.glpRebalanceTolerance;
uint256 totalVaultGlp = fsGLP.balanceOf(address(this));
uint256 upper = totalVaultGlp * (10_000 + tolerance) / 10_000;
uint256 lower = totalVaultGlp * (10_000 - tolerance) / 10_000;
if (vaultGlpPartialSum < lower || vaultGlpPartialSum > upper) {
revert RebalanceGlpAccountingError();
}
}
for (uint256 i = 0; i < 5; ++i) {
_vaultGlpAttribution[i] = (vaultGlpPartial[i] * 1e18) / vaultGlpPartialSum;
}
pullFeeAmountsFromEscrow(_avStorage, feeAmounts);
emit RebalanceGlpPosition(
previousVaultGlp, vaultGlpPartial, _nextGlpAllocation, vaultGlpDeltaAccount, feeAmounts
);
}
}
文件 38 的 54:Math.sol
pragma solidity ^0.8.0;
library Math {
enum Rounding {
Down,
Up,
Zero
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a & b) + (a ^ b) / 2;
}
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
return a == 0 ? 0 : (a - 1) / b + 1;
}
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
uint256 prod0;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
return prod0 / denominator;
}
require(denominator > prod1);
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = denominator & (~denominator + 1);
assembly {
denominator := div(denominator, twos)
prod0 := div(prod0, twos)
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
return result;
}
}
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 result = 1 << (log2(a) >> 1);
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}
文件 39 的 54:MerkleProof.sol
pragma solidity ^0.8.0;
library MerkleProof {
function verify(
bytes32[] memory proof,
bytes32 root,
bytes32 leaf
) internal pure returns (bool) {
return processProof(proof, leaf) == root;
}
function verifyCalldata(
bytes32[] calldata proof,
bytes32 root,
bytes32 leaf
) internal pure returns (bool) {
return processProofCalldata(proof, leaf) == root;
}
function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
function multiProofVerify(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProof(proof, proofFlags, leaves) == root;
}
function multiProofVerifyCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProofCalldata(proof, proofFlags, leaves) == root;
}
function processMultiProof(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
uint256 leavesLen = leaves.length;
uint256 totalHashes = proofFlags.length;
require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
return hashes[totalHashes - 1];
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function processMultiProofCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
uint256 leavesLen = leaves.length;
uint256 totalHashes = proofFlags.length;
require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
return hashes[totalHashes - 1];
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
}
function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
assembly {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}
文件 40 的 54:Multicall.sol
pragma solidity 0.8.17;
abstract contract Multicall {
function _multicall(bytes[] calldata data)
internal
returns (bytes[] memory results, uint256[] memory gasEstimates)
{
results = new bytes[](data.length);
gasEstimates = new uint[](data.length);
unchecked {
for (uint256 i = 0; i < data.length; ++i) {
uint256 startGas = gasleft();
(bool success, bytes memory result) = address(this).delegatecall(data[i]);
if (!success) {
assembly {
let resultLength := mload(result)
revert(add(result, 0x20), resultLength)
}
}
results[i] = result;
uint256 endGas = gasleft();
gasEstimates[i] = startGas - endGas;
}
}
}
}
文件 41 的 54:NettingMath.sol
pragma solidity 0.8.17;
import { SafeCast } from "./SafeCast.sol";
import { Solarray } from "./Solarray.sol";
contract NettingMath {
struct NettedParams {
uint256 vaultCumulativeGlpTvl;
uint256[5] glpComposition;
uint256 nettedThreshold;
}
struct NettedState {
uint256[5] glpHeld;
int256[5] externalPositions;
}
uint256 public immutable SCALE = 1e18;
uint256 public immutable BIPS = 10_000;
function vaultDeltaAdjustment(
NettedState memory nettingState,
uint256 _vaultCumulativeGlpTvl,
uint256[5] memory _glpComposition,
int256[5][5] memory externalPositions,
uint256 _threshold
) public pure returns (uint256[5] memory glpExposure, uint256[5] memory vaultRatio) {
int256 rowHedgeSum;
uint256 zeroDivisor;
for (uint256 i = 0; i < nettingState.glpHeld.length; i++) {
glpExposure[i] = _vaultCumulativeGlpTvl * _glpComposition[i] / SCALE;
if (nettingState.externalPositions[i] < 0) {
glpExposure[i] += uint256(-nettingState.externalPositions[i]);
} else {
if (glpExposure[i] < uint256(nettingState.externalPositions[i])) {
glpExposure[i] = uint256(nettingState.externalPositions[i]) - glpExposure[i];
} else {
glpExposure[i] -= uint256(nettingState.externalPositions[i]);
}
}
rowHedgeSum = Solarray.arraySum(externalPositions[i]);
if (rowHedgeSum < 0) {
glpExposure[i] -= uint256(-rowHedgeSum);
} else {
glpExposure[i] += uint256(rowHedgeSum);
}
if (nettingState.glpHeld[i] == 0) {
if (_vaultCumulativeGlpTvl == 0 && glpExposure[i] == 0) {
vaultRatio[i] = SCALE;
} else {
zeroDivisor = _vaultCumulativeGlpTvl != 0 ? _vaultCumulativeGlpTvl : glpExposure[i];
vaultRatio[i] = SCALE + (glpExposure[i] * SCALE / zeroDivisor);
}
} else {
vaultRatio[i] = glpExposure[i] * SCALE / nettingState.glpHeld[i];
}
}
}
function calculateNettedPositions(
int256[5][5] memory externalPositions,
uint256[5] memory glpComposition,
uint256[5] memory glpHeldDollars
) public pure returns (int256[5][5] memory nettedMatrix, int256[5][5] memory exposureMatrix) {
int256[5] memory vaultGlpExposure;
for (uint256 idx = 0; idx < externalPositions.length; idx++) {
vaultGlpExposure = _vaultExposureInt(glpHeldDollars[idx], glpComposition);
exposureMatrix[idx] = vaultGlpExposure;
nettedMatrix[idx] = _nettedPositionRow(externalPositions[idx], vaultGlpExposure, idx);
}
}
function isNetted(
NettedState memory nettingState,
NettedParams memory params,
int256[5][5] memory externalPositions
) public pure returns (bool netted) {
uint256[5] memory glpExposure;
uint256[5] memory vaultRatio;
if (params.vaultCumulativeGlpTvl < 1e18) return true;
(glpExposure, vaultRatio) = vaultDeltaAdjustment(
nettingState, params.vaultCumulativeGlpTvl, params.glpComposition, externalPositions, params.nettedThreshold
);
uint256 upper = SCALE * (BIPS + params.nettedThreshold) / BIPS;
uint256 lower = SCALE * (BIPS - params.nettedThreshold) / BIPS;
netted = true;
for (uint256 i = 0; i < vaultRatio.length; i++) {
if (vaultRatio[i] > upper || vaultRatio[i] < lower) {
netted = false;
}
}
}
function _nettedPositionRow(int256[5] memory _hedgeAllocation, int256[5] memory _glpAllocation, uint256 _vaultIdx)
internal
pure
returns (int256[5] memory nettedPositions)
{
for (uint256 i = 0; i < _hedgeAllocation.length; i++) {
if (i == _vaultIdx) {
nettedPositions[i] = _glpAllocation[i];
} else {
nettedPositions[i] = _glpAllocation[i] - _hedgeAllocation[i];
}
}
}
function _vaultExposureInt(uint256 glpHeldDollars, uint256[5] memory glpComposition)
internal
pure
returns (int256[5] memory exposure)
{
for (uint256 i = 0; i < glpComposition.length; i++) {
exposure[i] = SafeCast.toInt256((glpHeldDollars * glpComposition[i]) / 1e18);
}
}
}
文件 42 的 54:Pausable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Pausable is Context {
event Paused(address account);
event Unpaused(address account);
bool private _paused;
constructor() {
_paused = false;
}
modifier whenNotPaused() {
_requireNotPaused();
_;
}
modifier whenPaused() {
_requirePaused();
_;
}
function paused() public view virtual returns (bool) {
return _paused;
}
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
文件 43 的 54:PausableVault.sol
pragma solidity 0.8.17;
abstract contract PausableVault {
event Paused(address account);
event Unpaused(address account);
event DepositsPaused(address account);
event DepositsUnpaused(address account);
event WithdrawalsPaused(address account);
event WithdrawalsUnpaused(address account);
bool private _depositsPaused;
bool private _withdrawalPaused;
constructor() {
_depositsPaused = false;
_withdrawalPaused = false;
}
modifier whenDepositNotPaused() {
_requireDepositNotPaused();
_;
}
modifier whenWithdrawalNotPaused() {
_requireWithdrawalNotPaused();
_;
}
modifier whenDepositPaused() {
_requireDepositPaused();
_;
}
modifier whenWithdrawalPaused() {
_requireWithdrawalPaused();
_;
}
function depositPaused() public view virtual returns (bool) {
return _depositsPaused;
}
function withdrawalPaused() public view virtual returns (bool) {
return _withdrawalPaused;
}
function _requireDepositNotPaused() internal view virtual {
require(!depositPaused(), "Pausable: deposit paused");
}
function _requireWithdrawalNotPaused() internal view virtual {
require(!withdrawalPaused(), "Pausable: withdrawal paused");
}
function _requireDepositPaused() internal view virtual {
require(depositPaused(), "Pausable: deposit not paused");
}
function _requireWithdrawalPaused() internal view virtual {
require(withdrawalPaused(), "Pausable: withdrawal not paused");
}
function _pause() internal virtual {
if (!depositPaused()) {
_pauseDeposit();
}
if (!withdrawalPaused()) {
_pauseWithdrawal();
}
emit Paused(msg.sender);
}
function _unpause() internal virtual {
if (depositPaused()) {
_unpauseDeposit();
}
if (withdrawalPaused()) {
_unpauseWithdrawal();
}
emit Unpaused(msg.sender);
}
function _pauseDeposit() internal virtual whenDepositNotPaused {
_depositsPaused = true;
emit Paused(msg.sender);
}
function _unpauseDeposit() internal virtual whenDepositPaused {
_depositsPaused = false;
emit Unpaused(msg.sender);
}
function _pauseWithdrawal() internal virtual whenWithdrawalNotPaused {
_withdrawalPaused = true;
emit Paused(msg.sender);
}
function _unpauseWithdrawal() internal virtual whenWithdrawalPaused {
_withdrawalPaused = false;
emit Unpaused(msg.sender);
}
}
文件 44 的 54:PositionManagerRouter.sol
pragma solidity 0.8.17;
import { Auth, GlobalACL } from "../../Auth.sol";
import { Multicall } from "../../libraries/Multicall.sol";
import { IPositionManager } from "../../interfaces/IPositionManager.sol";
import { IHandlerContract } from "../../interfaces/IHandlerContract.sol";
import { ISwapManager } from "../../interfaces/ISwapManager.sol";
contract WhitelistedTokenRegistry is GlobalACL {
event UpdatedWhitelistedToken(address indexed _token, bool _isWhitelisted);
event UpdatedIsWhitelistingEnabled(bool _isEnabled);
mapping(address => bool) public whitelistedTokens;
bool public isWhitelistingEnabled = true;
constructor(Auth _auth) GlobalACL(_auth) { }
function updateWhitelistedToken(address _token, bool _isWhitelisted) external onlyConfigurator {
whitelistedTokens[_token] = _isWhitelisted;
emit UpdatedWhitelistedToken(_token, _isWhitelisted);
}
function updateIsWhitelistingEnabled(bool _isWhitelistingEnabled) external onlyConfigurator {
isWhitelistingEnabled = _isWhitelistingEnabled;
emit UpdatedIsWhitelistingEnabled(_isWhitelistingEnabled);
}
function isWhitelistedToken(address _token) external view returns (bool) {
if (isWhitelistingEnabled) {
return whitelistedTokens[_token];
}
return true;
}
}
library PositionManagerRouterLib {
error NotWhitelistedToken();
error UnknownHandlerContract();
function executeSwap(
ISwapManager _swapManager,
address _tokenIn,
address _tokenOut,
uint256 _amountIn,
uint256 _minOut,
bytes calldata _data,
WhitelistedTokenRegistry whitelistedTokenRegistry,
mapping(ISwapManager => bool) storage swapHandlers,
mapping(IHandlerContract => bool) storage handlerContracts
) external returns (uint256 _amountOut) {
if (
!whitelistedTokenRegistry.isWhitelistedToken(_tokenIn)
|| !whitelistedTokenRegistry.isWhitelistedToken(_tokenOut)
) revert NotWhitelistedToken();
bool isSwapHandler = swapHandlers[_swapManager];
bool isHandler = handlerContracts[_swapManager];
if (!isSwapHandler || !isHandler) {
revert UnknownHandlerContract();
}
bytes memory ret = _delegatecall(
address(_swapManager), abi.encodeCall(ISwapManager.swap, (_tokenIn, _tokenOut, _amountIn, _minOut, _data))
);
(_amountOut) = abi.decode(ret, (uint256));
}
function _delegatecall(address _target, bytes memory _data) internal returns (bytes memory ret) {
bool success;
(success, ret) = _target.delegatecall(_data);
if (!success) {
assembly {
let length := mload(ret)
let start := add(ret, 0x20)
revert(start, length)
}
}
return ret;
}
}
abstract contract PositionManagerRouter {
error UnknownCallback();
error CallbackHandlerNotSet();
error UnknownHandlerContract();
error OnlySelf();
error NotWhitelistedToken();
event CallbackHandlerUpdated(bytes4 indexed _sig, address indexed _handler, bool _enabled);
event HandlerContractUpdated(address indexed _contract, bool _enabled);
event DefaultHandlerContractUpdated(bytes4 indexed _sig, address indexed _handler);
event SwapHandlerUpdated(address indexed _handled, bool _enabled);
event WhitelistedTokenUpdated(address indexed _token, bool _isWhitelisted);
mapping(IHandlerContract => mapping(bytes4 => bool)) public handlerContractCallbacks;
mapping(IHandlerContract => bool) public handlerContracts;
address public currentCallbackHandler;
mapping(bytes4 => IHandlerContract) public defaultHandlers;
mapping(ISwapManager => bool) public swapHandlers;
WhitelistedTokenRegistry immutable whitelistedTokenRegistry;
constructor(WhitelistedTokenRegistry _registry) {
whitelistedTokenRegistry = _registry;
}
function updateHandlerContract(IHandlerContract _handler, bool _enabled) public {
_onlyConfigurator();
handlerContracts[_handler] = _enabled;
emit HandlerContractUpdated(address(_handler), _enabled);
_updateHandlerContractCallbacks(_handler, _enabled);
}
function updateDefaultHandlerContract(bytes4 _sig, IHandlerContract _handler) external {
_onlyConfigurator();
defaultHandlers[_sig] = _handler;
emit DefaultHandlerContractUpdated(_sig, address(_handler));
}
function updateSwapHandler(ISwapManager _manager, bool _enabled) external {
_onlyConfigurator();
updateHandlerContract(_manager, _enabled);
swapHandlers[_manager] = _enabled;
emit SwapHandlerUpdated(address(_manager), _enabled);
}
function execute(address _handler, bytes calldata data) public payable returns (bytes memory ret) {
_validateExecuteCallAuth();
bool isSwapHandler = swapHandlers[ISwapManager(_handler)];
if (isSwapHandler && msg.sender != address(this)) {
_onlySwapIssuer();
}
bool isHandler = handlerContracts[IHandlerContract(_handler)];
if (!isHandler) revert UnknownHandlerContract();
ret = _delegatecall(_handler, data);
}
function executeWithCallbackHandler(address _handler, bytes calldata data, address _callbackHandler)
external
payable
withHandler(_callbackHandler)
returns (bytes memory ret)
{
ret = execute(_handler, data);
}
function executeSwap(
ISwapManager _swapManager,
address _tokenIn,
address _tokenOut,
uint256 _amountIn,
uint256 _minOut,
bytes calldata _data
) external returns (uint256 _amountOut) {
if (msg.sender != address(this)) {
_onlySwapIssuer();
}
_amountOut = PositionManagerRouterLib.executeSwap(
_swapManager,
_tokenIn,
_tokenOut,
_amountIn,
_minOut,
_data,
whitelistedTokenRegistry,
swapHandlers,
handlerContracts
);
}
fallback() external payable {
bytes memory _ret = _handleCallback();
assembly {
let length := mload(_ret)
return(add(_ret, 0x20), length)
}
}
function _onlyConfigurator() internal virtual;
function _onlySwapIssuer() internal virtual;
function _validateExecuteCallAuth() internal virtual;
function _updateHandlerContractCallbacks(IHandlerContract _handler, bool _enabled) internal {
bytes4[] memory handlerSigs = _handler.callbackSigs();
unchecked {
for (uint256 i = 0; i < handlerSigs.length; ++i) {
bytes4 sig = handlerSigs[i];
handlerContractCallbacks[_handler][sig] = _enabled;
emit CallbackHandlerUpdated(sig, address(_handler), _enabled);
}
}
}
function _handleCallback() internal returns (bytes memory ret) {
IHandlerContract handler = IHandlerContract(currentCallbackHandler);
if (address(handler) == address(0)) {
handler = defaultHandlers[msg.sig];
if (handler == IHandlerContract(address(0))) {
revert CallbackHandlerNotSet();
}
}
if (!handlerContracts[handler]) revert UnknownHandlerContract();
if (!handlerContractCallbacks[handler][msg.sig]) {
revert UnknownCallback();
}
ret = _delegatecall(address(handler), msg.data);
}
function _delegatecall(address _target, bytes memory _data) internal returns (bytes memory ret) {
bool success;
(success, ret) = _target.delegatecall(_data);
if (!success) {
assembly {
let length := mload(ret)
let start := add(ret, 0x20)
revert(start, length)
}
}
return ret;
}
modifier withHandler(address _handler) {
if (!handlerContracts[IHandlerContract(_handler)]) {
revert UnknownHandlerContract();
}
currentCallbackHandler = _handler;
_;
currentCallbackHandler = address(0);
}
modifier onlySelf() {
if (msg.sender != address(this)) revert OnlySelf();
_;
}
receive() external payable { }
}
文件 45 的 54:SafeCast.sol
pragma solidity 0.8.17;
library SafeCast {
function toInt256(uint256 y) internal pure returns (int256 z) {
require(y < 2 ** 255);
z = int256(y);
}
}
文件 46 的 54:SafeTransferLib.sol
pragma solidity >=0.8.0;
import {ERC20} from "../tokens/ERC20.sol";
library SafeTransferLib {
function safeTransferETH(address to, uint256 amount) internal {
bool success;
assembly {
success := call(gas(), to, amount, 0, 0, 0, 0)
}
require(success, "ETH_TRANSFER_FAILED");
}
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 amount
) internal {
bool success;
assembly {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), from)
mstore(add(freeMemoryPointer, 36), to)
mstore(add(freeMemoryPointer, 68), amount)
success := and(
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
)
}
require(success, "TRANSFER_FROM_FAILED");
}
function safeTransfer(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
assembly {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), to)
mstore(add(freeMemoryPointer, 36), amount)
success := and(
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "TRANSFER_FAILED");
}
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
assembly {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), to)
mstore(add(freeMemoryPointer, 36), amount)
success := and(
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "APPROVE_FAILED");
}
}
文件 47 的 54:ShareMath.sol
pragma solidity 0.8.17;
library ShareMath {
uint256 internal constant PLACEHOLDER_UINT = 1;
function assetToShares(uint256 assetAmount, uint256 assetPerShare, uint256 decimals)
internal
pure
returns (uint256)
{
require(assetPerShare > PLACEHOLDER_UINT, "Invalid assetPerShare");
return (assetAmount * 10 ** decimals) / assetPerShare;
}
function sharesToAsset(uint256 shares, uint256 assetPerShare, uint256 decimals) internal pure returns (uint256) {
require(assetPerShare > PLACEHOLDER_UINT, "Invalid assetPerShare");
return (shares * assetPerShare) / 10 ** decimals;
}
function pricePerShare(uint256 totalSupply, uint256 totalBalance, uint256 decimals)
internal
pure
returns (uint256)
{
uint256 singleShare = 10 ** decimals;
return totalSupply > 0 ? (singleShare * totalBalance) / totalSupply : singleShare;
}
}
文件 48 的 54:Solarray.sol
pragma solidity 0.8.17;
import { SafeCast } from "./SafeCast.sol";
library Solarray {
function uint256s(uint256 a, uint256 b, uint256 c, uint256 d) internal pure returns (uint256[4] memory) {
uint256[4] memory arr;
arr[0] = a;
arr[1] = b;
arr[2] = c;
arr[3] = d;
return arr;
}
function uint256s(uint256 a, uint256 b, uint256 c, uint256 d, uint256 e)
internal
pure
returns (uint256[5] memory)
{
uint256[5] memory arr;
arr[0] = a;
arr[1] = b;
arr[2] = c;
arr[3] = d;
arr[4] = e;
return arr;
}
function int256s(int256 a, int256 b, int256 c, int256 d) internal pure returns (int256[4] memory) {
int256[4] memory arr;
arr[0] = a;
arr[1] = b;
arr[2] = c;
arr[3] = d;
return arr;
}
function int256s(int256 a, int256 b, int256 c, int256 d, int256 e) internal pure returns (int256[5] memory) {
int256[5] memory arr;
arr[0] = a;
arr[1] = b;
arr[2] = c;
arr[3] = d;
arr[4] = e;
return arr;
}
function addresss(address a, address b, address c, address d, address e)
internal
pure
returns (address[5] memory)
{
address[5] memory arr;
arr[0] = a;
arr[1] = b;
arr[2] = c;
arr[3] = d;
arr[4] = e;
return arr;
}
function intToUintArray(int256[5] memory _array) internal pure returns (uint256[5] memory uintArray) {
require(
_array[0] > 0 && _array[1] > 0 && _array[2] > 0 && _array[3] > 0 && _array[4] > 0,
"Solarray: intToUintArray: negative value"
);
uintArray = [uint256(_array[0]), uint256(_array[1]), uint256(_array[2]), uint256(_array[3]), uint256(_array[4])];
}
function arraySum(int256[4] memory _array) internal pure returns (int256 sum) {
for (uint256 i = 0; i < _array.length; i++) {
sum += _array[i];
}
}
function arraySum(int256[5] memory _array) internal pure returns (int256 sum) {
for (uint256 i = 0; i < _array.length; i++) {
sum += _array[i];
}
}
function arraySum(uint256[5] memory _array) internal pure returns (uint256 sum) {
for (uint256 i = 0; i < _array.length; i++) {
sum += _array[i];
}
}
function arraySumAbsolute(int256[5] memory _array) internal pure returns (uint256 sum) {
for (uint256 i = 0; i < _array.length; i++) {
sum += _array[i] > 0 ? uint256(_array[i]) : uint256(-_array[i]);
}
}
function arrayDifference(uint256[5] memory _base, int256[5] memory _difference)
internal
pure
returns (int256[5] memory result)
{
for (uint256 i = 0; i < 5; i++) {
result[i] = SafeCast.toInt256(_base[i]) + _difference[i];
}
}
function scaleArray(uint256[4] memory _array, uint256 _scale) internal pure returns (uint256[4] memory _retArray) {
for (uint256 i = 0; i < _array.length; i++) {
_retArray[i] = _array[i] * _scale / 1e18;
}
}
function scaleArray(uint256[5] memory _array, uint256 _scale) internal pure returns (uint256[5] memory _retArray) {
for (uint256 i = 0; i < _array.length; i++) {
_retArray[i] = _array[i] * _scale / 1e18;
}
}
function sumColumns(int256[5][4] memory _array) internal pure returns (int256[4] memory _retArray) {
for (uint256 i = 0; i < _array.length; i++) {
for (uint256 j = 0; j < 5; j++) {
_retArray[i] += _array[j][i];
}
}
}
function sumColumns(int256[5][5] memory _array) internal pure returns (int256[5] memory _retArray) {
for (uint256 i = 0; i < _array.length; i++) {
for (uint256 j = 0; j < _array.length; j++) {
_retArray[i] += _array[j][i];
}
}
}
function int5FixedToDynamic(int256[5] memory _arr) public view returns (int256[] memory _retArr) {
bytes memory _ret = fixedToDynamicArray(abi.encode(_arr), 5);
assembly {
_retArr := _ret
}
}
function uint5FixedToDynamic(uint256[5] memory _arr) internal view returns (uint256[] memory _retArr) {
bytes memory _ret = fixedToDynamicArray(abi.encode(_arr), 5);
assembly {
_retArr := _ret
}
}
function fixedToDynamicArray(bytes memory _arr, uint256 _fixedSize) public view returns (bytes memory _retArray) {
(bool success, bytes memory data) = address(0x04).staticcall(_arr);
require(success, "identity precompile failed");
assembly {
_retArray := data
mstore(_retArray, _fixedSize)
}
}
}
文件 49 的 54:Strings.sol
pragma solidity ^0.8.0;
import "./math/Math.sol";
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}
文件 50 的 54:UniswapV3SwapManager.sol
pragma solidity 0.8.17;
import { BaseSwapManager } from "./BaseSwapManager.sol";
import { ERC20 } from "solmate/tokens/ERC20.sol";
import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol";
import { ISwapRouter } from "../../interfaces/uniswap/ISwapRouter.sol";
import { IUniswapV3Pool } from "../../interfaces/uniswap/IUniswapV3Pool.sol";
import { IUniswapV3Factory } from "../../interfaces/uniswap/IUniswapV3Factory.sol";
import { UNISWAP_SWAP_ROUTER, UNISWAP_FACTORY } from "../../constants.sol";
contract UniswapV3SwapManager is BaseSwapManager {
using SafeTransferLib for ERC20;
struct Config {
uint24[] feeTiers;
address intermediaryAsset;
}
ISwapRouter public constant uniV3Router = ISwapRouter(UNISWAP_SWAP_ROUTER);
IUniswapV3Factory public constant uniV3factory = IUniswapV3Factory(UNISWAP_FACTORY);
bytes32 public constant CONFIG_SLOT = keccak256("swapManagers.UniswapV3.config");
address public immutable AGGREGATE_VAULT;
constructor(address _aggregateVault, address _intermediaryAsset) {
require(_aggregateVault != address(0), "!_aggregateVault");
require(_intermediaryAsset != address(0), "!_intermediaryAsset");
Config storage config = _configStorage();
AGGREGATE_VAULT = _aggregateVault;
config.intermediaryAsset = _intermediaryAsset;
}
function swap(address _tokenIn, address _tokenOut, uint256 _amountIn, uint256 _minOut, bytes calldata)
external
onlyDelegateCall
swapChecks(_tokenIn, _tokenOut, _amountIn, _minOut)
returns (uint256 _amountOut)
{
bytes memory path = _getSwapPath(_tokenIn, _tokenOut);
_amountOut = _swapTokenExactInput(_tokenIn, _amountIn, _minOut, path);
}
function exactOutputSwap(address _tokenIn, address _tokenOut, uint256 _amountOut, uint256 _maxIn)
external
onlyDelegateCall
swapChecks(_tokenIn, _tokenOut, _maxIn, _amountOut)
returns (uint256 _amountIn)
{
bytes memory path = _getSwapPath(_tokenIn, _tokenOut);
_amountIn = _swapTokenExactOutput(_tokenIn, _amountOut, _maxIn, path);
}
function addFeeTier(uint24 _feeTier) external onlyDelegateCall {
require(_feeTier > 0 && _feeTier < 100_000, "UniswapV3SwapManager: !_feeTier");
Config storage config = _configStorage();
config.feeTiers.push(_feeTier);
}
function removeFeeTierAt(uint24 _feeTierToRemove, uint256 _idx) external onlyDelegateCall {
Config storage config = _configStorage();
require(config.feeTiers[_idx] == _feeTierToRemove, "UniswapV3SwapManager: invalid idx");
config.feeTiers[_idx] = config.feeTiers[config.feeTiers.length - 1];
config.feeTiers.pop();
}
function setIntermediaryAsset(address _newAsset) external onlyDelegateCall {
require(_newAsset != address(0), "UniswapV3SwapManager: !_newAsset");
Config storage config = _configStorage();
config.intermediaryAsset = _newAsset;
}
function _swapTokenExactInput(address _tokenIn, uint256 _amountIn, uint256 _minOut, bytes memory _path)
internal
returns (uint256 _out)
{
ISwapRouter.ExactInputParams memory params = ISwapRouter.ExactInputParams({
path: _path,
recipient: address(this),
deadline: block.timestamp,
amountIn: _amountIn,
amountOutMinimum: _minOut
});
ERC20(_tokenIn).safeApprove(address(uniV3Router), _amountIn);
return uniV3Router.exactInput(params);
}
function _swapTokenExactOutput(address _tokenIn, uint256 _amountOut, uint256 _maxIn, bytes memory _path)
internal
returns (uint256 _in)
{
ISwapRouter.ExactOutputParams memory params = ISwapRouter.ExactOutputParams({
path: _path,
recipient: address(this),
deadline: block.timestamp,
amountOut: _amountOut,
amountInMaximum: _maxIn
});
ERC20(_tokenIn).safeApprove(address(uniV3Router), _maxIn);
return uniV3Router.exactOutput(params);
}
function _getSwapPath(address _tokenIn, address _tokenOut) internal view returns (bytes memory path) {
Config storage config = _configStorage();
uint24 tokenInFee = _getSwapFee(_tokenIn);
uint24 tokenOutFee = _getSwapFee(_tokenOut);
require(tokenInFee > 0, "UniswapV3SwapManager: !_tokenIn");
require(tokenOutFee > 0, "UniswapV3SwapManager: !_tokenOut");
require(_tokenIn != _tokenOut, "UniswapV3SwapManager: !unique tokens");
if (_tokenIn == config.intermediaryAsset || _tokenOut == config.intermediaryAsset) {
path = abi.encodePacked(_tokenIn, tokenInFee, _tokenOut);
} else {
path = abi.encodePacked(_tokenIn, tokenInFee, config.intermediaryAsset, tokenOutFee, _tokenOut);
}
}
function _getSwapFee(address _targetToken) internal view returns (uint24 swapFee) {
Config storage config = _configStorage();
address bestSwapPool;
address iterSwapPool;
for (uint256 i = 0; i < config.feeTiers.length; i++) {
iterSwapPool = uniV3factory.getPool(_targetToken, config.intermediaryAsset, config.feeTiers[i]);
if (bestSwapPool == address(0) && iterSwapPool != address(0)) {
swapFee = config.feeTiers[i];
bestSwapPool = iterSwapPool;
}
if (
iterSwapPool != address(0)
&& IUniswapV3Pool(bestSwapPool).liquidity() < IUniswapV3Pool(iterSwapPool).liquidity()
) {
swapFee = config.feeTiers[i];
bestSwapPool = iterSwapPool;
}
}
}
function _configStorage() internal pure returns (Config storage config) {
bytes32 slot = CONFIG_SLOT;
assembly {
config.slot := slot
}
}
}
文件 51 的 54:VaultMath.sol
pragma solidity 0.8.17;
library VaultMath {
uint256 constant SCALE = 1e30;
uint256 constant BIPS = 10_000;
function getSlippageAdjustedAmount(uint256 amount, uint256 slippage) internal pure returns (uint256) {
return (amount * (1 * SCALE - slippage)) / SCALE;
}
}
文件 52 的 54:Vester.sol
pragma solidity 0.8.17;
import { Auth, GlobalACL } from "../Auth.sol";
import { ERC20 } from "solmate/tokens/ERC20.sol";
import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol";
uint256 constant PRECISION = 1e18;
contract Vester is GlobalACL {
using SafeTransferLib for ERC20;
event SetVestDuration(uint256 previousVestDuration, uint256 newVestDuration);
event Claimed(address indexed token, uint256 amount);
event AddVest(address indexed token, uint256 amount);
error VestingPerSecondTooLow();
address public immutable aggregateVault;
struct VestingInfo {
uint256 vestingPerSecond;
uint256 lastClaim;
}
mapping(address => VestingInfo) public vestingInfo;
uint256 public vestDuration;
constructor(Auth _auth, address _aggregateVault, uint256 _vestDuration) GlobalACL(_auth) {
aggregateVault = _aggregateVault;
_setVestDuration(_vestDuration);
}
function setVestDuration(uint256 _vestDuration) external onlyConfigurator {
_setVestDuration(_vestDuration);
}
function claim(address _asset) public returns (uint256) {
uint256 vested = vested(_asset);
if (vested == 0) return 0;
vestingInfo[_asset].lastClaim = block.timestamp;
emit Claimed(_asset, vested);
ERC20(_asset).safeTransfer(aggregateVault, vested);
return vested;
}
function addVest(address _asset, uint256 _amount) external {
claim(_asset);
emit AddVest(_asset, _amount);
ERC20(_asset).safeTransferFrom(msg.sender, address(this), _amount);
uint256 currentBalance = ERC20(_asset).balanceOf(address(this));
uint256 vestingPerSecond = currentBalance * PRECISION / vestDuration;
if (vestingPerSecond == 0) revert VestingPerSecondTooLow();
vestingInfo[_asset] = VestingInfo({ vestingPerSecond: vestingPerSecond, lastClaim: block.timestamp });
}
function vested(address _asset) public view returns (uint256) {
uint256 duration = block.timestamp - vestingInfo[_asset].lastClaim;
uint256 totalVested = duration * vestingInfo[_asset].vestingPerSecond / PRECISION;
uint256 totalBalance = ERC20(_asset).balanceOf(address(this));
return totalVested > totalBalance ? totalBalance : totalVested;
}
function _setVestDuration(uint256 _newVestDuration) internal {
uint256 previousVestDuration = vestDuration;
vestDuration = _newVestDuration;
emit SetVestDuration(previousVestDuration, _newVestDuration);
}
}
文件 53 的 54:Whitelist.sol
pragma solidity 0.8.17;
import { Auth, GlobalACL } from "../Auth.sol";
import { MerkleProof } from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
contract Whitelist is GlobalACL {
address public immutable aggregateVault;
address public zap;
constructor(Auth _auth, address _aggregateVault, address _zap) GlobalACL(_auth) {
whitelistEnabled = true;
aggregateVault = _aggregateVault;
zap = _zap;
}
mapping(address => mapping(address => uint256)) public whitelistedDepositAmount;
mapping(address => bytes32) public merkleRoots;
mapping(address => uint256) public merkleDepositLimit;
mapping(address => mapping(address => uint256)) public merkleDepositorTracker;
bool public whitelistEnabled;
event WhitelistUpdated(address indexed account, address asset, uint256 whitelistedAmount);
function isWhitelistedPriority(address _asset, address _account) external view returns (bool) {
if (whitelistEnabled) return whitelistedDepositAmount[_account][_asset] > 0;
return true;
}
function isWhitelistedMerkle(address _asset, address _account, bytes32[] memory merkleProof)
external
view
returns (bool)
{
bytes32 leaf = keccak256(abi.encodePacked(_account));
if (whitelistEnabled) return MerkleProof.verify(merkleProof, merkleRoots[_asset], leaf);
return true;
}
function isWhitelisted(address _asset, address _account, bytes32[] memory merkleProof)
external
view
returns (bool)
{
bytes32 leaf = keccak256(abi.encodePacked(_account));
if (whitelistEnabled) {
return whitelistedDepositAmount[_account][_asset] > 0
|| MerkleProof.verify(merkleProof, merkleRoots[_asset], leaf);
}
return true;
}
function whitelistDeposit(address _asset, address _account, uint256 _amount) external onlyAggregateVaultOrZap {
require(whitelistedDepositAmount[_account][_asset] >= _amount, "Whitelist: amount > asset whitelist amount");
whitelistedDepositAmount[_account][_asset] -= _amount;
}
function whitelistDepositMerkle(address _asset, address _account, uint256 _amount, bytes32[] memory merkleProof)
external
onlyAggregateVaultOrZap
{
bytes32 leaf = keccak256(abi.encodePacked(_account));
require(MerkleProof.verify(merkleProof, merkleRoots[_asset], leaf), "Whitelist: invalid proof");
require(
merkleDepositorTracker[_asset][_account] + _amount <= merkleDepositLimit[_asset],
"Whitelist: amount > asset whitelist amount"
);
merkleDepositorTracker[_asset][_account] += _amount;
}
function updateWhitelist(address _asset, address _account, uint256 _amount) external onlyConfigurator {
whitelistedDepositAmount[_account][_asset] = _amount;
emit WhitelistUpdated(_account, _asset, _amount);
}
function updateWhitelistEnabled(bool _newVal) external onlyConfigurator {
whitelistEnabled = _newVal;
}
function updateMerkleRoot(address _asset, bytes32 _root) external onlyConfigurator {
merkleRoots[_asset] = _root;
}
function updateMerkleDepositLimit(address _asset, uint256 _depositLimit) external onlyConfigurator {
merkleDepositLimit[_asset] = _depositLimit;
}
function updateMerkleDepositorTracker(address _asset, address _account, uint256 _newValue)
external
onlyConfigurator
{
merkleDepositorTracker[_asset][_account] = _newValue;
}
function updateZap(address _newZap) external onlyConfigurator {
zap = _newZap;
}
modifier onlyAggregateVault() {
require(msg.sender == aggregateVault, "Whitelist: only aggregate vault");
_;
}
modifier onlyAggregateVaultOrZap() {
require(msg.sender == aggregateVault || msg.sender == zap, "Whitelist: only aggregate vault or zap");
_;
}
}
文件 54 的 54:constants.sol
pragma solidity 0.8.17;
address constant GMX_POSITION_ROUTER = 0xb87a436B93fFE9D75c5cFA7bAcFff96430b09868;
address constant GMX_VAULT = 0x489ee077994B6658eAfA855C308275EAd8097C4A;
address constant GMX_ROUTER = 0xaBBc5F99639c9B6bCb58544ddf04EFA6802F4064;
address constant GMX_GLP_REWARD_ROUTER = 0xB95DB5B167D75e6d04227CfFFA61069348d271F5;
address constant GMX_VAULT_PRICE_FEED = 0x2d68011bcA022ed0E474264145F46CC4de96a002;
address constant GMX_GLP_MANAGER = 0x3963FfC9dff443c2A94f21b129D429891E32ec18;
address constant GMX_FEE_STAKED_GLP = 0x1aDDD80E6039594eE970E5872D247bf0414C8903;
address constant GMX_STAKED_GLP = 0x5402B5F40310bDED796c7D0F3FF6683f5C0cFfdf;
address constant GMX_FEE_GLP = 0x4e971a87900b931fF39d1Aad67697F49835400b6;
address constant GMX_GLP = 0x4277f8F2c384827B5273592FF7CeBd9f2C1ac258;
address constant GMX_GLP_CLAIM_REWARDS = 0xA906F338CB21815cBc4Bc87ace9e68c87eF8d8F1;
address constant GMX_ACCOUNT_TRANSFER = 0xA906F338CB21815cBc4Bc87ace9e68c87eF8d8F1;
bytes32 constant GMX_REFERRAL = "umami";
address constant TOKEN_DAI = 0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1;
address constant TOKEN_FRAX = 0x17FC002b466eEc40DaE837Fc4bE5c67993ddBd6F;
address constant TOKEN_USDC = 0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8;
address constant TOKEN_USDT = 0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9;
address constant TOKEN_LINK = 0xf97f4df75117a78c1A5a0DBb814Af92458539FB4;
address constant TOKEN_UNI = 0xFa7F8980b0f1E64A2062791cc3b0871572f1F7f0;
address constant TOKEN_WETH = 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1;
address constant TOKEN_WBTC = 0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f;
address constant TOKEN_UMAMI = 0x1622bF67e6e5747b81866fE0b85178a93C7F86e3;
address constant ERC1967_FACTORY = 0x0000000000006396FF2a80c067f99B3d2Ab4Df24;
uint256 constant DECIMALS_USDC = 6;
uint256 constant DECIMALS_USDT = 6;
uint256 constant DECIMALS_DAI = 18;
uint256 constant DECIMALS_FRAX = 18;
uint256 constant DECIMALS_WETH = 18;
uint256 constant DECIMALS_WBTC = 8;
uint256 constant DECIMALS_LINK = 18;
uint256 constant DECIMALS_UNI = 18;
address constant AAVE_ORACLE = 0xb56c2F0B653B2e0b10C9b928C8580Ac5Df02C7C7;
address constant AAVE_POOL = 0x794a61358D6845594F94dc1DB02A252b5b4814aD;
address constant AAVE_POOL_ADDRESS_PROVIDER = 0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb;
uint16 constant AAVE_REFERRAL_CODE = 0;
address constant UNISWAP_SWAP_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564;
address constant UNISWAP_FACTORY = 0x1F98431c8aD98523631AE4a59f267346ea31F984;
address constant BALANCER_VAULT = 0xBA12222222228d8Ba445958a75a0704d566BF2C8;
address constant ODOS_ROUTER = 0xdd94018F54e565dbfc939F7C44a16e163FaAb331;
uint256 constant UMAMI_TOTAL_VAULTS = 5;
address constant UMAMI_TREASURY = 0xB0B4bd94D656353a30773Ac883591DDBaBC0c0bA;
address constant UMAMI_DEV_WALLET = 0x4e5645bee4eD80C6FEe04DCC15D14A3AC956748A;
uint256 constant VAULT_PERFORMANCE_FEE = 3e18;
uint256 constant VAULT_MANAGEMENT_FEE = 2e18;
uint256 constant VAULT_DEPOSIT_FEE = 0.75e18;
uint256 constant VAULT_WITHDRAWAL_FEE = 0.75e18;
uint256 constant VAULT_TIMELOCK_BOOST_FEE = 2e18;
uint256 constant NUMBER_OF_REBALANCES_PER_YEAR = 12 * 365;
uint256 constant TIMELOCK_DURATION = 86_400 * 14;
address constant KEEPER_RECIPIENT = 0xc7d873647AEa26902b9C2C243C21364468474b34;
uint256 constant KEEPER_SHARE_BPS = 1000;
uint256 constant SWAP_TOLERANCE_BPS = 500;
address constant DEPLOYMENT_MULTISIG = 0xb137d135Dc8482B633265c21191F50a4bA26145d;
{
"compilationTarget": {
"src/vaults/AssetVault.sol": "AssetVault"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 888
},
"remappings": [
":@chainlink/=lib/chainlink/",
":@openzeppelin/=lib/openzeppelin-contracts/",
":@solady/=lib/solady/src/",
":chainlink/=lib/chainlink/integration-tests/contracts/ethereum/src/",
":ds-test/=lib/forge-std/lib/ds-test/src/",
":forge-std/=lib/forge-std/src/",
":gmx-contracts/=lib/gmx-contracts/contracts/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/",
":solady/=lib/solady/",
":solmate/=lib/solmate/src/"
]
}
[{"inputs":[{"internalType":"contract ERC20","name":"_asset","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"address","name":"_aggregateVault","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"DepositsPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"DepositsUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"WithdrawalsPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"WithdrawalsUnpaused","type":"event"},{"inputs":[],"name":"AUTH","outputs":[{"internalType":"contract Auth","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aggregateVault","outputs":[{"internalType":"contract AggregateVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_mintAmount","type":"uint256"},{"internalType":"address","name":"_timelockContract","type":"address"}],"name":"mintTimelockBoost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauseDepositWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pauseDeposits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pauseWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pps","outputs":[{"internalType":"uint256","name":"pricePerShare","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"size","type":"uint256"}],"name":"previewDepositFee","outputs":[{"internalType":"uint256","name":"totalDepositFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"_mintAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"previewVaultCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"_withdrawAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"size","type":"uint256"}],"name":"previewWithdrawalFee","outputs":[{"internalType":"uint256","name":"totalWithdrawalFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tvl","outputs":[{"internalType":"uint256","name":"totalValueLocked","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpauseDepositWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpauseDeposits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpauseWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract AggregateVault","name":"_newAggregateVault","type":"address"}],"name":"updateAggregateVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"name":"whitelistDeposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]