编译器
0.8.10+commit.fc410830
文件 1 的 51: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 的 51:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 3 的 51: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;
}
}
文件 4 的 51: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;
}
}
文件 5 的 51:ERC20.sol
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function decimals() public view virtual override returns (uint8) {
return 18;
}
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}
文件 6 的 51:ERC4626.sol
pragma solidity ^0.8.0;
import "../ERC20.sol";
import "../utils/SafeERC20.sol";
import "../../../interfaces/IERC4626.sol";
import "../../../utils/math/Math.sol";
abstract contract ERC4626 is ERC20, IERC4626 {
using Math for uint256;
IERC20Metadata private immutable _asset;
constructor(IERC20Metadata asset_) {
_asset = asset_;
}
function asset() public view virtual override returns (address) {
return address(_asset);
}
function totalAssets() public view virtual override returns (uint256) {
return _asset.balanceOf(address(this));
}
function convertToShares(uint256 assets) public view virtual override returns (uint256 shares) {
return _convertToShares(assets, Math.Rounding.Down);
}
function convertToAssets(uint256 shares) public view virtual override returns (uint256 assets) {
return _convertToAssets(shares, Math.Rounding.Down);
}
function maxDeposit(address) public view virtual override returns (uint256) {
return _isVaultCollateralized() ? type(uint256).max : 0;
}
function maxMint(address) public view virtual override returns (uint256) {
return type(uint256).max;
}
function maxWithdraw(address owner) public view virtual override returns (uint256) {
return _convertToAssets(balanceOf(owner), Math.Rounding.Down);
}
function maxRedeem(address owner) public view virtual override returns (uint256) {
return balanceOf(owner);
}
function previewDeposit(uint256 assets) public view virtual override returns (uint256) {
return _convertToShares(assets, Math.Rounding.Down);
}
function previewMint(uint256 shares) public view virtual override returns (uint256) {
return _convertToAssets(shares, Math.Rounding.Up);
}
function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {
return _convertToShares(assets, Math.Rounding.Up);
}
function previewRedeem(uint256 shares) public view virtual override returns (uint256) {
return _convertToAssets(shares, Math.Rounding.Down);
}
function deposit(uint256 assets, address receiver) public virtual override returns (uint256) {
require(assets <= maxDeposit(receiver), "ERC4626: deposit more than max");
uint256 shares = previewDeposit(assets);
_deposit(_msgSender(), receiver, assets, shares);
return shares;
}
function mint(uint256 shares, address receiver) public virtual override returns (uint256) {
require(shares <= maxMint(receiver), "ERC4626: mint more than max");
uint256 assets = previewMint(shares);
_deposit(_msgSender(), receiver, assets, shares);
return assets;
}
function withdraw(
uint256 assets,
address receiver,
address owner
) public virtual override returns (uint256) {
require(assets <= maxWithdraw(owner), "ERC4626: withdraw more than max");
uint256 shares = previewWithdraw(assets);
_withdraw(_msgSender(), receiver, owner, assets, shares);
return shares;
}
function redeem(
uint256 shares,
address receiver,
address owner
) public virtual override returns (uint256) {
require(shares <= maxRedeem(owner), "ERC4626: redeem more than max");
uint256 assets = previewRedeem(shares);
_withdraw(_msgSender(), receiver, owner, assets, shares);
return assets;
}
function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256 shares) {
uint256 supply = totalSupply();
return
(assets == 0 || supply == 0)
? assets.mulDiv(10**decimals(), 10**_asset.decimals(), rounding)
: assets.mulDiv(supply, totalAssets(), rounding);
}
function _convertToAssets(uint256 shares, Math.Rounding rounding) internal view virtual returns (uint256 assets) {
uint256 supply = totalSupply();
return
(supply == 0)
? shares.mulDiv(10**_asset.decimals(), 10**decimals(), rounding)
: shares.mulDiv(totalAssets(), supply, rounding);
}
function _deposit(
address caller,
address receiver,
uint256 assets,
uint256 shares
) internal virtual {
SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);
_mint(receiver, shares);
emit Deposit(caller, receiver, assets, shares);
}
function _withdraw(
address caller,
address receiver,
address owner,
uint256 assets,
uint256 shares
) internal virtual {
if (caller != owner) {
_spendAllowance(owner, caller, shares);
}
_burn(owner, shares);
SafeERC20.safeTransfer(_asset, receiver, assets);
emit Withdraw(caller, receiver, owner, assets, shares);
}
function _isVaultCollateralized() private view returns (bool) {
return totalAssets() > 0 || totalSupply() == 0;
}
}
文件 7 的 51:Errors.sol
pragma solidity ^0.8.10;
interface Errors {
error AlreadyInitialized();
error CallerIsNotInternalContract();
error CallerIsNotWhitelisted();
error InvalidWithdrawalRetention();
error MaxGlpTvlReached();
error CannotSettleEpochInFuture();
error EpochAlreadySettled();
error EpochNotSettled();
error WithdrawalAlreadyCompleted();
error WithdrawalWithNoShares();
error WithdrawalSignalAlreadyDone();
error NotRightEpoch();
error NotEnoughStables();
error NoEpochToSettle();
error CannotCancelWithdrawal();
error AddressCannotBeZeroAddress();
error OnlyAdapter();
error DoesntHavePermission();
}
文件 8 的 51:GlpAdapter.sol
pragma solidity ^0.8.10;
import {IERC20, IERC20Metadata} from "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IERC4626} from "openzeppelin-contracts/contracts/interfaces/IERC4626.sol";
import {IGmxRewardRouter} from "../interfaces/IGmxRewardRouter.sol";
import {IGlpManager, IGMXVault} from "../interfaces/IGlpManager.sol";
import {IJonesGlpVaultRouter} from "../interfaces/IJonesGlpVaultRouter.sol";
import {Operable, Governable} from "../common/Operable.sol";
import {ReentrancyGuard} from "openzeppelin-contracts/contracts/security/ReentrancyGuard.sol";
import {MerkleProof} from "openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol";
import {WhitelistController} from "src/common/WhitelistController.sol";
import {IAggregatorV3} from "src/interfaces/IAggregatorV3.sol";
import {JonesGlpLeverageStrategy} from "src/glp/strategies/JonesGlpLeverageStrategy.sol";
import {JonesGlpStableVault} from "src/glp/vaults/JonesGlpStableVault.sol";
contract GlpAdapter is Operable, ReentrancyGuard {
IJonesGlpVaultRouter public vaultRouter;
IGmxRewardRouter public gmxRouter = IGmxRewardRouter(0xB95DB5B167D75e6d04227CfFFA61069348d271F5);
IAggregatorV3 public oracle = IAggregatorV3(0x50834F3163758fcC1Df9973b6e91f0F0F0434aD3);
IERC20 public glp = IERC20(0x5402B5F40310bDED796c7D0F3FF6683f5C0cFfdf);
IERC20 public usdc = IERC20(0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8);
WhitelistController public controller;
JonesGlpLeverageStrategy public strategy;
JonesGlpStableVault public stableVault;
bytes32 private root;
uint256 public flexibleTotalCap;
bool public hatlistStatus;
bool public useFlexibleCap;
mapping(address => bool) public isValid;
uint256 public constant BASIS_POINTS = 1e12;
constructor(address[] memory _tokens, address _controller, address _strategy, address _stableVault)
Governable(msg.sender)
{
uint8 i = 0;
for (; i < _tokens.length;) {
_editToken(_tokens[i], true);
unchecked {
i++;
}
}
controller = WhitelistController(_controller);
strategy = JonesGlpLeverageStrategy(_strategy);
stableVault = JonesGlpStableVault(_stableVault);
}
function zapToGlp(address _token, uint256 _amount, bool _compound, bytes32[] memory _proof)
external
nonReentrant
validToken(_token)
returns (uint256)
{
_validateSender(_proof);
IERC20(_token).transferFrom(msg.sender, address(this), _amount);
IERC20(_token).approve(gmxRouter.glpManager(), _amount);
uint256 mintedGlp = gmxRouter.mintAndStakeGlp(_token, _amount, 0, 0);
glp.approve(address(vaultRouter), mintedGlp);
uint256 receipts = vaultRouter.depositGlp(mintedGlp, msg.sender, _compound);
return receipts;
}
function zapToGlpEth(bool _compound, bytes32[] memory _proof) external payable nonReentrant returns (uint256) {
_validateSender(_proof);
uint256 mintedGlp = gmxRouter.mintAndStakeGlpETH{value: msg.value}(0, 0);
glp.approve(address(vaultRouter), mintedGlp);
uint256 receipts = vaultRouter.depositGlp(mintedGlp, msg.sender, _compound);
return receipts;
}
function redeemGlpBasket(uint256 _shares, bool _compound, address _token, bool _native)
external
nonReentrant
validToken(_token)
returns (uint256)
{
_onlyEOA();
uint256 assetsReceived = vaultRouter.redeemGlpAdapter(_shares, _compound, _token, msg.sender, _native);
return assetsReceived;
}
function depositGlp(uint256 _assets, bool _compound, bytes32[] memory _proof)
external
nonReentrant
returns (uint256)
{
_validateSender(_proof);
glp.transferFrom(msg.sender, address(this), _assets);
glp.approve(address(vaultRouter), _assets);
uint256 receipts = vaultRouter.depositGlp(_assets, msg.sender, _compound);
return receipts;
}
function depositStable(uint256 _assets, bool _compound, bytes32[] memory _proof)
external
nonReentrant
returns (uint256)
{
_validateSender(_proof);
if (useFlexibleCap) {
_checkUsdcCap(_assets);
}
usdc.transferFrom(msg.sender, address(this), _assets);
usdc.approve(address(vaultRouter), _assets);
uint256 receipts = vaultRouter.depositStable(_assets, _compound, msg.sender);
return receipts;
}
function updateGmxRouter(address _gmxRouter) external onlyGovernor {
gmxRouter = IGmxRewardRouter(_gmxRouter);
}
function updateVaultRouter(address _vaultRouter) external onlyGovernor {
vaultRouter = IJonesGlpVaultRouter(_vaultRouter);
}
function _editToken(address _token, bool _valid) internal {
isValid[_token] = _valid;
}
function updateRoot(bytes32 _root) external onlyGovernor {
root = _root;
}
function toggleHatlist(bool _status) external onlyGovernor {
hatlistStatus = _status;
}
function toggleFlexibleCap(bool _status) external onlyGovernor {
useFlexibleCap = _status;
}
function updateFlexibleCap(uint256 _newAmount) public onlyGovernor {
flexibleTotalCap = _newAmount;
}
function getFlexibleCap() public view returns (uint256) {
return flexibleTotalCap;
}
function usingFlexibleCap() public view returns (bool) {
return useFlexibleCap;
}
function usingHatlist() public view returns (bool) {
return hatlistStatus;
}
function getUsdcCap() public view returns (uint256 usdcCap) {
usdcCap = (flexibleTotalCap * (strategy.getTargetLeverage() - BASIS_POINTS)) / strategy.getTargetLeverage();
}
function belowCap(uint256 _amount) public view returns (bool) {
uint256 increaseDecimals = 10;
(, int256 lastPrice,,,) = oracle.latestRoundData();
uint256 price = uint256(lastPrice) * (10 ** increaseDecimals);
uint256 usdcCap = getUsdcCap();
uint256 stableTvl = stableVault.tvl();
uint256 denominator = 1e6;
uint256 notional = (price * _amount) / denominator;
if (stableTvl + notional > usdcCap) {
return false;
}
return true;
}
function _onlyEOA() private view {
if (msg.sender != tx.origin && !controller.isWhitelistedContract(msg.sender)) {
revert NotWhitelisted();
}
}
function _isHatlisted(bytes32[] memory _proof) private view {
bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(msg.sender))));
bool verified = MerkleProof.verify(_proof, root, leaf);
if (!verified) {
revert NotHatlisted();
}
}
function _validateSender(bytes32[] memory _proof) private view {
if (hatlistStatus) {
_isHatlisted(_proof);
_onlyEOA();
} else {
_onlyEOA();
}
}
function _checkUsdcCap(uint256 _amount) private view {
if (!belowCap(_amount)) {
revert OverUsdcCap();
}
}
function editToken(address _token, bool _valid) external onlyGovernor {
_editToken(_token, _valid);
}
modifier validToken(address _token) {
require(isValid[_token], "Invalid token.");
_;
}
error NotHatlisted();
error OverUsdcCap();
error NotWhitelisted();
}
文件 9 的 51:GlpJonesRewards.sol
pragma solidity ^0.8.10;
import {ReentrancyGuard} from "openzeppelin-contracts/contracts/security/ReentrancyGuard.sol";
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {Operable, Governable} from "../../common/Operable.sol";
contract GlpJonesRewards is Operable, ReentrancyGuard {
IERC20 public immutable rewardsToken;
uint256 public duration;
uint256 public finishAt;
uint256 public updatedAt;
uint256 public rewardRate;
uint256 public rewardPerTokenStored;
mapping(address => uint256) public userRewardPerTokenPaid;
mapping(address => uint256) public rewards;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
constructor(address _rewardToken) Governable(msg.sender) ReentrancyGuard() {
rewardsToken = IERC20(_rewardToken);
}
modifier updateReward(address _account) {
rewardPerTokenStored = rewardPerToken();
updatedAt = lastTimeRewardApplicable();
if (_account != address(0)) {
rewards[_account] = earned(_account);
userRewardPerTokenPaid[_account] = rewardPerTokenStored;
}
_;
}
function stake(address _user, uint256 _amount) external onlyOperator updateReward(_user) {
if (_amount == 0) {
revert ZeroAmount();
}
balanceOf[_user] += _amount;
totalSupply += _amount;
emit Stake(_user, _amount);
}
function withdraw(address _user, uint256 _amount) external onlyOperator updateReward(_user) {
if (_amount == 0) {
revert ZeroAmount();
}
balanceOf[_user] -= _amount;
totalSupply -= _amount;
emit Withdraw(_user, _amount);
}
function getReward(address _user) external onlyOperator updateReward(_user) nonReentrant returns (uint256) {
uint256 reward = rewards[_user];
if (reward > 0) {
rewards[_user] = 0;
rewardsToken.transfer(_user, reward);
}
emit GetReward(_user, reward);
return reward;
}
function lastTimeRewardApplicable() public view returns (uint256) {
return _min(finishAt, block.timestamp);
}
function rewardPerToken() public view returns (uint256) {
if (totalSupply == 0) {
return rewardPerTokenStored;
}
return rewardPerTokenStored + (rewardRate * (lastTimeRewardApplicable() - updatedAt) * 1e18) / totalSupply;
}
function earned(address _user) public view returns (uint256) {
return ((balanceOf[_user] * (rewardPerToken() - userRewardPerTokenPaid[_user])) / 1e18) + rewards[_user];
}
function setRewardsDuration(uint256 _duration) external onlyGovernor {
if (block.timestamp <= finishAt) {
revert DurationNotFinished();
}
duration = _duration;
emit UpdateRewardsDuration(finishAt, _duration + block.timestamp);
}
function notifyRewardAmount(uint256 _amount) external onlyGovernor updateReward(address(0)) {
if (block.timestamp >= finishAt) {
rewardRate = _amount / duration;
} else {
uint256 remainingRewards = (finishAt - block.timestamp) * rewardRate;
rewardRate = (_amount + remainingRewards) / duration;
}
if (rewardRate == 0) {
revert ZeroRewardRate();
}
if (rewardRate * duration > rewardsToken.balanceOf(address(this))) {
revert NotEnoughBalance();
}
finishAt = block.timestamp + duration;
updatedAt = block.timestamp;
emit NotifyRewardAmount(_amount, finishAt);
}
function _min(uint256 x, uint256 y) private pure returns (uint256) {
return x <= y ? x : y;
}
event Stake(address indexed _to, uint256 _amount);
event Withdraw(address indexed _to, uint256 _amount);
event GetReward(address indexed _to, uint256 _rewards);
event UpdateRewardsDuration(uint256 _oldEnding, uint256 _newEnding);
event NotifyRewardAmount(uint256 _amount, uint256 _finishAt);
error ZeroAmount();
error ZeroRewardRate();
error NotEnoughBalance();
error DurationNotFinished();
}
文件 10 的 51:Governable.sol
pragma solidity ^0.8.10;
import {AccessControl} from "openzeppelin-contracts/contracts/access/AccessControl.sol";
abstract contract Governable is AccessControl {
bytes32 public constant GOVERNOR = bytes32("GOVERNOR");
constructor(address _governor) {
_grantRole(GOVERNOR, _governor);
}
modifier onlyGovernor() {
_onlyGovernor();
_;
}
function updateGovernor(address _newGovernor) external onlyGovernor {
_revokeRole(GOVERNOR, msg.sender);
_grantRole(GOVERNOR, _newGovernor);
emit GovernorUpdated(msg.sender, _newGovernor);
}
function _onlyGovernor() private view {
if (!hasRole(GOVERNOR, msg.sender)) {
revert CallerIsNotGovernor();
}
}
event GovernorUpdated(address _oldGovernor, address _newGovernor);
error CallerIsNotGovernor();
}
文件 11 的 51: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;
}
文件 12 的 51:IAggregatorV3.sol
pragma solidity ^0.8.10;
interface IAggregatorV3 {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(uint80 _roundId)
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
function latestRoundData()
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}
文件 13 的 51:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 14 的 51:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
文件 15 的 51:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 16 的 51:IERC4626.sol
pragma solidity ^0.8.0;
import "../token/ERC20/IERC20.sol";
import "../token/ERC20/extensions/IERC20Metadata.sol";
interface IERC4626 is IERC20, IERC20Metadata {
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
);
function asset() external view returns (address assetTokenAddress);
function totalAssets() external view returns (uint256 totalManagedAssets);
function convertToShares(uint256 assets) external view returns (uint256 shares);
function convertToAssets(uint256 shares) external view returns (uint256 assets);
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
function previewDeposit(uint256 assets) external view returns (uint256 shares);
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
function maxMint(address receiver) external view returns (uint256 maxShares);
function previewMint(uint256 shares) external view returns (uint256 assets);
function mint(uint256 shares, address receiver) external returns (uint256 assets);
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
function withdraw(
uint256 assets,
address receiver,
address owner
) external returns (uint256 shares);
function maxRedeem(address owner) external view returns (uint256 maxShares);
function previewRedeem(uint256 shares) external view returns (uint256 assets);
function redeem(
uint256 shares,
address receiver,
address owner
) external returns (uint256 assets);
}
文件 17 的 51:IGMXVault.sol
pragma solidity ^0.8.10;
interface IGMXVault {
function whitelistedTokens(address) external view returns (bool);
function stableTokens(address) external view returns (bool);
function shortableTokens(address) external view returns (bool);
function getMaxPrice(address _token) external view returns (uint256);
function getMinPrice(address _token) external view returns (uint256);
function getPosition(address _account, address _collateralToken, address _indexToken, bool _isLong)
external
view
returns (uint256, uint256, uint256, uint256, uint256, uint256, bool, uint256);
function mintBurnFeeBasisPoints() external view returns (uint256);
function taxBasisPoints() external view returns (uint256);
function getFeeBasisPoints(
address _token,
uint256 _usdgDelta,
uint256 _feeBasisPoints,
uint256 _taxBasisPoints,
bool _increment
) external view returns (uint256);
function usdgAmounts(address _token) external view returns (uint256);
function maxUsdgAmounts(address _token) external view returns (uint256);
function hasDynamicFees() external view returns (bool);
function getTargetUsdgAmount(address _token) external view returns (uint256);
}
文件 18 的 51:IGlpManager.sol
pragma solidity ^0.8.10;
import {IGMXVault} from "./IGMXVault.sol";
interface IGlpManager {
function getAum(bool _maximize) external view returns (uint256);
function getAumInUsdg(bool _maximize) external view returns (uint256);
function vault() external view returns (address);
function glp() external view returns (address);
}
文件 19 的 51:IGmxRewardRouter.sol
pragma solidity ^0.8.10;
interface IGmxRewardRouter {
function mintAndStakeGlp(address _token, uint256 _amount, uint256 _minUsdg, uint256 _minGlp)
external
returns (uint256);
function unstakeAndRedeemGlp(address _tokenOut, uint256 _glpAmount, uint256 _minOut, address _receiver)
external
returns (uint256);
function unstakeAndRedeemGlpETH(uint256 _glpAmount, uint256 _minOut, address payable _receiver)
external
returns (uint256);
function glpManager() external view returns (address);
function handleRewards(
bool _shouldClaimGmx,
bool _shouldStakeGmx,
bool _shouldClaimEsGmx,
bool _shouldStakeEsGmx,
bool _shouldStakeMultiplierPoints,
bool _shouldClaimWeth,
bool _shouldConvertWethToEth
) external;
function signalTransfer(address _receiver) external;
function acceptTransfer(address _sender) external;
function pendingReceivers(address input) external returns (address);
function stakeEsGmx(uint256 _amount) external;
function mintAndStakeGlpETH(uint256 _minUsdg, uint256 _minGlp) external payable returns (uint256);
}
文件 20 的 51:IIncentiveReceiver.sol
pragma solidity ^0.8.2;
interface IIncentiveReceiver {
function deposit(address _token, uint256 _amount) external;
function addDepositor(address _depositor) external;
}
文件 21 的 51:IJonesBorrowableVault.sol
pragma solidity ^0.8.10;
import {IERC4626} from "openzeppelin-contracts/contracts/interfaces/IERC4626.sol";
interface IJonesBorrowableVault is IERC4626 {
function borrow(uint256 _amount) external returns (uint256);
function repay(uint256 _amount) external returns (uint256);
}
文件 22 的 51:IJonesGlpCompoundRewards.sol
pragma solidity ^0.8.10;
interface IJonesGlpCompoundRewards {
event Deposit(address indexed _caller, address indexed receiver, uint256 _assets, uint256 _shares);
event Withdraw(address indexed _caller, address indexed receiver, uint256 _assets, uint256 _shares);
event Compound(uint256 _rewards, uint256 _totalAssets, uint256 _retentions);
function deposit(uint256 assets, address receiver) external returns (uint256);
function redeem(uint256 shares, address receiver) external returns (uint256);
function compound() external;
function previewDeposit(uint256 assets) external view returns (uint256);
function previewRedeem(uint256 shares) external view returns (uint256);
function totalAssetsToDeposits(address recipient, uint256 assets) external view returns (uint256);
error AddressCannotBeZeroAddress();
error AmountCannotBeZero();
error AmountExceedsStakedAmount();
error RetentionPercentageOutOfRange();
}
文件 23 的 51:IJonesGlpLeverageStrategy.sol
pragma solidity ^0.8.10;
interface IJonesGlpLeverageStrategy {
function onGlpDeposit(uint256 _amount) external;
function onGlpRedeem(uint256 _amount) external returns (uint256);
function onStableDeposit() external;
function onStableRedeem(uint256 _amount, uint256 _amountAfterRetention) external returns (uint256);
function claimGlpRewards() external;
function utilization() external view returns (uint256);
function leverage() external view returns (uint256);
function getUnderlyingGlp() external view returns (uint256);
function stableDebt() external view returns (uint256);
function getStableGlpValue(uint256 _glpAmount) external view returns (uint256);
function buyGlpStableSimulation(uint256 _stableAmount) external view returns (uint256);
function getRequiredStableAmount(uint256 _glpAmount) external view returns (uint256);
function getRequiredGlpAmount(uint256 _stableAmount) external view returns (uint256);
function glpMintIncentive(uint256 _glpAmount) external view returns (uint256);
function getRedeemStableGMXIncentive(uint256 _stableAmount) external view returns (uint256);
function getMaxLeverage() external view returns (uint256);
function getMinLeverage() external view returns (uint256);
function getTargetLeverage() external view returns (uint256);
function getGMXCapDifference() external view returns (uint256);
function glpRedeemRetention(uint256 _glpAmount) external view returns (uint256);
event Rebalance(
uint256 _glpDebt, uint256 indexed _currentLeverage, uint256 indexed _newLeverage, address indexed _sender
);
event GetUnderlyingGlp(uint256 _amount);
event SetLeverageConfig(uint256 _target, uint256 _min, uint256 _max);
event ClaimGlpRewards(
address indexed _origin,
address indexed _sender,
uint256 _rewards,
uint256 _timestamp,
uint256 _leverage,
uint256 _glpBalance,
uint256 _underlyingGlp,
uint256 _glpShares,
uint256 _stableDebt,
uint256 _stableShares
);
event Liquidate(uint256 indexed _stablesReceived);
event BorrowGlp(uint256 indexed _amount);
event BorrowStable(uint256 indexed _amount);
event RepayStable(uint256 indexed _amount);
event RepayGlp(uint256 indexed _amount);
event EmergencyWithdraw(address indexed _to, uint256 indexed _amount);
event UpdateStableAddress(address _oldStableAddress, address _newStableAddress);
event UpdateGlpAddress(address _oldGlpAddress, address _newGlpAddress);
event Leverage(uint256 _glpDeposited, uint256 _glpMinted);
event LeverageUp(uint256 _stableDebt, uint256 _oldLeverage, uint256 _currentLeverage);
event LeverageDown(uint256 _stableDebt, uint256 _oldLeverage, uint256 _currentLeverage);
event Deleverage(uint256 _glpAmount, uint256 _glpRedeemed);
error ZeroAddressError();
error InvalidLeverageConfig();
error InvalidSlippage();
error ReachedSlippageTolerance();
error OverLeveraged();
error UnderLeveraged();
error NotEnoughUnderlyingGlp();
}
文件 24 的 51:IJonesGlpRewardDistributor.sol
pragma solidity ^0.8.10;
interface IJonesGlpRewardDistributor {
event Distribute(uint256 amount);
event SplitRewards(uint256 _glpRewards, uint256 _stableRewards, uint256 _jonesRewards);
function distributeRewards() external returns (uint256);
function splitRewards(uint256 _amount, uint256 _leverage, uint256 _utilization) external;
function pendingRewards(address _pool) external view returns (uint256);
error AddressCannotBeZeroAddress();
}
文件 25 的 51:IJonesGlpRewardTracker.sol
pragma solidity ^0.8.10;
interface IJonesGlpRewardTracker {
event Stake(address indexed depositor, uint256 amount);
event Withdraw(address indexed _account, uint256 _amount);
event Claim(address indexed receiver, uint256 amount);
event UpdateRewards(address indexed _account, uint256 _rewards, uint256 _totalShares, uint256 _rewardPerShare);
function stake(address _account, uint256 _amount) external returns (uint256);
function withdraw(address _account, uint256 _amount) external returns (uint256);
function claim(address _account) external returns (uint256);
function claimable(address _account) external view returns (uint256);
function stakedAmount(address _account) external view returns (uint256);
function updateRewards() external;
function depositRewards(uint256 _rewards) external;
error AddressCannotBeZeroAddress();
error AmountCannotBeZero();
error AmountExceedsStakedAmount();
}
文件 26 的 51:IJonesGlpVaultRouter.sol
pragma solidity ^0.8.10;
interface IJonesGlpVaultRouter {
function depositGlp(uint256 _assets, address _sender, bool _compound) external returns (uint256);
function depositStable(uint256 _assets, bool _compound, address _user) external returns (uint256);
function redeemGlpAdapter(uint256 _shares, bool _compound, address _token, address _user, bool _native)
external
returns (uint256);
}
文件 27 的 51:IJonesUsdVault.sol
pragma solidity ^0.8.10;
import {IAggregatorV3} from "./IAggregatorV3.sol";
interface IJonesUsdVault {
function priceOracle() external view returns (IAggregatorV3);
function tvl() external view returns (uint256);
}
文件 28 的 51:IRewardTracker.sol
pragma solidity 0.8.10;
interface IRewardTracker {
function depositBalances(address _account, address _depositToken) external view returns (uint256);
function stakedAmounts(address _account) external view returns (uint256);
function updateRewards() external;
function stake(address _depositToken, uint256 _amount) external;
function stakeForAccount(address _fundingAccount, address _account, address _depositToken, uint256 _amount)
external;
function unstake(address _depositToken, uint256 _amount) external;
function unstakeForAccount(address _account, address _depositToken, uint256 _amount, address _receiver) external;
function tokensPerInterval() external view returns (uint256);
function claim(address _receiver) external returns (uint256);
function claimForAccount(address _account, address _receiver) external returns (uint256);
function claimable(address _account) external view returns (uint256);
function averageStakedAmounts(address _account) external view returns (uint256);
function cumulativeRewards(address _account) external view returns (uint256);
}
文件 29 的 51:IStakedGlp.sol
pragma solidity ^0.8.10;
interface IStakedGlp {
function stakedGlpTracker() external view returns (address);
}
文件 30 的 51:IWhitelistController.sol
pragma solidity ^0.8.10;
interface IWhitelistController {
struct RoleInfo {
bool jGLP_BYPASS_CAP;
bool jUSDC_BYPASS_TIME;
uint256 jGLP_RETENTION;
uint256 jUSDC_RETENTION;
}
function isInternalContract(address _account) external view returns (bool);
function hasRole(bytes32 role, address account) external view returns (bool);
function getUserRole(address _user) external view returns (bytes32);
function getRoleInfo(bytes32 _role) external view returns (IWhitelistController.RoleInfo memory);
function getDefaultRole() external view returns (IWhitelistController.RoleInfo memory);
function isWhitelistedContract(address _account) external view returns (bool);
function addToInternalContract(address _account) external;
function addToWhitelistContracts(address _account) external;
function removeFromInternalContract(address _account) external;
function removeFromWhitelistContract(address _account) external;
function bulkAddToWhitelistContracts(address[] calldata _accounts) external;
function bulkRemoveFromWhitelistContract(address[] calldata _accounts) external;
}
文件 31 的 51:JonesBaseGlpVault.sol
pragma solidity ^0.8.10;
import {ERC4626} from "openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol";
import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {JonesUsdVault} from "../../vaults/JonesUsdVault.sol";
import {JonesBorrowableVault} from "../../vaults/JonesBorrowableVault.sol";
import {JonesOperableVault} from "../../vaults/JonesOperableVault.sol";
import {JonesGovernableVault} from "../../vaults/JonesGovernableVault.sol";
import {IAggregatorV3} from "../../interfaces/IAggregatorV3.sol";
import {IStakedGlp} from "../../interfaces/IStakedGlp.sol";
import {IJonesGlpLeverageStrategy} from "../../interfaces/IJonesGlpLeverageStrategy.sol";
abstract contract JonesBaseGlpVault is JonesOperableVault, JonesUsdVault, JonesBorrowableVault {
IJonesGlpLeverageStrategy public strategy;
address internal receiver;
constructor(IAggregatorV3 _oracle, IERC20Metadata _asset, string memory _name, string memory _symbol)
JonesGovernableVault(msg.sender)
JonesUsdVault(_oracle)
ERC4626(_asset)
ERC20(_name, _symbol)
{}
function deposit(uint256 _assets, address _receiver)
public
virtual
override(JonesOperableVault, ERC4626)
whenNotPaused
returns (uint256)
{
return super.deposit(_assets, _receiver);
}
function mint(uint256 _shares, address _receiver)
public
override(JonesOperableVault, ERC4626)
whenNotPaused
returns (uint256)
{
return super.mint(_shares, _receiver);
}
function withdraw(uint256 _assets, address _receiver, address _owner)
public
virtual
override(JonesOperableVault, ERC4626)
returns (uint256)
{
return super.withdraw(_assets, _receiver, _owner);
}
function redeem(uint256 _shares, address _receiver, address _owner)
public
virtual
override(JonesOperableVault, ERC4626)
returns (uint256)
{
return super.redeem(_shares, _receiver, _owner);
}
function setStrategyAddress(IJonesGlpLeverageStrategy _strategy) external onlyGovernor {
strategy = _strategy;
}
function setExcessReceiver(address _receiver) external onlyGovernor {
receiver = _receiver;
}
}
文件 32 的 51:JonesBorrowableVault.sol
pragma solidity ^0.8.10;
import {AccessControl} from "openzeppelin-contracts/contracts/access/AccessControl.sol";
import {ERC4626} from "openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol";
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {JonesGovernableVault} from "./JonesGovernableVault.sol";
import {IJonesBorrowableVault} from "../interfaces/IJonesBorrowableVault.sol";
import {Pausable} from "../common/Pausable.sol";
abstract contract JonesBorrowableVault is JonesGovernableVault, ERC4626, IJonesBorrowableVault, Pausable {
bytes32 public constant BORROWER = bytes32("BORROWER");
modifier onlyBorrower() {
if (!hasRole(BORROWER, msg.sender)) {
revert CallerIsNotBorrower();
}
_;
}
function addBorrower(address _newBorrower) external onlyGovernor {
_grantRole(BORROWER, _newBorrower);
emit BorrowerAdded(_newBorrower);
}
function removeBorrower(address _borrower) external onlyGovernor {
_revokeRole(BORROWER, _borrower);
emit BorrowerRemoved(_borrower);
}
function togglePause() external onlyGovernor {
if (paused()) {
_unpause();
return;
}
_pause();
}
function borrow(uint256 _amount) external virtual onlyBorrower whenNotPaused returns (uint256) {
IERC20(asset()).transfer(msg.sender, _amount);
emit AssetsBorrowed(msg.sender, _amount);
return _amount;
}
function repay(uint256 _amount) external virtual onlyBorrower returns (uint256) {
IERC20(asset()).transferFrom(msg.sender, address(this), _amount);
emit AssetsRepayed(msg.sender, _amount);
return _amount;
}
event BorrowerAdded(address _newBorrower);
event BorrowerRemoved(address _borrower);
event AssetsBorrowed(address _borrower, uint256 _amount);
event AssetsRepayed(address _borrower, uint256 _amount);
error CallerIsNotBorrower();
}
文件 33 的 51:JonesGlpCompoundRewards.sol
pragma solidity ^0.8.10;
import {ReentrancyGuard} from "openzeppelin-contracts/contracts/security/ReentrancyGuard.sol";
import {Governable} from "src/common/Governable.sol";
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
import {Math} from "openzeppelin-contracts/contracts/utils/math/Math.sol";
import {IERC20Metadata} from "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {OperableKeepable} from "src/common/OperableKeepable.sol";
import {IGmxRewardRouter} from "src/interfaces/IGmxRewardRouter.sol";
import {JonesGlpVaultRouter} from "src/glp/JonesGlpVaultRouter.sol";
import {IJonesGlpCompoundRewards} from "src/interfaces/IJonesGlpCompoundRewards.sol";
import {IJonesGlpRewardTracker} from "src/interfaces/IJonesGlpRewardTracker.sol";
import {IIncentiveReceiver} from "src/interfaces/IIncentiveReceiver.sol";
import {GlpJonesRewards} from "src/glp/rewards/GlpJonesRewards.sol";
contract JonesGlpCompoundRewards is IJonesGlpCompoundRewards, ERC20, OperableKeepable, ReentrancyGuard {
using Math for uint256;
uint256 public constant BASIS_POINTS = 1e12;
address public constant weth = 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1;
address public constant usdc = 0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8;
address public constant glp = 0x5402B5F40310bDED796c7D0F3FF6683f5C0cFfdf;
IGmxRewardRouter public gmxRouter = IGmxRewardRouter(0xB95DB5B167D75e6d04227CfFFA61069348d271F5);
IERC20 public asset;
IERC20Metadata public vaultToken;
uint256 public stableRetentionPercentage;
uint256 public glpRetentionPercentage;
uint256 public totalAssets;
uint256 public totalAssetsDeposits;
mapping(address => uint256) public receiptBalance;
JonesGlpVaultRouter public router;
IJonesGlpRewardTracker public tracker;
IIncentiveReceiver public incentiveReceiver;
GlpJonesRewards public jonesRewards;
constructor(
uint256 _stableRetentionPercentage,
uint256 _glpRetentionPercentage,
IIncentiveReceiver _incentiveReceiver,
IJonesGlpRewardTracker _tracker,
GlpJonesRewards _jonesRewards,
IERC20 _asset,
IERC20Metadata _vaultToken,
string memory _name,
string memory _symbol
) Governable(msg.sender) ERC20(_name, _symbol) ReentrancyGuard() {
if (_stableRetentionPercentage > BASIS_POINTS) {
revert RetentionPercentageOutOfRange();
}
if (_glpRetentionPercentage > BASIS_POINTS) {
revert RetentionPercentageOutOfRange();
}
stableRetentionPercentage = _stableRetentionPercentage;
glpRetentionPercentage = _glpRetentionPercentage;
incentiveReceiver = _incentiveReceiver;
jonesRewards = _jonesRewards;
asset = _asset;
vaultToken = _vaultToken;
tracker = _tracker;
}
function compound() external onlyOperatorOrKeeper {
_compound();
}
function deposit(uint256 _assets, address _receiver) external nonReentrant onlyOperator returns (uint256) {
uint256 shares = previewDeposit(_assets);
_deposit(_receiver, _assets, shares);
return shares;
}
function redeem(uint256 _shares, address _receiver) external nonReentrant onlyOperator returns (uint256) {
uint256 assets = previewRedeem(_shares);
_withdraw(_receiver, assets, _shares);
return assets;
}
function previewDeposit(uint256 assets) public view returns (uint256) {
return _convertToShares(assets, Math.Rounding.Down);
}
function previewRedeem(uint256 shares) public view returns (uint256) {
return _convertToAssets(shares, Math.Rounding.Down);
}
function totalAssetsToDeposits(address recipient, uint256 assets) public view returns (uint256) {
uint256 totalRecipientAssets = _convertToAssets(balanceOf(recipient), Math.Rounding.Down);
return assets.mulDiv(receiptBalance[recipient], totalRecipientAssets, Math.Rounding.Down);
}
function emergencyGlpWithdraw(address _to) external onlyGovernor {
_compound();
router.redeemGlp(tracker.stakedAmount(address(this)), false);
asset.transfer(_to, asset.balanceOf(address(this)));
}
function emergencyStableWithdraw(address _to) external onlyGovernor {
_compound();
router.stableWithdrawalSignal(tracker.stakedAmount(address(this)), false);
asset.transfer(_to, asset.balanceOf(address(this)));
}
function setRouter(JonesGlpVaultRouter _router) external onlyGovernor {
router = _router;
}
function setIncentiveReceiver(IIncentiveReceiver _incentiveReceiver) external onlyGovernor {
incentiveReceiver = _incentiveReceiver;
}
function setRewardTracker(IJonesGlpRewardTracker _tracker) external onlyGovernor {
tracker = _tracker;
}
function setAsset(IERC20Metadata _asset) external onlyGovernor {
asset = _asset;
}
function setVaultToken(IERC20Metadata _vaultToken) external onlyGovernor {
vaultToken = _vaultToken;
}
function setGmxRouter(IGmxRewardRouter _gmxRouter) external onlyGovernor {
gmxRouter = _gmxRouter;
}
function setNewRetentions(uint256 _stableRetentionPercentage, uint256 _glpRetentionPercentage)
external
onlyGovernor
{
if (_stableRetentionPercentage > BASIS_POINTS) {
revert RetentionPercentageOutOfRange();
}
if (_glpRetentionPercentage > BASIS_POINTS) {
revert RetentionPercentageOutOfRange();
}
stableRetentionPercentage = _stableRetentionPercentage;
glpRetentionPercentage = _glpRetentionPercentage;
}
function setJonesRewards(GlpJonesRewards _jonesRewards) external onlyGovernor {
jonesRewards = _jonesRewards;
}
function _deposit(address receiver, uint256 assets, uint256 shares) private {
vaultToken.transferFrom(msg.sender, address(this), assets);
receiptBalance[receiver] = receiptBalance[receiver] + assets;
vaultToken.approve(address(tracker), assets);
tracker.stake(address(this), assets);
totalAssetsDeposits = totalAssetsDeposits + assets;
totalAssets = tracker.stakedAmount(address(this));
_mint(receiver, shares);
emit Deposit(msg.sender, receiver, assets, shares);
}
function _withdraw(address receiver, uint256 assets, uint256 shares) private {
uint256 depositAssets = totalAssetsToDeposits(receiver, assets);
_burn(receiver, shares);
receiptBalance[receiver] = receiptBalance[receiver] - depositAssets;
totalAssetsDeposits = totalAssetsDeposits - depositAssets;
tracker.withdraw(address(this), assets);
vaultToken.approve(address(tracker), assets);
tracker.stake(receiver, assets);
totalAssets = tracker.stakedAmount(address(this));
emit Withdraw(msg.sender, receiver, assets, shares);
}
function _compound() private {
(uint256 stableRewards, uint256 glpRewards,) = router.claimRewards();
if (glpRewards > 0) {
uint256 retention = _retention(glpRewards, glpRetentionPercentage);
if (retention > 0) {
IERC20(weth).approve(address(incentiveReceiver), retention);
incentiveReceiver.deposit(weth, retention);
glpRewards = glpRewards - retention;
}
IERC20(weth).approve(gmxRouter.glpManager(), glpRewards);
uint256 glpAmount = gmxRouter.mintAndStakeGlp(weth, glpRewards, 0, 0);
glpRewards = glpAmount;
IERC20(glp).approve(address(router), glpRewards);
router.depositGlp(glpRewards, address(this), false);
totalAssets = tracker.stakedAmount(address(this));
emit Compound(glpRewards, totalAssets, retention);
}
if (stableRewards > 0) {
uint256 retention = _retention(stableRewards, stableRetentionPercentage);
if (retention > 0) {
IERC20(usdc).approve(address(incentiveReceiver), retention);
incentiveReceiver.deposit(usdc, retention);
stableRewards = stableRewards - retention;
}
IERC20(usdc).approve(address(router), stableRewards);
router.depositStable(stableRewards, false, address(this));
totalAssets = tracker.stakedAmount(address(this));
emit Compound(stableRewards, totalAssets, retention);
}
}
function _convertToShares(uint256 assets, Math.Rounding rounding) private view returns (uint256 shares) {
uint256 supply = totalSupply();
return (assets == 0 || supply == 0)
? assets.mulDiv(10 ** decimals(), 10 ** vaultToken.decimals(), rounding)
: assets.mulDiv(supply, totalAssets, rounding);
}
function _convertToAssets(uint256 shares, Math.Rounding rounding) private view returns (uint256 assets) {
uint256 supply = totalSupply();
return (supply == 0)
? shares.mulDiv(10 ** vaultToken.decimals(), 10 ** decimals(), rounding)
: shares.mulDiv(totalAssets, supply, rounding);
}
function _retention(uint256 _rewards, uint256 _retentionPercentage) private pure returns (uint256) {
return (_rewards * _retentionPercentage) / BASIS_POINTS;
}
function internalTransfer(address from, address to, uint256 amount) private {
uint256 assets = previewRedeem(amount);
uint256 depositAssets = totalAssetsToDeposits(from, assets);
receiptBalance[from] = receiptBalance[from] - depositAssets;
receiptBalance[to] = receiptBalance[to] + depositAssets;
if (address(asset) == usdc) {
jonesRewards.getReward(from);
jonesRewards.withdraw(from, depositAssets);
jonesRewards.stake(to, depositAssets);
}
}
function name() public view override returns (string memory) {
return super.name();
}
function symbol() public view override returns (string memory) {
return super.symbol();
}
function decimals() public view override returns (uint8) {
return super.decimals();
}
function totalSupply() public view override returns (uint256) {
return super.totalSupply();
}
function balanceOf(address account) public view override returns (uint256) {
return super.balanceOf(account);
}
function transfer(address to, uint256 amount) public override returns (bool) {
internalTransfer(msg.sender, to, amount);
return super.transfer(to, amount);
}
function allowance(address owner, address spender) public view override returns (uint256) {
return super.allowance(owner, spender);
}
function approve(address spender, uint256 amount) public override returns (bool) {
return super.approve(spender, amount);
}
function transferFrom(address from, address to, uint256 amount) public override returns (bool) {
internalTransfer(from, to, amount);
return super.transferFrom(from, to, amount);
}
}
文件 34 的 51:JonesGlpLeverageStrategy.sol
pragma solidity ^0.8.10;
import {ReentrancyGuard} from "openzeppelin-contracts/contracts/security/ReentrancyGuard.sol";
import {Governable, OperableKeepable} from "../../common/OperableKeepable.sol";
import {Math} from "openzeppelin-contracts/contracts/utils/math/Math.sol";
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IJonesBorrowableVault} from "../../interfaces/IJonesBorrowableVault.sol";
import {IJonesUsdVault} from "../../interfaces/IJonesUsdVault.sol";
import {IJonesGlpRewardDistributor} from "../../interfaces/IJonesGlpRewardDistributor.sol";
import {IAggregatorV3} from "../../interfaces/IAggregatorV3.sol";
import {IGmxRewardRouter} from "../../interfaces/IGmxRewardRouter.sol";
import {IJonesGlpLeverageStrategy} from "../../interfaces/IJonesGlpLeverageStrategy.sol";
import {IGlpManager} from "../../../src/interfaces/IGlpManager.sol";
import {IGMXVault} from "../../../src/interfaces/IGMXVault.sol";
import {IRewardTracker} from "../../../src/interfaces/IRewardTracker.sol";
contract JonesGlpLeverageStrategy is IJonesGlpLeverageStrategy, OperableKeepable, ReentrancyGuard {
using Math for uint256;
struct LeverageConfig {
uint256 target;
uint256 min;
uint256 max;
}
IGmxRewardRouter constant routerV1 = IGmxRewardRouter(0xA906F338CB21815cBc4Bc87ace9e68c87eF8d8F1);
IGmxRewardRouter constant routerV2 = IGmxRewardRouter(0xB95DB5B167D75e6d04227CfFFA61069348d271F5);
IGlpManager constant glpManager = IGlpManager(0x3963FfC9dff443c2A94f21b129D429891E32ec18);
address constant weth = 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1;
uint256 public constant PRECISION = 1e30;
uint256 public constant BASIS_POINTS = 1e12;
uint256 public constant GMX_BASIS = 1e4;
uint256 public constant USDC_DECIMALS = 1e6;
uint256 public constant GLP_DECIMALS = 1e18;
IERC20 public stable;
IERC20 public glp;
IJonesBorrowableVault stableVault;
IJonesBorrowableVault glpVault;
IJonesGlpRewardDistributor distributor;
uint256 public stableDebt;
LeverageConfig public leverageConfig;
constructor(
IJonesBorrowableVault _stableVault,
IJonesBorrowableVault _glpVault,
IJonesGlpRewardDistributor _distributor,
LeverageConfig memory _leverageConfig,
address _glp,
address _stable
) Governable(msg.sender) ReentrancyGuard() {
stableVault = _stableVault;
glpVault = _glpVault;
distributor = _distributor;
stable = IERC20(_stable);
glp = IERC20(_glp);
_setLeverageConfig(_leverageConfig);
}
function onGlpDeposit(uint256 _amount) external nonReentrant onlyOperator {
_borrowGlp(_amount);
if (leverage() < getTargetLeverage()) {
_leverage(_amount);
}
_rebalance(getUnderlyingGlp());
}
function onGlpRedeem(uint256 _amount) external nonReentrant onlyOperator returns (uint256) {
if (_amount > getUnderlyingGlp()) {
revert NotEnoughUnderlyingGlp();
}
uint256 glpRedeemRetention = glpRedeemRetention(_amount);
uint256 assetsToRedeem = _amount - glpRedeemRetention;
glp.transfer(msg.sender, assetsToRedeem);
uint256 underlying = getUnderlyingGlp();
uint256 leverageAmount = glp.balanceOf(address(this)) - underlying;
uint256 protocolExcess = ((underlying * (leverageConfig.target - BASIS_POINTS)) / BASIS_POINTS);
uint256 excessGlp;
if (leverageAmount < protocolExcess) {
excessGlp = leverageAmount;
} else {
excessGlp = ((_amount * (leverageConfig.target - BASIS_POINTS)) / BASIS_POINTS);
}
if (leverageAmount >= excessGlp && leverage() > getTargetLeverage()) {
_deleverage(excessGlp);
}
underlying = getUnderlyingGlp();
if (underlying > 0) {
_rebalance(underlying);
}
emit Deleverage(excessGlp, assetsToRedeem);
return assetsToRedeem;
}
function onStableDeposit() external nonReentrant onlyOperator {
_rebalance(getUnderlyingGlp());
}
function onStableRedeem(uint256 _amount, uint256 _amountAfterRetention) external onlyOperator returns (uint256) {
(uint256 glpAmount,) = _getRequiredGlpAmount(_amountAfterRetention + 2);
routerV2.unstakeAndRedeemGlp(address(stable), glpAmount, _amountAfterRetention, address(this));
stable.transfer(msg.sender, _amountAfterRetention);
stableDebt = stableDebt - _amount;
return _amountAfterRetention;
}
function claimGlpRewards() external nonReentrant onlyOperatorOrKeeper {
routerV1.handleRewards(false, false, true, true, true, true, false);
uint256 rewards = IERC20(weth).balanceOf(address(this));
uint256 currentLeverage = leverage();
IERC20(weth).approve(address(distributor), rewards);
distributor.splitRewards(rewards, currentLeverage, utilization());
emit ClaimGlpRewards(
tx.origin,
msg.sender,
rewards,
block.timestamp,
currentLeverage,
glp.balanceOf(address(this)),
getUnderlyingGlp(),
glpVault.totalSupply(),
stableDebt,
stableVault.totalSupply()
);
}
function utilization() public view returns (uint256) {
uint256 borrowed = stableDebt;
uint256 available = stable.balanceOf(address(stableVault));
uint256 total = borrowed + available;
if (total == 0) {
return 0;
}
return (borrowed * BASIS_POINTS) / total;
}
function leverage() public view returns (uint256) {
uint256 glpTvl = getUnderlyingGlp();
if (glpTvl == 0) {
return 0;
}
if (stableDebt == 0) {
return 1 * BASIS_POINTS;
}
return ((glp.balanceOf(address(this)) * BASIS_POINTS) / glpTvl);
}
function getUnderlyingGlp() public view returns (uint256) {
uint256 currentBalance = glp.balanceOf(address(this));
if (currentBalance == 0) {
return 0;
}
if (stableDebt > 0) {
(uint256 glpAmount,) = _getRequiredGlpAmount(stableDebt + 2);
return currentBalance > glpAmount ? currentBalance - glpAmount : 0;
} else {
return currentBalance;
}
}
function getStableGlpValue(uint256 _glpAmount) public view returns (uint256) {
(uint256 _value,) = _sellGlpStableSimulation(_glpAmount);
return _value;
}
function buyGlpStableSimulation(uint256 _stableAmount) public view returns (uint256) {
return _buyGlpStableSimulation(_stableAmount);
}
function getRequiredStableAmount(uint256 _glpAmount) external view returns (uint256) {
(uint256 stableAmount,) = _getRequiredStableAmount(_glpAmount);
return stableAmount;
}
function getRequiredGlpAmount(uint256 _stableAmount) external view returns (uint256) {
(uint256 glpAmount,) = _getRequiredGlpAmount(_stableAmount);
return glpAmount;
}
function getRedeemStableGMXIncentive(uint256 _stableAmount) external view returns (uint256) {
(, uint256 gmxRetention) = _getRequiredGlpAmount(_stableAmount);
return gmxRetention;
}
function glpMintIncentive(uint256 _glpAmount) public view returns (uint256) {
return _glpMintIncentive(_glpAmount);
}
function glpRedeemRetention(uint256 _glpAmount) public view returns (uint256) {
return _glpRedeemRetention(_glpAmount);
}
function getMaxLeverage() public view returns (uint256) {
return leverageConfig.max;
}
function getMinLeverage() public view returns (uint256) {
return leverageConfig.min;
}
function getGMXCapDifference() public view returns (uint256) {
return _getGMXCapDifference();
}
function getTargetLeverage() public view returns (uint256) {
return leverageConfig.target;
}
function setLeverageConfig(uint256 _target, uint256 _min, uint256 _max, bool rebalance_) public onlyGovernor {
_setLeverageConfig(LeverageConfig(_target, _min, _max));
emit SetLeverageConfig(_target, _min, _max);
if (rebalance_) {
_rebalance(getUnderlyingGlp());
}
}
function setGlpAddress(address _glp) external onlyGovernor {
address oldGlp = address(glp);
glp = IERC20(_glp);
emit UpdateGlpAddress(oldGlp, _glp);
}
function setStableAddress(address _stable) external onlyGovernor {
address oldStable = address(stable);
stable = IERC20(_stable);
emit UpdateStableAddress(oldStable, _stable);
}
function emergencyWithdraw(address _to) external onlyGovernor {
uint256 currentBalance = glp.balanceOf(address(this));
if (currentBalance == 0) {
return;
}
glp.transfer(_to, currentBalance);
emit EmergencyWithdraw(_to, currentBalance);
}
function transferAccount(address _to, address _gmxRouter) external onlyGovernor {
if (_to == address(0)) {
revert ZeroAddressError();
}
IGmxRewardRouter(_gmxRouter).signalTransfer(_to);
}
function acceptAccountTransfer(address _sender, address _gmxRouter) external onlyGovernor {
IGmxRewardRouter gmxRouter = IGmxRewardRouter(_gmxRouter);
gmxRouter.acceptTransfer(_sender);
}
function rebalance() external onlyKeeper {
_rebalance(getUnderlyingGlp());
}
function unwind() external onlyGovernorOrKeeper {
_setLeverageConfig(LeverageConfig(BASIS_POINTS + 1, BASIS_POINTS, BASIS_POINTS + 2));
_liquidate();
}
function leverageUp(uint256 _stableAmount) external onlyKeeper {
uint256 availableForBorrowing = stable.balanceOf(address(stableVault));
if (availableForBorrowing == 0) {
return;
}
uint256 oldLeverage = leverage();
_stableAmount = _adjustToGMXCap(_stableAmount);
if (_stableAmount < 1e4) {
return;
}
if (availableForBorrowing < _stableAmount) {
_stableAmount = availableForBorrowing;
}
uint256 stableToBorrow = _stableAmount - stable.balanceOf(address(this));
stableVault.borrow(stableToBorrow);
emit BorrowStable(stableToBorrow);
stableDebt = stableDebt + stableToBorrow;
address stableAsset = address(stable);
IERC20(stableAsset).approve(routerV2.glpManager(), _stableAmount);
routerV2.mintAndStakeGlp(stableAsset, _stableAmount, 0, 0);
uint256 newLeverage = leverage();
if (newLeverage > getMaxLeverage()) {
revert OverLeveraged();
}
emit LeverageUp(stableDebt, oldLeverage, newLeverage);
}
function leverageDown(uint256 _glpAmount) external onlyKeeper {
uint256 oldLeverage = leverage();
uint256 stablesReceived = routerV2.unstakeAndRedeemGlp(address(stable), _glpAmount, 0, address(this));
uint256 currentStableDebt = stableDebt;
if (stablesReceived <= currentStableDebt) {
_repayStable(stablesReceived);
} else {
_repayStable(currentStableDebt);
}
uint256 newLeverage = leverage();
if (newLeverage < getMinLeverage()) {
revert UnderLeveraged();
}
emit LeverageDown(stableDebt, oldLeverage, newLeverage);
}
function _rebalance(uint256 _glpDebt) private {
uint256 currentLeverage = leverage();
LeverageConfig memory currentLeverageConfig = leverageConfig;
if (currentLeverage < currentLeverageConfig.min) {
uint256 missingGlp = (_glpDebt * (currentLeverageConfig.target - currentLeverage)) / BASIS_POINTS;
(uint256 stableToDeposit,) = _getRequiredStableAmount(missingGlp);
stableToDeposit = _adjustToGMXCap(stableToDeposit);
if (stableToDeposit < 1e4) {
return;
}
uint256 availableForBorrowing = stable.balanceOf(address(stableVault));
if (availableForBorrowing == 0) {
return;
}
if (availableForBorrowing < stableToDeposit) {
stableToDeposit = availableForBorrowing;
}
uint256 stableToBorrow = stableToDeposit - stable.balanceOf(address(this));
stableVault.borrow(stableToBorrow);
emit BorrowStable(stableToBorrow);
stableDebt = stableDebt + stableToBorrow;
address stableAsset = address(stable);
IERC20(stableAsset).approve(routerV2.glpManager(), stableToDeposit);
routerV2.mintAndStakeGlp(stableAsset, stableToDeposit, 0, 0);
emit Rebalance(_glpDebt, currentLeverage, leverage(), tx.origin);
return;
}
if (currentLeverage > currentLeverageConfig.max) {
uint256 excessGlp = (_glpDebt * (currentLeverage - currentLeverageConfig.target)) / BASIS_POINTS;
uint256 stablesReceived = routerV2.unstakeAndRedeemGlp(address(stable), excessGlp, 0, address(this));
uint256 currentStableDebt = stableDebt;
if (stablesReceived <= currentStableDebt) {
_repayStable(stablesReceived);
} else {
_repayStable(currentStableDebt);
}
emit Rebalance(_glpDebt, currentLeverage, leverage(), tx.origin);
return;
}
return;
}
function _liquidate() private {
if (stableDebt == 0) {
return;
}
uint256 glpBalance = glp.balanceOf(address(this));
(uint256 glpAmount,) = _getRequiredGlpAmount(stableDebt + 2);
if (glpAmount > glpBalance) {
glpAmount = glpBalance;
}
uint256 stablesReceived = routerV2.unstakeAndRedeemGlp(address(stable), glpAmount, 0, address(this));
uint256 currentStableDebt = stableDebt;
if (stablesReceived <= currentStableDebt) {
_repayStable(stablesReceived);
} else {
_repayStable(currentStableDebt);
}
emit Liquidate(stablesReceived);
}
function _borrowGlp(uint256 _amount) private returns (uint256) {
glpVault.borrow(_amount);
emit BorrowGlp(_amount);
return _amount;
}
function _repayStable(uint256 _amount) internal returns (uint256) {
stable.approve(address(stableVault), _amount);
uint256 updatedAmount = stableDebt - stableVault.repay(_amount);
stableDebt = updatedAmount;
return updatedAmount;
}
function _setLeverageConfig(LeverageConfig memory _config) private {
if (
_config.min >= _config.max || _config.min >= _config.target || _config.max <= _config.target
|| _config.min < BASIS_POINTS
) {
revert InvalidLeverageConfig();
}
leverageConfig = _config;
}
function _getRequiredGlpAmount(uint256 _stableAmount) private view returns (uint256, uint256) {
IGlpManager manager = glpManager;
IGMXVault vault = IGMXVault(manager.vault());
address usdc = address(stable);
uint256 usdcPrice = vault.getMaxPrice(usdc);
uint256 glpSupply = glp.totalSupply();
uint256 glpPrice = manager.getAum(false).mulDiv(GLP_DECIMALS, glpSupply, Math.Rounding.Down);
uint256 usdgAmount = _stableAmount.mulDiv(usdcPrice, PRECISION, Math.Rounding.Down) * BASIS_POINTS;
uint256 glpAmount = _stableAmount.mulDiv(usdcPrice, glpPrice, Math.Rounding.Down) * BASIS_POINTS;
uint256 retentionBasisPoints =
vault.getFeeBasisPoints(usdc, usdgAmount, vault.mintBurnFeeBasisPoints(), vault.taxBasisPoints(), false);
uint256 glpRequired = (glpAmount * GMX_BASIS) / (GMX_BASIS - retentionBasisPoints);
(uint256 theoreticalStables,) = _sellGlpStableSimulation(glpRequired);
while (theoreticalStables < _stableAmount - 2) {
retentionBasisPoints = retentionBasisPoints + 1;
glpRequired = (glpAmount * GMX_BASIS) / (GMX_BASIS - retentionBasisPoints);
(theoreticalStables,) = _sellGlpStableSimulation(glpRequired);
}
return (glpRequired, retentionBasisPoints);
}
function _getRequiredStableAmount(uint256 _glpAmount) private view returns (uint256, uint256) {
IGlpManager manager = glpManager;
IGMXVault vault = IGMXVault(manager.vault());
address usdc = address(stable);
uint256 usdcPrice = vault.getMinPrice(usdc);
uint256 glpPrice = manager.getAum(true).mulDiv(GLP_DECIMALS, glp.totalSupply(), Math.Rounding.Down);
uint256 stableAmount = _glpAmount.mulDiv(glpPrice, usdcPrice, Math.Rounding.Down);
uint256 usdgAmount = _glpAmount.mulDiv(glpPrice, PRECISION, Math.Rounding.Down);
uint256 retentionBasisPoints =
vault.getFeeBasisPoints(usdc, usdgAmount, vault.mintBurnFeeBasisPoints(), vault.taxBasisPoints(), true);
return ((stableAmount * GMX_BASIS / (GMX_BASIS - retentionBasisPoints)) / BASIS_POINTS, retentionBasisPoints);
}
function _leverage(uint256 _glpAmount) private {
uint256 missingGlp = ((_glpAmount * (leverageConfig.target - BASIS_POINTS)) / BASIS_POINTS);
(uint256 stableToDeposit,) = _getRequiredStableAmount(missingGlp);
stableToDeposit = _adjustToGMXCap(stableToDeposit);
if (stableToDeposit < 1e4) {
return;
}
uint256 availableForBorrowing = stable.balanceOf(address(stableVault));
if (availableForBorrowing == 0) {
return;
}
if (availableForBorrowing < stableToDeposit) {
stableToDeposit = availableForBorrowing;
}
uint256 stableToBorrow = stableToDeposit - stable.balanceOf(address(this));
stableVault.borrow(stableToBorrow);
emit BorrowStable(stableToBorrow);
stableDebt = stableDebt + stableToBorrow;
address stableAsset = address(stable);
IERC20(stableAsset).approve(routerV2.glpManager(), stableToDeposit);
uint256 glpMinted = routerV2.mintAndStakeGlp(stableAsset, stableToDeposit, 0, 0);
emit Leverage(_glpAmount, glpMinted);
}
function _deleverage(uint256 _excessGlp) private returns (uint256) {
uint256 stablesReceived = routerV2.unstakeAndRedeemGlp(address(stable), _excessGlp, 0, address(this));
uint256 currentStableDebt = stableDebt;
if (stablesReceived <= currentStableDebt) {
_repayStable(stablesReceived);
} else {
_repayStable(currentStableDebt);
}
return stablesReceived;
}
function _adjustToGMXCap(uint256 _stableAmount) private view returns (uint256) {
IGlpManager manager = glpManager;
IGMXVault vault = IGMXVault(manager.vault());
address usdc = address(stable);
uint256 mintAmount = _buyGlpStableSimulation(_stableAmount);
uint256 currentUsdgAmount = vault.usdgAmounts(usdc);
uint256 nextAmount = currentUsdgAmount + mintAmount;
uint256 maxUsdgAmount = vault.maxUsdgAmounts(usdc);
if (nextAmount > maxUsdgAmount) {
(uint256 requiredStables,) = _getRequiredStableAmount(maxUsdgAmount - currentUsdgAmount);
return requiredStables;
} else {
return _stableAmount;
}
}
function _getGMXCapDifference() private view returns (uint256) {
IGlpManager manager = glpManager;
IGMXVault vault = IGMXVault(manager.vault());
address usdc = address(stable);
uint256 currentUsdgAmount = vault.usdgAmounts(usdc);
uint256 maxUsdgAmount = vault.maxUsdgAmounts(usdc);
return maxUsdgAmount - currentUsdgAmount;
}
function _buyGlpStableSimulation(uint256 _stableAmount) private view returns (uint256) {
IGlpManager manager = glpManager;
IGMXVault vault = IGMXVault(manager.vault());
address usdc = address(stable);
uint256 aumInUsdg = manager.getAumInUsdg(true);
uint256 usdcPrice = vault.getMinPrice(usdc);
uint256 usdgAmount = _stableAmount.mulDiv(usdcPrice, PRECISION);
usdgAmount = usdgAmount.mulDiv(GLP_DECIMALS, USDC_DECIMALS);
uint256 retentionBasisPoints =
vault.getFeeBasisPoints(usdc, usdgAmount, vault.mintBurnFeeBasisPoints(), vault.taxBasisPoints(), true);
uint256 amountAfterRetention = _stableAmount.mulDiv(GMX_BASIS - retentionBasisPoints, GMX_BASIS);
uint256 mintAmount = amountAfterRetention.mulDiv(usdcPrice, PRECISION);
mintAmount = mintAmount.mulDiv(GLP_DECIMALS, USDC_DECIMALS);
return aumInUsdg == 0 ? mintAmount : mintAmount.mulDiv(glp.totalSupply(), aumInUsdg);
}
function _buyGlpStableSimulationWhitoutRetention(uint256 _stableAmount) private view returns (uint256) {
IGlpManager manager = glpManager;
IGMXVault vault = IGMXVault(manager.vault());
address usdc = address(stable);
uint256 aumInUsdg = manager.getAumInUsdg(true);
uint256 usdcPrice = vault.getMinPrice(usdc);
uint256 usdgAmount = _stableAmount.mulDiv(usdcPrice, PRECISION);
usdgAmount = usdgAmount.mulDiv(GLP_DECIMALS, USDC_DECIMALS);
uint256 mintAmount = _stableAmount.mulDiv(usdcPrice, PRECISION);
mintAmount = mintAmount.mulDiv(GLP_DECIMALS, USDC_DECIMALS);
return aumInUsdg == 0 ? mintAmount : mintAmount.mulDiv(glp.totalSupply(), aumInUsdg);
}
function _sellGlpStableSimulation(uint256 _glpAmount) private view returns (uint256, uint256) {
IGlpManager manager = glpManager;
IGMXVault vault = IGMXVault(manager.vault());
address usdc = address(stable);
uint256 usdgAmount = _glpAmount.mulDiv(manager.getAumInUsdg(false), glp.totalSupply());
uint256 redemptionAmount = usdgAmount.mulDiv(PRECISION, vault.getMaxPrice(usdc));
redemptionAmount = redemptionAmount.mulDiv(USDC_DECIMALS, GLP_DECIMALS);
uint256 retentionBasisPoints =
_getGMXBasisRetention(usdc, usdgAmount, vault.mintBurnFeeBasisPoints(), vault.taxBasisPoints(), false);
return (redemptionAmount.mulDiv(GMX_BASIS - retentionBasisPoints, GMX_BASIS), retentionBasisPoints);
}
function _glpMintIncentive(uint256 _glpAmount) private view returns (uint256) {
uint256 amountToMint = _glpAmount.mulDiv(leverageConfig.target - BASIS_POINTS, BASIS_POINTS);
(uint256 stablesNeeded, uint256 gmxIncentive) = _getRequiredStableAmount(amountToMint + 2);
uint256 incentiveInStables = stablesNeeded.mulDiv(gmxIncentive, GMX_BASIS);
return _buyGlpStableSimulationWhitoutRetention(incentiveInStables);
}
function _glpRedeemRetention(uint256 _glpAmount) private view returns (uint256) {
uint256 amountToRedeem = _glpAmount.mulDiv(leverageConfig.target - BASIS_POINTS, BASIS_POINTS);
(, uint256 gmxRetention) = _sellGlpStableSimulation(amountToRedeem + 2);
uint256 retentionInGlp = amountToRedeem.mulDiv(gmxRetention, GMX_BASIS);
return retentionInGlp;
}
function _getGMXBasisRetention(
address _token,
uint256 _usdgDelta,
uint256 _retentionBasisPoints,
uint256 _taxBasisPoints,
bool _increment
) private view returns (uint256) {
IGMXVault vault = IGMXVault(glpManager.vault());
if (!vault.hasDynamicFees()) return _retentionBasisPoints;
uint256 initialAmount = _increment ? vault.usdgAmounts(_token) : vault.usdgAmounts(_token) - _usdgDelta;
uint256 nextAmount = initialAmount + _usdgDelta;
if (!_increment) {
nextAmount = _usdgDelta > initialAmount ? 0 : initialAmount - _usdgDelta;
}
uint256 targetAmount = vault.getTargetUsdgAmount(_token);
if (targetAmount == 0) return _retentionBasisPoints;
uint256 initialDiff = initialAmount > targetAmount ? initialAmount - targetAmount : targetAmount - initialAmount;
uint256 nextDiff = nextAmount > targetAmount ? nextAmount - targetAmount : targetAmount - nextAmount;
if (nextDiff < initialDiff) {
uint256 rebateBps = _taxBasisPoints.mulDiv(initialDiff, targetAmount);
return rebateBps > _retentionBasisPoints ? 0 : _retentionBasisPoints - rebateBps;
}
uint256 averageDiff = (initialDiff + nextDiff) / 2;
if (averageDiff > targetAmount) {
averageDiff = targetAmount;
}
uint256 taxBps = _taxBasisPoints.mulDiv(averageDiff, targetAmount);
return _retentionBasisPoints + taxBps;
}
}
文件 35 的 51:JonesGlpStableVault.sol
pragma solidity ^0.8.10;
import {JonesBaseGlpVault} from "./JonesBaseGlpVault.sol";
import {IERC20Metadata} from "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IAggregatorV3} from "../../interfaces/IAggregatorV3.sol";
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
contract JonesGlpStableVault is JonesBaseGlpVault {
uint256 public constant BASIS_POINTS = 1e12;
constructor()
JonesBaseGlpVault(
IAggregatorV3(0x50834F3163758fcC1Df9973b6e91f0F0F0434aD3),
IERC20Metadata(0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8),
"USDC Vault Receipt Token",
"UVRT"
)
{}
function deposit(uint256 _assets, address _receiver)
public
override(JonesBaseGlpVault)
whenNotPaused
returns (uint256)
{
_validate();
return super.deposit(_assets, _receiver);
}
function burn(address _user, uint256 _amount) public onlyOperator {
_validate();
_burn(_user, _amount);
}
function totalAssets() public view override returns (uint256) {
return super.totalAssets() + strategy.stableDebt();
}
function emergencyWithdraw(address _to) external onlyGovernor {
IERC20 underlyingAsset = IERC20(super.asset());
uint256 balance = underlyingAsset.balanceOf(address(this));
if (balance == 0) {
return;
}
underlyingAsset.transfer(_to, balance);
}
function _validate() private {
uint256 shares = totalSupply() / BASIS_POINTS;
uint256 assets = totalAssets();
address stable = asset();
if (assets > shares) {
uint256 ratioExcess = assets - shares;
IERC20(stable).transfer(receiver, ratioExcess);
}
}
}
文件 36 的 51:JonesGlpVault.sol
pragma solidity ^0.8.10;
import {JonesBaseGlpVault} from "./JonesBaseGlpVault.sol";
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IAggregatorV3} from "../../interfaces/IAggregatorV3.sol";
import {IStakedGlp} from "../../interfaces/IStakedGlp.sol";
import {IJonesGlpLeverageStrategy} from "../../interfaces/IJonesGlpLeverageStrategy.sol";
contract JonesGlpVault is JonesBaseGlpVault {
uint256 private freezedAssets;
constructor()
JonesBaseGlpVault(
IAggregatorV3(0xDFE51CC551949704E5C52C7BB98DCC3fd934E7fa),
IERC20Metadata(0x5402B5F40310bDED796c7D0F3FF6683f5C0cFfdf),
"GLP Vault Receipt Token",
"GVRT"
)
{}
function deposit(uint256 _assets, address _receiver)
public
override(JonesBaseGlpVault)
whenNotPaused
returns (uint256)
{
_validate();
return super.deposit(_assets, _receiver);
}
function burn(address _user, uint256 _amount) public onlyOperator {
_validate();
_burn(_user, _amount);
}
function totalAssets() public view override returns (uint256) {
if (freezedAssets != 0) {
return freezedAssets;
}
return super.totalAssets() + strategy.getUnderlyingGlp();
}
function _validate() private {
IERC20 asset = IERC20(asset());
uint256 balance = asset.balanceOf(address(this));
if (balance > 0) {
asset.transfer(receiver, balance);
}
}
}
文件 37 的 51:JonesGlpVaultRouter.sol
pragma solidity ^0.8.10;
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {IERC4626} from "openzeppelin-contracts/contracts/interfaces/IERC4626.sol";
import {Pausable} from "../common/Pausable.sol";
import {WhitelistController} from "../common/WhitelistController.sol";
import {JonesGlpVault} from "./vaults/JonesGlpVault.sol";
import {JonesGlpStableVault} from "./vaults/JonesGlpStableVault.sol";
import {Governable} from "../common/Governable.sol";
import {GlpJonesRewards} from "./rewards/GlpJonesRewards.sol";
import {IGmxRewardRouter} from "../interfaces/IGmxRewardRouter.sol";
import {IWhitelistController} from "../interfaces/IWhitelistController.sol";
import {IJonesGlpLeverageStrategy} from "../interfaces/IJonesGlpLeverageStrategy.sol";
import {IIncentiveReceiver} from "../interfaces/IIncentiveReceiver.sol";
import {IJonesGlpRewardTracker} from "../interfaces/IJonesGlpRewardTracker.sol";
import {GlpAdapter} from "../adapters/GlpAdapter.sol";
import {IJonesGlpCompoundRewards} from "../interfaces/IJonesGlpCompoundRewards.sol";
import {ReentrancyGuard} from "openzeppelin-contracts/contracts/security/ReentrancyGuard.sol";
import {Errors} from "src/interfaces/Errors.sol";
contract JonesGlpVaultRouter is Governable, Pausable, ReentrancyGuard {
bool public initialized;
struct WithdrawalSignal {
uint256 targetEpoch;
uint256 commitedShares;
bool redeemed;
bool compound;
}
IGmxRewardRouter private constant router = IGmxRewardRouter(0xB95DB5B167D75e6d04227CfFFA61069348d271F5);
address private constant weth = 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1;
JonesGlpVault private glpVault;
JonesGlpStableVault private glpStableVault;
IJonesGlpLeverageStrategy public strategy;
GlpJonesRewards private jonesRewards;
IJonesGlpRewardTracker public glpRewardTracker;
IJonesGlpRewardTracker public stableRewardTracker;
IJonesGlpCompoundRewards private stableCompoundRewards;
IJonesGlpCompoundRewards private glpCompoundRewards;
IWhitelistController private whitelistController;
IIncentiveReceiver private incentiveReceiver;
GlpAdapter private adapter;
IERC20 private glp;
IERC20 private stable;
mapping(address => IJonesGlpRewardTracker) public rewardTrackers;
mapping(address => IJonesGlpCompoundRewards) public rewardCompounder;
mapping(address => mapping(uint256 => WithdrawalSignal)) public userSignal;
uint256 private constant BASIS_POINTS = 1e12;
uint256 private constant EPOCH_DURATION = 1 days;
uint256 public EXIT_COOLDOWN;
uint256 public pendingWithdrawals;
constructor(
JonesGlpVault _glpVault,
JonesGlpStableVault _glpStableVault,
IJonesGlpLeverageStrategy _strategy,
GlpJonesRewards _jonesRewards,
IJonesGlpRewardTracker _glpRewardTracker,
IJonesGlpRewardTracker _stableRewardTracker,
IJonesGlpCompoundRewards _glpCompoundRewards,
IJonesGlpCompoundRewards _stableCompoundRewards,
IWhitelistController _whitelistController,
IIncentiveReceiver _incentiveReceiver
) Governable(msg.sender) {
glpVault = _glpVault;
glpStableVault = _glpStableVault;
strategy = _strategy;
jonesRewards = _jonesRewards;
glpRewardTracker = _glpRewardTracker;
stableRewardTracker = _stableRewardTracker;
glpCompoundRewards = _glpCompoundRewards;
stableCompoundRewards = _stableCompoundRewards;
whitelistController = _whitelistController;
incentiveReceiver = _incentiveReceiver;
}
function initialize(address _glp, address _stable, address _adapter) external onlyGovernor {
if (initialized) {
revert Errors.AlreadyInitialized();
}
rewardTrackers[_glp] = glpRewardTracker;
rewardTrackers[_stable] = stableRewardTracker;
rewardCompounder[_glp] = glpCompoundRewards;
rewardCompounder[_stable] = stableCompoundRewards;
glp = IERC20(_glp);
stable = IERC20(_stable);
adapter = GlpAdapter(_adapter);
initialized = true;
}
function depositGlp(uint256 _assets, address _sender, bool _compound) external whenNotPaused returns (uint256) {
_onlyInternalContract();
bytes32 role = whitelistController.getUserRole(_sender);
IWhitelistController.RoleInfo memory info = whitelistController.getRoleInfo(role);
IJonesGlpLeverageStrategy _strategy = strategy;
JonesGlpVault _glpVault = glpVault;
uint256 assetsUsdValue = _strategy.getStableGlpValue(_assets);
uint256 underlyingUsdValue = _strategy.getStableGlpValue(_strategy.getUnderlyingGlp());
uint256 maxTvlGlp = getMaxCapGlp();
if ((assetsUsdValue + underlyingUsdValue) * BASIS_POINTS > maxTvlGlp && !info.jGLP_BYPASS_CAP) {
revert Errors.MaxGlpTvlReached();
}
if (_compound) {
glpCompoundRewards.compound();
}
(uint256 compoundShares, uint256 vaultShares) = _deposit(_glpVault, _sender, _assets, _compound);
_strategy.onGlpDeposit(_assets);
if (_compound) {
emit DepositGlp(_sender, _assets, compoundShares, _compound);
return compoundShares;
}
emit DepositGlp(_sender, _assets, vaultShares, _compound);
return vaultShares;
}
function redeemGlp(uint256 _shares, bool _compound)
external
whenNotEmergencyPaused
nonReentrant
returns (uint256)
{
_onlyEOA();
if (_compound) {
glpCompoundRewards.compound();
_shares = _unCompoundGlp(_shares, msg.sender);
}
glpRewardTracker.withdraw(msg.sender, _shares);
JonesGlpVault _glpVault = glpVault;
uint256 glpAmount = _glpVault.previewRedeem(_shares);
_glpVault.burn(address(this), _shares);
glpAmount = strategy.onGlpRedeem(glpAmount);
if (glpAmount > 0) {
glpAmount = _distributeGlp(glpAmount, msg.sender, _compound);
}
return glpAmount;
}
function redeemGlpAdapter(uint256 _shares, bool _compound, address _token, address _user, bool _native)
external
whenNotEmergencyPaused
nonReentrant
returns (uint256)
{
if (msg.sender != address(adapter)) {
revert Errors.OnlyAdapter();
}
if (_compound) {
glpCompoundRewards.compound();
_shares = _unCompoundGlp(_shares, _user);
}
glpRewardTracker.withdraw(_user, _shares);
JonesGlpVault _glpVault = glpVault;
uint256 glpAmount = _glpVault.previewRedeem(_shares);
_glpVault.burn(address(this), _shares);
glpAmount = strategy.onGlpRedeem(glpAmount);
if (glpAmount > 0) {
glpAmount = _distributeGlpAdapter(glpAmount, _user, _token, _native, _compound);
}
return glpAmount;
}
function depositStable(uint256 _assets, bool _compound, address _user) external whenNotPaused returns (uint256) {
_onlyInternalContract();
if (_compound) {
stableCompoundRewards.compound();
}
(uint256 shares, uint256 track) = _deposit(glpStableVault, _user, _assets, _compound);
if (_user != address(rewardCompounder[address(stable)])) {
jonesRewards.stake(_user, track);
}
strategy.onStableDeposit();
emit DepositStables(_user, _assets, shares, _compound);
return shares;
}
function stableWithdrawalSignal(uint256 _shares, bool _compound)
external
whenNotEmergencyPaused
returns (uint256)
{
_onlyEOA();
bytes32 userRole = whitelistController.getUserRole(msg.sender);
IWhitelistController.RoleInfo memory info = whitelistController.getRoleInfo(userRole);
uint256 targetEpoch = currentEpoch() + EXIT_COOLDOWN;
WithdrawalSignal storage userWithdrawalSignal = userSignal[msg.sender][targetEpoch];
if (userWithdrawalSignal.commitedShares > 0) {
revert Errors.WithdrawalSignalAlreadyDone();
}
if (_compound) {
stableCompoundRewards.compound();
uint256 assets = stableCompoundRewards.previewRedeem(_shares);
uint256 assetDeposited = stableCompoundRewards.totalAssetsToDeposits(msg.sender, assets);
jonesRewards.getReward(msg.sender);
jonesRewards.withdraw(msg.sender, assetDeposited);
_shares = _unCompoundStables(_shares);
} else {
jonesRewards.getReward(msg.sender);
jonesRewards.withdraw(msg.sender, _shares);
}
rewardTrackers[address(stable)].withdraw(msg.sender, _shares);
if (info.jUSDC_BYPASS_TIME) {
return _redeemDirectly(_shares, info.jUSDC_RETENTION, _compound);
}
userWithdrawalSignal.targetEpoch = targetEpoch;
userWithdrawalSignal.commitedShares = _shares;
userWithdrawalSignal.compound = _compound;
pendingWithdrawals = pendingWithdrawals + glpStableVault.previewRedeem(_shares);
emit StableWithdrawalSignal(msg.sender, _shares, targetEpoch, _compound);
return targetEpoch;
}
function _redeemDirectly(uint256 _shares, uint256 _retention, bool _compound) private returns (uint256) {
uint256 stableAmount = glpStableVault.previewRedeem(_shares);
uint256 stablesFromVault = _borrowStables(stableAmount);
uint256 gmxIncentive;
if (stablesFromVault < stableAmount) {
uint256 difference = stableAmount - stablesFromVault;
gmxIncentive = (difference * strategy.getRedeemStableGMXIncentive(difference) * 1e8) / BASIS_POINTS;
strategy.onStableRedeem(difference, difference - gmxIncentive);
}
uint256 remainderStables = stableAmount - gmxIncentive;
IERC20 stableToken = stable;
if (stableToken.balanceOf(address(this)) < remainderStables) {
revert Errors.NotEnoughStables();
}
glpStableVault.burn(address(this), _shares);
uint256 retention = ((stableAmount * _retention) / BASIS_POINTS);
uint256 realRetention = gmxIncentive < retention ? retention - gmxIncentive : 0;
uint256 amountAfterRetention = remainderStables - realRetention;
if (amountAfterRetention > 0) {
stableToken.transfer(msg.sender, amountAfterRetention);
}
if (realRetention > 0) {
stableToken.approve(address(stableRewardTracker), realRetention);
stableRewardTracker.depositRewards(realRetention);
}
emit RedeemStable(msg.sender, amountAfterRetention, retention, realRetention, _compound);
return amountAfterRetention;
}
function cancelStableWithdrawalSignal(uint256 _epoch, bool _compound) external {
WithdrawalSignal memory userWithdrawalSignal = userSignal[msg.sender][_epoch];
if (userWithdrawalSignal.redeemed) {
revert Errors.WithdrawalAlreadyCompleted();
}
uint256 snapshotCommitedShares = userWithdrawalSignal.commitedShares;
if (snapshotCommitedShares == 0) {
return;
}
userWithdrawalSignal.commitedShares = 0;
userWithdrawalSignal.targetEpoch = 0;
userWithdrawalSignal.compound = false;
IJonesGlpRewardTracker tracker = stableRewardTracker;
jonesRewards.stake(msg.sender, snapshotCommitedShares);
if (_compound) {
stableCompoundRewards.compound();
IJonesGlpCompoundRewards compounder = rewardCompounder[address(stable)];
IERC20(address(glpStableVault)).approve(address(compounder), snapshotCommitedShares);
compounder.deposit(snapshotCommitedShares, msg.sender);
} else {
IERC20(address(glpStableVault)).approve(address(tracker), snapshotCommitedShares);
tracker.stake(msg.sender, snapshotCommitedShares);
}
userSignal[msg.sender][_epoch] = userWithdrawalSignal;
pendingWithdrawals = pendingWithdrawals - glpStableVault.previewRedeem(snapshotCommitedShares);
emit CancelStableWithdrawalSignal(msg.sender, snapshotCommitedShares, _compound);
}
function redeemStable(uint256 _epoch) external whenNotEmergencyPaused returns (uint256) {
bytes32 userRole = whitelistController.getUserRole(msg.sender);
IWhitelistController.RoleInfo memory info = whitelistController.getRoleInfo(userRole);
WithdrawalSignal memory userWithdrawalSignal = userSignal[msg.sender][_epoch];
if (currentEpoch() < userWithdrawalSignal.targetEpoch || userWithdrawalSignal.targetEpoch == 0) {
revert Errors.NotRightEpoch();
}
if (userWithdrawalSignal.redeemed) {
revert Errors.WithdrawalAlreadyCompleted();
}
if (userWithdrawalSignal.commitedShares == 0) {
revert Errors.WithdrawalWithNoShares();
}
uint256 stableAmount = glpStableVault.previewRedeem(userWithdrawalSignal.commitedShares);
uint256 stablesFromVault = _borrowStables(stableAmount);
uint256 gmxIncentive;
if (stablesFromVault < stableAmount) {
uint256 difference = stableAmount - stablesFromVault;
gmxIncentive = (difference * strategy.getRedeemStableGMXIncentive(difference) * 1e8) / BASIS_POINTS;
strategy.onStableRedeem(difference, difference - gmxIncentive);
}
uint256 remainderStables = stableAmount - gmxIncentive;
IERC20 stableToken = stable;
if (stableToken.balanceOf(address(this)) < remainderStables) {
revert Errors.NotEnoughStables();
}
glpStableVault.burn(address(this), userWithdrawalSignal.commitedShares);
WithdrawalSignal storage withdrawalSingal = userSignal[msg.sender][_epoch];
withdrawalSingal.redeemed = true;
uint256 retention = ((stableAmount * info.jUSDC_RETENTION) / BASIS_POINTS);
uint256 realRetention = gmxIncentive < retention ? retention - gmxIncentive : 0;
uint256 amountAfterRetention = remainderStables - realRetention;
if (amountAfterRetention > 0) {
stableToken.transfer(msg.sender, amountAfterRetention);
}
if (realRetention > 0) {
stableToken.approve(address(stableRewardTracker), realRetention);
stableRewardTracker.depositRewards(realRetention);
}
pendingWithdrawals = pendingWithdrawals - stableAmount;
emit RedeemStable(msg.sender, amountAfterRetention, retention, realRetention, userWithdrawalSignal.compound);
return amountAfterRetention;
}
function claimRewards() external returns (uint256, uint256, uint256) {
strategy.claimGlpRewards();
uint256 stableRewards = stableRewardTracker.claim(msg.sender);
stable.transfer(msg.sender, stableRewards);
uint256 glpRewards = glpRewardTracker.claim(msg.sender);
IERC20(weth).transfer(msg.sender, glpRewards);
uint256 _jonesRewards = jonesRewards.getReward(msg.sender);
emit ClaimRewards(msg.sender, stableRewards, glpRewards, _jonesRewards);
return (stableRewards, glpRewards, _jonesRewards);
}
function compoundRewards(uint256 _stableDeposits, uint256 _glpDeposits) external returns (uint256, uint256) {
return (compoundStableRewards(_stableDeposits), compoundGlpRewards(_glpDeposits));
}
function unCompoundRewards(uint256 _stableDeposits, uint256 _glpDeposits, address _user)
external
returns (uint256, uint256)
{
return (unCompoundStableRewards(_stableDeposits), unCompoundGlpRewards(_glpDeposits, _user));
}
function compoundGlpRewards(uint256 _shares) public returns (uint256) {
glpCompoundRewards.compound();
strategy.claimGlpRewards();
uint256 rewards = glpRewardTracker.claim(msg.sender);
uint256 rewardShares;
if (rewards != 0) {
IERC20(weth).approve(router.glpManager(), rewards);
uint256 glpAmount = router.mintAndStakeGlp(weth, rewards, 0, 0);
glp.approve(address(glpVault), glpAmount);
rewardShares = glpVault.deposit(glpAmount, address(this));
}
uint256 currentShares = glpRewardTracker.withdraw(msg.sender, _shares);
IJonesGlpCompoundRewards compounder = rewardCompounder[address(glp)];
uint256 totalShares = currentShares + rewardShares;
IERC20(address(glpVault)).approve(address(compounder), totalShares);
uint256 shares = compounder.deposit(totalShares, msg.sender);
emit CompoundGlp(msg.sender, totalShares);
return shares;
}
function unCompoundGlpRewards(uint256 _shares, address _user) public returns (uint256) {
glpCompoundRewards.compound();
return _unCompoundGlp(_shares, _user);
}
function compoundStableRewards(uint256 _shares) public returns (uint256) {
stableCompoundRewards.compound();
strategy.claimGlpRewards();
uint256 rewards = stableRewardTracker.claim(msg.sender);
uint256 rewardShares;
if (rewards > 0) {
stable.approve(address(glpStableVault), rewards);
rewardShares = glpStableVault.deposit(rewards, address(this));
}
uint256 currentShares = stableRewardTracker.withdraw(msg.sender, _shares);
IJonesGlpCompoundRewards compounder = rewardCompounder[address(stable)];
uint256 totalShares = currentShares + rewardShares;
IERC20(address(glpStableVault)).approve(address(compounder), totalShares);
uint256 shares = compounder.deposit(totalShares, msg.sender);
emit CompoundStables(msg.sender, totalShares);
return shares;
}
function unCompoundStableRewards(uint256 _shares) public returns (uint256) {
stableCompoundRewards.compound();
IJonesGlpCompoundRewards compounder = rewardCompounder[address(stable)];
uint256 assets = compounder.previewRedeem(_shares);
uint256 assetsDeposited = compounder.totalAssetsToDeposits(msg.sender, assets);
uint256 difference = assets - assetsDeposited;
if (difference > 0) {
jonesRewards.stake(msg.sender, difference);
}
return _unCompoundStables(_shares);
}
function withdrawSignal(address user, uint256 epoch) external view returns (uint256, uint256, bool, bool) {
WithdrawalSignal memory userWithdrawalSignal = userSignal[user][epoch];
return (
userWithdrawalSignal.targetEpoch,
userWithdrawalSignal.commitedShares,
userWithdrawalSignal.redeemed,
userWithdrawalSignal.compound
);
}
function getMaxCapGlp() public view returns (uint256) {
return (glpStableVault.tvl() * BASIS_POINTS) / (strategy.getTargetLeverage() - BASIS_POINTS);
}
function setExitCooldown(uint256 _days) external onlyGovernor {
EXIT_COOLDOWN = _days * EPOCH_DURATION;
}
function setJonesRewards(GlpJonesRewards _jonesRewards) external onlyGovernor {
address previousAddress = address(jonesRewards);
jonesRewards = _jonesRewards;
emit SetJonesRewards(previousAddress, address(_jonesRewards));
}
function setLeverageStrategy(address _leverageStrategy) external onlyGovernor {
address previousAddress = address(strategy);
strategy = IJonesGlpLeverageStrategy(_leverageStrategy);
emit SetJonesLeverageStrategy(previousAddress, _leverageStrategy);
}
function setStableCompoundRewards(address _stableCompoundRewards) external onlyGovernor {
address oldStableCompoundRewards = address(stableCompoundRewards);
stableCompoundRewards = IJonesGlpCompoundRewards(_stableCompoundRewards);
rewardCompounder[address(stable)] = stableCompoundRewards;
emit UpdateStableCompoundRewards(oldStableCompoundRewards, _stableCompoundRewards);
}
function setGlpCompoundRewards(address _glpCompoundRewards) external onlyGovernor {
address oldGlpCompoundRewards = address(glpCompoundRewards);
glpCompoundRewards = IJonesGlpCompoundRewards(_glpCompoundRewards);
rewardCompounder[address(glp)] = glpCompoundRewards;
emit UpdateGlpCompoundRewards(oldGlpCompoundRewards, _glpCompoundRewards);
}
function setStableRewardTracker(address _stableRewardTracker) external onlyGovernor {
address oldStableRewardTracker = address(stableRewardTracker);
stableRewardTracker = IJonesGlpRewardTracker(_stableRewardTracker);
rewardTrackers[address(stable)] = stableRewardTracker;
emit UpdateStableRewardTracker(oldStableRewardTracker, _stableRewardTracker);
}
function setGlpRewardTracker(address _glpRewardTracker) external onlyGovernor {
address oldGlpRewardTracker = address(glpRewardTracker);
glpRewardTracker = IJonesGlpRewardTracker(_glpRewardTracker);
rewardTrackers[address(glp)] = glpRewardTracker;
emit UpdateGlpRewardTracker(oldGlpRewardTracker, _glpRewardTracker);
}
function setIncentiveReceiver(address _newIncentiveReceiver) external onlyGovernor {
if (_newIncentiveReceiver == address(0)) {
revert Errors.AddressCannotBeZeroAddress();
}
address oldIncentiveReceiver = address(incentiveReceiver);
incentiveReceiver = IIncentiveReceiver(_newIncentiveReceiver);
emit UpdateIncentiveReceiver(oldIncentiveReceiver, _newIncentiveReceiver);
}
function setGlpAdapter(address _adapter) external onlyGovernor {
if (_adapter == address(0)) {
revert Errors.AddressCannotBeZeroAddress();
}
address oldAdapter = address(adapter);
adapter = GlpAdapter(_adapter);
emit UpdateAdapter(oldAdapter, _adapter);
}
function _deposit(IERC4626 _vault, address _caller, uint256 _assets, bool compound)
private
returns (uint256, uint256)
{
IERC20 asset = IERC20(_vault.asset());
address adapterAddress = address(adapter);
IJonesGlpRewardTracker tracker = rewardTrackers[address(asset)];
if (msg.sender == adapterAddress) {
asset.transferFrom(adapterAddress, address(this), _assets);
} else {
asset.transferFrom(_caller, address(this), _assets);
}
uint256 vaultShares = _vaultDeposit(_vault, _assets);
uint256 compoundShares;
if (compound) {
IJonesGlpCompoundRewards compounder = rewardCompounder[address(asset)];
IERC20(address(_vault)).approve(address(compounder), vaultShares);
compoundShares = compounder.deposit(vaultShares, _caller);
} else {
IERC20(address(_vault)).approve(address(tracker), vaultShares);
tracker.stake(_caller, vaultShares);
}
return (compoundShares, vaultShares);
}
function _distributeGlp(uint256 _amount, address _dest, bool _compound) private returns (uint256) {
uint256 retention = _chargeIncentive(_amount, _dest);
uint256 wethAmount;
if (retention > 0) {
wethAmount = router.unstakeAndRedeemGlp(weth, retention, 0, address(this));
uint256 jonesRetention = (wethAmount * 2) / 3;
IERC20(weth).approve(address(incentiveReceiver), jonesRetention);
incentiveReceiver.deposit(weth, jonesRetention);
IERC20(weth).approve(address(glpRewardTracker), wethAmount - jonesRetention);
glpRewardTracker.depositRewards(wethAmount - jonesRetention);
}
uint256 glpAfterRetention = _amount - retention;
glp.transfer(_dest, glpAfterRetention);
emit RedeemGlp(_dest, glpAfterRetention, retention, wethAmount, _compound);
return glpAfterRetention;
}
function _distributeGlpAdapter(uint256 _amount, address _dest, address _token, bool _native, bool _compound)
private
returns (uint256)
{
uint256 retention = _chargeIncentive(_amount, _dest);
uint256 wethAmount;
if (retention > 0) {
wethAmount = router.unstakeAndRedeemGlp(weth, retention, 0, address(this));
uint256 jonesRetention = (wethAmount * 2) / 3;
IERC20(weth).approve(address(incentiveReceiver), jonesRetention);
incentiveReceiver.deposit(weth, jonesRetention);
IERC20(weth).approve(address(glpRewardTracker), wethAmount - jonesRetention);
glpRewardTracker.depositRewards(wethAmount - jonesRetention);
}
if (_native) {
uint256 ethAmount = router.unstakeAndRedeemGlpETH(_amount - retention, 0, payable(_dest));
emit RedeemGlpEth(_dest, _amount - retention, retention, wethAmount, ethAmount);
return ethAmount;
}
uint256 assetAmount = router.unstakeAndRedeemGlp(_token, _amount - retention, 0, _dest);
emit RedeemGlpBasket(_dest, _amount - retention, retention, wethAmount, _token, _compound);
return assetAmount;
}
function currentEpoch() public view returns (uint256) {
return (block.timestamp / EPOCH_DURATION) * EPOCH_DURATION;
}
function _borrowStables(uint256 _amount) private returns (uint256) {
JonesGlpStableVault stableVault = glpStableVault;
uint256 balance = stable.balanceOf(address(stableVault));
if (balance == 0) {
return 0;
}
uint256 amountToBorrow = balance < _amount ? balance : _amount;
emit BorrowStables(amountToBorrow);
return stableVault.borrow(amountToBorrow);
}
function _chargeIncentive(uint256 _withdrawAmount, address _sender) private returns (uint256) {
bytes32 userRole = whitelistController.getUserRole(_sender);
IWhitelistController.RoleInfo memory info = whitelistController.getRoleInfo(userRole);
uint256 retention = (_withdrawAmount * info.jGLP_RETENTION) / BASIS_POINTS;
emit RetentionCharged(retention);
return retention;
}
function _unCompoundGlp(uint256 _shares, address _user) private returns (uint256) {
IJonesGlpCompoundRewards compounder = rewardCompounder[address(glp)];
uint256 shares = compounder.redeem(_shares, _user);
emit unCompoundGlp(_user, _shares);
return shares;
}
function _unCompoundStables(uint256 _shares) private returns (uint256) {
IJonesGlpCompoundRewards compounder = rewardCompounder[address(stable)];
uint256 shares = compounder.redeem(_shares, msg.sender);
emit unCompoundStables(msg.sender, _shares);
return shares;
}
function _vaultDeposit(IERC4626 _vault, uint256 _assets) private returns (uint256) {
address asset = _vault.asset();
address vaultAddress = address(_vault);
uint256 vaultShares;
if (_vault.asset() == address(glp)) {
uint256 glpMintIncentives = strategy.glpMintIncentive(_assets);
uint256 assetsToDeposit = _assets - glpMintIncentives;
IERC20(asset).approve(vaultAddress, assetsToDeposit);
vaultShares = _vault.deposit(assetsToDeposit, address(this));
if (glpMintIncentives > 0) {
glp.transfer(vaultAddress, glpMintIncentives);
}
emit VaultDeposit(vaultAddress, _assets, glpMintIncentives);
} else {
IERC20(asset).approve(vaultAddress, _assets);
vaultShares = _vault.deposit(_assets, address(this));
emit VaultDeposit(vaultAddress, _assets, 0);
}
return vaultShares;
}
function _onlyInternalContract() private view {
if (!whitelistController.isInternalContract(msg.sender)) {
revert Errors.CallerIsNotInternalContract();
}
}
function _onlyEOA() private view {
if (msg.sender != tx.origin && !whitelistController.isWhitelistedContract(msg.sender)) {
revert Errors.CallerIsNotWhitelisted();
}
}
function togglePause() external onlyGovernor {
if (paused()) {
_unpause();
return;
}
_pause();
}
function toggleEmergencyPause() external onlyGovernor {
if (emergencyPaused()) {
_emergencyUnpause();
return;
}
_emergencyPause();
}
event UpdateIncentiveReceiver(address _oldIncentiveReceiver, address _newIncentiveReceiver);
event UpdateStableRewardTracker(address _oldStableTracker, address _newStableTracker);
event UpdateGlpRewardTracker(address _oldGlpTracker, address _newGlpTracker);
event UpdateStableCompoundRewards(address _oldStableCompounder, address _newStableCompounder);
event UpdateGlpCompoundRewards(address _oldGlpeCompounder, address _newGlpCompounder);
event UpdateWithdrawalRetention(uint256 _newRetention);
event UpdateAdapter(address _oldAdapter, address _newAdapter);
event UpdateGlpVault(address _oldGlpVault, address _newGlpVault);
event UpdateStableVault(address _oldStableVault, address _newStableVault);
event UpdateStableAddress(address _oldStableAddress, address _newStableAddress);
event UpdateGlpAddress(address _oldGlpAddress, address _newGlpAddress);
event DepositGlp(address indexed _to, uint256 _amount, uint256 _sharesReceived, bool _compound);
event DepositStables(address indexed _to, uint256 _amount, uint256 _sharesReceived, bool _compound);
event VaultDeposit(address indexed vault, uint256 _amount, uint256 _retention);
event RedeemGlpBasket(
address indexed _to,
uint256 _amount,
uint256 _retentions,
uint256 _ethRetentions,
address _token,
bool _compound
);
event RedeemGlpEth(
address indexed _to, uint256 _amount, uint256 _retentions, uint256 _ethRetentions, uint256 _ethAmount
);
event RedeemGlp(address indexed _to, uint256 _amount, uint256 _retentions, uint256 _ethRetentions, bool _compound);
event RedeemStable(
address indexed _to, uint256 _amount, uint256 _retentions, uint256 _realRetentions, bool _compound
);
event ClaimRewards(address indexed _to, uint256 _stableAmount, uint256 _wEthAmount, uint256 _amountJones);
event CompoundGlp(address indexed _to, uint256 _amount);
event CompoundStables(address indexed _to, uint256 _amount);
event unCompoundGlp(address indexed _to, uint256 _amount);
event unCompoundStables(address indexed _to, uint256 _amount);
event SettleEpoch(uint256 _currentEpochTs, uint256 indexed _targetEpochTs);
event StableWithdrawalSignal(
address indexed sender, uint256 _shares, uint256 indexed _targetEpochTs, bool _compound
);
event CancelStableWithdrawalSignal(address indexed sender, uint256 _shares, bool _compound);
event RetentionCharged(uint256 indexed _retentions);
event BorrowStables(uint256 indexed _amountBorrowed);
event SetJonesRewards(address indexed _previousAddress, address indexed _newAddress);
event SetJonesLeverageStrategy(address indexed _previousADdress, address indexed _newAddress);
}
文件 38 的 51:JonesGovernableVault.sol
pragma solidity ^0.8.10;
import {AccessControl} from "openzeppelin-contracts/contracts/access/AccessControl.sol";
abstract contract JonesGovernableVault is AccessControl {
bytes32 public constant GOVERNOR = bytes32("GOVERNOR");
constructor(address _governor) {
_grantRole(GOVERNOR, _governor);
}
modifier onlyGovernor() {
if (!hasRole(GOVERNOR, msg.sender)) {
revert CallerIsNotGovernor();
}
_;
}
function updateGovernor(address _newGovernor) external onlyGovernor {
_revokeRole(GOVERNOR, msg.sender);
_grantRole(GOVERNOR, _newGovernor);
emit GovernorUpdated(msg.sender, _newGovernor);
}
event GovernorUpdated(address _oldGovernor, address _newGovernor);
error CallerIsNotGovernor();
}
文件 39 的 51:JonesOperableVault.sol
pragma solidity ^0.8.10;
import {JonesGovernableVault} from "./JonesGovernableVault.sol";
import {ERC4626} from "openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol";
abstract contract JonesOperableVault is JonesGovernableVault, ERC4626 {
bytes32 public constant OPERATOR = bytes32("OPERATOR");
modifier onlyOperator() {
if (!hasRole(OPERATOR, msg.sender)) {
revert CallerIsNotOperator();
}
_;
}
function addOperator(address _newOperator) external onlyGovernor {
_grantRole(OPERATOR, _newOperator);
emit OperatorAdded(_newOperator);
}
function removeOperator(address _operator) external onlyGovernor {
_revokeRole(OPERATOR, _operator);
emit OperatorRemoved(_operator);
}
function deposit(uint256 _assets, address _receiver) public virtual override onlyOperator returns (uint256) {
return super.deposit(_assets, _receiver);
}
function mint(uint256 _shares, address _receiver) public virtual override onlyOperator returns (uint256) {
return super.mint(_shares, _receiver);
}
function withdraw(uint256 _assets, address _receiver, address _owner)
public
virtual
override
onlyOperator
returns (uint256)
{
return super.withdraw(_assets, _receiver, _owner);
}
function redeem(uint256 _shares, address _receiver, address _owner)
public
virtual
override
onlyOperator
returns (uint256)
{
return super.redeem(_shares, _receiver, _owner);
}
event OperatorAdded(address _newOperator);
event OperatorRemoved(address _operator);
error CallerIsNotOperator();
}
文件 40 的 51:JonesUsdVault.sol
pragma solidity ^0.8.10;
import {ERC4626} from "openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol";
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {JonesGovernableVault} from "./JonesGovernableVault.sol";
import {IAggregatorV3} from "../interfaces/IAggregatorV3.sol";
import {IJonesUsdVault} from "../interfaces/IJonesUsdVault.sol";
abstract contract JonesUsdVault is JonesGovernableVault, ERC4626, IJonesUsdVault {
IAggregatorV3 public priceOracle;
constructor(IAggregatorV3 _priceOracle) {
priceOracle = _priceOracle;
}
function setPriceAggregator(IAggregatorV3 _newPriceOracle) external onlyGovernor {
emit PriceOracleUpdated(address(priceOracle), address(_newPriceOracle));
priceOracle = _newPriceOracle;
}
function tvl() external view returns (uint256) {
return _toUsdValue(totalAssets());
}
function _toUsdValue(uint256 _value) internal view returns (uint256) {
IAggregatorV3 oracle = priceOracle;
(, int256 currentPrice,,,) = oracle.latestRoundData();
uint8 totalDecimals = IERC20Metadata(asset()).decimals() + oracle.decimals();
uint8 targetDecimals = 18;
return totalDecimals > targetDecimals
? (_value * uint256(currentPrice)) / 10 ** (totalDecimals - targetDecimals)
: (_value * uint256(currentPrice)) * 10 ** (targetDecimals - totalDecimals);
}
event PriceOracleUpdated(address _oldPriceOracle, address _newPriceOracle);
}
文件 41 的 51: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;
uint256 x = a;
if (x >> 128 > 0) {
x >>= 128;
result <<= 64;
}
if (x >> 64 > 0) {
x >>= 64;
result <<= 32;
}
if (x >> 32 > 0) {
x >>= 32;
result <<= 16;
}
if (x >> 16 > 0) {
x >>= 16;
result <<= 8;
}
if (x >> 8 > 0) {
x >>= 8;
result <<= 4;
}
if (x >> 4 > 0) {
x >>= 4;
result <<= 2;
}
if (x >> 2 > 0) {
result <<= 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) {
uint256 result = sqrt(a);
if (rounding == Rounding.Up && result * result < a) {
result += 1;
}
return result;
}
}
文件 42 的 51: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)
}
}
}
文件 43 的 51:Operable.sol
pragma solidity ^0.8.10;
import {AccessControl} from "openzeppelin-contracts/contracts/access/AccessControl.sol";
import {Governable} from "./Governable.sol";
abstract contract Operable is Governable {
bytes32 public constant OPERATOR = bytes32("OPERATOR");
modifier onlyOperator() {
if (!hasRole(OPERATOR, msg.sender)) {
revert CallerIsNotOperator();
}
_;
}
function addOperator(address _newOperator) external onlyGovernor {
_grantRole(OPERATOR, _newOperator);
emit OperatorAdded(_newOperator);
}
function removeOperator(address _operator) external onlyGovernor {
_revokeRole(OPERATOR, _operator);
emit OperatorRemoved(_operator);
}
event OperatorAdded(address _newOperator);
event OperatorRemoved(address _operator);
error CallerIsNotOperator();
}
文件 44 的 51:OperableKeepable.sol
pragma solidity ^0.8.10;
import {Governable} from "./Governable.sol";
abstract contract OperableKeepable is Governable {
bytes32 public constant OPERATOR = bytes32("OPERATOR");
bytes32 public constant KEEPER = bytes32("KEEPER");
modifier onlyOperator() {
if (!hasRole(OPERATOR, msg.sender)) {
revert CallerIsNotOperator();
}
_;
}
modifier onlyKeeper() {
if (!hasRole(KEEPER, msg.sender)) {
revert CallerIsNotKeeper();
}
_;
}
modifier onlyOperatorOrKeeper() {
if (!(hasRole(OPERATOR, msg.sender) || hasRole(KEEPER, msg.sender))) {
revert CallerIsNotAllowed();
}
_;
}
modifier onlyGovernorOrKeeper() {
if (!(hasRole(GOVERNOR, msg.sender) || hasRole(KEEPER, msg.sender))) {
revert CallerIsNotAllowed();
}
_;
}
function addOperator(address _newOperator) external onlyGovernor {
_grantRole(OPERATOR, _newOperator);
emit OperatorAdded(_newOperator);
}
function removeOperator(address _operator) external onlyGovernor {
_revokeRole(OPERATOR, _operator);
emit OperatorRemoved(_operator);
}
function addKeeper(address _newKeeper) external onlyGovernor {
_grantRole(KEEPER, _newKeeper);
emit KeeperAdded(_newKeeper);
}
function removeKeeper(address _operator) external onlyGovernor {
_revokeRole(KEEPER, _operator);
emit KeeperRemoved(_operator);
}
event OperatorAdded(address _newOperator);
event OperatorRemoved(address _operator);
error CallerIsNotOperator();
event KeeperAdded(address _newKeeper);
event KeeperRemoved(address _operator);
error CallerIsNotKeeper();
error CallerIsNotAllowed();
}
文件 45 的 51:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 46 的 51:Pausable.sol
pragma solidity ^0.8.10;
abstract contract Pausable {
bool private _paused;
bool private _emergencyPaused;
constructor() {
_paused = false;
_emergencyPaused = false;
}
function paused() public view returns (bool) {
return _paused;
}
function emergencyPaused() public view returns (bool) {
return _emergencyPaused;
}
function _requireNotPaused() internal view {
if (paused()) {
revert ErrorPaused();
}
}
function _requireNotEmergencyPaused() internal view {
if (emergencyPaused()) {
revert ErrorEmergencyPaused();
}
}
function _pause() internal whenNotPaused {
_paused = true;
emit Paused(msg.sender);
}
function _unpause() internal whenPaused {
_paused = false;
emit Unpaused(msg.sender);
}
function _emergencyPause() internal whenNotEmergencyPaused {
_paused = true;
_emergencyPaused = true;
emit EmergencyPaused(msg.sender);
}
function _emergencyUnpause() internal whenEmergencyPaused {
_emergencyPaused = false;
_paused = false;
emit EmergencyUnpaused(msg.sender);
}
modifier whenPaused() {
if (!paused()) {
revert ErrorNotPaused();
}
_;
}
modifier whenNotPaused() {
_requireNotPaused();
_;
}
modifier whenEmergencyPaused() {
if (!emergencyPaused()) {
revert ErrorNotEmergencyPaused();
}
_;
}
modifier whenNotEmergencyPaused() {
_requireNotEmergencyPaused();
_;
}
event Paused(address _account);
event Unpaused(address _account);
event EmergencyPaused(address _account);
event EmergencyUnpaused(address _account);
error ErrorPaused();
error ErrorEmergencyPaused();
error ErrorNotPaused();
error ErrorNotEmergencyPaused();
}
文件 47 的 51:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
}
function _nonReentrantAfter() private {
_status = _NOT_ENTERED;
}
}
文件 48 的 51:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 49 的 51:Strings.sol
pragma solidity ^0.8.0;
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
function toString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
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] = _HEX_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 的 51:WhitelistController.sol
pragma solidity ^0.8.10;
import {AccessControl} from "openzeppelin-contracts/contracts/access/AccessControl.sol";
import {Ownable} from "openzeppelin-contracts/contracts/access/Ownable.sol";
import {IWhitelistController} from "../interfaces/IWhitelistController.sol";
contract WhitelistController is IWhitelistController, AccessControl, Ownable {
mapping(bytes32 => IWhitelistController.RoleInfo) public roleInfo;
mapping(address => bytes32) public userInfo;
mapping(bytes32 => bool) public roleExists;
bytes32 private constant INTERNAL = bytes32("INTERNAL");
bytes32 private constant WHITELISTED_CONTRACTS = bytes32("WHITELISTED_CONTRACTS");
uint256 public constant BASIS_POINTS = 1e12;
constructor() {
IWhitelistController.RoleInfo memory DEFAULT_ROLE = IWhitelistController.RoleInfo(false, false, 3e10, 97e8);
bytes32 defaultRole = bytes32(0);
createRole(defaultRole, DEFAULT_ROLE);
}
function updateDefaultRole(uint256 _jglpRetention, uint256 _jusdcRetention) public onlyOwner {
IWhitelistController.RoleInfo memory NEW_DEFAULT_ROLE =
IWhitelistController.RoleInfo(false, false, _jglpRetention, _jusdcRetention);
bytes32 defaultRole = bytes32(0);
createRole(defaultRole, NEW_DEFAULT_ROLE);
}
function hasRole(bytes32 role, address account)
public
view
override(IWhitelistController, AccessControl)
returns (bool)
{
return super.hasRole(role, account);
}
function isInternalContract(address _account) public view returns (bool) {
return hasRole(INTERNAL, _account);
}
function isWhitelistedContract(address _account) public view returns (bool) {
return hasRole(WHITELISTED_CONTRACTS, _account);
}
function addToRole(bytes32 ROLE, address _account) public onlyOwner validRole(ROLE) {
_addRoleUser(ROLE, _account);
}
function addToInternalContract(address _account) public onlyOwner {
_grantRole(INTERNAL, _account);
}
function addToWhitelistContracts(address _account) public onlyOwner {
_grantRole(WHITELISTED_CONTRACTS, _account);
}
function bulkAddToWhitelistContracts(address[] calldata _accounts) public onlyOwner {
uint256 length = _accounts.length;
for (uint8 i = 0; i < length;) {
_grantRole(WHITELISTED_CONTRACTS, _accounts[i]);
unchecked {
++i;
}
}
}
function createRole(bytes32 _roleName, IWhitelistController.RoleInfo memory _roleInfo) public onlyOwner {
roleExists[_roleName] = true;
roleInfo[_roleName] = _roleInfo;
}
function _addRoleUser(bytes32 _role, address _user) internal {
userInfo[_user] = _role;
}
function getUserRole(address _user) public view returns (bytes32) {
return userInfo[_user];
}
function getDefaultRole() public view returns (IWhitelistController.RoleInfo memory) {
bytes32 defaultRole = bytes32(0);
return getRoleInfo(defaultRole);
}
function getRoleInfo(bytes32 _role) public view returns (IWhitelistController.RoleInfo memory) {
return roleInfo[_role];
}
function removeUserFromRole(address _user) public onlyOwner {
bytes32 zeroRole = bytes32(0x0);
userInfo[_user] = zeroRole;
}
function removeFromInternalContract(address _account) public onlyOwner {
_revokeRole(INTERNAL, _account);
}
function removeFromWhitelistContract(address _account) public onlyOwner {
_revokeRole(WHITELISTED_CONTRACTS, _account);
}
function bulkRemoveFromWhitelistContract(address[] calldata _accounts) public onlyOwner {
uint256 length = _accounts.length;
for (uint8 i = 0; i < length;) {
_revokeRole(WHITELISTED_CONTRACTS, _accounts[i]);
unchecked {
++i;
}
}
}
modifier validRole(bytes32 _role) {
require(roleExists[_role], "Role does not exist!");
_;
}
}
文件 51 的 51:draft-IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
{
"compilationTarget": {
"src/glp/rewards/JonesGlpCompoundRewards.sol": "JonesGlpCompoundRewards"
},
"evmVersion": "london",
"libraries": {
"src/adapters/Curve2PoolAdapter.sol:Curve2PoolAdapter": "0xae026e73a9f802fc2d26f3a5e394a22a00189505",
"src/adapters/GmxAdapter.sol:GmxAdapter": "0x405775be91aab1d06a3afbb5a1a6d2a5cf7f5d2a",
"src/adapters/SsovAdapter.sol:SsovAdapter": "0xaa6348bfedfa57ce6db54529074905897b3d5d47",
"src/adapters/SushiAdapter.sol:SushiAdapter": "0xf9d9f8d9141a59b5e6ad3a88f35b5010edad71a2",
"src/libraries/LPStrategyLib.sol:LPStrategyLib": "0xb330a28c8518c4095c8411191120d1739c2d8f60",
"src/libraries/OneInchZapLib.sol:OneInchZapLib": "0x46be03489b730ea8a38e4383fa2aabc0c9419fa5"
},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":ds-test/=lib/solmate/lib/ds-test/src/",
":forge-std/=lib/forge-std/src/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/",
":solmate/=lib/solmate/src/"
]
}
[{"inputs":[{"internalType":"uint256","name":"_stableRetentionPercentage","type":"uint256"},{"internalType":"uint256","name":"_glpRetentionPercentage","type":"uint256"},{"internalType":"contract IIncentiveReceiver","name":"_incentiveReceiver","type":"address"},{"internalType":"contract IJonesGlpRewardTracker","name":"_tracker","type":"address"},{"internalType":"contract GlpJonesRewards","name":"_jonesRewards","type":"address"},{"internalType":"contract IERC20","name":"_asset","type":"address"},{"internalType":"contract IERC20Metadata","name":"_vaultToken","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressCannotBeZeroAddress","type":"error"},{"inputs":[],"name":"AmountCannotBeZero","type":"error"},{"inputs":[],"name":"AmountExceedsStakedAmount","type":"error"},{"inputs":[],"name":"CallerIsNotAllowed","type":"error"},{"inputs":[],"name":"CallerIsNotGovernor","type":"error"},{"inputs":[],"name":"CallerIsNotKeeper","type":"error"},{"inputs":[],"name":"CallerIsNotOperator","type":"error"},{"inputs":[],"name":"RetentionPercentageOutOfRange","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_rewards","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_totalAssets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_retentions","type":"uint256"}],"name":"Compound","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_caller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","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":"_oldGovernor","type":"address"},{"indexed":false,"internalType":"address","name":"_newGovernor","type":"address"}],"name":"GovernorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_newKeeper","type":"address"}],"name":"KeeperAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_operator","type":"address"}],"name":"KeeperRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_newOperator","type":"address"}],"name":"OperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_operator","type":"address"}],"name":"OperatorRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","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":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_caller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"_assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"BASIS_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"KEEPER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPERATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newKeeper","type":"address"}],"name":"addKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOperator","type":"address"}],"name":"addOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","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 IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"compound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assets","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"emergencyGlpWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"emergencyStableWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"glp","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"glpRetentionPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gmxRouter","outputs":[{"internalType":"contract IGmxRewardRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"incentiveReceiver","outputs":[{"internalType":"contract IIncentiveReceiver","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"jonesRewards","outputs":[{"internalType":"contract GlpJonesRewards","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"receiptBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"}],"name":"removeKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"}],"name":"removeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"contract JonesGlpVaultRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Metadata","name":"_asset","type":"address"}],"name":"setAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IGmxRewardRouter","name":"_gmxRouter","type":"address"}],"name":"setGmxRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IIncentiveReceiver","name":"_incentiveReceiver","type":"address"}],"name":"setIncentiveReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract GlpJonesRewards","name":"_jonesRewards","type":"address"}],"name":"setJonesRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stableRetentionPercentage","type":"uint256"},{"internalType":"uint256","name":"_glpRetentionPercentage","type":"uint256"}],"name":"setNewRetentions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IJonesGlpRewardTracker","name":"_tracker","type":"address"}],"name":"setRewardTracker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract JonesGlpVaultRouter","name":"_router","type":"address"}],"name":"setRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20Metadata","name":"_vaultToken","type":"address"}],"name":"setVaultToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stableRetentionPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","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":"totalAssetsDeposits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"totalAssetsToDeposits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tracker","outputs":[{"internalType":"contract IJonesGlpRewardTracker","name":"","type":"address"}],"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":[{"internalType":"address","name":"_newGovernor","type":"address"}],"name":"updateGovernor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"usdc","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultToken","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]