diff --git a/.gitignore b/.gitignore index ccfe7796..42abb5cc 100644 --- a/.gitignore +++ b/.gitignore @@ -48,7 +48,6 @@ bin # temporary delete typechain/cacheIndex.ts -contracts/mock/MockEulerReactor.sol # foundry /out diff --git a/.solcover.js b/.solcover.js index 52d3166a..0e5ac45d 100644 --- a/.solcover.js +++ b/.solcover.js @@ -13,7 +13,6 @@ module.exports = { 'oracle/implementations/', // Router here is a copy pasta of the router in another repo 'router', - 'reactor/BaseReactorStorage.sol', 'vaultManager/VaultManagerStorage.sol', 'keeperMulticall/KeeperMulticall.sol', ], diff --git a/.solhint.json b/.solhint.json index 88814e51..0e017cc5 100644 --- a/.solhint.json +++ b/.solhint.json @@ -2,14 +2,25 @@ "extends": "solhint:recommended", "plugins": ["prettier"], "rules": { - "prettier/prettier": "warning", + "avoid-call-value": "warn", + "avoid-low-level-calls": "off", + "avoid-tx-origin": "warn", + "const-name-snakecase": "warn", + "contract-name-camelcase": "warn", + "imports-on-top": "warn", + "prettier/prettier": "off", "ordering": "off", + "max-states-count": "off", "mark-callable-contracts": "off", "no-empty-blocks": "off", + "no-global-import": "off", "not-rely-on-time": "off", "compiler-version": "off", - "private-vars-leading-underscore": "error", + "private-vars-leading-underscore": "warn", + "reentrancy": "warn", + "no-inline-assembly": "off", + "no-complex-fallback": "off", "reason-string": "off", - "func-visibility": ["error", { "ignoreConstructors": true }] + "func-visibility": ["warn", { "ignoreConstructors": true }] } } diff --git a/contracts/mock/MockReactor.sol b/contracts/mock/MockReactor.sol deleted file mode 100644 index 0cefc1d8..00000000 --- a/contracts/mock/MockReactor.sol +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only - -pragma solidity ^0.8.12; - -import "../reactor/BaseReactor.sol"; - -contract MockReactor is BaseReactor { - uint256 public counter; - uint256 public multiplier; - - function initialize( - string memory _name, - string memory _symbol, - IVaultManager _vaultManager, - uint64 _lowerCF, - uint64 _targetCF, - uint64 _upperCF, - uint64 _protocolInterestShare - ) external { - _initialize(_name, _symbol, _vaultManager, _lowerCF, _targetCF, _upperCF, _protocolInterestShare); - multiplier = 10**9; - } - - function _pull(uint256 amount) internal override returns (uint256) { - counter += 1; - return (amount * multiplier) / 10**9; - } - - function increaseAccumulator(uint256 amount) external { - protocolInterestAccumulated += amount; - } - - function setMultiplier(uint256 _multiplier) external { - multiplier = _multiplier; - } -} diff --git a/contracts/oracle/BaseOracleChainlinkMulti.sol b/contracts/oracle/BaseOracleChainlinkMulti.sol index bdcd7d17..84aa1d6b 100644 --- a/contracts/oracle/BaseOracleChainlinkMulti.sol +++ b/contracts/oracle/BaseOracleChainlinkMulti.sol @@ -99,8 +99,8 @@ abstract contract BaseOracleChainlinkMulti is IOracle { revert InvalidChainlinkRate(); uint256 castedRatio = uint256(ratio); // Checking whether we should multiply or divide by the ratio computed - if (multiplied == 1) return (quoteAmount * castedRatio) / (10**decimals); - else return (quoteAmount * (10**decimals)) / castedRatio; + if (multiplied == 1) return (quoteAmount * castedRatio) / (10 ** decimals); + else return (quoteAmount * (10 ** decimals)) / castedRatio; } // ======================= Governance Related Functions ======================== diff --git a/contracts/oracle/implementations/mainnet/EUR/OracleIB01EURChainlink.sol b/contracts/oracle/implementations/mainnet/EUR/OracleIB01EURChainlink.sol new file mode 100644 index 00000000..9e48c496 --- /dev/null +++ b/contracts/oracle/implementations/mainnet/EUR/OracleIB01EURChainlink.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity ^0.8.12; + +import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; + +import "../../../BaseOracleChainlinkMultiTwoFeeds.sol"; + +/// @title OracleIB01EURChainlink +/// @author Angle Labs, Inc. +/// @notice Gives the price of IB01 in Euro in base 18 +contract OracleIB01EURChainlink is BaseOracleChainlinkMultiTwoFeeds { + string public constant DESCRIPTION = "IB01/EUR Oracle"; + + constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {} + + /// @inheritdoc IOracle + function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) { + AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2); + // Oracle IB01/USD + _circuitChainlink[0] = AggregatorV3Interface(0x788D911ae7c95121A89A0f0306db65D87422E1de); + // Oracle EUR/USD + _circuitChainlink[1] = AggregatorV3Interface(0xb49f677943BC038e9857d61E7d053CaA2C1734C1); + return _circuitChainlink; + } +} diff --git a/contracts/oracle/implementations/mainnet/EUR/OracleUSDCEURChainlink.sol b/contracts/oracle/implementations/mainnet/EUR/OracleUSDCEURChainlink.sol new file mode 100644 index 00000000..8f385e83 --- /dev/null +++ b/contracts/oracle/implementations/mainnet/EUR/OracleUSDCEURChainlink.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity ^0.8.12; + +import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; + +import "../../../BaseOracleChainlinkMultiTwoFeeds.sol"; + +/// @title OracleUSDCEURChainlink +/// @author Angle Labs, Inc. +/// @notice Gives the price of USDC in Euro in base 18 +contract OracleUSDCEURChainlink is BaseOracleChainlinkMultiTwoFeeds { + string public constant DESCRIPTION = "USDC/EUR Oracle"; + + constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {} + + /// @inheritdoc IOracle + function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) { + AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2); + // Oracle USDC/USD + _circuitChainlink[0] = AggregatorV3Interface(0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6); + // Oracle EUR/USD + _circuitChainlink[1] = AggregatorV3Interface(0xb49f677943BC038e9857d61E7d053CaA2C1734C1); + return _circuitChainlink; + } +} diff --git a/contracts/reactor/BaseReactor.sol b/contracts/reactor/BaseReactor.sol deleted file mode 100644 index f64cb310..00000000 --- a/contracts/reactor/BaseReactor.sol +++ /dev/null @@ -1,616 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only - -pragma solidity ^0.8.12; - -import "./BaseReactorStorage.sol"; - -/// @title BaseReactor -/// @notice Reactor for using a token as collateral for agTokens. ERC4646 tokenized Vault implementation. -/// @author Angle Labs, Inc., based on Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/mixins/ERC4626.sol) -/// @dev A token used as an asset built to exploit this reactor could perform reentrancy attacks if not enough checks -/// are performed: as such the protocol implements reentrancy checks on all external entry point -abstract contract BaseReactor is BaseReactorStorage, ERC20Upgradeable, IERC721ReceiverUpgradeable, IERC4626 { - using SafeERC20 for IERC20; - - /// @notice Initializes the `BaseReactor` contract and the underlying `VaultManager` - /// @param _name Name of the ERC4626 token - /// @param _symbol Symbol of the ERC4626 token - /// @param _vaultManager Underlying `VaultManager` used to borrow stablecoin - /// @param _lowerCF Lower Collateral Factor accepted without rebalancing - /// @param _targetCF Target Collateral Factor - /// @param _upperCF Upper Collateral Factor accepted without rebalancing - /// @param _protocolInterestShare Share of the profit (or losses) from strategies going to the protocol - function _initialize( - string memory _name, - string memory _symbol, - IVaultManager _vaultManager, - uint64 _lowerCF, - uint64 _targetCF, - uint64 _upperCF, - uint64 _protocolInterestShare - ) internal initializer { - __ERC20_init(_name, _symbol); - vaultManager = _vaultManager; - stablecoin = _vaultManager.stablecoin(); - IERC20 _asset = _vaultManager.collateral(); - treasury = _vaultManager.treasury(); - oracle = _vaultManager.oracle(); - vaultManagerDust = _vaultManager.dust(); - asset = _asset; - _assetBase = 10**(IERC20Metadata(address(_asset)).decimals()); - lastTime = block.timestamp; - - vaultID = _vaultManager.createVault(address(this)); - - if ( - 0 == _lowerCF || - _lowerCF > _targetCF || - _targetCF > _upperCF || - _upperCF > _vaultManager.collateralFactor() || - _protocolInterestShare > BASE_PARAMS - ) revert InvalidSetOfParameters(); - lowerCF = _lowerCF; - targetCF = _targetCF; - upperCF = _upperCF; - protocolInterestShare = _protocolInterestShare; - - asset.approve(address(vaultManager), type(uint256).max); - } - - // ============================== Modifiers ==================================== - - /// @notice Checks whether the `msg.sender` has the governor role or not - modifier onlyGovernor() { - if (!treasury.isGovernor(msg.sender)) revert NotGovernor(); - _; - } - - /// @notice Checks whether the `msg.sender` has the governor role or the guardian role - modifier onlyGovernorOrGuardian() { - if (!treasury.isGovernorOrGuardian(msg.sender)) revert NotGovernorOrGuardian(); - _; - } - - // ========================= External Access Functions ========================= - - /// @inheritdoc IERC4626 - function deposit(uint256 assets, address to) external nonReentrant returns (uint256 shares) { - (uint256 usedAssets, uint256 looseAssets) = _getAssets(); - shares = _convertToShares(assets, usedAssets + looseAssets, 0); - if (shares == 0) revert ZeroShares(); - _deposit(assets, shares, to, usedAssets, looseAssets + assets); - } - - /// @inheritdoc IERC4626 - function mint(uint256 shares, address to) external nonReentrant returns (uint256 assets) { - (uint256 usedAssets, uint256 looseAssets) = _getAssets(); - uint256 totalSupply = totalSupply(); - assets = _convertToAssets(shares, usedAssets + looseAssets, totalSupply); - assets += (_convertToShares(assets, usedAssets + looseAssets, totalSupply) < shares ? 1 : 0); - _deposit(assets, shares, to, usedAssets, looseAssets + assets); - } - - /// @inheritdoc IERC4626 - /// @dev The amount of assets specified should be smaller than the amount of assets controlled by the - /// reactor - /// @dev `assets` should also be inferior to maxWithdraw(from) - function withdraw( - uint256 assets, - address to, - address from - ) external nonReentrant returns (uint256 shares) { - (uint256 usedAssets, uint256 looseAssets) = _getAssets(); - uint256 totalSupply = totalSupply(); - shares = _convertToShares(assets, usedAssets + looseAssets, totalSupply); - shares += (_convertToAssets(shares, usedAssets + looseAssets, totalSupply) < assets ? 1 : 0); - _withdraw(assets, shares, to, from, usedAssets, looseAssets); - } - - /// @notice Rebalances the underlying vault - function rebalance() external nonReentrant { - (uint256 usedAssets, uint256 looseAssets) = _getAssets(); - _rebalance(0, usedAssets, looseAssets); - } - - /// @inheritdoc IERC4626 - /// @dev `shares` should be inferior to maxRedeem(from) - function redeem( - uint256 shares, - address to, - address from - ) external nonReentrant returns (uint256 assets) { - (uint256 usedAssets, uint256 looseAssets) = _getAssets(); - assets = _convertToAssets(shares, usedAssets + looseAssets, 0); - if (assets == 0) revert ZeroAssets(); - _withdraw(assets, shares, to, from, usedAssets, looseAssets); - } - - /// @notice Claims earned rewards - /// @param from Address to claim for - /// @return Amount claimed - function claim(address from) external nonReentrant returns (uint256) { - _updateAccumulator(from); - return _claim(from); - } - - // ============================= View Functions ================================ - - /// @inheritdoc IERC4626 - function totalAssets() public view returns (uint256 assets) { - (uint256 usedAssets, uint256 looseAssets) = _getAssets(); - assets = usedAssets + looseAssets; - } - - /// @inheritdoc IERC4626 - function convertToShares(uint256 assets) public view returns (uint256) { - return _convertToShares(assets, totalAssets(), 0); - } - - /// @inheritdoc IERC4626 - function convertToAssets(uint256 shares) public view returns (uint256) { - return _convertToAssets(shares, totalAssets(), 0); - } - - /// @inheritdoc IERC4626 - function previewDeposit(uint256 assets) external view returns (uint256) { - return convertToShares(assets); - } - - /// @inheritdoc IERC4626 - function previewMint(uint256 shares) external view returns (uint256) { - uint256 totalAssetAmount = totalAssets(); - uint256 totalSupply = totalSupply(); - uint256 assets = _convertToAssets(shares, totalAssetAmount, totalSupply); - return assets + (_convertToShares(assets, totalAssetAmount, totalSupply) < shares ? 1 : 0); - } - - /// @notice Computes how many shares one would need to withdraw assets - /// @param assets Amount of asset to withdraw - /// @inheritdoc IERC4626 - function previewWithdraw(uint256 assets) external view returns (uint256) { - uint256 totalAssetAmount = totalAssets(); - uint256 totalSupply = totalSupply(); - uint256 shares = _convertToShares(assets, totalAssetAmount, totalSupply); - return shares + (_convertToAssets(shares, totalAssetAmount, totalSupply) < assets ? 1 : 0); - } - - /// @notice Computes how many assets one would get by burning shares - /// @param shares Amount of shares to burn - /// @inheritdoc IERC4626 - function previewRedeem(uint256 shares) external view returns (uint256) { - return convertToAssets(shares); - } - - /// @inheritdoc IERC4626 - /// @dev Technically, the maximum deposit could be less than the max uint256 - /// if there is a `debtCeiling` in the associated `VaultManager`. This implementation - /// assumes that the `VaultManager` does not have any debt ceiling - function maxDeposit(address) public view virtual returns (uint256) { - return type(uint256).max; - } - - /// @inheritdoc IERC4626 - function maxMint(address) external view virtual returns (uint256) { - return type(uint256).max; - } - - /// @inheritdoc IERC4626 - function maxWithdraw(address user) public view virtual returns (uint256) { - return convertToAssets(balanceOf(user)); - } - - /// @inheritdoc IERC4626 - function maxRedeem(address user) external view virtual returns (uint256) { - return balanceOf(user); - } - - /// @inheritdoc IERC721ReceiverUpgradeable - function onERC721Received( - address, - address, - uint256, - bytes memory - ) external view returns (bytes4) { - if (msg.sender != address(vaultManager)) revert NotVaultManager(); - return this.onERC721Received.selector; - } - - // =========================== Internal Functions ============================== - - /// @notice Gets the assets controlled by the reactor: those in the associated vaultManager - /// as well as those in the contract - /// @return usedAssets Amount of the `asset` in the associated `VaultManager` - /// @return looseAssets Amount of the `asset` in the contract - function _getAssets() internal view returns (uint256 usedAssets, uint256 looseAssets) { - (usedAssets, ) = vaultManager.vaultData(vaultID); - looseAssets = asset.balanceOf(address(this)); - } - - /// @notice Converts an amount of assets to shares of the reactor from an amount of assets controlled by the vault - /// @param assets Amount of assets to convert - /// @param totalAssetAmount Total amount of asset controlled by the vault - /// @param _supply Optional value of the total supply of the reactor, it is recomputed if zero - /// @return Corresponding amount of shares - function _convertToShares( - uint256 assets, - uint256 totalAssetAmount, - uint256 _supply - ) internal view returns (uint256) { - uint256 supply = _supply == 0 ? totalSupply() : _supply; - return supply == 0 ? assets : (assets * supply) / totalAssetAmount; - } - - /// @notice Converts an amount of shares of the reactor to assets - /// @param shares Amount of shares to convert - /// @param totalAssetAmount Total amount of asset controlled by the vault - /// @param _supply Optional value of the total supply of the reactor, it is recomputed if zero - /// @return Corresponding amount of assets - /// @dev It is at the level of this function that losses from liquidations are taken into account, because this - /// reduces the `totalAssetAmount` and hence the amount of assets you are entitled to get from your shares - function _convertToAssets( - uint256 shares, - uint256 totalAssetAmount, - uint256 _supply - ) internal view returns (uint256) { - uint256 supply = _supply == 0 ? totalSupply() : _supply; - return supply == 0 ? shares : (shares * totalAssetAmount) / supply; - } - - /// @notice Handles the new value of the debt: propagates a loss to the claimable rewards - /// or a gain depending on the evolution of this debt - /// @param currentDebt Current value of the debt - /// @notice In the case where you get liquidated, you actually record a gain in stablecoin, - /// which is normal to compensate for the decrease of the collateral in the vault - /// @dev In case where a loss (like from interest taken by the `VaultManager`) is planned, then stakeholders - /// are incentivized to front run it and claim their rewards in advance. In normal times, this reactor therefore - /// works well mostly with `VaultManager` on which there are no interest taken (and no borrowing fees) - function _handleCurrentDebt(uint256 currentDebt) internal { - if (lastDebt >= currentDebt) { - // This happens if you have been liquidated or if debt has been paid on your behalf - _handleGain(lastDebt - currentDebt); - } else { - _handleLoss(currentDebt - lastDebt); - } - } - - /// @notice Propagates a gain to the claimable rewards - /// @param gain Gain to propagate - function _handleGain(uint256 gain) internal { - uint256 currentLossVariable = currentLoss; - if (currentLossVariable >= gain) { - currentLoss -= gain; - } else { - claimableRewards += gain - currentLossVariable; - currentLoss = 0; - } - } - - /// @notice Propagates a loss to the claimable rewards and/or currentLoss - /// @param loss Loss to propagate - function _handleLoss(uint256 loss) internal { - if (claimableRewards >= loss) { - claimableRewards -= loss; - } else { - currentLoss += loss - claimableRewards; - claimableRewards = 0; - } - } - - /// @notice Rebalances the underlying vault - /// @param toWithdraw Amount of assets to withdraw - /// @param usedAssets Amount of assets in the vault - /// @param looseAssets Amount of assets already in the contract - /// @dev `toWithdraw` is always lower than managed assets (`= usedAssets+looseAssets`): indeed if it was superior - /// it would mean either - /// - that the `withdraw` function was called with an amount of assets greater than the amount of asset controlled - /// by the reactor - /// - or that the `redeem` function was called with an amount of shares greater than the total supply - /// @dev `usedAssets` and `looseAssets` are passed as parameters here to avoid performing the same calculation twice - function _rebalance( - uint256 toWithdraw, - uint256 usedAssets, - uint256 looseAssets - ) internal { - uint256 debt = vaultManager.getVaultDebt(vaultID); - _handleCurrentDebt(debt); - lastDebt = debt; - - uint256 toRepay; - uint256 toBorrow; - - (uint256 futureStablecoinsInVault, uint256 collateralFactor) = _getFutureDebtAndCF( - toWithdraw, - usedAssets, - looseAssets, - debt, - oracle.read() - ); - - // 1 action to add or remove collateral + 1 additional action if we need to borrow or repay - uint8 len = (collateralFactor >= upperCF) || - (collateralFactor <= lowerCF && futureStablecoinsInVault > vaultManagerDust) - ? 2 - : 1; - - ActionType[] memory actions = new ActionType[](len); - bytes[] memory datas = new bytes[](len); - - len = 0; - - if (toWithdraw <= looseAssets) { - // Add Collateral - actions[len] = ActionType.addCollateral; - datas[len] = abi.encodePacked(vaultID, looseAssets - toWithdraw); - len += 1; - } - - // Dust is also handled here to avoid reverting calls: if repaying the debt would leave a dusty - // amount then all the debt is repaid - // If borrowing would only create a dusty debt amount, then nothing happens - if (collateralFactor >= upperCF) { - // If the `collateralFactor` is too high, then too much has been borrowed - // and stablecoins should be repaid - actions[len] = ActionType.repayDebt; - toRepay = debt - futureStablecoinsInVault; - lastDebt -= toRepay; - if (futureStablecoinsInVault <= vaultManagerDust) { - // If this happens in a moment at which the reactor has a loss, then it will not be able - // to repay it all, and the function will revert - toRepay = type(uint256).max; - lastDebt = 0; - } - datas[len] = abi.encodePacked(vaultID, toRepay); - len += 1; - } else if (collateralFactor <= lowerCF && futureStablecoinsInVault > vaultManagerDust) { - // If the `collateralFactor` is too low, then stablecoins can be borrowed and later - // invested in strategies - toBorrow = futureStablecoinsInVault - debt; - actions[len] = ActionType.borrow; - datas[len] = abi.encodePacked(vaultID, toBorrow); - len += 1; - // We don't directly update the debt in this contract as there may be some rounding issues - } - - if (toWithdraw > looseAssets) { - // Removes Collateral - actions[len] = ActionType.removeCollateral; - datas[len] = abi.encodePacked(vaultID, toWithdraw - looseAssets); - } - - if (toRepay != 0) { - toRepay = toRepay == type(uint256).max ? debt : toRepay; - _pull(toRepay); - } - - PaymentData memory paymentData = vaultManager.angle( - actions, - datas, - address(this), - address(this), - address(this), - "" - ); - - // VaultManagers always round to their advantages + there can be a borrow fee taken - if (toBorrow != 0) { - lastDebt += paymentData.stablecoinAmountToGive; - // If there is a borrow fee, then it will be seen as a loss at the next rebalance - _push(paymentData.stablecoinAmountToGive); - } - } - - /// @notice Computes future debt to the `vaultManager` and the collateral factor of the current debt with future assets - /// @param toWithdraw Amount of assets to withdraw - /// @param usedAssets Amount of assets in the vault - /// @param looseAssets Amount of assets already in the contract - /// @param debt Current debt owed to the `vaultManager` - /// @param oracleRate Exchange rate from asset to stablecoin - /// @return futureStablecoinsInVault Future amount of stablecoins borrowed in the vault - /// if this vault is at `targetCF` at the end of the call - /// @return collateralFactor Collateral factor of the vault if its debt remains unchanged but `toWithdraw` collateral - /// is removed from it - function _getFutureDebtAndCF( - uint256 toWithdraw, - uint256 usedAssets, - uint256 looseAssets, - uint256 debt, - uint256 oracleRate - ) internal view returns (uint256 futureStablecoinsInVault, uint256 collateralFactor) { - // We're first using as an intermediate in this variable something that does not correspond - // to the future amount of stablecoins borrowed in the vault: it is the future collateral amount in - // the vault expressed in stablecoin value and in a custom base - futureStablecoinsInVault = (usedAssets + looseAssets - toWithdraw) * oracleRate; - // The function will revert above if `toWithdraw` is too big - - if (futureStablecoinsInVault == 0) collateralFactor = type(uint256).max; - else { - collateralFactor = (debt * BASE_PARAMS * _assetBase) / futureStablecoinsInVault; - } - // This is the targeted debt at the end of the call, which might not be reached if the collateral - // factor is not moved enough - futureStablecoinsInVault = (futureStablecoinsInVault * targetCF) / (BASE_PARAMS * _assetBase); - } - - /// @notice Virtual function to invest stablecoins - /// @param amount Amount of new stablecoins managed - /// @return amountInvested Amount invested in the strategy - /// @dev Calling this function should eventually trigger something regarding strategies depending - /// on a threshold - function _push(uint256 amount) internal virtual returns (uint256 amountInvested) {} - - /// @notice Virtual function to withdraw stablecoins to the reactor: full amounts may not be available - /// @param amount Amount needed at the end of the call - /// @return amountAvailable Amount available in the contracts, it's like a new `looseAssets` value - function _pull(uint256 amount) internal virtual returns (uint256 amountAvailable) {} - - /// @notice Claims rewards earned by a user - /// @param from Address to claim rewards from - /// @return amount Amount claimed by the user - /// @dev Function will revert if there has been no mint - function _claim(address from) internal returns (uint256 amount) { - amount = (claimableRewards * rewardsAccumulatorOf[from]) / (rewardsAccumulator - claimedRewardsAccumulator); - uint256 amountAvailable = _pull(amount); - // If we cannot pull enough from the strat then `claim` has no effect - if (amountAvailable >= amount) { - claimedRewardsAccumulator += rewardsAccumulatorOf[from]; - rewardsAccumulatorOf[from] = 0; - lastTimeOf[from] = block.timestamp; - claimableRewards -= amount; - stablecoin.transfer(from, amount); - } - } - - /// @notice Updates global and `msg.sender` accumulator and rewards share - /// @param from Address balance changed - function _updateAccumulator(address from) internal { - rewardsAccumulator += (block.timestamp - lastTime) * totalSupply(); - lastTime = block.timestamp; - - // This will be 0 on the first deposit since the balance is initialized later - rewardsAccumulatorOf[from] += (block.timestamp - lastTimeOf[from]) * balanceOf(from); - lastTimeOf[from] = block.timestamp; - } - - /// @notice Internal function for `deposit` and `mint` - /// @dev This function takes `usedAssets` and `looseAssets` as parameters to avoid repeated external calls - function _deposit( - uint256 assets, - uint256 shares, - address to, - uint256 usedAssets, - uint256 looseAssets - ) internal { - // Need to transfer before minting or ERC777s could reenter. - asset.safeTransferFrom(msg.sender, address(this), assets); - _updateAccumulator(to); - _mint(to, shares); - - emit Deposit(msg.sender, to, assets, shares); - - _rebalance(0, usedAssets, looseAssets); - } - - /// @notice Internal function for `redeem` and `withdraw` - /// @dev This function takes `usedAssets` and `looseAssets` as parameters to avoid repeated external calls - function _withdraw( - uint256 assets, - uint256 shares, - address to, - address from, - uint256 usedAssets, - uint256 looseAssets - ) internal { - if (msg.sender != from) { - uint256 currentAllowance = allowance(from, msg.sender); - if (currentAllowance < shares) revert TransferAmountExceedsAllowance(); - if (currentAllowance != type(uint256).max) { - unchecked { - _approve(from, msg.sender, currentAllowance - shares); - } - } - } - - _updateAccumulator(from); - _burn(from, shares); - - _rebalance(assets, usedAssets, looseAssets); - - _claim(from); - - emit Withdraw(from, to, assets, shares); - asset.safeTransfer(to, assets); - } - - // ======================== Governance Functions =============================== - - /// @notice Changes the reference to the `oracle` contract - /// @dev This is a permissionless function anyone can call to make sure that the oracle - /// contract of the `VaultManager` is the same as the oracle contract of this contract - function setOracle() external { - oracle = vaultManager.oracle(); - } - - /// @notice Changes the treasury contract - /// @dev Like the function above, this permissionless function just adjusts the treasury to - /// the address of the treasury contract from the `VaultManager` in case it has been modified - function setTreasury() external { - treasury = vaultManager.treasury(); - } - - /// @notice Changes the dust parameter by querying the `VaultManager` - function setDust() external { - vaultManagerDust = vaultManager.dust(); - } - - /// @notice Sets parameters encoded as uint64 - /// @param param Value for the parameter - /// @param what Parameter to change - /// @dev This function performs the required checks when updating a parameter - function setUint64(uint64 param, bytes32 what) external onlyGovernorOrGuardian { - if (what == "lowerCF") { - if (0 == param || param > targetCF) revert InvalidParameterValue(); - lowerCF = param; - } else if (what == "targetCF") { - if (lowerCF > param || param > upperCF) revert InvalidParameterValue(); - targetCF = param; - } else if (what == "upperCF") { - if (targetCF > param || param > vaultManager.collateralFactor()) revert InvalidParameterValue(); - upperCF = param; - } else if (what == "protocolInterestShare") { - if (param > BASE_PARAMS) revert TooHighParameterValue(); - protocolInterestShare = param; - } else { - revert InvalidParameterType(); - } - emit FiledUint64(param, what); - } - - function setSurplusManager(address _newSurplusManager) external onlyGovernorOrGuardian { - if (_newSurplusManager == address(0)) revert ZeroAddress(); - surplusManager = _newSurplusManager; - } - - /// @notice Allows to recover any ERC20 token, including the asset managed by the reactor - /// @param tokenAddress Address of the token to recover - /// @param to Address of the contract to send collateral to - /// @param amountToRecover Amount of collateral to transfer - /// @dev Can be used to handle partial liquidation and debt repayment in case it is needed: in this - /// case governance can withdraw assets, swap in stablecoins to repay debt - function recoverERC20( - address tokenAddress, - address to, - uint256 amountToRecover - ) external onlyGovernor { - if (tokenAddress == address(stablecoin)) revert InvalidToken(); - IERC20(tokenAddress).safeTransfer(to, amountToRecover); - emit Recovered(tokenAddress, to, amountToRecover); - } - - /// @notice Pulls the fees accumulated by the protocol from its strategies - /// @param to Address to which tokens should be sent - function pushProtocolFees(address to) external { - if (to == address(0)) revert ZeroAddress(); - if (to != surplusManager) { - if (!treasury.isGovernorOrGuardian(msg.sender)) revert NotGovernorOrGuardian(); - } - uint256 amountToRecover = protocolInterestAccumulated; - uint256 amountAvailable = _pull(amountToRecover); - amountToRecover = amountToRecover <= amountAvailable ? amountToRecover : amountAvailable; - protocolInterestAccumulated -= amountToRecover; - stablecoin.transfer(to, amountToRecover); - } -} - -contract Reactor is BaseReactor { - function initialize( - string memory _name, - string memory _symbol, - IVaultManager _vaultManager, - uint64 _lowerCF, - uint64 _targetCF, - uint64 _upperCF, - uint64 _protocolInterestShare - ) external { - _initialize(_name, _symbol, _vaultManager, _lowerCF, _targetCF, _upperCF, _protocolInterestShare); - } -} diff --git a/contracts/reactor/BaseReactorStorage.sol b/contracts/reactor/BaseReactorStorage.sol deleted file mode 100644 index 3af477a5..00000000 --- a/contracts/reactor/BaseReactorStorage.sol +++ /dev/null @@ -1,107 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only - -pragma solidity ^0.8.12; - -import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; -import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; -import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol"; -import "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; -import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; - -import "../interfaces/external/IERC4626.sol"; -import "../interfaces/IVaultManager.sol"; - -/// @title BaseReactorStorage -/// @author Angle Labs, Inc. -/// @dev Variables, references, parameters and events needed in the `BaseReactor` contract -// solhint-disable-next-line max-states-count -contract BaseReactorStorage is Initializable, ReentrancyGuardUpgradeable { - /// @notice Base used for parameter computation - uint256 public constant BASE_PARAMS = 10**9; - - // =============================== References ================================== - - /// @notice Reference to the asset controlled by this reactor - IERC20 public asset; - /// @notice Reference to the stablecoin this reactor handles - IAgToken public stablecoin; - /// @notice Oracle giving the price of the asset with respect to the stablecoin - IOracle public oracle; - /// @notice Treasury contract handling access control - ITreasury public treasury; - /// @notice VaultManager contract on which this contract has a vault. All references should - /// be fetched from here - IVaultManager public vaultManager; - /// @notice ID of the vault handled by this contract - uint256 public vaultID; - /// @notice Dust parameter for the stablecoins in a vault in `VaultManager` - uint256 public vaultManagerDust; - /// @notice Base of the `asset`. While it is assumed in this contract that the base of the stablecoin is 18, - /// the base of the `asset` may not be 18 - uint256 internal _assetBase; - - // =============================== Parameters ================================== - - /// @notice Lower value of the collateral factor: below this the reactor can borrow stablecoins - uint64 public lowerCF; - /// @notice Value of the collateral factor targeted by this vault - uint64 public targetCF; - /// @notice Value of the collateral factor above which stablecoins should be repaid to avoid liquidations - uint64 public upperCF; - /// @notice Value of the fees going to the protocol at each yield gain from the strategy - uint64 public protocolInterestShare; - /// @notice Address responsible for handling the surplus of the protocol - address public surplusManager; - - // =============================== Variables =================================== - - /// @notice Protocol fee surplus: the protocol should only accumulate yield from the strategies and not make a gain - /// in situations where there are liquidations or so. - uint256 public protocolInterestAccumulated; - /// @notice Loss accumulated to be taken from the protocol - uint256 public protocolDebt; - /// @notice Rewards (in stablecoin) claimable by depositors of the reactor - uint256 public claimableRewards; - /// @notice Loss (in stablecoin) accumulated by the reactor: it's going to prevent the reactor from - /// repaying its debt - uint256 public currentLoss; - /// @notice Used to track rewards accumulated by all depositors of the reactor - uint256 public rewardsAccumulator; - /// @notice Tracks rewards already claimed by all depositors - uint256 public claimedRewardsAccumulator; - /// @notice Last time rewards were claimed in the reactor - uint256 public lastTime; - /// @notice Last known stable debt to the `VaultManager` - uint256 public lastDebt; - - /// @notice Maps an address to the last time it claimed its rewards - mapping(address => uint256) public lastTimeOf; - /// @notice Maps an address to a quantity depending on time and shares of the reactors used - /// to compute the rewards an address can claim - mapping(address => uint256) public rewardsAccumulatorOf; - - uint256[50] private __gap; - - // =============================== Events ====================================== - - event FiledUint64(uint64 param, bytes32 what); - event Recovered(address indexed token, address indexed to, uint256 amount); - - // =============================== Errors ====================================== - - error InvalidParameterValue(); - error InvalidParameterType(); - error InvalidSetOfParameters(); - error InvalidToken(); - error NotGovernor(); - error NotGovernorOrGuardian(); - error NotVaultManager(); - error TooHighParameterValue(); - error TransferAmountExceedsAllowance(); - error ZeroAddress(); - error ZeroAssets(); - error ZeroShares(); - - /// @custom:oz-upgrades-unsafe-allow constructor - constructor() initializer {} -} diff --git a/contracts/reactor/EulerReactor.sol b/contracts/reactor/EulerReactor.sol deleted file mode 100644 index e8567e1f..00000000 --- a/contracts/reactor/EulerReactor.sol +++ /dev/null @@ -1,248 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only - -pragma solidity ^0.8.12; - -import "../interfaces/external/euler/IEulerMarket.sol"; - -import "./BaseReactor.sol"; - -/// @title EulerReactor -/// @notice Reactor to mint agEUR and deposit them on Euler Finance (https://www.euler.finance/) -/// @notice Euler markets only work with token with decimal <= 18 -/// @author Angle Labs, Inc. -contract EulerReactor is BaseReactor { - using SafeERC20 for IERC20; - - IEulerEToken public euler; - uint256 public lastBalance; - uint256 public minInvest; - - // =============================== Events ====================================== - - event MinInvestUpdated(uint256); - - /// @notice Initializes the `BaseReactor` contract and the underlying `VaultManager` - /// @param _name Name of the ERC4626 token - /// @param _symbol Symbol of the ERC4626 token - /// @param _vaultManager Underlying `VaultManager` used to borrow stablecoin - /// @param _lowerCF Lower Collateral Factor accepted without rebalancing - /// @param _targetCF Target Collateral Factor - /// @param _upperCF Upper Collateral Factor accepted without rebalancing - function initialize( - IEulerEToken _euler, - uint256 minInvest_, - string memory _name, - string memory _symbol, - IVaultManager _vaultManager, - uint64 _lowerCF, - uint64 _targetCF, - uint64 _upperCF, - uint64 _protocolInterestShare - ) external { - euler = _euler; - minInvest = minInvest_; - _initialize(_name, _symbol, _vaultManager, _lowerCF, _targetCF, _upperCF, _protocolInterestShare); - IERC20(address(stablecoin)).safeApprove(address(euler), type(uint256).max); - } - - /// @inheritdoc IERC4626 - /// @dev Users are limited by the `debtCeiling` in the associated `VaultManager` and the `maxExternalAmount` defined on Euler - /// @dev A given user address has no impact on the `maxDeposit`: conditions are the same for every users - /// @dev Contrary to `maxWithdraw` you don't need to check conditions on upperCF - function maxDeposit(address) public view override returns (uint256 maxAssetDeposit) { - (uint256 usedAssets, uint256 looseAssets) = _getAssets(); - uint256 debt = vaultManager.getVaultDebt(vaultID); - uint256 debtCeiling = vaultManager.debtCeiling(); - uint256 availableStablecoins = debtCeiling - vaultManager.getTotalDebt(); - // Angle stablecoins are in base 18 no scaling needed - uint256 maxDepositEuler = euler.MAX_SANE_AMOUNT(); - // By default you can deposit maxUint if there are no restrictions - maxAssetDeposit = type(uint256).max; - // debtCeiling max value is `type(uint256).max / BASE_INTEREST` (otherwise it could overflow in the `VaultManager`) - if (debtCeiling != (type(uint256).max / 10**27) || maxDepositEuler != type(uint112).max) { - // If there is a debt ceiling or a max Euler deposit, then the max deposit for a user is the amount of collateral - // such that borrowing against it would exceed this debt ceiling - uint256 oracleRate = oracle.read(); - if (availableStablecoins >= maxDepositEuler) availableStablecoins = maxDepositEuler; - uint256 newDebt = availableStablecoins + debt; - maxAssetDeposit = (newDebt * _assetBase * BASE_PARAMS) / targetCF; - uint256 collateralFactor = (debt * BASE_PARAMS * _assetBase) / maxAssetDeposit; - // If CF is larger than lowerCF then no borrow will be made and user can deposit up until reaching a CF of lowerCF - if (collateralFactor > lowerCF) { - maxAssetDeposit = (debt * _assetBase * BASE_PARAMS) / lowerCF; - } - maxAssetDeposit = (maxAssetDeposit / oracleRate) - usedAssets - looseAssets; - } - } - - /// @inheritdoc IERC4626 - /// @param user Address of the user who will interact with the contract - /// @dev user address has no impact on the maxMint - function maxMint(address user) public view override returns (uint256) { - return convertToShares(maxDeposit(user)); - } - - /// @inheritdoc IERC4626 - /// @dev Users are limited in the amount to be withdrawn by liquidity on Euler contracts - /// @dev We do not take into account the `claim(amount)` call in these computations - function maxWithdraw(address user) public view virtual override returns (uint256) { - (uint256 usedAssets, uint256 looseAssets) = _getAssets(); - uint256 toWithdraw = _convertToAssets(balanceOf(user), usedAssets + looseAssets, 0); - if (toWithdraw <= looseAssets) return toWithdraw; - else return looseAssets + _maxAmountWithdrawable(toWithdraw, usedAssets, looseAssets); - } - - /// @inheritdoc IERC4626 - /// @dev Users are limited in the amount to be withdrawn by liquidity on Euler contracts - function maxRedeem(address user) public view virtual override returns (uint256) { - return convertToShares(maxWithdraw(user)); - } - - function setMinInvest(uint256 minInvest_) public onlyGovernorOrGuardian { - minInvest = minInvest_; - emit MinInvestUpdated(minInvest_); - } - - /// @notice Changes allowance of this contract to Euler deposit contract - /// @param amount Amount allowed - function changeAllowance(uint256 amount) external onlyGovernorOrGuardian { - uint256 currentAllowance = IERC20(address(stablecoin)).allowance(address(this), address(euler)); - if (currentAllowance < amount) { - IERC20(address(stablecoin)).safeIncreaseAllowance(address(euler), amount - currentAllowance); - } else if (currentAllowance > amount) { - IERC20(address(stablecoin)).safeDecreaseAllowance(address(euler), currentAllowance - amount); - } - } - - /// @notice Returns the maximum amount of assets that can be withdrawn considering current Euler liquidity - /// @param amount Amount of assets wanted to be withdrawn - /// @param usedAssets Amount of assets collateralizing the vault - /// @param looseAssets Amount of assets directly accessible in the contract balance - /// @return maxAmount Max amount of assets that can be withdrawn from the reactor considering Euler liquidity - /// for the stablecoin - /// @dev If reaching the `upperCF`, users are limited in the amount to be withdrawn by liquidity on Euler contracts - function _maxAmountWithdrawable( - uint256 amount, - uint256 usedAssets, - uint256 looseAssets - ) internal view returns (uint256 maxAmount) { - uint256 toWithdraw = amount - looseAssets; - uint256 oracleRate = oracle.read(); - - uint256 debt = vaultManager.getVaultDebt(vaultID); - (uint256 futureStablecoinsInVault, uint256 collateralFactor) = _getFutureDebtAndCF( - toWithdraw, - usedAssets, - looseAssets, - debt, - oracleRate - ); - - // Initialisation that users can withdraw it all, if it can't then maxAmount will be updated - // This equality will stand if: - // 1) collateralFactor < upperCF: contract does not need to repay debt and therefore do not need to remove Euler Liquidity - // 2) looseStablecoins >= stablecoinsValueToRedeem : debt to be repaid is lower than the reactor stablecoin balance - // 3) Euler liquidity available to the reactor is larger than the debt to be repaid - maxAmount = toWithdraw; - - uint256 stablecoinsValueToRedeem; - // If the collateral factor after a withdraw goes above upperCF, we need to repay stablecoins to free collateral, - // and therefore we need to withdraw liquidity on Euler. - // If both the reactor balance on Euler and poolSize (available liquidity on Euler) are larger than the needed - // stablecoins --> users can withdraw `toWithdraw`, in the other case it's not possible - // Computation here mimics the `_rebalance()` function in a case of a withdraw - if (collateralFactor >= upperCF) { - stablecoinsValueToRedeem = debt - futureStablecoinsInVault; - if (futureStablecoinsInVault <= vaultManagerDust) { - stablecoinsValueToRedeem = type(uint256).max; - } - // Takes into account non invested stablecoins as they are at hand - uint256 looseStablecoins = stablecoin.balanceOf(address(this)); - if (stablecoinsValueToRedeem > looseStablecoins) { - stablecoinsValueToRedeem -= looseStablecoins; - // Liquidity on Euler - uint256 poolSize = stablecoin.balanceOf(address(euler)); - uint256 reactorBalanceEuler = euler.balanceOfUnderlying(address(this)); - uint256 maxEulerWithdrawal = poolSize > reactorBalanceEuler ? reactorBalanceEuler : poolSize; - // if we can fully reimburse with Euler liquidity then users can withdraw their whole balance - if (maxEulerWithdrawal < stablecoinsValueToRedeem) { - stablecoinsValueToRedeem = maxEulerWithdrawal; - maxAmount = (stablecoinsValueToRedeem * _assetBase * BASE_PARAMS) / (oracleRate * targetCF); - maxAmount = maxAmount > toWithdraw ? toWithdraw : maxAmount; - } - } - } - } - - /// @notice Function to invest stablecoins - /// @param amount Amount of new stablecoins managed - /// @return amountInvested Amount truly invested in the strategy - /// @dev Amount should not be above maxExternalAmount defined in Euler otherwise it will revert - function _push(uint256 amount) internal override returns (uint256 amountInvested) { - (uint256 lentStablecoins, uint256 looseStablecoins) = _report(amount); - - if (looseStablecoins > minInvest) { - euler.deposit(0, looseStablecoins); - amountInvested = looseStablecoins; - // as looseStablecoins should be null - lastBalance = euler.balanceOfUnderlying(address(this)); - } else { - lastBalance = lentStablecoins + looseStablecoins; - } - return amountInvested; - } - - /// @notice Function to withdraw stablecoins - /// @param amount Amount needed at the end of the call - /// @return amountAvailable Amount available in the contracts, new `looseStablecoins` - function _pull(uint256 amount) internal override returns (uint256 amountAvailable) { - (uint256 lentStablecoins, uint256 looseStablecoins) = _report(0); - amountAvailable = looseStablecoins; - if (looseStablecoins < amount) { - uint256 amountWithdrawnFromEuler = (amount - looseStablecoins) > lentStablecoins - ? type(uint256).max - : (amount - looseStablecoins); - euler.withdraw(0, amountWithdrawnFromEuler); - amountAvailable += amountWithdrawnFromEuler; - - lastBalance = euler.balanceOfUnderlying(address(this)); - } else { - lastBalance = lentStablecoins + looseStablecoins - amount; - } - } - - function _report(uint256 amountToAdd) internal returns (uint256 lentStablecoins, uint256 looseStablecoins) { - lentStablecoins = euler.balanceOfUnderlying(address(this)); - looseStablecoins = stablecoin.balanceOf(address(this)); - - // always positive otherwise we couldn't do the operation - uint256 total = looseStablecoins + lentStablecoins - amountToAdd; - uint256 lastBalance_ = lastBalance; - if (total > lastBalance_) { - // In case of a yield gain a portion goes to the protocol, the rest goes to users - // If there is already a loss, the gain is used to compensate the previous loss - uint256 gain = total - lastBalance_; - uint256 protocolGain = (gain * protocolInterestShare) / BASE_PARAMS; - uint256 protocolDebtPre = protocolDebt; - if (protocolDebtPre == 0) protocolInterestAccumulated += protocolGain; - else if (protocolDebtPre <= protocolGain) { - protocolInterestAccumulated += protocolGain - protocolDebtPre; - protocolDebt = 0; - } else protocolDebt -= protocolGain; - _handleGain(gain - protocolGain); - } else { - // In case of a loss, we first try to compensate it from previous gains for the part that concerns - // the protocol - uint256 loss = lastBalance_ - total; - uint256 lossForProtocol = (loss * protocolInterestShare) / BASE_PARAMS; - uint256 protocolInterestAccumulatedPreLoss = protocolInterestAccumulated; - // If the loss can not be entirely soaked by the gains already made then - // the protocol keeps track of the debt - if (lossForProtocol > protocolInterestAccumulatedPreLoss) { - protocolInterestAccumulated = 0; - protocolDebt += lossForProtocol - protocolInterestAccumulatedPreLoss; - } else protocolInterestAccumulated -= lossForProtocol; - _handleLoss(loss - lossForProtocol); - } - } -} diff --git a/contracts/vaultManager/VaultManager.sol b/contracts/vaultManager/VaultManager.sol index 95ce84d1..cb707b05 100644 --- a/contracts/vaultManager/VaultManager.sol +++ b/contracts/vaultManager/VaultManager.sol @@ -686,6 +686,8 @@ contract VaultManager is VaultManagerPermit, IVaultManagerFunctions { /// @return liqData Data about the liquidation process for the liquidator to track everything that has been going on (like how much /// stablecoins have been repaid, how much collateral has been received) /// @dev This function will revert if it's called on a vault that cannot be liquidated or that does not exist + /// @dev A whitelist check may be performed on the address liquidating the vault or on the address receiving + /// the funds from the liquidiation function liquidate( uint256[] memory vaultIDs, uint256[] memory amounts, @@ -694,6 +696,8 @@ contract VaultManager is VaultManagerPermit, IVaultManagerFunctions { address who, bytes memory data ) public whenNotPaused nonReentrant returns (LiquidatorData memory liqData) { + if (_whitelistingActivated() && isWhitelisted[msg.sender] != 1 && isWhitelisted[to] != 1) + revert NotWhitelisted(); uint256 vaultIDsLength = vaultIDs.length; if (vaultIDsLength != amounts.length || vaultIDsLength == 0) revert IncompatibleLengths(); // Stores all the data about an ongoing liquidation of multiple vaults diff --git a/contracts/vaultManager/VaultManagerERC721.sol b/contracts/vaultManager/VaultManagerERC721.sol index 7d636815..c219791e 100644 --- a/contracts/vaultManager/VaultManagerERC721.sol +++ b/contracts/vaultManager/VaultManagerERC721.sol @@ -93,20 +93,12 @@ abstract contract VaultManagerERC721 is IERC721MetadataUpgradeable, VaultManager } /// @inheritdoc IERC721Upgradeable - function transferFrom( - address from, - address to, - uint256 vaultID - ) external onlyApprovedOrOwner(msg.sender, vaultID) { + function transferFrom(address from, address to, uint256 vaultID) external onlyApprovedOrOwner(msg.sender, vaultID) { _transfer(from, to, vaultID); } /// @inheritdoc IERC721Upgradeable - function safeTransferFrom( - address from, - address to, - uint256 vaultID - ) external { + function safeTransferFrom(address from, address to, uint256 vaultID) external { safeTransferFrom(from, to, vaultID, ""); } @@ -145,12 +137,7 @@ abstract contract VaultManagerERC721 is IERC721MetadataUpgradeable, VaultManager } /// @notice Internal version of the `safeTransferFrom` function (with the data parameter) - function _safeTransfer( - address from, - address to, - uint256 vaultID, - bytes memory _data - ) internal { + function _safeTransfer(address from, address to, uint256 vaultID, bytes memory _data) internal { _transfer(from, to, vaultID); if (!_checkOnERC721Received(from, to, vaultID, _data)) revert NonERC721Receiver(); } @@ -174,8 +161,6 @@ abstract contract VaultManagerERC721 is IERC721MetadataUpgradeable, VaultManager /// @dev This method is equivalent to the `_safeMint` method used in OpenZeppelin ERC721 contract /// @dev Emits a {Transfer} event function _mint(address to) internal returns (uint256 vaultID) { - if (_whitelistingActivated() && (isWhitelisted[to] != 1 || isWhitelisted[msg.sender] != 1)) - revert NotWhitelisted(); if (to == address(0)) revert ZeroAddress(); unchecked { @@ -218,15 +203,9 @@ abstract contract VaultManagerERC721 is IERC721MetadataUpgradeable, VaultManager /// this imposes no restrictions on msg.sender /// @dev `to` cannot be the zero address and `perpetualID` must be owned by `from` /// @dev Emits a {Transfer} event - /// @dev A whitelist check is performed if necessary on the `to` address - function _transfer( - address from, - address to, - uint256 vaultID - ) internal { + function _transfer(address from, address to, uint256 vaultID) internal { if (_ownerOf(vaultID) != from) revert NotApproved(); if (to == address(0)) revert ZeroAddress(); - if (_whitelistingActivated() && isWhitelisted[to] != 1) revert NotWhitelisted(); _beforeTokenTransfer(from, to, vaultID); @@ -250,11 +229,7 @@ abstract contract VaultManagerERC721 is IERC721MetadataUpgradeable, VaultManager /// @notice Internal version of the `setApprovalForAll` function /// @dev It contains an `approver` field to be used in case someone signs a permit for a particular /// address, and this signature is given to the contract by another address (like a router) - function _setApprovalForAll( - address approver, - address operator, - bool approved - ) internal { + function _setApprovalForAll(address approver, address operator, bool approved) internal { if (operator == approver) revert ApprovalToCaller(); uint256 approval = approved ? 1 : 0; _operatorApprovals[approver][operator] = approval; @@ -302,11 +277,7 @@ abstract contract VaultManagerERC721 is IERC721MetadataUpgradeable, VaultManager /// - When `from` is zero, `vaultID` will be minted for `to`. /// - When `to` is zero, `from`'s `vaultID` will be burned. /// - `from` and `to` are never both zero. - function _beforeTokenTransfer( - address from, - address to, - uint256 vaultID - ) internal virtual {} + function _beforeTokenTransfer(address from, address to, uint256 vaultID) internal virtual {} /// @notice Get `whitelistingActivated` in storage only if needed function _whitelistingActivated() internal view virtual returns (bool) { diff --git a/deploy/4_oracle.ts b/deploy/4_oracle.ts index 14e83aa0..339a7f9a 100644 --- a/deploy/4_oracle.ts +++ b/deploy/4_oracle.ts @@ -1,56 +1,66 @@ -import { ChainId } from '@angleprotocol/sdk'; +import { ChainId, registry } from '@angleprotocol/sdk'; import { DeployFunction } from 'hardhat-deploy/types'; import yargs from 'yargs'; +import { OracleIB01EURChainlink, OracleIB01EURChainlink__factory } from '../typechain'; + const argv = yargs.env('').boolean('ci').parseSync(); const func: DeployFunction = async ({ deployments, ethers, network }) => { const { deploy } = deployments; const { deployer } = await ethers.getNamedSigners(); - const stableName = 'GOLD'; - const treasury = (await deployments.get(`Treasury_${stableName}`)).address; - + const stableName = 'EUR'; + // const treasury = (await deployments.get(`Treasury_${stableName}`)).address; + let treasury: string; let chainName: string; if (!network.live || network.config.chainId == 1) { chainName = ''; + treasury = registry(ChainId.MAINNET)?.agEUR?.Treasury!; } else { chainName = network.name.charAt(0).toUpperCase() + network.name.substring(1); + treasury = registry(network.config.chainId as ChainId)?.agEUR?.Treasury!; } - console.log('Now deploying the Oracle ETH/XAU'); - await deploy('Oracle_ETH_XAU', { - contract: `OracleETHXAUChainlink${chainName}`, + console.log('Now deploying the Oracle IB01/EUR'); + await deploy('Oracle_IB01_EUR', { + contract: `OracleIB01EURChainlink`, from: deployer.address, args: [3600 * 30, treasury], log: !argv.ci, }); - const oracle = (await deployments.get('Oracle_ETH_XAU')).address; - console.log(`Successfully deployed Oracle ETH/XAU at the address ${oracle}`); + const oracle = (await deployments.get('Oracle_IB01_EUR')).address; + console.log(`Successfully deployed Oracle IB01/EUR at the address ${oracle}`); console.log(''); - console.log('Now deploying the Oracle WSTETH/XAU'); - await deploy('Oracle_WSTETH_XAU', { - contract: `OracleWSTETHXAUChainlink${chainName}`, + await deploy('Oracle_USDC_EUR', { + contract: `OracleUSDCEURChainlink`, from: deployer.address, args: [3600 * 30, treasury], log: !argv.ci, }); - const oracle2 = (await deployments.get('Oracle_WSTETH_XAU')).address; - console.log(`Successfully deployed Oracle WSTETH/XAU at the address ${oracle2}`); + const oracle2 = (await deployments.get('Oracle_USDC_EUR')).address; + console.log(`Successfully deployed Oracle USDC/EUR at the address ${oracle2}`); console.log(''); - console.log('Now deploying the Oracle USDC/XAU'); - await deploy('Oracle_USDC_XAU', { - contract: `OracleUSDCXAUChainlink${chainName}`, - from: deployer.address, - args: [3600 * 30, treasury], - log: !argv.ci, - }); - const oracle3 = (await deployments.get('Oracle_USDC_XAU')).address; - console.log(`Successfully deployed Oracle USDC/XAU at the address ${oracle3}`); - console.log(''); + const oracleContract = new ethers.Contract( + oracle, + OracleIB01EURChainlink__factory.createInterface(), + deployer, + ) as OracleIB01EURChainlink; + + const oracleContract2 = new ethers.Contract( + oracle2, + OracleIB01EURChainlink__factory.createInterface(), + deployer, + ) as OracleIB01EURChainlink; + + const oracleValue = await oracleContract.read(); + console.log(oracleValue.toString()); + + const oracleValue2 = await oracleContract2.read(); + console.log(oracleValue2.toString()); }; func.tags = ['oracle']; -func.dependencies = ['treasury']; +// func.dependencies = ['treasury']; export default func; diff --git a/deploy/5_vaultManagerImplementation.ts b/deploy/5_vaultManagerImplementation.ts index e204b3a5..0955d64a 100644 --- a/deploy/5_vaultManagerImplementation.ts +++ b/deploy/5_vaultManagerImplementation.ts @@ -6,7 +6,7 @@ const func: DeployFunction = async ({ deployments, ethers }) => { const { deploy } = deployments; const { deployer } = await ethers.getNamedSigners(); - const implementationName = 'VaultManager_V2_0_Implementation'; + const implementationName = 'VaultManager_PermissionedLiquidations_Implementation'; try { await deployments.get(implementationName); @@ -25,5 +25,5 @@ const func: DeployFunction = async ({ deployments, ethers }) => { }; func.tags = ['vaultManagerImplementation']; -func.dependencies = ['oracle']; +// func.dependencies = ['oracle']; export default func; diff --git a/deploy/6_vaultManagerProxy.ts b/deploy/6_vaultManagerProxy.ts index 38ec2e18..6ad75fcb 100644 --- a/deploy/6_vaultManagerProxy.ts +++ b/deploy/6_vaultManagerProxy.ts @@ -1,4 +1,4 @@ -import { ChainId, CONTRACTS_ADDRESSES } from '@angleprotocol/sdk/dist'; +import { ChainId, CONTRACTS_ADDRESSES, registry } from '@angleprotocol/sdk/dist'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; import { Contract } from 'ethers'; import hre from 'hardhat'; @@ -12,6 +12,9 @@ import params from './networks'; const argv = yargs.env('').boolean('ci').parseSync(); const func: DeployFunction = async ({ deployments, ethers, network }) => { + /** + * TODO: change implementation depending on what is being deployed + */ const { deploy } = deployments; const { deployer } = await ethers.getNamedSigners(); @@ -19,14 +22,17 @@ const func: DeployFunction = async ({ deployments, ethers, network }) => { const json = await import('./networks/' + network.name + '.json'); const vaultsList = json.vaultsList; - const stableName = 'GOLD'; + const stableName = 'EUR'; + let treasuryAddress; if (!network.live) { // If we're in mainnet fork, we're using the `ProxyAdmin` address from mainnet proxyAdminAddress = CONTRACTS_ADDRESSES[ChainId.MAINNET].ProxyAdmin!; + treasuryAddress = registry(ChainId.MAINNET)?.agEUR?.Treasury!; } else { // Otherwise, we're using the proxy admin address from the desired network proxyAdminAddress = (await ethers.getContract('ProxyAdmin')).address; + treasuryAddress = registry(network.config.chainId as ChainId)?.agEUR?.Treasury!; } console.log(`Deploying proxies for the following vaultManager: ${vaultsList}`); @@ -56,10 +62,9 @@ const func: DeployFunction = async ({ deployments, ethers, network }) => { console.log(`whitelistingActivated: ${vaultManagerParams.params.whitelistingActivated.toString()}`); console.log(''); - const treasuryAddress = (await ethers.getContract(`Treasury_${stableName}`)).address; const treasury = new Contract(treasuryAddress, Treasury__factory.abi, deployer); - const implementation = (await ethers.getContract('VaultManager_V2_0_Implementation')).address; + const implementation = (await ethers.getContract('VaultManager_PermissionedLiquidations_Implementation')).address; const callData = new ethers.Contract( implementation, VaultManager__factory.createInterface(), @@ -70,7 +75,6 @@ const func: DeployFunction = async ({ deployments, ethers, network }) => { vaultManagerParams.params, vaultManagerParams.symbol, ]); - await deploy(name, { contract: 'TransparentUpgradeableProxy', from: deployer.address, diff --git a/deploy/bridges/LayerZeroSetSources.ts b/deploy/bridges/LayerZeroSetSources.ts index abf6aaa6..4d3d3256 100644 --- a/deploy/bridges/LayerZeroSetSources.ts +++ b/deploy/bridges/LayerZeroSetSources.ts @@ -26,10 +26,11 @@ const func: DeployFunction = async ({ ethers, network }) => { console.log(chain); const trustedRemote = ethers.utils.solidityPack(['address', 'address'], [OFTs[chain], local]); console.log(`Trusted remote ${trustedRemote}`); - + console.log(local); console.log( contractAngleOFT.interface.encodeFunctionData('setTrustedRemote', [(LZ_CHAINIDS as any)[chain], trustedRemote]), ); + console.log((LZ_CHAINIDS as any)[chain], trustedRemote); console.log(''); } diff --git a/deploy/networks/hardhat.json b/deploy/networks/hardhat.json index 4481253f..6ecc03b1 100644 --- a/deploy/networks/hardhat.json +++ b/deploy/networks/hardhat.json @@ -9,5 +9,5 @@ "oneInchRouter": "0x1111111254fb6c44bAC0beD2854e76F90643097d", "angleRouter": "0xBB755240596530be0c1DE5DFD77ec6398471561d", "dust": "0", - "vaultsList": ["USDC", "wETH", "wstETH"] + "vaultsList": ["USDC"] } diff --git a/deploy/networks/mainnet.json b/deploy/networks/mainnet.json index 28685bcc..140f5919 100644 --- a/deploy/networks/mainnet.json +++ b/deploy/networks/mainnet.json @@ -9,5 +9,5 @@ "oneInchRouter": "0x1111111254eeb25477b68fb85ed929f73a960582", "angleRouter": "0xBB755240596530be0c1DE5DFD77ec6398471561d", "dust": "0", - "vaultsList": ["USDC", "wETH", "wstETH"] + "vaultsList": ["bIB01"] } diff --git a/deployments/mainnet/Oracle_IB01_EUR.json b/deployments/mainnet/Oracle_IB01_EUR.json new file mode 100644 index 00000000..bd06ccdb --- /dev/null +++ b/deployments/mainnet/Oracle_IB01_EUR.json @@ -0,0 +1,247 @@ +{ + "address": "0x598342fCEDb4325b16ae9618e433710070195019", + "abi": [ + { + "inputs": [ + { + "internalType": "uint32", + "name": "_stalePeriod", + "type": "uint32" + }, + { + "internalType": "address", + "name": "_treasury", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "InvalidChainlinkRate", + "type": "error" + }, + { + "inputs": [], + "name": "NotGovernorOrGuardian", + "type": "error" + }, + { + "inputs": [], + "name": "NotVaultManagerOrGovernor", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint32", + "name": "_stalePeriod", + "type": "uint32" + } + ], + "name": "StalePeriodUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "DESCRIPTION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "_stalePeriod", + "type": "uint32" + } + ], + "name": "changeStalePeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "circuitChainlink", + "outputs": [ + { + "internalType": "contract AggregatorV3Interface[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "read", + "outputs": [ + { + "internalType": "uint256", + "name": "quoteAmount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_treasury", + "type": "address" + } + ], + "name": "setTreasury", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "stalePeriod", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "treasury", + "outputs": [ + { + "internalType": "contract ITreasury", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x06d67e512daa80ef3ac09c9cf9d9df404dfe2e53a6acec959e5316bc4fa8eb0d", + "receipt": { + "to": null, + "from": "0xfdA462548Ce04282f4B6D6619823a7C64Fdc0185", + "contractAddress": "0x598342fCEDb4325b16ae9618e433710070195019", + "transactionIndex": 60, + "gasUsed": "722375", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x81689bbae9de09ab6a2cbe80a6fdea0ece39ff2191d06e89c127dc76ba61e89b", + "transactionHash": "0x06d67e512daa80ef3ac09c9cf9d9df404dfe2e53a6acec959e5316bc4fa8eb0d", + "logs": [], + "blockNumber": 17228919, + "cumulativeGasUsed": "26445415", + "status": 1, + "byzantium": true + }, + "args": [ + 108000, + "0x8667DBEBf68B0BFa6Db54f550f41Be16c4067d60" + ], + "numDeployments": 1, + "solcInputHash": "9a2b71309fb0718473c1f135df2b8dfe", + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_stalePeriod\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"_treasury\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidChainlinkRate\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotGovernorOrGuardian\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotVaultManagerOrGovernor\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"_stalePeriod\",\"type\":\"uint32\"}],\"name\":\"StalePeriodUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DESCRIPTION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_stalePeriod\",\"type\":\"uint32\"}],\"name\":\"changeStalePeriod\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"circuitChainlink\",\"outputs\":[{\"internalType\":\"contract AggregatorV3Interface[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"read\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"quoteAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_treasury\",\"type\":\"address\"}],\"name\":\"setTreasury\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stalePeriod\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"treasury\",\"outputs\":[{\"internalType\":\"contract ITreasury\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Angle Labs, Inc.\",\"kind\":\"dev\",\"methods\":{\"changeStalePeriod(uint32)\":{\"params\":{\"_stalePeriod\":\"New stale period (in seconds)\"}},\"read()\":{\"details\":\"For instance if the out currency is EUR (and hence agEUR), then the base of the returned value is 10**18\",\"returns\":{\"quoteAmount\":\"The current rate between the in-currency and out-currency in the base of the out currency\"}},\"setTreasury(address)\":{\"details\":\"This function can be called by an approved `VaultManager` contract which can call this function after being requested to do so by a `treasury` contractIn some situations (like reactor contracts), the `VaultManager` may not directly be linked to the `oracle` contract and as such we may need governors to be able to call this function as well\",\"params\":{\"_treasury\":\"Address of the new treasury contract\"}}},\"title\":\"OracleIB01EURChainlink\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"changeStalePeriod(uint32)\":{\"notice\":\"Changes the stale period\"},\"circuitChainlink()\":{\"notice\":\"Array with the list of Chainlink feeds in the order in which they are read\"},\"read()\":{\"notice\":\"Reads the rate from the Chainlink circuit and other data provided\"},\"setTreasury(address)\":{\"notice\":\"Changes the treasury contract\"},\"stalePeriod()\":{\"notice\":\"Represent the maximum amount of time (in seconds) between each Chainlink update before the price feed is considered stale\"},\"treasury()\":{\"notice\":\"Reference to the `treasury` contract handling this `VaultManager`\"}},\"notice\":\"Gives the price of IB01 in Euro in base 18\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/oracle/implementations/mainnet/EUR/OracleIB01EURChainlink.sol\":\"OracleIB01EURChainlink\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface AggregatorV3Interface {\\n\\n function decimals()\\n external\\n view\\n returns (\\n uint8\\n );\\n\\n function description()\\n external\\n view\\n returns (\\n string memory\\n );\\n\\n function version()\\n external\\n view\\n returns (\\n uint256\\n );\\n\\n // getRoundData and latestRoundData should both raise \\\"No data present\\\"\\n // if they do not have data to report, instead of returning unset values\\n // which could be misinterpreted as actual reported values.\\n function getRoundData(\\n uint80 _roundId\\n )\\n external\\n view\\n returns (\\n uint80 roundId,\\n int256 answer,\\n uint256 startedAt,\\n uint256 updatedAt,\\n uint80 answeredInRound\\n );\\n\\n function latestRoundData()\\n external\\n view\\n returns (\\n uint80 roundId,\\n int256 answer,\\n uint256 startedAt,\\n uint256 updatedAt,\\n uint80 answeredInRound\\n );\\n\\n}\\n\",\"keccak256\":\"0xe6f5ac8c47f3b9b6135051efb9216f9ba5b312a6ecc20209b4f66a780443c328\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20Upgradeable {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x4e733d3164f73f461eaf9d8087a7ad1ea180bdc8ba0d3d61b0e1ae16d8e63dff\",\"license\":\"MIT\"},\"contracts/interfaces/IAgToken.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity ^0.8.12;\\n\\nimport \\\"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\\\";\\n\\n/// @title IAgToken\\n/// @author Angle Labs, Inc.\\n/// @notice Interface for the stablecoins `AgToken` contracts\\n/// @dev This interface only contains functions of the `AgToken` contract which are called by other contracts\\n/// of this module or of the first module of the Angle Protocol\\ninterface IAgToken is IERC20Upgradeable {\\n // ======================= Minter Role Only Functions ===========================\\n\\n /// @notice Lets the `StableMaster` contract or another whitelisted contract mint agTokens\\n /// @param account Address to mint to\\n /// @param amount Amount to mint\\n /// @dev The contracts allowed to issue agTokens are the `StableMaster` contract, `VaultManager` contracts\\n /// associated to this stablecoin as well as the flash loan module (if activated) and potentially contracts\\n /// whitelisted by governance\\n function mint(address account, uint256 amount) external;\\n\\n /// @notice Burns `amount` tokens from a `burner` address after being asked to by `sender`\\n /// @param amount Amount of tokens to burn\\n /// @param burner Address to burn from\\n /// @param sender Address which requested the burn from `burner`\\n /// @dev This method is to be called by a contract with the minter right after being requested\\n /// to do so by a `sender` address willing to burn tokens from another `burner` address\\n /// @dev The method checks the allowance between the `sender` and the `burner`\\n function burnFrom(\\n uint256 amount,\\n address burner,\\n address sender\\n ) external;\\n\\n /// @notice Burns `amount` tokens from a `burner` address\\n /// @param amount Amount of tokens to burn\\n /// @param burner Address to burn from\\n /// @dev This method is to be called by a contract with a minter right on the AgToken after being\\n /// requested to do so by an address willing to burn tokens from its address\\n function burnSelf(uint256 amount, address burner) external;\\n\\n // ========================= Treasury Only Functions ===========================\\n\\n /// @notice Adds a minter in the contract\\n /// @param minter Minter address to add\\n /// @dev Zero address checks are performed directly in the `Treasury` contract\\n function addMinter(address minter) external;\\n\\n /// @notice Removes a minter from the contract\\n /// @param minter Minter address to remove\\n /// @dev This function can also be called by a minter wishing to revoke itself\\n function removeMinter(address minter) external;\\n\\n /// @notice Sets a new treasury contract\\n /// @param _treasury New treasury address\\n function setTreasury(address _treasury) external;\\n\\n // ========================= External functions ================================\\n\\n /// @notice Checks whether an address has the right to mint agTokens\\n /// @param minter Address for which the minting right should be checked\\n /// @return Whether the address has the right to mint agTokens or not\\n function isMinter(address minter) external view returns (bool);\\n\\n /// @notice Get the associated treasury\\n function treasury() external view returns (address);\\n}\\n\",\"keccak256\":\"0xd671dbd00b28a86b839fd455ada4d1ef9203694d06142be76853e00a91f80b5f\",\"license\":\"GPL-3.0\"},\"contracts/interfaces/ICoreBorrow.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity ^0.8.12;\\n\\n/// @title ICoreBorrow\\n/// @author Angle Labs, Inc.\\n/// @notice Interface for the `CoreBorrow` contract\\n/// @dev This interface only contains functions of the `CoreBorrow` contract which are called by other contracts\\n/// of this module\\ninterface ICoreBorrow {\\n /// @notice Checks if an address corresponds to a treasury of a stablecoin with a flash loan\\n /// module initialized on it\\n /// @param treasury Address to check\\n /// @return Whether the address has the `FLASHLOANER_TREASURY_ROLE` or not\\n function isFlashLoanerTreasury(address treasury) external view returns (bool);\\n\\n /// @notice Checks whether an address is governor of the Angle Protocol or not\\n /// @param admin Address to check\\n /// @return Whether the address has the `GOVERNOR_ROLE` or not\\n function isGovernor(address admin) external view returns (bool);\\n\\n /// @notice Checks whether an address is governor or a guardian of the Angle Protocol or not\\n /// @param admin Address to check\\n /// @return Whether the address has the `GUARDIAN_ROLE` or not\\n /// @dev Governance should make sure when adding a governor to also give this governor the guardian\\n /// role by calling the `addGovernor` function\\n function isGovernorOrGuardian(address admin) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x10249210cbf522775f040baf981d7d037472168ce2746d87473ac7c29a34e62e\",\"license\":\"GPL-3.0\"},\"contracts/interfaces/IFlashAngle.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity ^0.8.12;\\n\\nimport \\\"./IAgToken.sol\\\";\\nimport \\\"./ICoreBorrow.sol\\\";\\n\\n/// @title IFlashAngle\\n/// @author Angle Labs, Inc.\\n/// @notice Interface for the `FlashAngle` contract\\n/// @dev This interface only contains functions of the contract which are called by other contracts\\n/// of this module\\ninterface IFlashAngle {\\n /// @notice Reference to the `CoreBorrow` contract managing the FlashLoan module\\n function core() external view returns (ICoreBorrow);\\n\\n /// @notice Sends the fees taken from flash loans to the treasury contract associated to the stablecoin\\n /// @param stablecoin Stablecoin from which profits should be sent\\n /// @return balance Amount of profits sent\\n /// @dev This function can only be called by the treasury contract\\n function accrueInterestToTreasury(IAgToken stablecoin) external returns (uint256 balance);\\n\\n /// @notice Adds support for a stablecoin\\n /// @param _treasury Treasury associated to the stablecoin to add support for\\n /// @dev This function can only be called by the `CoreBorrow` contract\\n function addStablecoinSupport(address _treasury) external;\\n\\n /// @notice Removes support for a stablecoin\\n /// @param _treasury Treasury associated to the stablecoin to remove support for\\n /// @dev This function can only be called by the `CoreBorrow` contract\\n function removeStablecoinSupport(address _treasury) external;\\n\\n /// @notice Sets a new core contract\\n /// @param _core Core contract address to set\\n /// @dev This function can only be called by the `CoreBorrow` contract\\n function setCore(address _core) external;\\n}\\n\",\"keccak256\":\"0x39b0097f695b9e934bccdc72676c91513f1077cc5d0fd151908fd25a7c5cfbe4\",\"license\":\"GPL-3.0\"},\"contracts/interfaces/IOracle.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity ^0.8.12;\\n\\nimport \\\"./ITreasury.sol\\\";\\nimport \\\"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\\\";\\n\\n/// @title IOracle\\n/// @author Angle Labs, Inc.\\n/// @notice Interface for the `Oracle` contract\\n/// @dev This interface only contains functions of the contract which are called by other contracts\\n/// of this module\\ninterface IOracle {\\n /// @notice Reads the rate from the Chainlink circuit and other data provided\\n /// @return quoteAmount The current rate between the in-currency and out-currency in the base\\n /// of the out currency\\n /// @dev For instance if the out currency is EUR (and hence agEUR), then the base of the returned\\n /// value is 10**18\\n function read() external view returns (uint256);\\n\\n /// @notice Changes the treasury contract\\n /// @param _treasury Address of the new treasury contract\\n /// @dev This function can be called by an approved `VaultManager` contract which can call\\n /// this function after being requested to do so by a `treasury` contract\\n /// @dev In some situations (like reactor contracts), the `VaultManager` may not directly be linked\\n /// to the `oracle` contract and as such we may need governors to be able to call this function as well\\n function setTreasury(address _treasury) external;\\n\\n /// @notice Reference to the `treasury` contract handling this `VaultManager`\\n function treasury() external view returns (ITreasury treasury);\\n\\n /// @notice Array with the list of Chainlink feeds in the order in which they are read\\n function circuitChainlink() external view returns (AggregatorV3Interface[] memory);\\n}\\n\",\"keccak256\":\"0x66fe2bb27f26b86e5832fc7d1ebd320cac8b3d79c5998ce148cf7279b2b359be\",\"license\":\"GPL-3.0\"},\"contracts/interfaces/ITreasury.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity ^0.8.12;\\n\\nimport \\\"./IAgToken.sol\\\";\\nimport \\\"./ICoreBorrow.sol\\\";\\nimport \\\"./IFlashAngle.sol\\\";\\n\\n/// @title ITreasury\\n/// @author Angle Labs, Inc.\\n/// @notice Interface for the `Treasury` contract\\n/// @dev This interface only contains functions of the `Treasury` which are called by other contracts\\n/// of this module\\ninterface ITreasury {\\n /// @notice Stablecoin handled by this `treasury` contract\\n function stablecoin() external view returns (IAgToken);\\n\\n /// @notice Checks whether a given address has the governor role\\n /// @param admin Address to check\\n /// @return Whether the address has the governor role\\n /// @dev Access control is only kept in the `CoreBorrow` contract\\n function isGovernor(address admin) external view returns (bool);\\n\\n /// @notice Checks whether a given address has the guardian or the governor role\\n /// @param admin Address to check\\n /// @return Whether the address has the guardian or the governor role\\n /// @dev Access control is only kept in the `CoreBorrow` contract which means that this function\\n /// queries the `CoreBorrow` contract\\n function isGovernorOrGuardian(address admin) external view returns (bool);\\n\\n /// @notice Checks whether a given address has well been initialized in this contract\\n /// as a `VaultManager`\\n /// @param _vaultManager Address to check\\n /// @return Whether the address has been initialized or not\\n function isVaultManager(address _vaultManager) external view returns (bool);\\n\\n /// @notice Sets a new flash loan module for this stablecoin\\n /// @param _flashLoanModule Reference to the new flash loan module\\n /// @dev This function removes the minting right to the old flash loan module and grants\\n /// it to the new module\\n function setFlashLoanModule(address _flashLoanModule) external;\\n}\\n\",\"keccak256\":\"0x624733dae1bfb98721ba994573aed10997f7448c893b791ed985300531c361fd\",\"license\":\"GPL-3.0\"},\"contracts/oracle/BaseOracleChainlinkMulti.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\n/*\\n * \\u2588 \\n ***** \\u2593\\u2593\\u2593 \\n * \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\n * ///. \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\n ***** //////// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\n * ///////////// \\u2593\\u2593\\u2593 \\n \\u2593\\u2593 ////////////////// \\u2588 \\u2593\\u2593 \\n \\u2593\\u2593 \\u2593\\u2593 /////////////////////// \\u2593\\u2593 \\u2593\\u2593 \\n \\u2593\\u2593 \\u2593\\u2593 //////////////////////////// \\u2593\\u2593 \\u2593\\u2593 \\n \\u2593\\u2593 \\u2593\\u2593 /////////\\u2593\\u2593\\u2593///////\\u2593\\u2593\\u2593///////// \\u2593\\u2593 \\u2593\\u2593 \\n \\u2593\\u2593 ,////////////////////////////////////// \\u2593\\u2593 \\u2593\\u2593 \\n \\u2593\\u2593 ////////////////////////////////////////// \\u2593\\u2593 \\n \\u2593\\u2593 //////////////////////\\u2593\\u2593\\u2593\\u2593///////////////////// \\n ,//////////////////////////////////////////////////// \\n .////////////////////////////////////////////////////////// \\n .//////////////////////////\\u2588\\u2588.,//////////////////////////\\u2588 \\n .//////////////////////\\u2588\\u2588\\u2588\\u2588..,./////////////////////\\u2588\\u2588 \\n ...////////////////\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588.....,.////////////////\\u2588\\u2588\\u2588 \\n ,.,////////////\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 ........,///////////\\u2588\\u2588\\u2588\\u2588 \\n .,.,//////\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 ,.......///////\\u2588\\u2588\\u2588\\u2588 \\n ,..//\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 ........./\\u2588\\u2588\\u2588\\u2588 \\n ..,\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 .....,\\u2588\\u2588\\u2588 \\n .\\u2588\\u2588 ,.,\\u2588 \\n \\n \\n \\n \\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\n \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593 \\u2593\\u2593 \\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593 \\n \\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593 \\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\n \\u2593\\u2593\\u2593 \\u2593\\u2593 \\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\n*/\\n\\npragma solidity ^0.8.12;\\n\\nimport \\\"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\\\";\\n\\nimport \\\"../interfaces/IOracle.sol\\\";\\nimport \\\"../interfaces/ITreasury.sol\\\";\\n\\n/// @title BaseOracleChainlinkMulti\\n/// @author Angle Labs, Inc.\\n/// @notice Base Contract to be overriden by all contracts of the protocol\\n/// @dev This base contract concerns an oracle that uses Chainlink with multiple pools to read from\\n/// @dev All gas-efficient implementation of the `OracleChainlinkMulti` contract should inherit from this\\nabstract contract BaseOracleChainlinkMulti is IOracle {\\n // ========================= Parameters and References =========================\\n\\n /// @inheritdoc IOracle\\n ITreasury public override treasury;\\n /// @notice Represent the maximum amount of time (in seconds) between each Chainlink update\\n /// before the price feed is considered stale\\n uint32 public stalePeriod;\\n\\n // =================================== Event ===================================\\n\\n event StalePeriodUpdated(uint32 _stalePeriod);\\n\\n // =================================== Errors ===================================\\n\\n error InvalidChainlinkRate();\\n error NotGovernorOrGuardian();\\n error NotVaultManagerOrGovernor();\\n\\n /// @notice Constructor for an oracle using Chainlink with multiple pools to read from\\n /// @param _stalePeriod Minimum feed update frequency for the oracle to not revert\\n /// @param _treasury Treasury associated to the VaultManager which reads from this feed\\n constructor(uint32 _stalePeriod, address _treasury) {\\n stalePeriod = _stalePeriod;\\n treasury = ITreasury(_treasury);\\n }\\n\\n // ============================= Reading Oracles ===============================\\n\\n /// @inheritdoc IOracle\\n function read() external view virtual override returns (uint256 quoteAmount);\\n\\n /// @inheritdoc IOracle\\n function circuitChainlink() public view virtual returns (AggregatorV3Interface[] memory);\\n\\n /// @notice Reads a Chainlink feed using a quote amount and converts the quote amount to\\n /// the out-currency\\n /// @param quoteAmount The amount for which to compute the price expressed with base decimal\\n /// @param feed Chainlink feed to query\\n /// @param multiplied Whether the ratio outputted by Chainlink should be multiplied or divided\\n /// to the `quoteAmount`\\n /// @param decimals Number of decimals of the corresponding Chainlink pair\\n /// @return The `quoteAmount` converted in out-currency\\n function _readChainlinkFeed(\\n uint256 quoteAmount,\\n AggregatorV3Interface feed,\\n uint8 multiplied,\\n uint256 decimals\\n ) internal view returns (uint256) {\\n (uint80 roundId, int256 ratio, , uint256 updatedAt, uint80 answeredInRound) = feed.latestRoundData();\\n if (ratio <= 0 || roundId > answeredInRound || block.timestamp - updatedAt > stalePeriod)\\n revert InvalidChainlinkRate();\\n uint256 castedRatio = uint256(ratio);\\n // Checking whether we should multiply or divide by the ratio computed\\n if (multiplied == 1) return (quoteAmount * castedRatio) / (10 ** decimals);\\n else return (quoteAmount * (10 ** decimals)) / castedRatio;\\n }\\n\\n // ======================= Governance Related Functions ========================\\n\\n /// @notice Changes the stale period\\n /// @param _stalePeriod New stale period (in seconds)\\n function changeStalePeriod(uint32 _stalePeriod) external {\\n if (!treasury.isGovernorOrGuardian(msg.sender)) revert NotGovernorOrGuardian();\\n stalePeriod = _stalePeriod;\\n emit StalePeriodUpdated(_stalePeriod);\\n }\\n\\n /// @inheritdoc IOracle\\n function setTreasury(address _treasury) external override {\\n if (!treasury.isVaultManager(msg.sender) && !treasury.isGovernor(msg.sender))\\n revert NotVaultManagerOrGovernor();\\n treasury = ITreasury(_treasury);\\n }\\n}\\n\",\"keccak256\":\"0x6dc796277e844596455ea6d486fd5d439e407688ba4573055ab0b61c924588ed\",\"license\":\"GPL-3.0\"},\"contracts/oracle/BaseOracleChainlinkMultiTwoFeeds.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity ^0.8.12;\\n\\nimport \\\"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\\\";\\n\\nimport \\\"./BaseOracleChainlinkMulti.sol\\\";\\n\\n/// @title BaseOracleChainlinkMultiTwoFeeds\\n/// @author Angle Labs, Inc.\\n/// @notice Base contract for an oracle that reads into two Chainlink feeds (including an EUR/USD feed) which both have\\n/// 8 decimals\\nabstract contract BaseOracleChainlinkMultiTwoFeeds is BaseOracleChainlinkMulti {\\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMulti(_stalePeriod, _treasury) {}\\n\\n /// @notice Returns the quote amount of the oracle contract\\n function _getQuoteAmount() internal view virtual returns (uint256) {\\n return 10**18;\\n }\\n\\n /// @inheritdoc IOracle\\n function read() external view virtual override returns (uint256 quoteAmount) {\\n quoteAmount = _getQuoteAmount();\\n AggregatorV3Interface[] memory _circuitChainlink = circuitChainlink();\\n uint8[2] memory circuitChainIsMultiplied = [1, 0];\\n uint8[2] memory chainlinkDecimals = [8, 8];\\n uint256 circuitLength = _circuitChainlink.length;\\n for (uint256 i; i < circuitLength; ++i) {\\n quoteAmount = _readChainlinkFeed(\\n quoteAmount,\\n _circuitChainlink[i],\\n circuitChainIsMultiplied[i],\\n chainlinkDecimals[i]\\n );\\n }\\n }\\n}\\n\",\"keccak256\":\"0xebb59af75b56f0a458717897371327c3373c6e260b2589d22485ff3a026a3f4e\",\"license\":\"GPL-3.0\"},\"contracts/oracle/implementations/mainnet/EUR/OracleIB01EURChainlink.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity ^0.8.12;\\n\\nimport \\\"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\\\";\\n\\nimport \\\"../../../BaseOracleChainlinkMultiTwoFeeds.sol\\\";\\n\\n/// @title OracleIB01EURChainlink\\n/// @author Angle Labs, Inc.\\n/// @notice Gives the price of IB01 in Euro in base 18\\ncontract OracleIB01EURChainlink is BaseOracleChainlinkMultiTwoFeeds {\\n string public constant DESCRIPTION = \\\"IB01/EUR Oracle\\\";\\n\\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\\n\\n /// @inheritdoc IOracle\\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\\n // Oracle IB01/USD\\n _circuitChainlink[0] = AggregatorV3Interface(0x788D911ae7c95121A89A0f0306db65D87422E1de);\\n // Oracle EUR/USD\\n _circuitChainlink[1] = AggregatorV3Interface(0xb49f677943BC038e9857d61E7d053CaA2C1734C1);\\n return _circuitChainlink;\\n }\\n}\\n\",\"keccak256\":\"0x3f716dc7c4d5229631d7a12bfe075fcff0fa62a2e88c0a4933c0a1419e87fa4e\",\"license\":\"GPL-3.0\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b50604051610c85380380610c8583398101604081905261002f91610071565b600080546001600160c01b031916600160a01b63ffffffff94909416939093026001600160a01b031916929092176001600160a01b03919091161790556100c0565b6000806040838503121561008457600080fd5b825163ffffffff8116811461009857600080fd5b60208401519092506001600160a01b03811681146100b557600080fd5b809150509250929050565b610bb6806100cf6000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c8063630914d11161005b578063630914d1146100fb578063a5b36a3614610110578063f0f442601461014d578063f1ae88561461016057600080fd5b80634994cc671461008257806357de26a4146100a057806361d027b3146100b6575b600080fd5b61008a6101a9565b6040516100979190610799565b60405180910390f35b6100a8610282565b604051908152602001610097565b6000546100d69073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610097565b61010e6101093660046107f3565b61033c565b005b6000546101389074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610097565b61010e61015b366004610820565b610487565b61019c6040518060400160405280600f81526020017f494230312f455552204f7261636c65000000000000000000000000000000000081525081565b6040516100979190610856565b6040805160028082526060808301845292600092919060208301908036833701905050905073788d911ae7c95121a89a0f0306db65d87422e1de816000815181106101f6576101f66108c2565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073b49f677943bc038e9857d61e7d053caa2c1734c181600181518110610258576102586108c2565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910190910152919050565b670de0b6b3a764000060006102956101a9565b6040805180820182526001815260006020808301829052835180850190945260088085529084015283519394509092905b8181101561033457610322868683815181106102e4576102e46108c2565b60200260200101518684600281106102fe576102fe6108c2565b6020020151868560028110610315576103156108c2565b602002015160ff16610633565b955061032d81610920565b90506102c6565b505050505090565b6000546040517f521d4de900000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091169063521d4de990602401602060405180830381865afa1580156103aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103ce9190610958565b610404576040517f99e120bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f4040b15332969bfd8b2035c1a701c8e13f2b5d62ce89b311684a601b2eb44e019060200160405180910390a150565b6000546040517f676a553e00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091169063676a553e90602401602060405180830381865afa1580156104f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105199190610958565b1580156105b557506000546040517fe43581b800000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091169063e43581b890602401602060405180830381865afa15801561058f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b39190610958565b155b156105ec576040517fb05b9b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008060008060008773ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015610686573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106aa9190610999565b9450945050935093506000831315806106da57508069ffffffffffffffffffff168469ffffffffffffffffffff16115b8061070d575060005474010000000000000000000000000000000000000000900463ffffffff1661070b83426109e9565b115b15610744576040517fae19356300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260ff881660010361077b5761075b87600a610b22565b610765828c610b2e565b61076f9190610b45565b95505050505050610791565b8061078788600a610b22565b610765908c610b2e565b949350505050565b6020808252825182820181905260009190848201906040850190845b818110156107e757835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016107b5565b50909695505050505050565b60006020828403121561080557600080fd5b813563ffffffff8116811461081957600080fd5b9392505050565b60006020828403121561083257600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461081957600080fd5b600060208083528351808285015260005b8181101561088357858101830151858201604001528201610867565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610951576109516108f1565b5060010190565b60006020828403121561096a57600080fd5b8151801515811461081957600080fd5b805169ffffffffffffffffffff8116811461099457600080fd5b919050565b600080600080600060a086880312156109b157600080fd5b6109ba8661097a565b94506020860151935060408601519250606086015191506109dd6080870161097a565b90509295509295909350565b818103818111156109fc576109fc6108f1565b92915050565b600181815b80851115610a5b57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115610a4157610a416108f1565b80851615610a4e57918102915b93841c9390800290610a07565b509250929050565b600082610a72575060016109fc565b81610a7f575060006109fc565b8160018114610a955760028114610a9f57610abb565b60019150506109fc565b60ff841115610ab057610ab06108f1565b50506001821b6109fc565b5060208310610133831016604e8410600b8410161715610ade575081810a6109fc565b610ae88383610a02565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115610b1a57610b1a6108f1565b029392505050565b60006108198383610a63565b80820281158282048414176109fc576109fc6108f1565b600082610b7b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b50049056fea26469706673582212203291a4690e43ad8eb1fa735f45ca525012f4f8f39b157379c0b44263417f840764736f6c63430008110033", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061007d5760003560e01c8063630914d11161005b578063630914d1146100fb578063a5b36a3614610110578063f0f442601461014d578063f1ae88561461016057600080fd5b80634994cc671461008257806357de26a4146100a057806361d027b3146100b6575b600080fd5b61008a6101a9565b6040516100979190610799565b60405180910390f35b6100a8610282565b604051908152602001610097565b6000546100d69073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610097565b61010e6101093660046107f3565b61033c565b005b6000546101389074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610097565b61010e61015b366004610820565b610487565b61019c6040518060400160405280600f81526020017f494230312f455552204f7261636c65000000000000000000000000000000000081525081565b6040516100979190610856565b6040805160028082526060808301845292600092919060208301908036833701905050905073788d911ae7c95121a89a0f0306db65d87422e1de816000815181106101f6576101f66108c2565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073b49f677943bc038e9857d61e7d053caa2c1734c181600181518110610258576102586108c2565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910190910152919050565b670de0b6b3a764000060006102956101a9565b6040805180820182526001815260006020808301829052835180850190945260088085529084015283519394509092905b8181101561033457610322868683815181106102e4576102e46108c2565b60200260200101518684600281106102fe576102fe6108c2565b6020020151868560028110610315576103156108c2565b602002015160ff16610633565b955061032d81610920565b90506102c6565b505050505090565b6000546040517f521d4de900000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091169063521d4de990602401602060405180830381865afa1580156103aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103ce9190610958565b610404576040517f99e120bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f4040b15332969bfd8b2035c1a701c8e13f2b5d62ce89b311684a601b2eb44e019060200160405180910390a150565b6000546040517f676a553e00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091169063676a553e90602401602060405180830381865afa1580156104f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105199190610958565b1580156105b557506000546040517fe43581b800000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091169063e43581b890602401602060405180830381865afa15801561058f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b39190610958565b155b156105ec576040517fb05b9b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008060008060008773ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015610686573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106aa9190610999565b9450945050935093506000831315806106da57508069ffffffffffffffffffff168469ffffffffffffffffffff16115b8061070d575060005474010000000000000000000000000000000000000000900463ffffffff1661070b83426109e9565b115b15610744576040517fae19356300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260ff881660010361077b5761075b87600a610b22565b610765828c610b2e565b61076f9190610b45565b95505050505050610791565b8061078788600a610b22565b610765908c610b2e565b949350505050565b6020808252825182820181905260009190848201906040850190845b818110156107e757835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016107b5565b50909695505050505050565b60006020828403121561080557600080fd5b813563ffffffff8116811461081957600080fd5b9392505050565b60006020828403121561083257600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461081957600080fd5b600060208083528351808285015260005b8181101561088357858101830151858201604001528201610867565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610951576109516108f1565b5060010190565b60006020828403121561096a57600080fd5b8151801515811461081957600080fd5b805169ffffffffffffffffffff8116811461099457600080fd5b919050565b600080600080600060a086880312156109b157600080fd5b6109ba8661097a565b94506020860151935060408601519250606086015191506109dd6080870161097a565b90509295509295909350565b818103818111156109fc576109fc6108f1565b92915050565b600181815b80851115610a5b57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115610a4157610a416108f1565b80851615610a4e57918102915b93841c9390800290610a07565b509250929050565b600082610a72575060016109fc565b81610a7f575060006109fc565b8160018114610a955760028114610a9f57610abb565b60019150506109fc565b60ff841115610ab057610ab06108f1565b50506001821b6109fc565b5060208310610133831016604e8410600b8410161715610ade575081810a6109fc565b610ae88383610a02565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115610b1a57610b1a6108f1565b029392505050565b60006108198383610a63565b80820281158282048414176109fc576109fc6108f1565b600082610b7b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b50049056fea26469706673582212203291a4690e43ad8eb1fa735f45ca525012f4f8f39b157379c0b44263417f840764736f6c63430008110033", + "devdoc": { + "author": "Angle Labs, Inc.", + "kind": "dev", + "methods": { + "changeStalePeriod(uint32)": { + "params": { + "_stalePeriod": "New stale period (in seconds)" + } + }, + "read()": { + "details": "For instance if the out currency is EUR (and hence agEUR), then the base of the returned value is 10**18", + "returns": { + "quoteAmount": "The current rate between the in-currency and out-currency in the base of the out currency" + } + }, + "setTreasury(address)": { + "details": "This function can be called by an approved `VaultManager` contract which can call this function after being requested to do so by a `treasury` contractIn some situations (like reactor contracts), the `VaultManager` may not directly be linked to the `oracle` contract and as such we may need governors to be able to call this function as well", + "params": { + "_treasury": "Address of the new treasury contract" + } + } + }, + "title": "OracleIB01EURChainlink", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "changeStalePeriod(uint32)": { + "notice": "Changes the stale period" + }, + "circuitChainlink()": { + "notice": "Array with the list of Chainlink feeds in the order in which they are read" + }, + "read()": { + "notice": "Reads the rate from the Chainlink circuit and other data provided" + }, + "setTreasury(address)": { + "notice": "Changes the treasury contract" + }, + "stalePeriod()": { + "notice": "Represent the maximum amount of time (in seconds) between each Chainlink update before the price feed is considered stale" + }, + "treasury()": { + "notice": "Reference to the `treasury` contract handling this `VaultManager`" + } + }, + "notice": "Gives the price of IB01 in Euro in base 18", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 27025, + "contract": "contracts/oracle/implementations/mainnet/EUR/OracleIB01EURChainlink.sol:OracleIB01EURChainlink", + "label": "treasury", + "offset": 0, + "slot": "0", + "type": "t_contract(ITreasury)19443" + }, + { + "astId": 27028, + "contract": "contracts/oracle/implementations/mainnet/EUR/OracleIB01EURChainlink.sol:OracleIB01EURChainlink", + "label": "stalePeriod", + "offset": 20, + "slot": "0", + "type": "t_uint32" + } + ], + "types": { + "t_contract(ITreasury)19443": { + "encoding": "inplace", + "label": "contract ITreasury", + "numberOfBytes": "20" + }, + "t_uint32": { + "encoding": "inplace", + "label": "uint32", + "numberOfBytes": "4" + } + } + } +} \ No newline at end of file diff --git a/deployments/mainnet/Oracle_USDC_EUR.json b/deployments/mainnet/Oracle_USDC_EUR.json new file mode 100644 index 00000000..6741bdb6 --- /dev/null +++ b/deployments/mainnet/Oracle_USDC_EUR.json @@ -0,0 +1,247 @@ +{ + "address": "0x8c55A4145Ca4FF8830f39F74feED9059f1BDce68", + "abi": [ + { + "inputs": [ + { + "internalType": "uint32", + "name": "_stalePeriod", + "type": "uint32" + }, + { + "internalType": "address", + "name": "_treasury", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "InvalidChainlinkRate", + "type": "error" + }, + { + "inputs": [], + "name": "NotGovernorOrGuardian", + "type": "error" + }, + { + "inputs": [], + "name": "NotVaultManagerOrGovernor", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint32", + "name": "_stalePeriod", + "type": "uint32" + } + ], + "name": "StalePeriodUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "DESCRIPTION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "_stalePeriod", + "type": "uint32" + } + ], + "name": "changeStalePeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "circuitChainlink", + "outputs": [ + { + "internalType": "contract AggregatorV3Interface[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "read", + "outputs": [ + { + "internalType": "uint256", + "name": "quoteAmount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_treasury", + "type": "address" + } + ], + "name": "setTreasury", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "stalePeriod", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "treasury", + "outputs": [ + { + "internalType": "contract ITreasury", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x7b3e5a8ca441f2ef65b807d3bf8515502bcf8d2d3ac1506e956d1b6fd27dbe12", + "receipt": { + "to": null, + "from": "0xfdA462548Ce04282f4B6D6619823a7C64Fdc0185", + "contractAddress": "0x8c55A4145Ca4FF8830f39F74feED9059f1BDce68", + "transactionIndex": 27, + "gasUsed": "722375", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xd9deaf703587e672417ddb3875239cda6debfd62742c6b97b8f14e9611e0fa26", + "transactionHash": "0x7b3e5a8ca441f2ef65b807d3bf8515502bcf8d2d3ac1506e956d1b6fd27dbe12", + "logs": [], + "blockNumber": 17228920, + "cumulativeGasUsed": "3184889", + "status": 1, + "byzantium": true + }, + "args": [ + 108000, + "0x8667DBEBf68B0BFa6Db54f550f41Be16c4067d60" + ], + "numDeployments": 1, + "solcInputHash": "9a2b71309fb0718473c1f135df2b8dfe", + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_stalePeriod\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"_treasury\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidChainlinkRate\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotGovernorOrGuardian\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotVaultManagerOrGovernor\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"_stalePeriod\",\"type\":\"uint32\"}],\"name\":\"StalePeriodUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DESCRIPTION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_stalePeriod\",\"type\":\"uint32\"}],\"name\":\"changeStalePeriod\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"circuitChainlink\",\"outputs\":[{\"internalType\":\"contract AggregatorV3Interface[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"read\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"quoteAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_treasury\",\"type\":\"address\"}],\"name\":\"setTreasury\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stalePeriod\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"treasury\",\"outputs\":[{\"internalType\":\"contract ITreasury\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Angle Labs, Inc.\",\"kind\":\"dev\",\"methods\":{\"changeStalePeriod(uint32)\":{\"params\":{\"_stalePeriod\":\"New stale period (in seconds)\"}},\"read()\":{\"details\":\"For instance if the out currency is EUR (and hence agEUR), then the base of the returned value is 10**18\",\"returns\":{\"quoteAmount\":\"The current rate between the in-currency and out-currency in the base of the out currency\"}},\"setTreasury(address)\":{\"details\":\"This function can be called by an approved `VaultManager` contract which can call this function after being requested to do so by a `treasury` contractIn some situations (like reactor contracts), the `VaultManager` may not directly be linked to the `oracle` contract and as such we may need governors to be able to call this function as well\",\"params\":{\"_treasury\":\"Address of the new treasury contract\"}}},\"title\":\"OracleUSDCEURChainlink\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"changeStalePeriod(uint32)\":{\"notice\":\"Changes the stale period\"},\"circuitChainlink()\":{\"notice\":\"Array with the list of Chainlink feeds in the order in which they are read\"},\"read()\":{\"notice\":\"Reads the rate from the Chainlink circuit and other data provided\"},\"setTreasury(address)\":{\"notice\":\"Changes the treasury contract\"},\"stalePeriod()\":{\"notice\":\"Represent the maximum amount of time (in seconds) between each Chainlink update before the price feed is considered stale\"},\"treasury()\":{\"notice\":\"Reference to the `treasury` contract handling this `VaultManager`\"}},\"notice\":\"Gives the price of USDC in Euro in base 18\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/oracle/implementations/mainnet/EUR/OracleUSDCEURChainlink.sol\":\"OracleUSDCEURChainlink\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface AggregatorV3Interface {\\n\\n function decimals()\\n external\\n view\\n returns (\\n uint8\\n );\\n\\n function description()\\n external\\n view\\n returns (\\n string memory\\n );\\n\\n function version()\\n external\\n view\\n returns (\\n uint256\\n );\\n\\n // getRoundData and latestRoundData should both raise \\\"No data present\\\"\\n // if they do not have data to report, instead of returning unset values\\n // which could be misinterpreted as actual reported values.\\n function getRoundData(\\n uint80 _roundId\\n )\\n external\\n view\\n returns (\\n uint80 roundId,\\n int256 answer,\\n uint256 startedAt,\\n uint256 updatedAt,\\n uint80 answeredInRound\\n );\\n\\n function latestRoundData()\\n external\\n view\\n returns (\\n uint80 roundId,\\n int256 answer,\\n uint256 startedAt,\\n uint256 updatedAt,\\n uint80 answeredInRound\\n );\\n\\n}\\n\",\"keccak256\":\"0xe6f5ac8c47f3b9b6135051efb9216f9ba5b312a6ecc20209b4f66a780443c328\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20Upgradeable {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x4e733d3164f73f461eaf9d8087a7ad1ea180bdc8ba0d3d61b0e1ae16d8e63dff\",\"license\":\"MIT\"},\"contracts/interfaces/IAgToken.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity ^0.8.12;\\n\\nimport \\\"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\\\";\\n\\n/// @title IAgToken\\n/// @author Angle Labs, Inc.\\n/// @notice Interface for the stablecoins `AgToken` contracts\\n/// @dev This interface only contains functions of the `AgToken` contract which are called by other contracts\\n/// of this module or of the first module of the Angle Protocol\\ninterface IAgToken is IERC20Upgradeable {\\n // ======================= Minter Role Only Functions ===========================\\n\\n /// @notice Lets the `StableMaster` contract or another whitelisted contract mint agTokens\\n /// @param account Address to mint to\\n /// @param amount Amount to mint\\n /// @dev The contracts allowed to issue agTokens are the `StableMaster` contract, `VaultManager` contracts\\n /// associated to this stablecoin as well as the flash loan module (if activated) and potentially contracts\\n /// whitelisted by governance\\n function mint(address account, uint256 amount) external;\\n\\n /// @notice Burns `amount` tokens from a `burner` address after being asked to by `sender`\\n /// @param amount Amount of tokens to burn\\n /// @param burner Address to burn from\\n /// @param sender Address which requested the burn from `burner`\\n /// @dev This method is to be called by a contract with the minter right after being requested\\n /// to do so by a `sender` address willing to burn tokens from another `burner` address\\n /// @dev The method checks the allowance between the `sender` and the `burner`\\n function burnFrom(\\n uint256 amount,\\n address burner,\\n address sender\\n ) external;\\n\\n /// @notice Burns `amount` tokens from a `burner` address\\n /// @param amount Amount of tokens to burn\\n /// @param burner Address to burn from\\n /// @dev This method is to be called by a contract with a minter right on the AgToken after being\\n /// requested to do so by an address willing to burn tokens from its address\\n function burnSelf(uint256 amount, address burner) external;\\n\\n // ========================= Treasury Only Functions ===========================\\n\\n /// @notice Adds a minter in the contract\\n /// @param minter Minter address to add\\n /// @dev Zero address checks are performed directly in the `Treasury` contract\\n function addMinter(address minter) external;\\n\\n /// @notice Removes a minter from the contract\\n /// @param minter Minter address to remove\\n /// @dev This function can also be called by a minter wishing to revoke itself\\n function removeMinter(address minter) external;\\n\\n /// @notice Sets a new treasury contract\\n /// @param _treasury New treasury address\\n function setTreasury(address _treasury) external;\\n\\n // ========================= External functions ================================\\n\\n /// @notice Checks whether an address has the right to mint agTokens\\n /// @param minter Address for which the minting right should be checked\\n /// @return Whether the address has the right to mint agTokens or not\\n function isMinter(address minter) external view returns (bool);\\n\\n /// @notice Get the associated treasury\\n function treasury() external view returns (address);\\n}\\n\",\"keccak256\":\"0xd671dbd00b28a86b839fd455ada4d1ef9203694d06142be76853e00a91f80b5f\",\"license\":\"GPL-3.0\"},\"contracts/interfaces/ICoreBorrow.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity ^0.8.12;\\n\\n/// @title ICoreBorrow\\n/// @author Angle Labs, Inc.\\n/// @notice Interface for the `CoreBorrow` contract\\n/// @dev This interface only contains functions of the `CoreBorrow` contract which are called by other contracts\\n/// of this module\\ninterface ICoreBorrow {\\n /// @notice Checks if an address corresponds to a treasury of a stablecoin with a flash loan\\n /// module initialized on it\\n /// @param treasury Address to check\\n /// @return Whether the address has the `FLASHLOANER_TREASURY_ROLE` or not\\n function isFlashLoanerTreasury(address treasury) external view returns (bool);\\n\\n /// @notice Checks whether an address is governor of the Angle Protocol or not\\n /// @param admin Address to check\\n /// @return Whether the address has the `GOVERNOR_ROLE` or not\\n function isGovernor(address admin) external view returns (bool);\\n\\n /// @notice Checks whether an address is governor or a guardian of the Angle Protocol or not\\n /// @param admin Address to check\\n /// @return Whether the address has the `GUARDIAN_ROLE` or not\\n /// @dev Governance should make sure when adding a governor to also give this governor the guardian\\n /// role by calling the `addGovernor` function\\n function isGovernorOrGuardian(address admin) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x10249210cbf522775f040baf981d7d037472168ce2746d87473ac7c29a34e62e\",\"license\":\"GPL-3.0\"},\"contracts/interfaces/IFlashAngle.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity ^0.8.12;\\n\\nimport \\\"./IAgToken.sol\\\";\\nimport \\\"./ICoreBorrow.sol\\\";\\n\\n/// @title IFlashAngle\\n/// @author Angle Labs, Inc.\\n/// @notice Interface for the `FlashAngle` contract\\n/// @dev This interface only contains functions of the contract which are called by other contracts\\n/// of this module\\ninterface IFlashAngle {\\n /// @notice Reference to the `CoreBorrow` contract managing the FlashLoan module\\n function core() external view returns (ICoreBorrow);\\n\\n /// @notice Sends the fees taken from flash loans to the treasury contract associated to the stablecoin\\n /// @param stablecoin Stablecoin from which profits should be sent\\n /// @return balance Amount of profits sent\\n /// @dev This function can only be called by the treasury contract\\n function accrueInterestToTreasury(IAgToken stablecoin) external returns (uint256 balance);\\n\\n /// @notice Adds support for a stablecoin\\n /// @param _treasury Treasury associated to the stablecoin to add support for\\n /// @dev This function can only be called by the `CoreBorrow` contract\\n function addStablecoinSupport(address _treasury) external;\\n\\n /// @notice Removes support for a stablecoin\\n /// @param _treasury Treasury associated to the stablecoin to remove support for\\n /// @dev This function can only be called by the `CoreBorrow` contract\\n function removeStablecoinSupport(address _treasury) external;\\n\\n /// @notice Sets a new core contract\\n /// @param _core Core contract address to set\\n /// @dev This function can only be called by the `CoreBorrow` contract\\n function setCore(address _core) external;\\n}\\n\",\"keccak256\":\"0x39b0097f695b9e934bccdc72676c91513f1077cc5d0fd151908fd25a7c5cfbe4\",\"license\":\"GPL-3.0\"},\"contracts/interfaces/IOracle.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity ^0.8.12;\\n\\nimport \\\"./ITreasury.sol\\\";\\nimport \\\"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\\\";\\n\\n/// @title IOracle\\n/// @author Angle Labs, Inc.\\n/// @notice Interface for the `Oracle` contract\\n/// @dev This interface only contains functions of the contract which are called by other contracts\\n/// of this module\\ninterface IOracle {\\n /// @notice Reads the rate from the Chainlink circuit and other data provided\\n /// @return quoteAmount The current rate between the in-currency and out-currency in the base\\n /// of the out currency\\n /// @dev For instance if the out currency is EUR (and hence agEUR), then the base of the returned\\n /// value is 10**18\\n function read() external view returns (uint256);\\n\\n /// @notice Changes the treasury contract\\n /// @param _treasury Address of the new treasury contract\\n /// @dev This function can be called by an approved `VaultManager` contract which can call\\n /// this function after being requested to do so by a `treasury` contract\\n /// @dev In some situations (like reactor contracts), the `VaultManager` may not directly be linked\\n /// to the `oracle` contract and as such we may need governors to be able to call this function as well\\n function setTreasury(address _treasury) external;\\n\\n /// @notice Reference to the `treasury` contract handling this `VaultManager`\\n function treasury() external view returns (ITreasury treasury);\\n\\n /// @notice Array with the list of Chainlink feeds in the order in which they are read\\n function circuitChainlink() external view returns (AggregatorV3Interface[] memory);\\n}\\n\",\"keccak256\":\"0x66fe2bb27f26b86e5832fc7d1ebd320cac8b3d79c5998ce148cf7279b2b359be\",\"license\":\"GPL-3.0\"},\"contracts/interfaces/ITreasury.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity ^0.8.12;\\n\\nimport \\\"./IAgToken.sol\\\";\\nimport \\\"./ICoreBorrow.sol\\\";\\nimport \\\"./IFlashAngle.sol\\\";\\n\\n/// @title ITreasury\\n/// @author Angle Labs, Inc.\\n/// @notice Interface for the `Treasury` contract\\n/// @dev This interface only contains functions of the `Treasury` which are called by other contracts\\n/// of this module\\ninterface ITreasury {\\n /// @notice Stablecoin handled by this `treasury` contract\\n function stablecoin() external view returns (IAgToken);\\n\\n /// @notice Checks whether a given address has the governor role\\n /// @param admin Address to check\\n /// @return Whether the address has the governor role\\n /// @dev Access control is only kept in the `CoreBorrow` contract\\n function isGovernor(address admin) external view returns (bool);\\n\\n /// @notice Checks whether a given address has the guardian or the governor role\\n /// @param admin Address to check\\n /// @return Whether the address has the guardian or the governor role\\n /// @dev Access control is only kept in the `CoreBorrow` contract which means that this function\\n /// queries the `CoreBorrow` contract\\n function isGovernorOrGuardian(address admin) external view returns (bool);\\n\\n /// @notice Checks whether a given address has well been initialized in this contract\\n /// as a `VaultManager`\\n /// @param _vaultManager Address to check\\n /// @return Whether the address has been initialized or not\\n function isVaultManager(address _vaultManager) external view returns (bool);\\n\\n /// @notice Sets a new flash loan module for this stablecoin\\n /// @param _flashLoanModule Reference to the new flash loan module\\n /// @dev This function removes the minting right to the old flash loan module and grants\\n /// it to the new module\\n function setFlashLoanModule(address _flashLoanModule) external;\\n}\\n\",\"keccak256\":\"0x624733dae1bfb98721ba994573aed10997f7448c893b791ed985300531c361fd\",\"license\":\"GPL-3.0\"},\"contracts/oracle/BaseOracleChainlinkMulti.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\n/*\\n * \\u2588 \\n ***** \\u2593\\u2593\\u2593 \\n * \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\n * ///. \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\n ***** //////// \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\n * ///////////// \\u2593\\u2593\\u2593 \\n \\u2593\\u2593 ////////////////// \\u2588 \\u2593\\u2593 \\n \\u2593\\u2593 \\u2593\\u2593 /////////////////////// \\u2593\\u2593 \\u2593\\u2593 \\n \\u2593\\u2593 \\u2593\\u2593 //////////////////////////// \\u2593\\u2593 \\u2593\\u2593 \\n \\u2593\\u2593 \\u2593\\u2593 /////////\\u2593\\u2593\\u2593///////\\u2593\\u2593\\u2593///////// \\u2593\\u2593 \\u2593\\u2593 \\n \\u2593\\u2593 ,////////////////////////////////////// \\u2593\\u2593 \\u2593\\u2593 \\n \\u2593\\u2593 ////////////////////////////////////////// \\u2593\\u2593 \\n \\u2593\\u2593 //////////////////////\\u2593\\u2593\\u2593\\u2593///////////////////// \\n ,//////////////////////////////////////////////////// \\n .////////////////////////////////////////////////////////// \\n .//////////////////////////\\u2588\\u2588.,//////////////////////////\\u2588 \\n .//////////////////////\\u2588\\u2588\\u2588\\u2588..,./////////////////////\\u2588\\u2588 \\n ...////////////////\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588.....,.////////////////\\u2588\\u2588\\u2588 \\n ,.,////////////\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 ........,///////////\\u2588\\u2588\\u2588\\u2588 \\n .,.,//////\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 ,.......///////\\u2588\\u2588\\u2588\\u2588 \\n ,..//\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 ........./\\u2588\\u2588\\u2588\\u2588 \\n ..,\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 .....,\\u2588\\u2588\\u2588 \\n .\\u2588\\u2588 ,.,\\u2588 \\n \\n \\n \\n \\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\n \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593 \\u2593\\u2593 \\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593 \\n \\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593 \\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593 \\n \\u2593\\u2593\\u2593 \\u2593\\u2593 \\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593\\u2593 \\n*/\\n\\npragma solidity ^0.8.12;\\n\\nimport \\\"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\\\";\\n\\nimport \\\"../interfaces/IOracle.sol\\\";\\nimport \\\"../interfaces/ITreasury.sol\\\";\\n\\n/// @title BaseOracleChainlinkMulti\\n/// @author Angle Labs, Inc.\\n/// @notice Base Contract to be overriden by all contracts of the protocol\\n/// @dev This base contract concerns an oracle that uses Chainlink with multiple pools to read from\\n/// @dev All gas-efficient implementation of the `OracleChainlinkMulti` contract should inherit from this\\nabstract contract BaseOracleChainlinkMulti is IOracle {\\n // ========================= Parameters and References =========================\\n\\n /// @inheritdoc IOracle\\n ITreasury public override treasury;\\n /// @notice Represent the maximum amount of time (in seconds) between each Chainlink update\\n /// before the price feed is considered stale\\n uint32 public stalePeriod;\\n\\n // =================================== Event ===================================\\n\\n event StalePeriodUpdated(uint32 _stalePeriod);\\n\\n // =================================== Errors ===================================\\n\\n error InvalidChainlinkRate();\\n error NotGovernorOrGuardian();\\n error NotVaultManagerOrGovernor();\\n\\n /// @notice Constructor for an oracle using Chainlink with multiple pools to read from\\n /// @param _stalePeriod Minimum feed update frequency for the oracle to not revert\\n /// @param _treasury Treasury associated to the VaultManager which reads from this feed\\n constructor(uint32 _stalePeriod, address _treasury) {\\n stalePeriod = _stalePeriod;\\n treasury = ITreasury(_treasury);\\n }\\n\\n // ============================= Reading Oracles ===============================\\n\\n /// @inheritdoc IOracle\\n function read() external view virtual override returns (uint256 quoteAmount);\\n\\n /// @inheritdoc IOracle\\n function circuitChainlink() public view virtual returns (AggregatorV3Interface[] memory);\\n\\n /// @notice Reads a Chainlink feed using a quote amount and converts the quote amount to\\n /// the out-currency\\n /// @param quoteAmount The amount for which to compute the price expressed with base decimal\\n /// @param feed Chainlink feed to query\\n /// @param multiplied Whether the ratio outputted by Chainlink should be multiplied or divided\\n /// to the `quoteAmount`\\n /// @param decimals Number of decimals of the corresponding Chainlink pair\\n /// @return The `quoteAmount` converted in out-currency\\n function _readChainlinkFeed(\\n uint256 quoteAmount,\\n AggregatorV3Interface feed,\\n uint8 multiplied,\\n uint256 decimals\\n ) internal view returns (uint256) {\\n (uint80 roundId, int256 ratio, , uint256 updatedAt, uint80 answeredInRound) = feed.latestRoundData();\\n if (ratio <= 0 || roundId > answeredInRound || block.timestamp - updatedAt > stalePeriod)\\n revert InvalidChainlinkRate();\\n uint256 castedRatio = uint256(ratio);\\n // Checking whether we should multiply or divide by the ratio computed\\n if (multiplied == 1) return (quoteAmount * castedRatio) / (10 ** decimals);\\n else return (quoteAmount * (10 ** decimals)) / castedRatio;\\n }\\n\\n // ======================= Governance Related Functions ========================\\n\\n /// @notice Changes the stale period\\n /// @param _stalePeriod New stale period (in seconds)\\n function changeStalePeriod(uint32 _stalePeriod) external {\\n if (!treasury.isGovernorOrGuardian(msg.sender)) revert NotGovernorOrGuardian();\\n stalePeriod = _stalePeriod;\\n emit StalePeriodUpdated(_stalePeriod);\\n }\\n\\n /// @inheritdoc IOracle\\n function setTreasury(address _treasury) external override {\\n if (!treasury.isVaultManager(msg.sender) && !treasury.isGovernor(msg.sender))\\n revert NotVaultManagerOrGovernor();\\n treasury = ITreasury(_treasury);\\n }\\n}\\n\",\"keccak256\":\"0x6dc796277e844596455ea6d486fd5d439e407688ba4573055ab0b61c924588ed\",\"license\":\"GPL-3.0\"},\"contracts/oracle/BaseOracleChainlinkMultiTwoFeeds.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity ^0.8.12;\\n\\nimport \\\"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\\\";\\n\\nimport \\\"./BaseOracleChainlinkMulti.sol\\\";\\n\\n/// @title BaseOracleChainlinkMultiTwoFeeds\\n/// @author Angle Labs, Inc.\\n/// @notice Base contract for an oracle that reads into two Chainlink feeds (including an EUR/USD feed) which both have\\n/// 8 decimals\\nabstract contract BaseOracleChainlinkMultiTwoFeeds is BaseOracleChainlinkMulti {\\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMulti(_stalePeriod, _treasury) {}\\n\\n /// @notice Returns the quote amount of the oracle contract\\n function _getQuoteAmount() internal view virtual returns (uint256) {\\n return 10**18;\\n }\\n\\n /// @inheritdoc IOracle\\n function read() external view virtual override returns (uint256 quoteAmount) {\\n quoteAmount = _getQuoteAmount();\\n AggregatorV3Interface[] memory _circuitChainlink = circuitChainlink();\\n uint8[2] memory circuitChainIsMultiplied = [1, 0];\\n uint8[2] memory chainlinkDecimals = [8, 8];\\n uint256 circuitLength = _circuitChainlink.length;\\n for (uint256 i; i < circuitLength; ++i) {\\n quoteAmount = _readChainlinkFeed(\\n quoteAmount,\\n _circuitChainlink[i],\\n circuitChainIsMultiplied[i],\\n chainlinkDecimals[i]\\n );\\n }\\n }\\n}\\n\",\"keccak256\":\"0xebb59af75b56f0a458717897371327c3373c6e260b2589d22485ff3a026a3f4e\",\"license\":\"GPL-3.0\"},\"contracts/oracle/implementations/mainnet/EUR/OracleUSDCEURChainlink.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity ^0.8.12;\\n\\nimport \\\"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\\\";\\n\\nimport \\\"../../../BaseOracleChainlinkMultiTwoFeeds.sol\\\";\\n\\n/// @title OracleUSDCEURChainlink\\n/// @author Angle Labs, Inc.\\n/// @notice Gives the price of USDC in Euro in base 18\\ncontract OracleUSDCEURChainlink is BaseOracleChainlinkMultiTwoFeeds {\\n string public constant DESCRIPTION = \\\"USDC/EUR Oracle\\\";\\n\\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\\n\\n /// @inheritdoc IOracle\\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\\n // Oracle USDC/USD\\n _circuitChainlink[0] = AggregatorV3Interface(0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6);\\n // Oracle EUR/USD\\n _circuitChainlink[1] = AggregatorV3Interface(0xb49f677943BC038e9857d61E7d053CaA2C1734C1);\\n return _circuitChainlink;\\n }\\n}\\n\",\"keccak256\":\"0x1b7c4c545920b087e1ac6d82e1c7802912280e0bdf00f7af3bf3ae9f3888dab5\",\"license\":\"GPL-3.0\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b50604051610c85380380610c8583398101604081905261002f91610071565b600080546001600160c01b031916600160a01b63ffffffff94909416939093026001600160a01b031916929092176001600160a01b03919091161790556100c0565b6000806040838503121561008457600080fd5b825163ffffffff8116811461009857600080fd5b60208401519092506001600160a01b03811681146100b557600080fd5b809150509250929050565b610bb6806100cf6000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c8063630914d11161005b578063630914d1146100fb578063a5b36a3614610110578063f0f442601461014d578063f1ae88561461016057600080fd5b80634994cc671461008257806357de26a4146100a057806361d027b3146100b6575b600080fd5b61008a6101a9565b6040516100979190610799565b60405180910390f35b6100a8610282565b604051908152602001610097565b6000546100d69073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610097565b61010e6101093660046107f3565b61033c565b005b6000546101389074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610097565b61010e61015b366004610820565b610487565b61019c6040518060400160405280600f81526020017f555344432f455552204f7261636c65000000000000000000000000000000000081525081565b6040516100979190610856565b60408051600280825260608083018452926000929190602083019080368337019050509050738fffffd4afb6115b954bd326cbe7b4ba576818f6816000815181106101f6576101f66108c2565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073b49f677943bc038e9857d61e7d053caa2c1734c181600181518110610258576102586108c2565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910190910152919050565b670de0b6b3a764000060006102956101a9565b6040805180820182526001815260006020808301829052835180850190945260088085529084015283519394509092905b8181101561033457610322868683815181106102e4576102e46108c2565b60200260200101518684600281106102fe576102fe6108c2565b6020020151868560028110610315576103156108c2565b602002015160ff16610633565b955061032d81610920565b90506102c6565b505050505090565b6000546040517f521d4de900000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091169063521d4de990602401602060405180830381865afa1580156103aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103ce9190610958565b610404576040517f99e120bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f4040b15332969bfd8b2035c1a701c8e13f2b5d62ce89b311684a601b2eb44e019060200160405180910390a150565b6000546040517f676a553e00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091169063676a553e90602401602060405180830381865afa1580156104f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105199190610958565b1580156105b557506000546040517fe43581b800000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091169063e43581b890602401602060405180830381865afa15801561058f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b39190610958565b155b156105ec576040517fb05b9b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008060008060008773ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015610686573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106aa9190610999565b9450945050935093506000831315806106da57508069ffffffffffffffffffff168469ffffffffffffffffffff16115b8061070d575060005474010000000000000000000000000000000000000000900463ffffffff1661070b83426109e9565b115b15610744576040517fae19356300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260ff881660010361077b5761075b87600a610b22565b610765828c610b2e565b61076f9190610b45565b95505050505050610791565b8061078788600a610b22565b610765908c610b2e565b949350505050565b6020808252825182820181905260009190848201906040850190845b818110156107e757835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016107b5565b50909695505050505050565b60006020828403121561080557600080fd5b813563ffffffff8116811461081957600080fd5b9392505050565b60006020828403121561083257600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461081957600080fd5b600060208083528351808285015260005b8181101561088357858101830151858201604001528201610867565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610951576109516108f1565b5060010190565b60006020828403121561096a57600080fd5b8151801515811461081957600080fd5b805169ffffffffffffffffffff8116811461099457600080fd5b919050565b600080600080600060a086880312156109b157600080fd5b6109ba8661097a565b94506020860151935060408601519250606086015191506109dd6080870161097a565b90509295509295909350565b818103818111156109fc576109fc6108f1565b92915050565b600181815b80851115610a5b57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115610a4157610a416108f1565b80851615610a4e57918102915b93841c9390800290610a07565b509250929050565b600082610a72575060016109fc565b81610a7f575060006109fc565b8160018114610a955760028114610a9f57610abb565b60019150506109fc565b60ff841115610ab057610ab06108f1565b50506001821b6109fc565b5060208310610133831016604e8410600b8410161715610ade575081810a6109fc565b610ae88383610a02565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115610b1a57610b1a6108f1565b029392505050565b60006108198383610a63565b80820281158282048414176109fc576109fc6108f1565b600082610b7b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b50049056fea2646970667358221220e6a0e7b1dad88c9c025ea54cc307b6ccbeb468f504e568b78eecc8d48c16423264736f6c63430008110033", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061007d5760003560e01c8063630914d11161005b578063630914d1146100fb578063a5b36a3614610110578063f0f442601461014d578063f1ae88561461016057600080fd5b80634994cc671461008257806357de26a4146100a057806361d027b3146100b6575b600080fd5b61008a6101a9565b6040516100979190610799565b60405180910390f35b6100a8610282565b604051908152602001610097565b6000546100d69073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610097565b61010e6101093660046107f3565b61033c565b005b6000546101389074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610097565b61010e61015b366004610820565b610487565b61019c6040518060400160405280600f81526020017f555344432f455552204f7261636c65000000000000000000000000000000000081525081565b6040516100979190610856565b60408051600280825260608083018452926000929190602083019080368337019050509050738fffffd4afb6115b954bd326cbe7b4ba576818f6816000815181106101f6576101f66108c2565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073b49f677943bc038e9857d61e7d053caa2c1734c181600181518110610258576102586108c2565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910190910152919050565b670de0b6b3a764000060006102956101a9565b6040805180820182526001815260006020808301829052835180850190945260088085529084015283519394509092905b8181101561033457610322868683815181106102e4576102e46108c2565b60200260200101518684600281106102fe576102fe6108c2565b6020020151868560028110610315576103156108c2565b602002015160ff16610633565b955061032d81610920565b90506102c6565b505050505090565b6000546040517f521d4de900000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091169063521d4de990602401602060405180830381865afa1580156103aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103ce9190610958565b610404576040517f99e120bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416908102919091179091556040519081527f4040b15332969bfd8b2035c1a701c8e13f2b5d62ce89b311684a601b2eb44e019060200160405180910390a150565b6000546040517f676a553e00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091169063676a553e90602401602060405180830381865afa1580156104f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105199190610958565b1580156105b557506000546040517fe43581b800000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091169063e43581b890602401602060405180830381865afa15801561058f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b39190610958565b155b156105ec576040517fb05b9b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008060008060008773ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015610686573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106aa9190610999565b9450945050935093506000831315806106da57508069ffffffffffffffffffff168469ffffffffffffffffffff16115b8061070d575060005474010000000000000000000000000000000000000000900463ffffffff1661070b83426109e9565b115b15610744576040517fae19356300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260ff881660010361077b5761075b87600a610b22565b610765828c610b2e565b61076f9190610b45565b95505050505050610791565b8061078788600a610b22565b610765908c610b2e565b949350505050565b6020808252825182820181905260009190848201906040850190845b818110156107e757835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016107b5565b50909695505050505050565b60006020828403121561080557600080fd5b813563ffffffff8116811461081957600080fd5b9392505050565b60006020828403121561083257600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461081957600080fd5b600060208083528351808285015260005b8181101561088357858101830151858201604001528201610867565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610951576109516108f1565b5060010190565b60006020828403121561096a57600080fd5b8151801515811461081957600080fd5b805169ffffffffffffffffffff8116811461099457600080fd5b919050565b600080600080600060a086880312156109b157600080fd5b6109ba8661097a565b94506020860151935060408601519250606086015191506109dd6080870161097a565b90509295509295909350565b818103818111156109fc576109fc6108f1565b92915050565b600181815b80851115610a5b57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115610a4157610a416108f1565b80851615610a4e57918102915b93841c9390800290610a07565b509250929050565b600082610a72575060016109fc565b81610a7f575060006109fc565b8160018114610a955760028114610a9f57610abb565b60019150506109fc565b60ff841115610ab057610ab06108f1565b50506001821b6109fc565b5060208310610133831016604e8410600b8410161715610ade575081810a6109fc565b610ae88383610a02565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115610b1a57610b1a6108f1565b029392505050565b60006108198383610a63565b80820281158282048414176109fc576109fc6108f1565b600082610b7b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b50049056fea2646970667358221220e6a0e7b1dad88c9c025ea54cc307b6ccbeb468f504e568b78eecc8d48c16423264736f6c63430008110033", + "devdoc": { + "author": "Angle Labs, Inc.", + "kind": "dev", + "methods": { + "changeStalePeriod(uint32)": { + "params": { + "_stalePeriod": "New stale period (in seconds)" + } + }, + "read()": { + "details": "For instance if the out currency is EUR (and hence agEUR), then the base of the returned value is 10**18", + "returns": { + "quoteAmount": "The current rate between the in-currency and out-currency in the base of the out currency" + } + }, + "setTreasury(address)": { + "details": "This function can be called by an approved `VaultManager` contract which can call this function after being requested to do so by a `treasury` contractIn some situations (like reactor contracts), the `VaultManager` may not directly be linked to the `oracle` contract and as such we may need governors to be able to call this function as well", + "params": { + "_treasury": "Address of the new treasury contract" + } + } + }, + "title": "OracleUSDCEURChainlink", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "changeStalePeriod(uint32)": { + "notice": "Changes the stale period" + }, + "circuitChainlink()": { + "notice": "Array with the list of Chainlink feeds in the order in which they are read" + }, + "read()": { + "notice": "Reads the rate from the Chainlink circuit and other data provided" + }, + "setTreasury(address)": { + "notice": "Changes the treasury contract" + }, + "stalePeriod()": { + "notice": "Represent the maximum amount of time (in seconds) between each Chainlink update before the price feed is considered stale" + }, + "treasury()": { + "notice": "Reference to the `treasury` contract handling this `VaultManager`" + } + }, + "notice": "Gives the price of USDC in Euro in base 18", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 27025, + "contract": "contracts/oracle/implementations/mainnet/EUR/OracleUSDCEURChainlink.sol:OracleUSDCEURChainlink", + "label": "treasury", + "offset": 0, + "slot": "0", + "type": "t_contract(ITreasury)19443" + }, + { + "astId": 27028, + "contract": "contracts/oracle/implementations/mainnet/EUR/OracleUSDCEURChainlink.sol:OracleUSDCEURChainlink", + "label": "stalePeriod", + "offset": 20, + "slot": "0", + "type": "t_uint32" + } + ], + "types": { + "t_contract(ITreasury)19443": { + "encoding": "inplace", + "label": "contract ITreasury", + "numberOfBytes": "20" + }, + "t_uint32": { + "encoding": "inplace", + "label": "uint32", + "numberOfBytes": "4" + } + } + } +} \ No newline at end of file diff --git a/deployments/mainnet/VaultManager_PermissionedLiquidations_Implementation.json b/deployments/mainnet/VaultManager_PermissionedLiquidations_Implementation.json new file mode 100644 index 00000000..a3507b8a --- /dev/null +++ b/deployments/mainnet/VaultManager_PermissionedLiquidations_Implementation.json @@ -0,0 +1,1828 @@ +{ + "address": "0x88fE06D438F5264dA8e2CDCAc3DAED1eA70F995a", + "abi": [ + { + "inputs": [], + "name": "ApprovalToCaller", + "type": "error" + }, + { + "inputs": [], + "name": "ApprovalToOwner", + "type": "error" + }, + { + "inputs": [], + "name": "DebtCeilingExceeded", + "type": "error" + }, + { + "inputs": [], + "name": "DustyLeftoverAmount", + "type": "error" + }, + { + "inputs": [], + "name": "ExpiredDeadline", + "type": "error" + }, + { + "inputs": [], + "name": "HealthyVault", + "type": "error" + }, + { + "inputs": [], + "name": "IncompatibleLengths", + "type": "error" + }, + { + "inputs": [], + "name": "InsolventVault", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidParameterType", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidParameterValue", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidSetOfParameters", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidSignature", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidTreasury", + "type": "error" + }, + { + "inputs": [], + "name": "NonERC721Receiver", + "type": "error" + }, + { + "inputs": [], + "name": "NonexistentVault", + "type": "error" + }, + { + "inputs": [], + "name": "NotApproved", + "type": "error" + }, + { + "inputs": [], + "name": "NotGovernor", + "type": "error" + }, + { + "inputs": [], + "name": "NotGovernorOrGuardian", + "type": "error" + }, + { + "inputs": [], + "name": "NotTreasury", + "type": "error" + }, + { + "inputs": [], + "name": "NotVaultManager", + "type": "error" + }, + { + "inputs": [], + "name": "NotWhitelisted", + "type": "error" + }, + { + "inputs": [], + "name": "Paused", + "type": "error" + }, + { + "inputs": [], + "name": "TooHighParameterValue", + "type": "error" + }, + { + "inputs": [], + "name": "TooSmallParameterValue", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "surplusEndValue", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "badDebtEndValue", + "type": "uint256" + } + ], + "name": "AccruedToTreasury", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "vaultID", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "collateralAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "isIncrease", + "type": "uint8" + } + ], + "name": "CollateralAmountUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "debtCeiling", + "type": "uint256" + } + ], + "name": "DebtCeilingUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "srcVaultID", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dstVaultID", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "dstVaultManager", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "DebtTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "param", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "what", + "type": "bytes32" + } + ], + "name": "FiledUint64", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "InterestAccumulatorUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "vaultID", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "internalAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "isIncrease", + "type": "uint8" + } + ], + "name": "InternalDebtUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256[]", + "name": "vaultIDs", + "type": "uint256[]" + } + ], + "name": "LiquidatedVaults", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_veBoostProxy", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "xBoost", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "yBoost", + "type": "uint256[]" + } + ], + "name": "LiquidationBoostParametersUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [], + "name": "BASE_INTEREST", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "BASE_PARAMS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "HALF_BASE_INTEREST", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "accrueInterestToTreasury", + "outputs": [ + { + "internalType": "uint256", + "name": "surplusValue", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "badDebtValue", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum ActionType[]", + "name": "actions", + "type": "uint8[]" + }, + { + "internalType": "bytes[]", + "name": "datas", + "type": "bytes[]" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "angle", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "stablecoinAmountToGive", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stablecoinAmountToReceive", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "collateralAmountToGive", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "collateralAmountToReceive", + "type": "uint256" + } + ], + "internalType": "struct PaymentData", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum ActionType[]", + "name": "actions", + "type": "uint8[]" + }, + { + "internalType": "bytes[]", + "name": "datas", + "type": "bytes[]" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "address", + "name": "who", + "type": "address" + }, + { + "internalType": "bytes", + "name": "repayData", + "type": "bytes" + } + ], + "name": "angle", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "stablecoinAmountToGive", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stablecoinAmountToReceive", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "collateralAmountToGive", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "collateralAmountToReceive", + "type": "uint256" + } + ], + "internalType": "struct PaymentData", + "name": "paymentData", + "type": "tuple" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "vaultID", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "badDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "borrowFee", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "vaultID", + "type": "uint256" + }, + { + "internalType": "address", + "name": "liquidator", + "type": "address" + } + ], + "name": "checkLiquidation", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "maxStablecoinAmountToRepay", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxCollateralAmountGiven", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "thresholdRepayAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "discount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currentDebt", + "type": "uint256" + } + ], + "internalType": "struct LiquidationOpportunity", + "name": "liqOpp", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collateral", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collateralFactor", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "toVault", + "type": "address" + } + ], + "name": "createVault", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "debtCeiling", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dust", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dustLiquidation", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "vaultID", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "vaultID", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stablecoinAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "senderBorrowFee", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "senderRepayFee", + "type": "uint256" + } + ], + "name": "getDebtOut", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getTotalDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "vaultID", + "type": "uint256" + } + ], + "name": "getVaultDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ITreasury", + "name": "_treasury", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "_collateral", + "type": "address" + }, + { + "internalType": "contract IOracle", + "name": "_oracle", + "type": "address" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "debtCeiling", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "collateralFactor", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "targetHealthFactor", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "interestRate", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "liquidationSurcharge", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "maxLiquidationDiscount", + "type": "uint64" + }, + { + "internalType": "bool", + "name": "whitelistingActivated", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "baseBoost", + "type": "uint256" + } + ], + "internalType": "struct VaultParameters", + "name": "params", + "type": "tuple" + }, + { + "internalType": "string", + "name": "_symbol", + "type": "string" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "interestAccumulator", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "interestRate", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "vaultID", + "type": "uint256" + } + ], + "name": "isApprovedOrOwner", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isWhitelisted", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastInterestAccumulatorUpdated", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "vaultIDs", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "address", + "name": "who", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "liquidate", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "stablecoinAmountToReceive", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "collateralAmountToGive", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "badDebtFromLiquidation", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "oracleValue", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "newInterestAccumulator", + "type": "uint256" + } + ], + "internalType": "struct LiquidatorData", + "name": "liqData", + "type": "tuple" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "vaultIDs", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "liquidate", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "stablecoinAmountToReceive", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "collateralAmountToGive", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "badDebtFromLiquidation", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "oracleValue", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "newInterestAccumulator", + "type": "uint256" + } + ], + "internalType": "struct LiquidatorData", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "liquidationSurcharge", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxLiquidationDiscount", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "oracle", + "outputs": [ + { + "internalType": "contract IOracle", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "vaultID", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "repayFee", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "vaultID", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "vaultID", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "baseURI_", + "type": "string" + } + ], + "name": "setBaseURI", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_debtCeiling", + "type": "uint256" + } + ], + "name": "setDebtCeiling", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dust", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_dustLiquidation", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dustCollateral_", + "type": "uint256" + } + ], + "name": "setDusts", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_veBoostProxy", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "xBoost", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "yBoost", + "type": "uint256[]" + } + ], + "name": "setLiquidationBoostParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_oracle", + "type": "address" + } + ], + "name": "setOracle", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_treasury", + "type": "address" + } + ], + "name": "setTreasury", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "param", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "what", + "type": "bytes32" + } + ], + "name": "setUint64", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "stablecoin", + "outputs": [ + { + "internalType": "contract IAgToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "surplus", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "targetHealthFactor", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "togglePause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "toggleWhitelist", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "vaultID", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalNormalizedDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "vaultID", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "treasury", + "outputs": [ + { + "internalType": "contract ITreasury", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "vaultData", + "outputs": [ + { + "internalType": "uint256", + "name": "collateralAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "normalizedDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "vaultIDCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "veBoostProxy", + "outputs": [ + { + "internalType": "contract IVeBoostProxy", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "whitelistingActivated", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "xLiquidationBoost", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "yLiquidationBoost", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x7c1582a36ce2a35a332e8dc2d0467bcadadfc86903698f2e12b2817bb8c5d7fb", + "receipt": { + "to": null, + "from": "0xfdA462548Ce04282f4B6D6619823a7C64Fdc0185", + "contractAddress": "0x88fE06D438F5264dA8e2CDCAc3DAED1eA70F995a", + "transactionIndex": 70, + "gasUsed": "5346322", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000080000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000080000000000000000000000000000000000000000000000000000000000000080000000000000000000000000", + "blockHash": "0x238bb752d9fca38fd7fb274915da222ca2c25805e54eb28b9515e1ac73fe98de", + "transactionHash": "0x7c1582a36ce2a35a332e8dc2d0467bcadadfc86903698f2e12b2817bb8c5d7fb", + "logs": [ + { + "transactionIndex": 70, + "blockNumber": 17228932, + "transactionHash": "0x7c1582a36ce2a35a332e8dc2d0467bcadadfc86903698f2e12b2817bb8c5d7fb", + "address": "0x88fE06D438F5264dA8e2CDCAc3DAED1eA70F995a", + "topics": [ + "0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logIndex": 154, + "blockHash": "0x238bb752d9fca38fd7fb274915da222ca2c25805e54eb28b9515e1ac73fe98de" + } + ], + "blockNumber": 17228932, + "cumulativeGasUsed": "10846100", + "status": 1, + "byzantium": true + }, + "args": [], + "numDeployments": 1, + "solcInputHash": "dd5bbe02f1e84bb60ce90a2cdb3bdbaa", + "metadata": "{\"compiler\":{\"version\":\"0.8.12+commit.f00d7308\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"ApprovalToCaller\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ApprovalToOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DebtCeilingExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DustyLeftoverAmount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExpiredDeadline\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"HealthyVault\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncompatibleLengths\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsolventVault\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidParameterType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidParameterValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSetOfParameters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSignature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTreasury\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NonERC721Receiver\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NonexistentVault\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotApproved\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotGovernor\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotGovernorOrGuardian\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotTreasury\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotVaultManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotWhitelisted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Paused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooHighParameterValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooSmallParameterValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"surplusEndValue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"badDebtEndValue\",\"type\":\"uint256\"}],\"name\":\"AccruedToTreasury\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"approved\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"vaultID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"collateralAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"isIncrease\",\"type\":\"uint8\"}],\"name\":\"CollateralAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"debtCeiling\",\"type\":\"uint256\"}],\"name\":\"DebtCeilingUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"srcVaultID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dstVaultID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"dstVaultManager\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"DebtTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"param\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"what\",\"type\":\"bytes32\"}],\"name\":\"FiledUint64\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"InterestAccumulatorUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"vaultID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"internalAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"isIncrease\",\"type\":\"uint8\"}],\"name\":\"InternalDebtUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"vaultIDs\",\"type\":\"uint256[]\"}],\"name\":\"LiquidatedVaults\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_veBoostProxy\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"xBoost\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"yBoost\",\"type\":\"uint256[]\"}],\"name\":\"LiquidationBoostParametersUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BASE_INTEREST\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"BASE_PARAMS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"HALF_BASE_INTEREST\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"accrueInterestToTreasury\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"surplusValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"badDebtValue\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"enum ActionType[]\",\"name\":\"actions\",\"type\":\"uint8[]\"},{\"internalType\":\"bytes[]\",\"name\":\"datas\",\"type\":\"bytes[]\"},{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"angle\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stablecoinAmountToGive\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stablecoinAmountToReceive\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"collateralAmountToGive\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"collateralAmountToReceive\",\"type\":\"uint256\"}],\"internalType\":\"struct PaymentData\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"enum ActionType[]\",\"name\":\"actions\",\"type\":\"uint8[]\"},{\"internalType\":\"bytes[]\",\"name\":\"datas\",\"type\":\"bytes[]\"},{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"who\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"repayData\",\"type\":\"bytes\"}],\"name\":\"angle\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stablecoinAmountToGive\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stablecoinAmountToReceive\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"collateralAmountToGive\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"collateralAmountToReceive\",\"type\":\"uint256\"}],\"internalType\":\"struct PaymentData\",\"name\":\"paymentData\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"vaultID\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"badDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"borrowFee\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"vaultID\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"liquidator\",\"type\":\"address\"}],\"name\":\"checkLiquidation\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"maxStablecoinAmountToRepay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCollateralAmountGiven\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"thresholdRepayAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"discount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currentDebt\",\"type\":\"uint256\"}],\"internalType\":\"struct LiquidationOpportunity\",\"name\":\"liqOpp\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collateral\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"collateralFactor\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"toVault\",\"type\":\"address\"}],\"name\":\"createVault\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"debtCeiling\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dust\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"dustLiquidation\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"vaultID\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"vaultID\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stablecoinAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"senderBorrowFee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"senderRepayFee\",\"type\":\"uint256\"}],\"name\":\"getDebtOut\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTotalDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"vaultID\",\"type\":\"uint256\"}],\"name\":\"getVaultDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract ITreasury\",\"name\":\"_treasury\",\"type\":\"address\"},{\"internalType\":\"contract IERC20\",\"name\":\"_collateral\",\"type\":\"address\"},{\"internalType\":\"contract IOracle\",\"name\":\"_oracle\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"debtCeiling\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"collateralFactor\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"targetHealthFactor\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"interestRate\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"liquidationSurcharge\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"maxLiquidationDiscount\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"whitelistingActivated\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"baseBoost\",\"type\":\"uint256\"}],\"internalType\":\"struct VaultParameters\",\"name\":\"params\",\"type\":\"tuple\"},{\"internalType\":\"string\",\"name\":\"_symbol\",\"type\":\"string\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"interestAccumulator\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"interestRate\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"vaultID\",\"type\":\"uint256\"}],\"name\":\"isApprovedOrOwner\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isWhitelisted\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastInterestAccumulatorUpdated\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"vaultIDs\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"who\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"liquidate\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stablecoinAmountToReceive\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"collateralAmountToGive\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"badDebtFromLiquidation\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"oracleValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"newInterestAccumulator\",\"type\":\"uint256\"}],\"internalType\":\"struct LiquidatorData\",\"name\":\"liqData\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"vaultIDs\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"liquidate\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stablecoinAmountToReceive\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"collateralAmountToGive\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"badDebtFromLiquidation\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"oracleValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"newInterestAccumulator\",\"type\":\"uint256\"}],\"internalType\":\"struct LiquidatorData\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"liquidationSurcharge\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxLiquidationDiscount\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracle\",\"outputs\":[{\"internalType\":\"contract IOracle\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"vaultID\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"repayFee\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"vaultID\",\"type\":\"uint256\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"vaultID\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"baseURI_\",\"type\":\"string\"}],\"name\":\"setBaseURI\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_debtCeiling\",\"type\":\"uint256\"}],\"name\":\"setDebtCeiling\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dust\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_dustLiquidation\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dustCollateral_\",\"type\":\"uint256\"}],\"name\":\"setDusts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_veBoostProxy\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"xBoost\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"yBoost\",\"type\":\"uint256[]\"}],\"name\":\"setLiquidationBoostParameters\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_oracle\",\"type\":\"address\"}],\"name\":\"setOracle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_treasury\",\"type\":\"address\"}],\"name\":\"setTreasury\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"param\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"what\",\"type\":\"bytes32\"}],\"name\":\"setUint64\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stablecoin\",\"outputs\":[{\"internalType\":\"contract IAgToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"surplus\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"targetHealthFactor\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"togglePause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"toggleWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"vaultID\",\"type\":\"uint256\"}],\"name\":\"tokenURI\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalNormalizedDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"vaultID\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"treasury\",\"outputs\":[{\"internalType\":\"contract ITreasury\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"vaultData\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"collateralAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"normalizedDebt\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"vaultIDCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"veBoostProxy\",\"outputs\":[{\"internalType\":\"contract IVeBoostProxy\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"whitelistingActivated\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"xLiquidationBoost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"yLiquidationBoost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Angle Labs, Inc.\",\"kind\":\"dev\",\"methods\":{\"accrueInterestToTreasury()\":{\"details\":\"`surplus` and `badDebt` should be reset to 0 once their current value have been given to the `treasury` contract\",\"returns\":{\"badDebtValue\":\"Value of the bad debt communicated to the `Treasury`\",\"surplusValue\":\"Value of the surplus communicated to the `Treasury`\"}},\"angle(uint8[],bytes[],address,address,address,bytes)\":{\"details\":\"This function is optimized to reduce gas cost due to payment from or to the user and that expensive calls or computations (like `oracleValue`) are done only onceWhen specifying `vaultID` in `data`, it is important to know that if you specify `vaultID = 0`, it will simply use the latest `vaultID`. This is the default behavior, and unless you're engaging into some complex protocol actions it is encouraged to use `vaultID = 0` only when the first action of the batch is `createVault`\",\"params\":{\"actions\":\"Set of actions to perform\",\"datas\":\"Data to be decoded for each action: it can include like the `vaultID` or the `stablecoinAmount` to borrow\",\"from\":\"Address from which stablecoins will be taken if one action includes burning stablecoins. This address should either be the `msg.sender` or be approved by the latter\",\"repayData\":\"Data to pass to the repayment contract in case of\",\"to\":\"Address to which stablecoins and/or collateral will be sent in case of\",\"who\":\"Address of the contract to handle in case of repayment of stablecoins from received collateral\"},\"returns\":{\"paymentData\":\"Struct containing the accounting changes from the protocol's perspective (like how much of collateral or how much has been received). Note that the values in the struct are not aggregated and you could have in the output a positive amount of stablecoins to receive as well as a positive amount of stablecoins to give\"}},\"approve(address,uint256)\":{\"details\":\"Gives permission to `to` to transfer `tokenId` token to another account. The approval is cleared when the token is transferred. Only a single account can be approved at a time, so approving the zero address clears previous approvals. Requirements: - The caller must own the token or be an approved operator. - `tokenId` must exist. Emits an {Approval} event.\"},\"balanceOf(address)\":{\"details\":\"Returns the number of tokens in ``owner``'s account.\"},\"checkLiquidation(uint256,address)\":{\"details\":\"This function will revert if it's called on a vault that does not exist\",\"params\":{\"liquidator\":\"Address of the liquidator which will be performing the liquidation\",\"vaultID\":\"ID of the vault to check\"},\"returns\":{\"liqOpp\":\"Description of the opportunity of liquidation\"}},\"createVault(address)\":{\"details\":\"This function just creates the vault without doing any collateral or\",\"params\":{\"toVault\":\"Address for which the va\"},\"returns\":{\"_0\":\"vaultID ID of the vault created\"}},\"getApproved(uint256)\":{\"details\":\"Returns the account approved for `tokenId` token. Requirements: - `tokenId` must exist.\"},\"getDebtOut(uint256,uint256,uint256,uint256)\":{\"details\":\"This function can only be called from a vaultManager registered in the same Treasury\",\"params\":{\"amountStablecoins\":\"Amount of stablecoins to remove from the debt: this amount is to be converted to an internal debt amount\",\"senderBorrowFee\":\"Borrowing fees from the contract which requested this: this is to make sure that people are not arbitraging difference in minting fees\",\"senderRepayFee\":\"Repay fees from the contract which requested this: this is to make sure that people are not arbitraging differences in repay fees\",\"vaultID\":\"ID of the vault to remove debt from\"}},\"getTotalDebt()\":{\"returns\":{\"_0\":\"Total debt across all vaults, taking into account the interest accumulated over time\"}},\"getVaultDebt(uint256)\":{\"params\":{\"vaultID\":\"ID of the vault to check\"},\"returns\":{\"_0\":\"Debt of the vault\"}},\"initialize(address,address,address,(uint256,uint64,uint64,uint64,uint64,uint64,bool,uint256),string)\":{\"details\":\"The parameters and the oracle are the only elements which could be modified once the contract has been initializedFor the contract to be fully initialized, governance needs to set the parameters for the liquidation boost\",\"params\":{\"_collateral\":\"Collateral supported by this contract\",\"_oracle\":\"Oracle contract used\",\"_symbol\":\"Symbol used to define the `VaultManager` name and symbol\",\"_treasury\":\"Treasury address handling the contract\"}},\"isApprovedForAll(address,address)\":{\"details\":\"Returns if the `operator` is allowed to manage all of the assets of `owner`. See {setApprovalForAll}\"},\"isApprovedOrOwner(address,uint256)\":{\"params\":{\"spender\":\"Address for which vault ownership should be checked\",\"vaultID\":\"ID of the vault to check\"},\"returns\":{\"_0\":\"Whether the `spender` address owns or is approved for `vaultID`\"}},\"liquidate(uint256[],uint256[],address,address)\":{\"details\":\"This function is a simplified wrapper of the function below. It is built to remove for liquidators the need to specify a `who` and a `data` parameter\"},\"liquidate(uint256[],uint256[],address,address,address,bytes)\":{\"details\":\"This function will revert if it's called on a vault that cannot be liquidated or that does not existA whitelist check may be performed on the address liquidating the vault or on the address receiving the funds from the liquidiation\",\"params\":{\"amounts\":\"Amount of stablecoin to bring for the liquidation of each vault\",\"data\":\"Data to pass to the repayment contract in case of. If empty, liquidators simply have to bring the exact amount of stablecoins to get the discounted collateral. If not, it is used by the repayment contract to swap a portion or all of the collateral received to stablecoins to be sent to the `from` address. More details in the `_handleRepay` function\",\"from\":\"Address from which the stablecoins for the liquidation should be taken: this address should be the `msg.sender` or have received an approval\",\"to\":\"Address to which discounted collateral should be sent\",\"vaultIDs\":\"List of the vaults to liquidate\",\"who\":\"Address of the contract to handle repayment of stablecoins from received collateral\"},\"returns\":{\"liqData\":\"Data about the liquidation process for the liquidator to track everything that has been going on (like how much stablecoins have been repaid, how much collateral has been received)\"}},\"ownerOf(uint256)\":{\"details\":\"Returns the owner of the `tokenId` token. Requirements: - `tokenId` must exist.\"},\"permit(address,address,bool,uint256,uint8,bytes32,bytes32)\":{\"details\":\"The `v`, `r`, and `s` parameters are used as signature data\",\"params\":{\"approved\":\"Whether to give or revoke the approval\",\"deadline\":\"Deadline parameter for the signature to be valid\",\"owner\":\"Address signing the permit and giving (or revoking) its approval for all the controlled vaults\",\"spender\":\"Address to give approval to\"}},\"safeTransferFrom(address,address,uint256)\":{\"details\":\"Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients are aware of the ERC721 protocol to prevent tokens from being forever locked. Requirements: - `from` cannot be the zero address. - `to` cannot be the zero address. - `tokenId` token must exist and be owned by `from`. - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. Emits a {Transfer} event.\"},\"safeTransferFrom(address,address,uint256,bytes)\":{\"details\":\"Safely transfers `tokenId` token from `from` to `to`. Requirements: - `from` cannot be the zero address. - `to` cannot be the zero address. - `tokenId` token must exist and be owned by `from`. - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. Emits a {Transfer} event.\"},\"setApprovalForAll(address,bool)\":{\"details\":\"Approve or remove `operator` as an operator for the caller. Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. Requirements: - The `operator` cannot be the caller. Emits an {ApprovalForAll} event.\"},\"setDebtCeiling(uint256)\":{\"details\":\"`debtCeiling` should not be bigger than `type(uint256).max / 10**27` otherwise there could be overflows\",\"params\":{\"_debtCeiling\":\"New value for `debtCeiling`\"}},\"setDusts(uint256,uint256,uint256)\":{\"details\":\"dustCollateral_ is in stable value\",\"params\":{\"_dust\":\"New minimum debt allowed\",\"_dustLiquidation\":\"New `dustLiquidation` value\",\"dustCollateral_\":\"New minimum collateral allowed in a vault after a liquidation\"}},\"setLiquidationBoostParameters(address,uint256[],uint256[])\":{\"details\":\"There are 2 modes: When boost is enabled, `xBoost` and `yBoost` should have a length of 2, but if they have a higher length contract will still work as expected. Contract will also work as expected if their length differ When boost is disabled, `_veBoostProxy` needs to be zero address and `yBoost[0]` is the base boost\",\"params\":{\"_veBoostProxy\":\"Address which queries veANGLE balances and adjusted balances from delegation\",\"xBoost\":\"Threshold values of veANGLE adjusted balances\",\"yBoost\":\"Values of the liquidation boost at the threshold values of x\"}},\"setOracle(address)\":{\"params\":{\"_oracle\":\"Reference to the oracle contract\"}},\"setTreasury(address)\":{\"details\":\"All required checks when setting up a treasury contract are performed in the contract calling this function\",\"params\":{\"_treasury\":\"New treasury contract\"}},\"setUint64(uint64,bytes32)\":{\"details\":\"This function performs the required checks when updating a parameterWhen setting parameters governance or the guardian should make sure that when `HF < CF/((1-surcharge)(1-discount))` and hence when liquidating a vault is going to decrease its health factor, `discount = max discount`. Otherwise, it may be profitable for the liquidator to liquidate in multiple times: as it will decrease the HF and therefore increase the discount between each time\",\"params\":{\"param\":\"Value for the parameter\",\"what\":\"Parameter to change\"}},\"supportsInterface(bytes4)\":{\"details\":\"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.\"},\"toggleWhitelist(address)\":{\"details\":\"If the `target` address is the zero address then this function toggles whitelisting for all addresses\",\"params\":{\"target\":\"Address to toggle\"}},\"tokenURI(uint256)\":{\"details\":\"Returns the Uniform Resource Identifier (URI) for `tokenId` token.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"Transfers `tokenId` token from `from` to `to`. WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. Requirements: - `from` cannot be the zero address. - `to` cannot be the zero address. - `tokenId` token must be owned by `from`. - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. Emits a {Transfer} event.\"}},\"title\":\"VaultManagerLiquidationBoost\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"BASE_INTEREST()\":{\"notice\":\"Base used for interest rate computation\"},\"BASE_PARAMS()\":{\"notice\":\"Base used for parameter computation: almost all the parameters of this contract are set in `BASE_PARAMS`\"},\"DOMAIN_SEPARATOR()\":{\"notice\":\"Returns the domain separator for the current chain.\"},\"HALF_BASE_INTEREST()\":{\"notice\":\"Used for interest rate computation\"},\"accrueInterestToTreasury()\":{\"notice\":\"Accrues interest accumulated across all vaults to the surplus and sends the surplus to the treasury\"},\"angle(uint8[],bytes[],address,address)\":{\"notice\":\"This function is a wrapper built on top of the function above. It enables users to interact with the contract without having to provide `who` and `repayData` parameters\"},\"angle(uint8[],bytes[],address,address,address,bytes)\":{\"notice\":\"Allows composability between calls to the different entry points of this module. Any user calling this function can perform any of the allowed actions in the order of their choice\"},\"badDebt()\":{\"notice\":\"Bad debt made from liquidated vaults which ended up having no collateral and a positive amount of stablecoins\"},\"borrowFee()\":{\"notice\":\"Upfront fee taken when borrowing stablecoins: this fee is optional and should in practice not be used\"},\"checkLiquidation(uint256,address)\":{\"notice\":\"Checks whether a given vault is liquidable and if yes gives information regarding its liquidation\"},\"collateral()\":{\"notice\":\"Reference to the collateral handled by this `VaultManager`\"},\"collateralFactor()\":{\"notice\":\"Encodes the maximum ratio stablecoin/collateral a vault can have before being liquidated. It's what determines the minimum collateral ratio of a position\"},\"createVault(address)\":{\"notice\":\"Creates a vault\"},\"debtCeiling()\":{\"notice\":\"Maximum amount of stablecoins that can be issued with this contract (in `BASE_TOKENS`). This parameter should not be bigger than `type(uint256).max / BASE_INTEREST` otherwise there may be some overflows in the `increaseDebt` function\"},\"dust()\":{\"notice\":\"Minimum amount of debt a vault can have, expressed in `BASE_TOKENS` that is to say the base of the agTokens\"},\"dustLiquidation()\":{\"notice\":\"If the amount of debt of a vault that gets liquidated is below this amount, then the liquidator can liquidate all the debt of the vault (and not just what's needed to get to the target health factor)\"},\"getDebtOut(uint256,uint256,uint256,uint256)\":{\"notice\":\"Removes debt from a vault after being requested to do so by another `VaultManager` contract\"},\"getTotalDebt()\":{\"notice\":\"Gets the total debt across all vaults\"},\"getVaultDebt(uint256)\":{\"notice\":\"Gets the current debt of a vault\"},\"initialize(address,address,address,(uint256,uint64,uint64,uint64,uint64,uint64,bool,uint256),string)\":{\"notice\":\"Initializes the `VaultManager` contract\"},\"interestAccumulator()\":{\"notice\":\"The `interestAccumulator` variable keeps track of the interest that should accrue to the protocol. The stored value is not necessarily the true value: this one is recomputed every time an action takes place within the protocol. It is in base `BASE_INTEREST`\"},\"interestRate()\":{\"notice\":\"Per second interest taken to borrowers taking agToken loans. Contrarily to other parameters, it is set in `BASE_INTEREST` that is to say in base 10**27\"},\"isApprovedOrOwner(address,uint256)\":{\"notice\":\"Checks whether a given address is approved for a vault or owns this vault\"},\"isWhitelisted(address)\":{\"notice\":\"Maps an address to 1 if it's whitelisted and can open or own a vault\"},\"lastInterestAccumulatorUpdated()\":{\"notice\":\"Timestamp at which the `interestAccumulator` was updated\"},\"liquidate(uint256[],uint256[],address,address)\":{\"notice\":\"Liquidates an ensemble of vaults specified by their IDs\"},\"liquidate(uint256[],uint256[],address,address,address,bytes)\":{\"notice\":\"Liquidates an ensemble of vaults specified by their IDs\"},\"liquidationSurcharge()\":{\"notice\":\"Fee taken by the protocol during a liquidation. Technically, this value is not the fee per se, it's 1 - fee. For instance for a 2% fee, `liquidationSurcharge` should be 98%\"},\"maxLiquidationDiscount()\":{\"notice\":\"Maximum discount given to liquidators\"},\"nonces(address)\":{\"notice\":\"Returns the current nonce for an `owner` address\"},\"oracle()\":{\"notice\":\"Oracle contract to get access to the price of the collateral with respect to the stablecoin\"},\"paused()\":{\"notice\":\"Whether the contract is paused or not\"},\"permit(address,address,bool,uint256,uint8,bytes32,bytes32)\":{\"notice\":\"Allows an address to give or revoke approval for all its vaults to another address\"},\"repayFee()\":{\"notice\":\"Upfront fee taken when repaying stablecoins: this fee is optional as well. It should be smaller than the liquidation surcharge (cf below) to avoid exploits where people voluntarily get liquidated at a 0 discount to pay smaller repaying fees\"},\"setBaseURI(string)\":{\"notice\":\"Changes the ERC721 metadata URI\"},\"setDebtCeiling(uint256)\":{\"notice\":\"Sets `debtCeiling`\"},\"setDusts(uint256,uint256,uint256)\":{\"notice\":\"Sets the dust variables\"},\"setLiquidationBoostParameters(address,uint256[],uint256[])\":{\"notice\":\"Sets the parameters for the liquidation booster which encodes the slope of the discount\"},\"setOracle(address)\":{\"notice\":\"Changes the reference to the oracle contract used to get the price of the oracle\"},\"setTreasury(address)\":{\"notice\":\"Sets the treasury contract\"},\"setUint64(uint64,bytes32)\":{\"notice\":\"Sets parameters encoded as uint64\"},\"stablecoin()\":{\"notice\":\"Stablecoin handled by this contract. Another `VaultManager` contract could have the same rights as this `VaultManager` on the stablecoin contract\"},\"surplus()\":{\"notice\":\"Surplus accumulated by the contract: surplus is always in stablecoins, and is then reset when the value is communicated to the treasury contract\"},\"targetHealthFactor()\":{\"notice\":\"Maximum Health factor at which a vault can end up after a liquidation (unless it's fully liquidated)\"},\"togglePause()\":{\"notice\":\"Pauses external permissionless functions of the contract\"},\"toggleWhitelist(address)\":{\"notice\":\"Changes the whitelisting of an address\"},\"totalNormalizedDebt()\":{\"notice\":\"Total normalized amount of stablecoins borrowed, not taking into account the potential bad debt accumulated This value is expressed in the base of Angle stablecoins (`BASE_TOKENS = 10**18`)\"},\"treasury()\":{\"notice\":\"Reference to the `treasury` contract handling this `VaultManager`\"},\"vaultData(uint256)\":{\"notice\":\"Maps a `vaultID` to its data (namely collateral amount and normalized debt)\"},\"vaultIDCount()\":{\"notice\":\"ID of the last vault created. The `vaultIDCount` variables serves as a counter to generate a unique `vaultID` for each vault: it is like `tokenID` in basic ERC721 contracts\"},\"veBoostProxy()\":{\"notice\":\"Reference to the contract which computes adjusted veANGLE balances for liquidators boosts\"},\"whitelistingActivated()\":{\"notice\":\"Whether whitelisting is required to own a vault or not\"},\"xLiquidationBoost(uint256)\":{\"notice\":\"Threshold veANGLE balance values for the computation of the boost for liquidators: the length of this array should normally be 2. The base of the x-values in this array should be `BASE_TOKENS`\"},\"yLiquidationBoost(uint256)\":{\"notice\":\"Values of the liquidation boost at the threshold values of x\"}},\"notice\":\"Liquidation discount depending also on the liquidator veANGLE balance\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/vaultManager/VaultManagerLiquidationBoost.sol\":\"VaultManagerLiquidationBoost\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":1},\"remappings\":[]},\"sources\":{\"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\":{\"keccak256\":\"0xe6f5ac8c47f3b9b6135051efb9216f9ba5b312a6ecc20209b4f66a780443c328\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ded4aa77b7b8f222a2d992eb95b03592be3250b826b6a38a4c790d2dec8b0d47\",\"dweb:/ipfs/QmNUKpTKXWsBBNMyzZuYvEZ2pUhZ2zEhQuyvxYZpTwo4eT\"]},\"@openzeppelin/contracts-upgradeable/interfaces/IERC721MetadataUpgradeable.sol\":{\"keccak256\":\"0xc0e1ac396ac591a4c38ddcdd220321128eb94424d73e41a573cf58d5c643af38\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://2bd729caa85e0c3740b2d3a28a91fac0fd1ef66e0907145005a37f1927ae7a22\",\"dweb:/ipfs/QmcfVoLnE2PZj3U6KbACk6ykqE5WXuAM3hsXLJxC2sxZGt\"]},\"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\":{\"keccak256\":\"0x0203dcadc5737d9ef2c211d6fa15d18ebc3b30dfa51903b64870b01a062b0b4e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6eb2fd1e9894dbe778f4b8131adecebe570689e63cf892f4e21257bfe1252497\",\"dweb:/ipfs/QmXgUGNfZvrn6N2miv3nooSs7Jm34A41qz94fu2GtDFcx8\"]},\"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\":{\"keccak256\":\"0x8cc03c5ac17e8a7396e487cda41fc1f1dfdb91db7d528e6da84bee3b6dd7e167\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://607818f1b44548c2d8268176f73cdb290e1faed971b1061930d92698366e2a11\",\"dweb:/ipfs/QmQibMe3r5no95b6q7isGT5R75V8xSofWEDLXzp95b7LgZ\"]},\"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\":{\"keccak256\":\"0x4e733d3164f73f461eaf9d8087a7ad1ea180bdc8ba0d3d61b0e1ae16d8e63dff\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://75b47c3aeca7b66ea6752f8be020ec5c1c502de6ec9065272dae23d3a52196e2\",\"dweb:/ipfs/QmUebPMHv16tYKFh5BmBQkMfRFb5b8UZ2RgVwdjxCeufVF\"]},\"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol\":{\"keccak256\":\"0xcc70d8e2281fb3ff69e8ab242500f10142cd0a7fa8dd9e45882be270d4d09024\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://17a4063bc918df0f7bb9cbf04c6f0bb4977afab3f2fc212bc138a178312a221d\",\"dweb:/ipfs/QmZMdvsHP5mDEAAdrK4bNeNh47TfmSFgN9qEBFTbie7zmm\"]},\"@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol\":{\"keccak256\":\"0xbb2ed8106d94aeae6858e2551a1e7174df73994b77b13ebd120ccaaef80155f5\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://8bc3c6a456dba727d8dd9fd33420febede490abb49a07469f61d2a3ace66a95a\",\"dweb:/ipfs/QmVAWtEVj7K5AbvgJa9Dz22KiDq9eoptCjnVZqsTMtKXyd\"]},\"@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol\":{\"keccak256\":\"0x016298e66a5810253c6c905e61966bb31c8775c3f3517bf946ff56ee31d6c005\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://1723de5ae414f210db039b19e6487c19c2d643483c9be7c445cf481a80c199d2\",\"dweb:/ipfs/QmcBLbmPdZsNngYhA1KDadNUqQZoGACytFWuUH74RC4AXC\"]},\"@openzeppelin/contracts-upgradeable/token/ERC721/extensions/IERC721MetadataUpgradeable.sol\":{\"keccak256\":\"0x95a471796eb5f030fdc438660bebec121ad5d063763e64d92376ffb4b5ce8b70\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://4ffbd627e6958983d288801acdedbf3491ee0ebf1a430338bce47c96481ce9e3\",\"dweb:/ipfs/QmUM1vpmNgBV34sYf946SthDJNGhwwqjoRggmj4TUUQmdB\"]},\"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\":{\"keccak256\":\"0x611aa3f23e59cfdd1863c536776407b3e33d695152a266fa7cfb34440a29a8a3\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://9b4b2110b7f2b3eb32951bc08046fa90feccffa594e1176cb91cdfb0e94726b4\",\"dweb:/ipfs/QmSxLwYjicf9zWFuieRc8WQwE4FisA1Um5jp1iSa731TGt\"]},\"@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol\":{\"keccak256\":\"0xc6cef87559d0aeffdf0a99803de655938a7779ec0a3cd5d4383483ad85565a09\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://92ad7e572cf44e6b4b37631b44b62f9eb9fb1cf14d9ce51c1504d5dc7ccaf758\",\"dweb:/ipfs/QmcnbqX85tsWnUXPmtuPLE4SczME2sJaTfmqEFkuAJvWhy\"]},\"@openzeppelin/contracts/interfaces/IERC721Metadata.sol\":{\"keccak256\":\"0x1e88abdf82fcbbf98f97be17ea56c924376350637896bc37366ec9f89b7c2628\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c8eb8afc411b87c9718cfe5c68669d5210d7012a96890c520c0fc321f74f0992\",\"dweb:/ipfs/Qmcr74gEtRpWER5qjFN86AKUep66pGuzp9WDYueaNtt97n\"]},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://5a7d5b1ef5d8d5889ad2ed89d8619c09383b80b72ab226e0fe7bde1636481e34\",\"dweb:/ipfs/QmebXWgtEfumQGBdVeM6c71McLixYXQP5Bk6kKXuoY4Bmr\"]},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://5a376d3dda2cb70536c0a45c208b29b34ac560c4cb4f513a42079f96ba47d2dd\",\"dweb:/ipfs/QmZQg6gn1sUpM8wHzwNvSnihumUCAhxD119MpXeKp8B9s8\"]},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b2717fd2bdac99daa960a6de500754ea1b932093c946388c381da48658234b95\",\"dweb:/ipfs/QmP6QVMn6UeA3ByahyJbYQr5M6coHKBKsf3ySZSfbyA8R7\"]},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"keccak256\":\"0x032807210d1d7d218963d7355d62e021a84bf1b3339f4f50be2f63b53cccaf29\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://11756f42121f6541a35a8339ea899ee7514cfaa2e6d740625fcc844419296aa6\",\"dweb:/ipfs/QmekMuk6BY4DAjzeXr4MSbKdgoqqsZnA8JPtuyWc6CwXHf\"]},\"@openzeppelin/contracts/token/ERC721/IERC721.sol\":{\"keccak256\":\"0xed6a749c5373af398105ce6ee3ac4763aa450ea7285d268c85d9eeca809cdb1f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://20a97f891d06f0fe91560ea1a142aaa26fdd22bed1b51606b7d48f670deeb50f\",\"dweb:/ipfs/QmTbCtZKChpaX5H2iRiTDMcSz29GSLCpTCDgJpcMR4wg8x\"]},\"@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol\":{\"keccak256\":\"0x75b829ff2f26c14355d1cba20e16fe7b29ca58eb5fef665ede48bc0f9c6c74b9\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://a0a107160525724f9e1bbbab031defc2f298296dd9e331f16a6f7130cec32146\",\"dweb:/ipfs/QmemujxSd7gX8A9M8UwmNbz4Ms3U9FG9QfudUgxwvTmPWf\"]},\"@openzeppelin/contracts/utils/Address.sol\":{\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://35c47bece3c03caaa07fab37dd2bb3413bfbca20db7bd9895024390e0a469487\",\"dweb:/ipfs/QmPGWT2x3QHcKxqe6gRmAkdakhbaRgx3DLzcakHz5M4eXG\"]},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://be161e54f24e5c6fae81a12db1a8ae87bc5ae1b0ddc805d82a1440a68455088f\",\"dweb:/ipfs/QmP7C3CHdY9urF4dEMb9wmsp1wMxHF6nhA2yQE5SKiPAdy\"]},\"contracts/interfaces/IAgToken.sol\":{\"keccak256\":\"0xd671dbd00b28a86b839fd455ada4d1ef9203694d06142be76853e00a91f80b5f\",\"license\":\"GPL-3.0\",\"urls\":[\"bzz-raw://de67e7e10ecb8480bd6c1105d7224f68d1400c918ea1c03a430b476b4936c65c\",\"dweb:/ipfs/QmXZWoVQ2GrBxuBJ3eckG4rsdnyqqeDVk8M99dE3gbS7c4\"]},\"contracts/interfaces/ICoreBorrow.sol\":{\"keccak256\":\"0x10249210cbf522775f040baf981d7d037472168ce2746d87473ac7c29a34e62e\",\"license\":\"GPL-3.0\",\"urls\":[\"bzz-raw://5662508bcc221233db54b5b311c4e371bd8616b3c5c3572ae207c04060758b67\",\"dweb:/ipfs/QmZCQVyMFbWkBZJnwwB3vxLZkvSXGxEg3Hu1UFJQfpV9fi\"]},\"contracts/interfaces/IFlashAngle.sol\":{\"keccak256\":\"0x39b0097f695b9e934bccdc72676c91513f1077cc5d0fd151908fd25a7c5cfbe4\",\"license\":\"GPL-3.0\",\"urls\":[\"bzz-raw://5b0f3c3581f390b0242d8252a4a215dd04b4c5b74e1efb7396bbba72c3922a02\",\"dweb:/ipfs/Qmc7BxyifSkpKtneN2gMsKkworGPDwVfBdT2t66iGMDerm\"]},\"contracts/interfaces/IOracle.sol\":{\"keccak256\":\"0x66fe2bb27f26b86e5832fc7d1ebd320cac8b3d79c5998ce148cf7279b2b359be\",\"license\":\"GPL-3.0\",\"urls\":[\"bzz-raw://6fb1e0a9e4d71e8ba0ecce45d86b0459a8a12ad575e49278d277d40a85ed9850\",\"dweb:/ipfs/QmXCjer5F4aGUwJaN5b2jgXK19q5Q7fuZQ3sCPQjnQvAFQ\"]},\"contracts/interfaces/ISwapper.sol\":{\"keccak256\":\"0x2c18883cbff92d1e558e670480f5e2f517bce8c95c202cc3f6602ac276222609\",\"license\":\"GPL-3.0\",\"urls\":[\"bzz-raw://948ebdaf95b08d6617f490aa0651a90d8cc3ef3d4c0b9edc3a50e4fe6df73013\",\"dweb:/ipfs/QmejFnT3zzN2StAUnVDHS62iFxZ4e5ZQBTQ3kghDPXRR9g\"]},\"contracts/interfaces/ITreasury.sol\":{\"keccak256\":\"0x624733dae1bfb98721ba994573aed10997f7448c893b791ed985300531c361fd\",\"license\":\"GPL-3.0\",\"urls\":[\"bzz-raw://8ef7cfe9121192bc39d0906c1585c288f1302237fdf8c0a1575395233d25b90a\",\"dweb:/ipfs/QmWCUt4VTope9mFQd1opjom4CnGpdV4yiG3AQpNkeAgsRp\"]},\"contracts/interfaces/IVaultManager.sol\":{\"keccak256\":\"0x9d2dca11dba2fa9d646ccf88b3c0929d7601de925f1a6270f9ef2bef9390e6e4\",\"license\":\"GPL-3.0\",\"urls\":[\"bzz-raw://8b4991cb79afa8a717f66e4d9ef0c92a619574706affd2462c2b48937ca3585e\",\"dweb:/ipfs/QmWAxyT7jJkuQeFdvQmLVjZbBpEHhZbtfyhijXaqHEdumW\"]},\"contracts/interfaces/external/IERC1271.sol\":{\"keccak256\":\"0x6887d50d488064e481dfba3a9c54c049430b1ffc0a5536387fa89ff5133e6479\",\"license\":\"GPL-2.0-or-later\",\"urls\":[\"bzz-raw://0b080810d65481a97abbb7306b31ed944cd01dd19cb27a7a8e779f81bd9b6d11\",\"dweb:/ipfs/QmZUoJgs3JxAeki6CkbFD8uxBypipefhMS8uuVkQcxnsug\"]},\"contracts/interfaces/governance/IVeBoostProxy.sol\":{\"keccak256\":\"0xce73b8dcafcfaba4d01216f02f49930c078617e11223290004c6f662fc900d6b\",\"license\":\"GPL-3.0\",\"urls\":[\"bzz-raw://eb1eec1ea1c000dc07fa89e4f5f8e7009c1777a03960d7e02dcf3fa6f1630333\",\"dweb:/ipfs/QmbMqqz6nBHQmY57EqfhQA5Ep8WVnQSjaejW79XWtowHzv\"]},\"contracts/vaultManager/VaultManager.sol\":{\"keccak256\":\"0x903aa8486ae20779f33980980a0ca50ddc704f5c72d6c498210cd509a88beeed\",\"license\":\"GPL-3.0\",\"urls\":[\"bzz-raw://a3a712779218d0485ff46b9b47f86d3a8bd7efab9e9b2d0c8c9f7ca2eb3f6980\",\"dweb:/ipfs/QmTgUE4R7rXrt7MFEkC2MWj5QA5xg4QKnMphexyucWMKEq\"]},\"contracts/vaultManager/VaultManagerERC721.sol\":{\"keccak256\":\"0x1169ae296e188224be8716c6c4be19cb6de30e2a55ee7b4e1d4a554ba07573b1\",\"license\":\"GPL-3.0\",\"urls\":[\"bzz-raw://9e87a1905680d1c9d4a3ac07b0a009d0b82e3c73d7ca735b85f6eda042a283bf\",\"dweb:/ipfs/QmczgGUKMzChBV8XAVkxaYftc7wWstx3FLTLCMTFVt8WbT\"]},\"contracts/vaultManager/VaultManagerLiquidationBoost.sol\":{\"keccak256\":\"0xbe2a172d8bd96149ac6bd0113644d59337a40c99b8e9eff0a6393efc3ae8de81\",\"license\":\"GPL-3.0\",\"urls\":[\"bzz-raw://e114f045f071084f504b96d28796d391867346a95cf9004b3f47e10ce906bee1\",\"dweb:/ipfs/QmXSW6XnDTpCredi8KEjwNgntPL6kRPb1mMX5YF9QgHiXQ\"]},\"contracts/vaultManager/VaultManagerPermit.sol\":{\"keccak256\":\"0x1303785eb96597effcbf7d7969be0c5c40c0c7d5a5c6b5b2f7eb20325f07e61f\",\"license\":\"GPL-3.0\",\"urls\":[\"bzz-raw://e9c853c15dc80a49de107cb02788b55006a0797f4ac6c003ea7db2dc62b80ea5\",\"dweb:/ipfs/QmT1XyC5L8u95fYti9DnGTXsyWCQLBcvqGoEKmDazf8pog\"]},\"contracts/vaultManager/VaultManagerStorage.sol\":{\"keccak256\":\"0x612208b1e1f538968d270671f67d1e0e54183872d8a18ddb0f4d0ab3985e8bf3\",\"license\":\"GPL-3.0\",\"urls\":[\"bzz-raw://e78aaffe7506abe8ea1f1568e0f19091703bdd1a264ae59496415a4f53e76dcb\",\"dweb:/ipfs/QmSgEJaWmsRMwxuwviZuKM4s4BLCBfYAtHN6ak2PuAJLPc\"]}},\"version\":1}", + "bytecode": "0x60806040523480156200001157600080fd5b50600054610100900460ff1615808015620000335750600054600160ff909116105b8062000063575062000050306200013d60201b62002f931760201c565b15801562000063575060005460ff166001145b620000cb5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b6000805460ff191660011790558015620000ef576000805461ff0019166101001790555b801562000136576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b506200014c565b6001600160a01b03163b151590565b615f2f806200015c6000396000f3fe608060405234801561001057600080fd5b50600436106103015760003560e01c8063010db1951461030657806301ffc9a71461032f57806306fdde0314610352578063081812fc14610367578063087a60071461037a578063095ea7b3146103915780630e198f22146103a657806313888565146103af57806323b872dd146103b8578063254cf439146103cb578063307439af146103fd57806334ce998a1461041d57806335836f15146104255780633644e5151461043857806339393ac91461044057806339eb4dc6146104535780633ae2325f146104675780633af32abf1461047a5780633c2e941b1461049a57806342842e0e146104a3578063430c2081146104b65780634f7e43df146104c957806355f804b3146104e35780635c975abb146104f657806361d027b31461050a5780636352211e1461051d57806370a082311461053057806374107543146105435780637aacfffa146105565780637adbf973146105925780637c0f59f4146105a55780637c3a00fd146105bf5780637dc0d1d0146105d25780637e53bd97146105e55780637e56d47c146105f85780637ecebe001461060b578063835986b41461063457806389050f1d1461064757806395d89b41146106595780639a3b6f2f146106615780639f48118f146106a7578063a22cb465146106b2578063af2c8c2e146106c5578063b1511cc9146106ce578063b4bd6f46146106e1578063b88d4fde146106f4578063bbcac55714610707578063bfc7ad2e14610710578063c13cacae14610719578063c4ae31681461072c578063c66d8b0114610734578063c87b56dd1461074e578063d8dfeb4514610761578063d9b1cb5b14610774578063de1f776514610787578063de8fc69814610799578063df011c41146107ac578063e182b883146107bf578063e1c84ea4146107d2578063e626648a146107db578063e985e9c5146107f5578063e9cbd82214610808578063f0f442601461081b578063f51cc7dd1461082e578063fad9aba314610841578063fc29b0211461084a578063fd527cf81461085d575b600080fd5b603754610319906001600160a01b031681565b6040516103269190614e36565b60405180910390f35b61034261033d366004614e60565b610865565b6040519015158152602001610326565b61035a6108d2565b6040516103269190614ed5565b610319610375366004614ee8565b610960565b610383603f5481565b604051908152602001610326565b6103a461039f366004614f16565b610991565b005b610383603e5481565b61038360415481565b6103a46103c6366004614f42565b610a1e565b603c546103e590600160401b90046001600160401b031681565b6040516001600160401b039091168152602001610326565b61041061040b366004614f83565b610a59565b6040516103269190614fb3565b610383610b0b565b610383610433366004614ee8565b610b3d565b610383610b79565b6103a461044e366004614fec565b610b83565b603d5461034290600160c01b900460ff1681565b610383610475366004614ee8565b610c83565b610383610488366004614fec565b60446020526000908152604090205481565b61038360455481565b6103a46104b1366004614f42565b610ca4565b6103426104c4366004614f16565b610cbf565b603d546103e590600160801b90046001600160401b031681565b6103a46104f13660046150be565b610ccb565b603d5461034290600160c81b900460ff1681565b603354610319906001600160a01b031681565b61031961052b366004614ee8565b610d70565b61038361053e366004614fec565b610d7b565b6103a4610551366004615109565b610dc0565b61057d610564366004614ee8565b6043602052600090815260409020805460019091015482565b60408051928352602083019190915201610326565b6103a46105a0366004614fec565b61118c565b603c546103e590600160c01b90046001600160401b031681565b603d546103e5906001600160401b031681565b603654610319906001600160a01b031681565b6103a46105f33660046151b3565b6112d3565b610410610606366004615228565b6114c4565b610383610619366004614fec565b6001600160a01b03166000908152607f602052604090205490565b6103a46106423660046152ec565b611ad8565b610383676765c793fa10079d601a1b81565b61035a611c79565b61067461066f366004615406565b611c86565b60405161032691908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b610383633b9aca0081565b6103a46106c036600461549c565b611cbb565b61038360405481565b6103a46106dc366004614ee8565b611cc6565b6103836106ef366004614fec565b611d8f565b6103a46107023660046154ca565b611dc5565b61038360425481565b61038360b65481565b6103a4610727366004615535565b611e02565b6103a4611ebf565b603d546103e590600160401b90046001600160401b031681565b61035a61075c366004614ee8565b611f6e565b603454610319906001600160a01b031681565b6103a4610782366004615561565b6120c3565b610383676765c793fa10079d601b1b81565b6106746107a73660046155f5565b61222f565b603c546103e5906001600160401b031681565b6103836107cd366004614ee8565b612aad565b61038360395481565b603c546103e590600160801b90046001600160401b031681565b610342610803366004615653565b612abd565b603554610319906001600160a01b031681565b6103a4610829366004614fec565b612aeb565b6103a461083c366004615690565b612b8b565b61038360b45481565b61041061085836600461570a565b612e4a565b61057d612e74565b60006001600160e01b03198216635b5e139f60e01b148061089657506001600160e01b031982166380ac58cd60e01b145b806108b157506001600160e01b0319821663430c208160e01b145b806108cc57506001600160e01b031982166301ffc9a760e01b145b92915050565b607d80546108df90615766565b80601f016020809104026020016040519081016040528092919081815260200182805461090b90615766565b80156109585780601f1061092d57610100808354040283529160200191610958565b820191906000526020600020905b81548152906001019060200180831161093b57829003601f168201915b505050505081565b600061096b82612fa2565b6109885760405163062a39dd60e11b815260040160405180910390fd5b6108cc82612fbf565b600061099c82612fda565b9050806001600160a01b0316836001600160a01b031614156109d1576040516349fa8bc360e11b815260040160405180910390fd5b336001600160a01b038216148015906109f157506109ef8133612abd565b155b15610a0f5760405163c19f17a960e01b815260040160405180910390fd5b610a198383613010565b505050565b3381610a2a828261307e565b610a475760405163c19f17a960e01b815260040160405180910390fd5b610a528585856130fc565b5050505050565b610a61614d0c565b60008381526043602090815260409182902082518084018452815481526001909101548183015260365483516315f789a960e21b81529351610b0494929387936001600160a01b03909316926357de26a492600480830193928290030181865afa158015610ad3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af7919061579b565b610aff6131d3565b613368565b9392505050565b6000676765c793fa10079d601b1b610b216131d3565b604054610b2e91906157ca565b610b3891906157ff565b905090565b6000676765c793fa10079d601b1b610b536131d3565b600084815260436020526040902060010154610b6f91906157ca565b6108cc91906157ff565b6000610b386136d1565b603354604051631c86b03760e31b81526001600160a01b039091169063e43581b890610bb3903390600401614e36565b602060405180830381865afa158015610bd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bf49190615813565b610c1157604051633b8d9d7560e21b815260040160405180910390fd5b6001600160a01b03811615610c60576001600160a01b038116600090815260446020526040902054610c44906001615830565b6001600160a01b03821660009081526044602052604090205550565b603d805460ff60c01b198116600160c01b9182900460ff16159091021790555b50565b603b8181548110610c9357600080fd5b600091825260209091200154905081565b610a1983838360405180602001604052806000815250611dc5565b6000610b04838361307e565b60335460405163521d4de960e01b81526001600160a01b039091169063521d4de990610cfb903390600401614e36565b602060405180830381865afa158015610d18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d3c9190615813565b610d5957604051632678482f60e21b815260040160405180910390fd5b8051610d6c906046906020840190614d3b565b5050565b60006108cc82612fda565b60006001600160a01b038216610da45760405163d92e233d60e01b815260040160405180910390fd5b506001600160a01b031660009081526048602052604090205490565b60335460405163521d4de960e01b81526001600160a01b039091169063521d4de990610df0903390600401614e36565b602060405180830381865afa158015610e0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e319190615813565b610e4e57604051632678482f60e21b815260040160405180910390fd5b806121a360f11b1415610eb257603d546001600160401b03600160401b90910481169083161115610e9257604051637650e96360e11b815260040160405180910390fd5b603c80546001600160401b0319166001600160401b038416179055611145565b80622a242360e91b1415610f1757633b9aca00826001600160401b03161015610eee5760405163da6a17b960e01b815260040160405180910390fd5b603c8054600160401b600160801b031916600160401b6001600160401b03851602179055611145565b8061212360f11b1415610f7b57633b9aca00826001600160401b03161115610f5257604051637650e96360e11b815260040160405180910390fd5b603c8054600160801b600160c01b031916600160801b6001600160401b03851602179055611145565b8061292360f11b1415610ff857603d54633b9aca0090610fab90600160401b90046001600160401b031684615847565b6001600160401b03161115610fd357604051637650e96360e11b815260040160405180910390fd5b603c80546001600160c01b0316600160c01b6001600160401b03851602179055611145565b806124a960f11b141561102e5761100d61373d565b50603d80546001600160401b0319166001600160401b038416179055611145565b80614c5360f01b14156110c757603c546001600160401b03808416911611806110805750603c54633b9aca009061107590600160c01b90046001600160401b031684615847565b6001600160401b0316115b1561109e5760405163180d062b60e31b815260040160405180910390fd5b603d8054600160401b600160801b031916600160401b6001600160401b03851602179055611145565b806213531160ea1b141561112c57633b9aca00826001600160401b0316111561110357604051637650e96360e11b815260040160405180910390fd5b603d8054600160801b600160c01b031916600160801b6001600160401b03851602179055611145565b60405163e1daa9cf60e01b815260040160405180910390fd5b604080516001600160401b0384168152602081018390527f13b367dac93b85d1ed9b3d8961d8b48e1a677c9800bb1613b4b0416b2d5b61d091015b60405180910390a15050565b603354604051631c86b03760e31b81526001600160a01b039091169063e43581b8906111bc903390600401614e36565b602060405180830381865afa1580156111d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111fd9190615813565b61121a57604051633b8d9d7560e21b815260040160405180910390fd5b603354604080516361d027b360e01b815290516001600160a01b03928316928416916361d027b39160048083019260209291908290030181865afa158015611266573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128a9190615872565b6001600160a01b0316146112b1576040516302979eb960e31b815260040160405180910390fd5b603680546001600160a01b0319166001600160a01b0392909216919091179055565b60335460405163521d4de960e01b81526001600160a01b039091169063521d4de990611303903390600401614e36565b602060405180830381865afa158015611320573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113449190615813565b61136157604051632678482f60e21b815260040160405180910390fd5b8051825114158061138c5750806000815181106113805761138061588f565b60200260200101516000145b8061141b57506001600160a01b0383161580159061141b5750816000815181106113b8576113b861588f565b6020026020010151826001815181106113d3576113d361588f565b602002602001015111158061141b5750806000815181106113f6576113f661588f565b6020026020010151816001815181106114115761141161588f565b6020026020010151105b1561143957604051631746545d60e11b815260040160405180910390fd5b603780546001600160a01b0319166001600160a01b038516179055815161146790603a906020850190614dbf565b50805161147b90603b906020840190614dbf565b50826001600160a01b03167feb74d4d9fea592587c926aeb35eb6a7893fb28db0c1c8eb2eb3c586e7164b76c83836040516114b79291906158e0565b60405180910390a2505050565b6114cc614d0c565b6114d46137de565b156114f2576040516313d0ff5960e31b815260040160405180910390fd5b6002600154141561151e5760405162461bcd60e51b815260040161151590615905565b60405180910390fd5b6002600155603d54600160c01b900460ff16801561154c575033600090815260446020526040902054600114155b801561157157506001600160a01b038416600090815260446020526040902054600114155b1561158f57604051630b094f2760e31b815260040160405180910390fd5b865186518114158061159f575080155b156115bd576040516346282e8d60e01b815260040160405180910390fd5b603660009054906101000a90046001600160a01b03166001600160a01b03166357de26a46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611610573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611634919061579b565b606083015261164161373d565b60808301526040517f965a177723c641ee49150b583a0b9ad4730bb20d3474e00ae5a65e777c00d67b90611676908a9061593c565b60405180910390a160005b81811015611a48576000604360008b84815181106116a1576116a161588f565b6020026020010151815260200190815260200160002060405180604001604052908160008201548152602001600182015481525050905060006116ee823387606001518860800151613368565b90508060400151600014158015611722575080604001518a84815181106117175761171761588f565b602002602001015110155b80611749575080600001518a848151811061173f5761173f61588f565b6020026020010151115b156117725780600001518a84815181106117655761176561588f565b6020026020010181815250505b60008560600151826060015161178891906157ca565b603854633b9aca008d87815181106117a2576117a261588f565b60200260200101516117b491906157ca565b6117be91906157ca565b6117c891906157ff565b90506117f68c85815181106117df576117df61588f565b60200260200101518285600001511115610c805750565b8251811061192c57508151602083015160408054600090611818908490615830565b92505081905550604360008d86815181106118355761183561588f565b60209081029190910181015182528101919091526040016000908120818155600101819055603d548c51633b9aca0091600160401b90046001600160401b0316908e90889081106118885761188861588f565b602002602001015161189a91906157ca565b6118a491906157ff565b9050826080015181106118b85760006118c8565b8083608001516118c89190615830565b876040018181516118d9919061594f565b905250508b51600080516020615e9a833981519152908d90869081106119015761190161588f565b60200260200101518460200151600060405161191f93929190615967565b60405180910390a16119ed565b80604360008e87815181106119435761194361588f565b60200260200101518152602001908152602001600020600001600082825461196b9190615830565b925050819055506119eb8c85815181106119875761198761588f565b6020026020010151633b9aca00603d60089054906101000a90046001600160401b03166001600160401b03168e88815181106119c5576119c561588f565b60200260200101516119d791906157ca565b6119e191906157ff565b88608001516137ee565b505b80866020018181516119ff919061594f565b9052508a518b9085908110611a1657611a1661588f565b602002602001015186600001818151611a2f919061594f565b905250611a4192508391506159809050565b9050611681565b50603d54633b9aca0090611a6c90600160401b90046001600160401b031682615830565b8351611a7891906157ca565b611a8291906157ff565b60416000828254611a93919061594f565b9091555050604082015160428054600090611aaf90849061594f565b909155505060208201518251611ac991908888888861391d565b50600180559695505050505050565b611ae06137de565b15611afe576040516313d0ff5960e31b815260040160405180910390fd5b6033546040516333b52a9f60e11b81526001600160a01b039091169063676a553e90611b2e903390600401614e36565b602060405180830381865afa158015611b4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b6f9190615813565b611b8c5760405163027f480760e01b815260040160405180910390fd5b600080611b97613a27565b6001600160401b0316905082811115611bb757611bb48382615830565b91505b50603c54600090600160801b90046001600160401b0316841115611bf557603c54611bf290600160801b90046001600160401b031685615830565b90505b6000611c066002633b9aca00615a7f565b611c1483633b9aca00615830565b611c2285633b9aca00615830565b611c2c90896157ca565b611c3691906157ca565b611c4091906157ff565b9050611c4c8187615830565b60416000828254611c5d919061594f565b90915550611c6f9050878260006137ee565b5050505050505050565b607e80546108df90615766565b611c8e614df9565b60408051600080825260208201909252611cb09187918791879187919061222f565b90505b949350505050565b610d6c338383613a3d565b60335460405163521d4de960e01b81526001600160a01b039091169063521d4de990611cf6903390600401614e36565b602060405180830381865afa158015611d13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d379190615813565b611d5457604051632678482f60e21b815260040160405180910390fd5b60398190556040518181527fdd63b3dcdbebad734892f7c7a26d0f647fbc7eec973e0775f5229018ac4ab47a9060200160405180910390a150565b6000611d996137de565b15611db7576040516313d0ff5960e31b815260040160405180910390fd5b6108cc82613af3565b919050565b3382611dd1828261307e565b611dee5760405163c19f17a960e01b815260040160405180910390fd5b611dfa86868686613bb6565b505050505050565b603354604051631c86b03760e31b81526001600160a01b039091169063e43581b890611e32903390600401614e36565b602060405180830381865afa158015611e4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e739190615813565b611e9057604051633b8d9d7560e21b815260040160405180910390fd5b81831115611eb15760405163180d062b60e31b815260040160405180910390fd5b60b49290925560b65560b555565b60335460405163521d4de960e01b81526001600160a01b039091169063521d4de990611eef903390600401614e36565b602060405180830381865afa158015611f0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f309190615813565b611f4d57604051632678482f60e21b815260040160405180910390fd5b603d805460ff60c81b198116600160c81b9182900460ff1615909102179055565b6060611f7982612fa2565b611f965760405163062a39dd60e11b815260040160405180910390fd5b8160005b8115611fbd57611fa981615980565b9050611fb6600a836157ff565b9150611f9a565b6000816001600160401b03811115611fd757611fd7615009565b6040519080825280601f01601f191660200182016040528015612001576020820181803683370190505b5090505b841561206c57612016600183615830565b9150612023600a86615a8e565b61202e90603061594f565b60f81b8183815181106120435761204361588f565b60200101906001600160f81b031916908160001a905350612065600a866157ff565b9450612005565b6046805461207990615766565b1515905061209657604051806020016040528060008152506120ba565b6046816040516020016120aa929190615abe565b6040516020818303038152906040525b95945050505050565b600054610100900460ff16158080156120e35750600054600160ff909116105b8061210457506120f230612f93565b158015612104575060005460ff166001145b6121675760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401611515565b6000805460ff19166001179055801561218a576000805461ff0019166101001790555b6121a586868661219f36889003880188615b5c565b86613bf0565b6121b560e0840160c08501615c1a565b603d805460ff60c81b19921515600160c01b029290921661ffff60c01b1990921691909117600160c81b1790558015611dfa576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b612237614df9565b61223f6137de565b1561225d576040516313d0ff5960e31b815260040160405180910390fd5b600260015414156122805760405162461bcd60e51b815260040161151590615905565b60026001558551875114158061229557508651155b156122b3576040516346282e8d60e01b815260040160405180910390fd5b6000806000806000805b8c518110156128165760008d82815181106122da576122da61588f565b60200260200101519050600060078111156122f7576122f7615c37565b81600781111561230957612309615c37565b141561234a576123448d83815181106123245761232461588f565b602002602001015180602001905181019061233f9190615872565b613af3565b50612805565b600281600781111561235e5761235e615c37565b14156123c4578c82815181106123765761237661588f565b60200260200101518060200190518101906123919190615c4d565b95509250826123a05760455492505b6123aa8386613f79565b84886060018181516123bc919061594f565b905250612805565b60078160078111156123d8576123d8615c37565b14156124b15760008060008f85815181106123f5576123f561588f565b60200260200101518060200190518101906124109190615c71565b60345460405163d505accf60e01b81526001600160a01b038089166004830152306024830152604482018890526064820187905260ff8616608483015260a4820185905260c48201849052969f50939d50939b509497509550929350169063d505accf9060e401600060405180830381600087803b15801561249157600080fd5b505af11580156124a5573d6000803e3d6000fd5b50505050505050612805565b866124c1576124be61373d565b96505b60048160078111156124d5576124d5615c37565b141561259d578c82815181106124ed576124ed61588f565b60200260200101518060200190518101906125089190615c4d565b94509250826125175760455492505b6125228385896137ee565b9350600061252e613a27565b612545906001600160401b0316633b9aca00615830565b612553633b9aca00876157ca565b61255d91906157ff565b90506125698582615830565b6041600082825461257a919061594f565b925050819055508089602001818151612593919061594f565b9052506128059050565b8561261c57603660009054906101000a90046001600160a01b03166001600160a01b03166357de26a46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156125f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612619919061579b565b95505b600181600781111561263057612630615c37565b14156126ac578c82815181106126485761264861588f565b6020026020010151806020019051810190612663919061579b565b9250826126705760455492505b61267b838789613fe5565b80965081955050508488604001818151612695919061594f565b9052506020880180518591906123bc90839061594f565b60038160078111156126c0576126c0615c37565b1415612720578c82815181106126d8576126d861588f565b60200260200101518060200190518101906126f39190615c4d565b95509250826127025760455492505b61270e8386888a614102565b84886040018181516123bc919061594f565b600581600781111561273457612734615c37565b1415612796578c828151811061274c5761274c61588f565b60200260200101518060200190518101906127679190615c4d565b94509250826127765760455492505b6127828385888a6141dc565b935083886000018181516123bc919061594f565b60068160078111156127aa576127aa615c37565b1415612805576000808e84815181106127c5576127c561588f565b60200260200101518060200190518101906127e09190615cc4565b985091965092509050846127f45760455494505b612802858383898c8e614277565b50505b5061280f81615980565b90506122bd565b50855160208701511061290d578551602087015160009161283691615830565b9050866060015187604001511061286d576128688760600151886040015161285e9190615830565b828d8d8d8d61391d565b612907565b80156128da57603554604051630d43af8160e21b81526001600160a01b039091169063350ebe04906128a79084908f903390600401615d02565b600060405180830381600087803b1580156128c157600080fd5b505af11580156128d5573d6000803e3d6000fd5b505050505b612907333089604001518a606001516128f39190615830565b6034546001600160a01b03169291906143c7565b50612a99565b6020860151865160009161292091615830565b6035546040516340c10f1960e01b81529192506001600160a01b0316906340c10f1990612953908d908590600401615d21565b600060405180830381600087803b15801561296d57600080fd5b505af1158015612981573d6000803e3d6000fd5b505050508660600151876040015111156129c5576129c08a886060015189604001516129ad9190615830565b6034546001600160a01b03169190614432565b612a97565b6000876040015188606001516129db9190615830565b90508015612a9557885115612a7d57896001600160a01b031663a5d4096b603560009054906101000a90046001600160a01b0316603460009054906101000a90046001600160a01b03163385878f6040518763ffffffff1660e01b8152600401612a4a96959493929190615d3a565b600060405180830381600087803b158015612a6457600080fd5b505af1158015612a78573d6000803e3d6000fd5b505050505b603454612a95906001600160a01b03163330846143c7565b505b505b505060018055509198975050505050505050565b603a8181548110610c9357600080fd5b6001600160a01b039182166000908152604a6020908152604080832093909416825291909152205460011490565b6033546001600160a01b03163314612b165760405163b90cdbb160e01b815260040160405180910390fd5b603380546001600160a01b0319166001600160a01b0383811691909117909155603654604051630787a21360e51b815291169063f0f4426090612b5d908490600401614e36565b600060405180830381600087803b158015612b7757600080fd5b505af1158015610a52573d6000803e3d6000fd5b83421115612bac5760405163f87d927160e01b815260040160405180910390fd5b6fa2a8918ca85bafe22016d0b997e4df60600160ff1b03811180612be357508260ff16601b14158015612be357508260ff16601c14155b15612c0157604051638baa579f60e01b815260040160405180910390fd5b6000612c0b6136d1565b608254898989612c1a8d614451565b6040805160208101969096526001600160a01b03948516908601529290911660608401521515608083015260a082015260c0810187905260e00160405160208183030381529060405280519060200120604051602001612c9192919061190160f01b81526002810192909252602282015260420190565b604051602081830303815290604052805190602001209050612cbb886001600160a01b0316612f93565b15612d9757604080516020810185905280820184905260f886901b6001600160f81b0319166060820152815160418183030181526061820192839052630b135d3f60e11b9092526001600160a01b038a1691631626ba7e91612d21918591606501615d7c565b602060405180830381865afa158015612d3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d629190615d95565b6001600160e01b031916631626ba7e60e01b14612d9257604051638baa579f60e01b815260040160405180910390fd5b612e3f565b6040805160008082526020820180845284905260ff871692820192909252606081018590526080810184905260019060a0016020604051602081039080840390855afa158015612deb573d6000803e3d6000fd5b505050602060405103519050886001600160a01b0316816001600160a01b0316141580612e1f57506001600160a01b038116155b15612e3d57604051638baa579f60e01b815260040160405180910390fd5b505b611c6f888888613a3d565b612e52614d0c565b60408051600080825260208201909252611cb0918791879187918791906114c4565b60335460009081906001600160a01b03163314612ea45760405163b90cdbb160e01b815260040160405180910390fd5b612eac61373d565b505060418054604280546000938490559290559150808210612f4557612ed28183615830565b6035546033546040516340c10f1960e01b8152929450600093506001600160a01b03918216926340c10f1992612f0e9216908690600401615d21565b600060405180830381600087803b158015612f2857600080fd5b505af1158015612f3c573d6000803e3d6000fd5b50505050612f56565b612f4f8282615830565b9050600091505b60408051838152602081018390527ffeb12225c131aab793a00c5239afb778932d170fa28ce6e9d23703e4bd892121910160405180910390a19091565b6001600160a01b03163b151590565b6000908152604760205260409020546001600160a01b0316151590565b6000908152604960205260409020546001600160a01b031690565b6000818152604760205260409020546001600160a01b031680611dc05760405163062a39dd60e11b815260040160405180910390fd5b600081815260496020526040902080546001600160a01b0319166001600160a01b038416908117909155819061304582612fda565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60008061308a83612fda565b9050806001600160a01b0316846001600160a01b031614806130c55750836001600160a01b03166130ba84612fbf565b6001600160a01b0316145b80611cb357506001600160a01b038082166000908152604a6020908152604080832093881683529290522054600114949350505050565b826001600160a01b031661310f82612fda565b6001600160a01b0316146131365760405163c19f17a960e01b815260040160405180910390fd5b6001600160a01b03821661315d5760405163d92e233d60e01b815260040160405180910390fd5b613168600082613010565b6001600160a01b038084166000818152604860209081526040808320805460001901905593861680835284832080546001019055858352604790915283822080546001600160a01b03191682179055925184939291600080516020615eda83398151915291a4505050565b600080603e54426131e49190615830565b603d549091506001600160401b03168115806131fe575080155b1561320d57603f549250505090565b600061321a600184615830565b905060006002841161322d576000613238565b613238600285615830565b90506000676765c793fa10079d601b1b676765c793fa10079d601a1b61325e86806157ca565b613268919061594f565b61327291906157ff565b90506000676765c793fa10079d601b1b676765c793fa10079d601a1b61329887856157ca565b6132a2919061594f565b6132ac91906157ff565b905060006002836132bd878a6157ca565b6132c791906157ca565b6132d191906157ff565b90506000600683866132e3898c6157ca565b6132ed91906157ca565b6132f791906157ca565b61330191906157ff565b9050676765c793fa10079d601b1b818361331b8b8b6157ca565b61333090676765c793fa10079d601b1b61594f565b61333a919061594f565b613344919061594f565b603f5461335191906157ca565b61335b91906157ff565b9850505050505050505090565b613370614d0c565b6000806000613380888787614495565b925092509250633b9aca0083106133aa576040516315fe9b6160e21b815260040160405180910390fd5b6000633b9aca006133bb8582615830565b6133c48a61451e565b6133ce91906157ca565b6133d891906157ff565b603d54909150600160801b90046001600160401b03168110156134085761340381633b9aca00615830565b613429565b603d5461342990600160801b90046001600160401b0316633b9aca00615830565b603d54909150600160401b90046001600160401b03166000806134516002633b9aca00615a7f565b603c5461346791906001600160401b03166157ca565b83613472868a6157ca565b61347c91906157ca565b1061360157603c546001600160401b031661349c6002633b9aca00615a7f565b6134a691906157ca565b603c5485906134c590600160401b90046001600160401b0316866157ca565b6134cf91906157ca565b6134d99190615830565b603c548590633b9aca00906134f7906001600160401b0316896157ca565b603c54613515908b90600160401b90046001600160401b03166157ca565b61351f9190615830565b61352991906157ca565b61353391906157ca565b61353d91906157ff565b60b654909250613551633b9aca00826157ca565b61355b85856157ca565b613565919061594f565b613573633b9aca00896157ca565b116135fb5761358d676765c793fa10079d601b1b856157ca565b633b9aca008b8f602001516135a291906157ca565b6135ac91906157ca565b6135b691906157ff565b6135c190600161594f565b9250808711156135f65783633b9aca006135db838a615830565b6135e591906157ca565b6135ef91906157ff565b91506135fb565b600191505b5061367f565b60385461361290633b9aca006157ca565b8c518b906136219087906157ca565b61362b91906157ca565b61363591906157ff565b61364090600161594f565b915060b55485111561367b57633b9aca008460b554876136609190615830565b61366a91906157ca565b61367491906157ff565b905061367f565b5060015b81885261368c848b6157ca565b60385461369d633b9aca00856157ca565b6136a791906157ca565b6136b191906157ff565b602089015260408801525050606085015250608083015250949350505050565b60808054608154604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f602082015290810192909252606082015246918101919091523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60006137476131d3565b90506000676765c793fa10079d601b1b603f54836137659190615830565b60405461377291906157ca565b61377c91906157ff565b90508060416000828254613790919061594f565b9091555050603f82905542603e8190556040805184815260208101929092527fd1fa8ba00a3bf20274346919dce0de62d2a140af2c71fe7e29fa6472eea3bb9d910160405180910390a15090565b603d54600160c81b900460ff1690565b600081613800576137fd61373d565b91505b60008481526043602052604081206001015490676765c793fa10079d601b1b61382985846157ca565b61383391906157ff565b905080851061384457935080613867565b8361385a676765c793fa10079d601b1b876157ca565b61386491906157ff565b90505b6138718183615830565b915080604060008282546138859190615830565b909155505081158015906138ba5750676765c793fa10079d601b1b60b4546138ad91906157ca565b6138b785846157ca565b11155b156138d85760405163228af07f60e21b815260040160405180910390fd5b60008681526043602052604080822060010184905551600080516020615e9a8339815191529161390b9189918591615967565b60405180910390a15092949350505050565b851561393a5760345461393a906001600160a01b03168488614432565b8415611dfa578051156139b95760345460355460405163a5d4096b60e01b81526001600160a01b038086169363a5d4096b936139869391831692169089908b908d908990600401615d3a565b600060405180830381600087803b1580156139a057600080fd5b505af11580156139b4573d6000803e3d6000fd5b505050505b603554604051630d43af8160e21b81526001600160a01b039091169063350ebe04906139ed90889088903390600401615d02565b600060405180830381600087803b158015613a0757600080fd5b505af1158015613a1b573d6000803e3d6000fd5b50505050505050505050565b603c54600160c01b90046001600160401b031690565b826001600160a01b0316826001600160a01b03161415613a70576040516320c5195360e21b815260040160405180910390fd5b600081613a7e576000613a81565b60015b6001600160a01b038581166000818152604a602090815260408083209489168084529482529182902060ff959095169485905590518615158152939450919290917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a350505050565b60006001600160a01b038216613b1c5760405163d92e233d60e01b815260040160405180910390fd5b5060458054600101908190556001600160a01b038216600081815260486020908152604080832080546001019055848352604790915280822080546001600160a01b031916841790555183929190600080516020615eda833981519152908290a4613b99600083836040518060200160405280600081525061474d565b611dc0576040516320149b4360e21b815260040160405180910390fd5b613bc18484846130fc565b613bcd8484848461474d565b613bea576040516320149b4360e21b815260040160405180910390fd5b50505050565b846001600160a01b0316836001600160a01b03166361d027b36040518163ffffffff1660e01b8152600401602060405180830381865afa158015613c38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c5c9190615872565b6001600160a01b031614613c83576040516302979eb960e31b815260040160405180910390fd5b603380546001600160a01b038088166001600160a01b0319928316179092556034805492871692909116821790556040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa158015613cec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d109190615db2565b613d1b90600a615a7f565b603881905550846001600160a01b031663e9cbd8226040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d839190615872565b603580546001600160a01b03199081166001600160a01b039384161790915560368054909116918516919091179055604051600090613dc6908390602001615dcf565b60408051601f198184030181529190528051909150613dec90607d906020840190614d3b565b50613df681614850565b81604051602001613e079190615e16565b604051602081830303815290604052607e9080519060200190613e2b929190614d3b565b50676765c793fa10079d601b1b603f5542603e55608083015160208401516001600160401b0391821691161180613e725750633b9aca0083608001516001600160401b0316115b80613e8d575082604001516001600160401b0316633b9aca00115b80613ea95750633b9aca008360a001516001600160401b031610155b80613eb6575060e0830151155b15613ed457604051631746545d60e11b815260040160405180910390fd5b8251603955602080840151603c80546040808801516001600160401b039485166001600160801b031993841617600160401b9186168202179093556060880151603d805460808b015160a08c0151938816919095161793861690940292909217600160801b600160c01b031916600160801b92909416919091029290921790558051918201905260e08401518152613f7090603b906001614dbf565b50505050505050565b613f8282612fa2565b613f9f5760405163062a39dd60e11b815260040160405180910390fd5b60008281526043602052604081208054839290613fbd90849061594f565b9091555050604051600080516020615eba833981519152906111809084908490600190615967565b6000803385613ff4828261307e565b6140115760405163c19f17a960e01b815260040160405180910390fd5b600087815260436020908152604080832081518083019092528054825260010154918101919091529080614046838a8a614495565b5091509150633b9aca00821161406f57604051631527804d60e31b815260040160405180910390fd5b8260200151604060008282546140859190615830565b9091555061409490508a614926565b600061409e613a27565b6140b5906001600160401b0316633b9aca00615830565b6140c3633b9aca00846157ca565b6140cd91906157ff565b90506140d98282615830565b604160008282546140ea919061594f565b90915550509251929a92995091975050505050505050565b338461410e828261307e565b61412b5760405163c19f17a960e01b815260040160405180910390fd5b60008681526043602052604081208054879290614149908490615830565b909155505060008681526043602090815260408083208151808301909252805482526001015491810191909152614181908686614495565b50509050633b9aca0081116141a957604051631527804d60e31b815260040160405180910390fd5b600080516020615eba833981519152878760006040516141cb93929190615967565b60405180910390a150505050505050565b600033856141ea828261307e565b6142075760405163c19f17a960e01b815260040160405180910390fd5b614213878787876149a5565b603c54909650600090633b9aca009061423d908990600160801b90046001600160401b03166157ca565b61424791906157ff565b9050806041600082825461425b919061594f565b9091555061426b90508188615830565b98975050505050505050565b3386614283828261307e565b6142a05760405163c19f17a960e01b815260040160405180910390fd5b60408051898152602081018890526001600160a01b038916818301526060810187905290517fddd3b70af631334f7552aadb582ed091018e62e103fa8b150ca66cc700d4dac69181900360800190a16142fb888686866149a5565b94506001600160a01b03871630141561431f576143198686856137ee565b50611c6f565b866001600160a01b031663835986b48787603c60109054906101000a90046001600160401b031661434e613a27565b6040516001600160e01b031960e087901b168152600481019490945260248401929092526001600160401b039081166044840152166064820152608401600060405180830381600087803b1580156143a557600080fd5b505af11580156143b9573d6000803e3d6000fd5b505050505050505050505050565b6040516001600160a01b0380851660248301528316604482015260648101829052613bea9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614b38565b610a198363a9059cbb60e01b84846040516024016143fb929190615d21565b6001600160a01b0381166000908152607f602052604090205461447581600161594f565b6001600160a01b039092166000908152607f602052604090209190915590565b6000806000676765c793fa10079d601b1b8487602001516144b691906157ca565b6144c091906157ff565b91506038548587600001516144d591906157ca565b6144df91906157ff565b9050816144f0576000199250614515565b603c548290614508906001600160401b0316836157ca565b61451291906157ff565b92505b93509350939050565b6037546000906001600160a01b031661455757603b6000815481106145455761454561588f565b90600052602060002001549050919050565b603754604051635dfba04560e11b81526000916001600160a01b03169063bbf7408a90614588908690600401614e36565b602060405180830381865afa1580156145a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145c9919061579b565b9050603a6001815481106145df576145df61588f565b9060005260206000200154811061461757603b6001815481106146045761460461588f565b9060005260206000200154915050919050565b603a60008154811061462b5761462b61588f565b9060005260206000200154811161465057603b6000815481106146045761460461588f565b603a6000815481106146645761466461588f565b9060005260206000200154603a6001815481106146835761468361588f565b90600052602060002001546146989190615830565b603a6000815481106146ac576146ac61588f565b9060005260206000200154826146c29190615830565b603b6000815481106146d6576146d661588f565b9060005260206000200154603b6001815481106146f5576146f561588f565b906000526020600020015461470a9190615830565b61471491906157ca565b61471e91906157ff565b603b6000815481106147325761473261588f565b9060005260206000200154610b04919061594f565b50919050565b6000614761846001600160a01b0316612f93565b1561484857604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290614798903390899088908890600401615e40565b6020604051808303816000875af19250505080156147d3575060408051601f3d908101601f191682019092526147d091810190615d95565b60015b61482e573d808015614801576040519150601f19603f3d011682016040523d82523d6000602084013e614806565b606091505b508051614826576040516320149b4360e21b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611cb3565b506001611cb3565b600054610100900460ff166148bb5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401611515565b7f3f43a9c6bafb5c7aab4e0cfe239dc5d4c15caf0381c6104188191f78a6640bd860825580516020918201206080556040805180820190915260018152603160f81b9101527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6608155565b600061493182612fda565b905061493e600083613010565b6001600160a01b038116600081815260486020908152604080832080546000190190558583526047825280832080546001600160a01b0319169055604390915280822082815560010182905551849290600080516020615eda833981519152908390a45050565b600080826149be676765c793fa10079d601b1b876157ca565b6149c891906157ff565b600087815260436020526040902060010154909150614a035760b4548511614a035760405163228af07f60e21b815260040160405180910390fd5b60008681526043602052604081206001018054839290614a2490849061594f565b925050819055508060406000828254614a3d919061594f565b9091555050603954614a5b90676765c793fa10079d601b1b906157ca565b83604054614a6991906157ca565b1115614a88576040516371239a6160e11b815260040160405180910390fd5b60008681526043602090815260408083208151808301909252805482526001015491810191909152614abb908686614495565b50509050633b9aca008111614ae357604051631527804d60e31b815260040160405180910390fd5b600080516020615e9a83398151915287836001604051614b0593929190615967565b60405180910390a1676765c793fa10079d601b1b614b2385846157ca565b614b2d91906157ff565b979650505050505050565b6000614b8d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614c0a9092919063ffffffff16565b805190915015610a195780806020019051810190614bab9190615813565b610a195760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611515565b6060611cb3848460008585614c1e85612f93565b614c6a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611515565b600080866001600160a01b03168587604051614c869190615e7d565b60006040518083038185875af1925050503d8060008114614cc3576040519150601f19603f3d011682016040523d82523d6000602084013e614cc8565b606091505b5091509150614b2d82828660608315614ce2575081610b04565b825115614cf25782518084602001fd5b8160405162461bcd60e51b81526004016115159190614ed5565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b828054614d4790615766565b90600052602060002090601f016020900481019282614d695760008555614daf565b82601f10614d8257805160ff1916838001178555614daf565b82800160010185558215614daf579182015b82811115614daf578251825591602001919060010190614d94565b50614dbb929150614e21565b5090565b828054828255906000526020600020908101928215614daf5791602002820182811115614daf578251825591602001919060010190614d94565b6040518060800160405280600081526020016000815260200160008152602001600081525090565b5b80821115614dbb5760008155600101614e22565b6001600160a01b0391909116815260200190565b6001600160e01b031981168114610c8057600080fd5b600060208284031215614e7257600080fd5b8135610b0481614e4a565b60005b83811015614e98578181015183820152602001614e80565b83811115613bea5750506000910152565b60008151808452614ec1816020860160208601614e7d565b601f01601f19169290920160200192915050565b602081526000610b046020830184614ea9565b600060208284031215614efa57600080fd5b5035919050565b6001600160a01b0381168114610c8057600080fd5b60008060408385031215614f2957600080fd5b8235614f3481614f01565b946020939093013593505050565b600080600060608486031215614f5757600080fd5b8335614f6281614f01565b92506020840135614f7281614f01565b929592945050506040919091013590565b60008060408385031215614f9657600080fd5b823591506020830135614fa881614f01565b809150509250929050565b60a081016108cc828480518252602081015160208301526040810151604083015260608101516060830152608081015160808301525050565b600060208284031215614ffe57600080fd5b8135610b0481614f01565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561504757615047615009565b604052919050565b600082601f83011261506057600080fd5b81356001600160401b0381111561507957615079615009565b61508c601f8201601f191660200161501f565b8181528460208386010111156150a157600080fd5b816020850160208301376000918101602001919091529392505050565b6000602082840312156150d057600080fd5b81356001600160401b038111156150e657600080fd5b611cb38482850161504f565b80356001600160401b0381168114611dc057600080fd5b6000806040838503121561511c57600080fd5b614f34836150f2565b60006001600160401b0382111561513e5761513e615009565b5060051b60200190565b600082601f83011261515957600080fd5b8135602061516e61516983615125565b61501f565b82815260059290921b8401810191818101908684111561518d57600080fd5b8286015b848110156151a85780358352918301918301615191565b509695505050505050565b6000806000606084860312156151c857600080fd5b83356151d381614f01565b925060208401356001600160401b03808211156151ef57600080fd5b6151fb87838801615148565b9350604086013591508082111561521157600080fd5b5061521e86828701615148565b9150509250925092565b60008060008060008060c0878903121561524157600080fd5b86356001600160401b038082111561525857600080fd5b6152648a838b01615148565b9750602089013591508082111561527a57600080fd5b6152868a838b01615148565b96506040890135915061529882614f01565b9094506060880135906152aa82614f01565b9093506080880135906152bc82614f01565b90925060a088013590808211156152d257600080fd5b506152df89828a0161504f565b9150509295509295509295565b6000806000806080858703121561530257600080fd5b5050823594602084013594506040840135936060013592509050565b600082601f83011261532f57600080fd5b8135602061533f61516983615125565b82815260059290921b8401810191818101908684111561535e57600080fd5b8286015b848110156151a85780356008811061537a5760008081fd5b8352918301918301615362565b600082601f83011261539857600080fd5b813560206153a861516983615125565b82815260059290921b840181019181810190868411156153c757600080fd5b8286015b848110156151a85780356001600160401b038111156153ea5760008081fd5b6153f88986838b010161504f565b8452509183019183016153cb565b6000806000806080858703121561541c57600080fd5b84356001600160401b038082111561543357600080fd5b61543f8883890161531e565b9550602087013591508082111561545557600080fd5b5061546287828801615387565b935050604085013561547381614f01565b9150606085013561548381614f01565b939692955090935050565b8015158114610c8057600080fd5b600080604083850312156154af57600080fd5b82356154ba81614f01565b91506020830135614fa88161548e565b600080600080608085870312156154e057600080fd5b84356154eb81614f01565b935060208501356154fb81614f01565b92506040850135915060608501356001600160401b0381111561551d57600080fd5b6155298782880161504f565b91505092959194509250565b60008060006060848603121561554a57600080fd5b505081359360208301359350604090920135919050565b600080600080600085870361018081121561557b57600080fd5b863561558681614f01565b9550602087013561559681614f01565b945060408701356155a681614f01565b9350610100605f19820112156155bb57600080fd5b506060860191506101608601356001600160401b038111156155dc57600080fd5b6155e88882890161504f565b9150509295509295909350565b60008060008060008060c0878903121561560e57600080fd5b86356001600160401b038082111561562557600080fd5b6156318a838b0161531e565b9750602089013591508082111561564757600080fd5b6152868a838b01615387565b6000806040838503121561566657600080fd5b823561567181614f01565b91506020830135614fa881614f01565b60ff81168114610c8057600080fd5b600080600080600080600060e0888a0312156156ab57600080fd5b87356156b681614f01565b965060208801356156c681614f01565b955060408801356156d68161548e565b94506060880135935060808801356156ed81615681565b9699959850939692959460a0840135945060c09093013592915050565b6000806000806080858703121561572057600080fd5b84356001600160401b038082111561573757600080fd5b61574388838901615148565b9550602087013591508082111561575957600080fd5b5061546287828801615148565b600181811c9082168061577a57607f821691505b6020821081141561474757634e487b7160e01b600052602260045260246000fd5b6000602082840312156157ad57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b60008160001904831182151516156157e4576157e46157b4565b500290565b634e487b7160e01b600052601260045260246000fd5b60008261580e5761580e6157e9565b500490565b60006020828403121561582557600080fd5b8151610b048161548e565b600082821015615842576158426157b4565b500390565b60006001600160401b03828116848216808303821115615869576158696157b4565b01949350505050565b60006020828403121561588457600080fd5b8151610b0481614f01565b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b838110156158d5578151875295820195908201906001016158b9565b509495945050505050565b6040815260006158f360408301856158a5565b82810360208401526120ba81856158a5565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b602081526000610b0460208301846158a5565b60008219821115615962576159626157b4565b500190565b928352602083019190915260ff16604082015260600190565b6000600019821415615994576159946157b4565b5060010190565b600181815b808511156159d65781600019048211156159bc576159bc6157b4565b808516156159c957918102915b93841c93908002906159a0565b509250929050565b6000826159ed575060016108cc565b816159fa575060006108cc565b8160018114615a105760028114615a1a57615a36565b60019150506108cc565b60ff841115615a2b57615a2b6157b4565b50506001821b6108cc565b5060208310610133831016604e8410600b8410161715615a59575081810a6108cc565b615a63838361599b565b8060001904821115615a7757615a776157b4565b029392505050565b6000610b0460ff8416836159de565b600082615a9d57615a9d6157e9565b500690565b60008151615ab4818560208601614e7d565b9290920192915050565b600080845481600182811c915080831680615ada57607f831692505b6020808410821415615afa57634e487b7160e01b86526022600452602486fd5b818015615b0e5760018114615b1f57615b4c565b60ff19861689528489019650615b4c565b60008b81526020902060005b86811015615b445781548b820152908501908301615b2b565b505084890196505b5050505050506120ba8185615aa2565b6000610100808385031215615b7057600080fd5b604051908101906001600160401b0382118183101715615b9257615b92615009565b8160405283358152615ba6602085016150f2565b6020820152615bb7604085016150f2565b6040820152615bc8606085016150f2565b6060820152615bd9608085016150f2565b6080820152615bea60a085016150f2565b60a082015260c08401359150615bff8261548e565b8160c082015260e084013560e0820152809250505092915050565b600060208284031215615c2c57600080fd5b8135610b048161548e565b634e487b7160e01b600052602160045260246000fd5b60008060408385031215615c6057600080fd5b505080516020909101519092909150565b60008060008060008060c08789031215615c8a57600080fd5b8651615c9581614f01565b6020880151604089015160608a015160808b015160a0909b0151939c929b509099909850965090945092505050565b60008060008060808587031215615cda57600080fd5b845193506020850151615cec81614f01565b6040860151606090960151949790965092505050565b9283526001600160a01b03918216602084015216604082015260600190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b038781168252868116602083015285166040820152606081018490526080810183905260c060a0820181905260009061426b90830184614ea9565b828152604060208201526000611cb36040830184614ea9565b600060208284031215615da757600080fd5b8151610b0481614e4a565b600060208284031215615dc457600080fd5b8151610b0481615681565b6e020b733b63290283937ba37b1b7b61608d1b815260008251615df981600f850160208701614e7d565b650815985d5b1d60d21b600f939091019283015250601501919050565b60008251615e28818460208701614e7d565b650b5d985d5b1d60d21b920191825250600601919050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090615e7390830184614ea9565b9695505050505050565b60008251615e8f818460208701614e7d565b919091019291505056fe70cf49afe7355562d5b022e594790f22b71ad8cc7eec902fa5feac7c67f71091722cb71fa87c947148cefc06dd890af5802a6a00207c5ddecf1191bf71ce3cd4ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122078f88412fac305d48d14da508160f0c03b8a2dabd2ce26c193dad112345b201664736f6c634300080c0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106103015760003560e01c8063010db1951461030657806301ffc9a71461032f57806306fdde0314610352578063081812fc14610367578063087a60071461037a578063095ea7b3146103915780630e198f22146103a657806313888565146103af57806323b872dd146103b8578063254cf439146103cb578063307439af146103fd57806334ce998a1461041d57806335836f15146104255780633644e5151461043857806339393ac91461044057806339eb4dc6146104535780633ae2325f146104675780633af32abf1461047a5780633c2e941b1461049a57806342842e0e146104a3578063430c2081146104b65780634f7e43df146104c957806355f804b3146104e35780635c975abb146104f657806361d027b31461050a5780636352211e1461051d57806370a082311461053057806374107543146105435780637aacfffa146105565780637adbf973146105925780637c0f59f4146105a55780637c3a00fd146105bf5780637dc0d1d0146105d25780637e53bd97146105e55780637e56d47c146105f85780637ecebe001461060b578063835986b41461063457806389050f1d1461064757806395d89b41146106595780639a3b6f2f146106615780639f48118f146106a7578063a22cb465146106b2578063af2c8c2e146106c5578063b1511cc9146106ce578063b4bd6f46146106e1578063b88d4fde146106f4578063bbcac55714610707578063bfc7ad2e14610710578063c13cacae14610719578063c4ae31681461072c578063c66d8b0114610734578063c87b56dd1461074e578063d8dfeb4514610761578063d9b1cb5b14610774578063de1f776514610787578063de8fc69814610799578063df011c41146107ac578063e182b883146107bf578063e1c84ea4146107d2578063e626648a146107db578063e985e9c5146107f5578063e9cbd82214610808578063f0f442601461081b578063f51cc7dd1461082e578063fad9aba314610841578063fc29b0211461084a578063fd527cf81461085d575b600080fd5b603754610319906001600160a01b031681565b6040516103269190614e36565b60405180910390f35b61034261033d366004614e60565b610865565b6040519015158152602001610326565b61035a6108d2565b6040516103269190614ed5565b610319610375366004614ee8565b610960565b610383603f5481565b604051908152602001610326565b6103a461039f366004614f16565b610991565b005b610383603e5481565b61038360415481565b6103a46103c6366004614f42565b610a1e565b603c546103e590600160401b90046001600160401b031681565b6040516001600160401b039091168152602001610326565b61041061040b366004614f83565b610a59565b6040516103269190614fb3565b610383610b0b565b610383610433366004614ee8565b610b3d565b610383610b79565b6103a461044e366004614fec565b610b83565b603d5461034290600160c01b900460ff1681565b610383610475366004614ee8565b610c83565b610383610488366004614fec565b60446020526000908152604090205481565b61038360455481565b6103a46104b1366004614f42565b610ca4565b6103426104c4366004614f16565b610cbf565b603d546103e590600160801b90046001600160401b031681565b6103a46104f13660046150be565b610ccb565b603d5461034290600160c81b900460ff1681565b603354610319906001600160a01b031681565b61031961052b366004614ee8565b610d70565b61038361053e366004614fec565b610d7b565b6103a4610551366004615109565b610dc0565b61057d610564366004614ee8565b6043602052600090815260409020805460019091015482565b60408051928352602083019190915201610326565b6103a46105a0366004614fec565b61118c565b603c546103e590600160c01b90046001600160401b031681565b603d546103e5906001600160401b031681565b603654610319906001600160a01b031681565b6103a46105f33660046151b3565b6112d3565b610410610606366004615228565b6114c4565b610383610619366004614fec565b6001600160a01b03166000908152607f602052604090205490565b6103a46106423660046152ec565b611ad8565b610383676765c793fa10079d601a1b81565b61035a611c79565b61067461066f366004615406565b611c86565b60405161032691908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b610383633b9aca0081565b6103a46106c036600461549c565b611cbb565b61038360405481565b6103a46106dc366004614ee8565b611cc6565b6103836106ef366004614fec565b611d8f565b6103a46107023660046154ca565b611dc5565b61038360425481565b61038360b65481565b6103a4610727366004615535565b611e02565b6103a4611ebf565b603d546103e590600160401b90046001600160401b031681565b61035a61075c366004614ee8565b611f6e565b603454610319906001600160a01b031681565b6103a4610782366004615561565b6120c3565b610383676765c793fa10079d601b1b81565b6106746107a73660046155f5565b61222f565b603c546103e5906001600160401b031681565b6103836107cd366004614ee8565b612aad565b61038360395481565b603c546103e590600160801b90046001600160401b031681565b610342610803366004615653565b612abd565b603554610319906001600160a01b031681565b6103a4610829366004614fec565b612aeb565b6103a461083c366004615690565b612b8b565b61038360b45481565b61041061085836600461570a565b612e4a565b61057d612e74565b60006001600160e01b03198216635b5e139f60e01b148061089657506001600160e01b031982166380ac58cd60e01b145b806108b157506001600160e01b0319821663430c208160e01b145b806108cc57506001600160e01b031982166301ffc9a760e01b145b92915050565b607d80546108df90615766565b80601f016020809104026020016040519081016040528092919081815260200182805461090b90615766565b80156109585780601f1061092d57610100808354040283529160200191610958565b820191906000526020600020905b81548152906001019060200180831161093b57829003601f168201915b505050505081565b600061096b82612fa2565b6109885760405163062a39dd60e11b815260040160405180910390fd5b6108cc82612fbf565b600061099c82612fda565b9050806001600160a01b0316836001600160a01b031614156109d1576040516349fa8bc360e11b815260040160405180910390fd5b336001600160a01b038216148015906109f157506109ef8133612abd565b155b15610a0f5760405163c19f17a960e01b815260040160405180910390fd5b610a198383613010565b505050565b3381610a2a828261307e565b610a475760405163c19f17a960e01b815260040160405180910390fd5b610a528585856130fc565b5050505050565b610a61614d0c565b60008381526043602090815260409182902082518084018452815481526001909101548183015260365483516315f789a960e21b81529351610b0494929387936001600160a01b03909316926357de26a492600480830193928290030181865afa158015610ad3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af7919061579b565b610aff6131d3565b613368565b9392505050565b6000676765c793fa10079d601b1b610b216131d3565b604054610b2e91906157ca565b610b3891906157ff565b905090565b6000676765c793fa10079d601b1b610b536131d3565b600084815260436020526040902060010154610b6f91906157ca565b6108cc91906157ff565b6000610b386136d1565b603354604051631c86b03760e31b81526001600160a01b039091169063e43581b890610bb3903390600401614e36565b602060405180830381865afa158015610bd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bf49190615813565b610c1157604051633b8d9d7560e21b815260040160405180910390fd5b6001600160a01b03811615610c60576001600160a01b038116600090815260446020526040902054610c44906001615830565b6001600160a01b03821660009081526044602052604090205550565b603d805460ff60c01b198116600160c01b9182900460ff16159091021790555b50565b603b8181548110610c9357600080fd5b600091825260209091200154905081565b610a1983838360405180602001604052806000815250611dc5565b6000610b04838361307e565b60335460405163521d4de960e01b81526001600160a01b039091169063521d4de990610cfb903390600401614e36565b602060405180830381865afa158015610d18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d3c9190615813565b610d5957604051632678482f60e21b815260040160405180910390fd5b8051610d6c906046906020840190614d3b565b5050565b60006108cc82612fda565b60006001600160a01b038216610da45760405163d92e233d60e01b815260040160405180910390fd5b506001600160a01b031660009081526048602052604090205490565b60335460405163521d4de960e01b81526001600160a01b039091169063521d4de990610df0903390600401614e36565b602060405180830381865afa158015610e0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e319190615813565b610e4e57604051632678482f60e21b815260040160405180910390fd5b806121a360f11b1415610eb257603d546001600160401b03600160401b90910481169083161115610e9257604051637650e96360e11b815260040160405180910390fd5b603c80546001600160401b0319166001600160401b038416179055611145565b80622a242360e91b1415610f1757633b9aca00826001600160401b03161015610eee5760405163da6a17b960e01b815260040160405180910390fd5b603c8054600160401b600160801b031916600160401b6001600160401b03851602179055611145565b8061212360f11b1415610f7b57633b9aca00826001600160401b03161115610f5257604051637650e96360e11b815260040160405180910390fd5b603c8054600160801b600160c01b031916600160801b6001600160401b03851602179055611145565b8061292360f11b1415610ff857603d54633b9aca0090610fab90600160401b90046001600160401b031684615847565b6001600160401b03161115610fd357604051637650e96360e11b815260040160405180910390fd5b603c80546001600160c01b0316600160c01b6001600160401b03851602179055611145565b806124a960f11b141561102e5761100d61373d565b50603d80546001600160401b0319166001600160401b038416179055611145565b80614c5360f01b14156110c757603c546001600160401b03808416911611806110805750603c54633b9aca009061107590600160c01b90046001600160401b031684615847565b6001600160401b0316115b1561109e5760405163180d062b60e31b815260040160405180910390fd5b603d8054600160401b600160801b031916600160401b6001600160401b03851602179055611145565b806213531160ea1b141561112c57633b9aca00826001600160401b0316111561110357604051637650e96360e11b815260040160405180910390fd5b603d8054600160801b600160c01b031916600160801b6001600160401b03851602179055611145565b60405163e1daa9cf60e01b815260040160405180910390fd5b604080516001600160401b0384168152602081018390527f13b367dac93b85d1ed9b3d8961d8b48e1a677c9800bb1613b4b0416b2d5b61d091015b60405180910390a15050565b603354604051631c86b03760e31b81526001600160a01b039091169063e43581b8906111bc903390600401614e36565b602060405180830381865afa1580156111d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111fd9190615813565b61121a57604051633b8d9d7560e21b815260040160405180910390fd5b603354604080516361d027b360e01b815290516001600160a01b03928316928416916361d027b39160048083019260209291908290030181865afa158015611266573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128a9190615872565b6001600160a01b0316146112b1576040516302979eb960e31b815260040160405180910390fd5b603680546001600160a01b0319166001600160a01b0392909216919091179055565b60335460405163521d4de960e01b81526001600160a01b039091169063521d4de990611303903390600401614e36565b602060405180830381865afa158015611320573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113449190615813565b61136157604051632678482f60e21b815260040160405180910390fd5b8051825114158061138c5750806000815181106113805761138061588f565b60200260200101516000145b8061141b57506001600160a01b0383161580159061141b5750816000815181106113b8576113b861588f565b6020026020010151826001815181106113d3576113d361588f565b602002602001015111158061141b5750806000815181106113f6576113f661588f565b6020026020010151816001815181106114115761141161588f565b6020026020010151105b1561143957604051631746545d60e11b815260040160405180910390fd5b603780546001600160a01b0319166001600160a01b038516179055815161146790603a906020850190614dbf565b50805161147b90603b906020840190614dbf565b50826001600160a01b03167feb74d4d9fea592587c926aeb35eb6a7893fb28db0c1c8eb2eb3c586e7164b76c83836040516114b79291906158e0565b60405180910390a2505050565b6114cc614d0c565b6114d46137de565b156114f2576040516313d0ff5960e31b815260040160405180910390fd5b6002600154141561151e5760405162461bcd60e51b815260040161151590615905565b60405180910390fd5b6002600155603d54600160c01b900460ff16801561154c575033600090815260446020526040902054600114155b801561157157506001600160a01b038416600090815260446020526040902054600114155b1561158f57604051630b094f2760e31b815260040160405180910390fd5b865186518114158061159f575080155b156115bd576040516346282e8d60e01b815260040160405180910390fd5b603660009054906101000a90046001600160a01b03166001600160a01b03166357de26a46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611610573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611634919061579b565b606083015261164161373d565b60808301526040517f965a177723c641ee49150b583a0b9ad4730bb20d3474e00ae5a65e777c00d67b90611676908a9061593c565b60405180910390a160005b81811015611a48576000604360008b84815181106116a1576116a161588f565b6020026020010151815260200190815260200160002060405180604001604052908160008201548152602001600182015481525050905060006116ee823387606001518860800151613368565b90508060400151600014158015611722575080604001518a84815181106117175761171761588f565b602002602001015110155b80611749575080600001518a848151811061173f5761173f61588f565b6020026020010151115b156117725780600001518a84815181106117655761176561588f565b6020026020010181815250505b60008560600151826060015161178891906157ca565b603854633b9aca008d87815181106117a2576117a261588f565b60200260200101516117b491906157ca565b6117be91906157ca565b6117c891906157ff565b90506117f68c85815181106117df576117df61588f565b60200260200101518285600001511115610c805750565b8251811061192c57508151602083015160408054600090611818908490615830565b92505081905550604360008d86815181106118355761183561588f565b60209081029190910181015182528101919091526040016000908120818155600101819055603d548c51633b9aca0091600160401b90046001600160401b0316908e90889081106118885761188861588f565b602002602001015161189a91906157ca565b6118a491906157ff565b9050826080015181106118b85760006118c8565b8083608001516118c89190615830565b876040018181516118d9919061594f565b905250508b51600080516020615e9a833981519152908d90869081106119015761190161588f565b60200260200101518460200151600060405161191f93929190615967565b60405180910390a16119ed565b80604360008e87815181106119435761194361588f565b60200260200101518152602001908152602001600020600001600082825461196b9190615830565b925050819055506119eb8c85815181106119875761198761588f565b6020026020010151633b9aca00603d60089054906101000a90046001600160401b03166001600160401b03168e88815181106119c5576119c561588f565b60200260200101516119d791906157ca565b6119e191906157ff565b88608001516137ee565b505b80866020018181516119ff919061594f565b9052508a518b9085908110611a1657611a1661588f565b602002602001015186600001818151611a2f919061594f565b905250611a4192508391506159809050565b9050611681565b50603d54633b9aca0090611a6c90600160401b90046001600160401b031682615830565b8351611a7891906157ca565b611a8291906157ff565b60416000828254611a93919061594f565b9091555050604082015160428054600090611aaf90849061594f565b909155505060208201518251611ac991908888888861391d565b50600180559695505050505050565b611ae06137de565b15611afe576040516313d0ff5960e31b815260040160405180910390fd5b6033546040516333b52a9f60e11b81526001600160a01b039091169063676a553e90611b2e903390600401614e36565b602060405180830381865afa158015611b4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b6f9190615813565b611b8c5760405163027f480760e01b815260040160405180910390fd5b600080611b97613a27565b6001600160401b0316905082811115611bb757611bb48382615830565b91505b50603c54600090600160801b90046001600160401b0316841115611bf557603c54611bf290600160801b90046001600160401b031685615830565b90505b6000611c066002633b9aca00615a7f565b611c1483633b9aca00615830565b611c2285633b9aca00615830565b611c2c90896157ca565b611c3691906157ca565b611c4091906157ff565b9050611c4c8187615830565b60416000828254611c5d919061594f565b90915550611c6f9050878260006137ee565b5050505050505050565b607e80546108df90615766565b611c8e614df9565b60408051600080825260208201909252611cb09187918791879187919061222f565b90505b949350505050565b610d6c338383613a3d565b60335460405163521d4de960e01b81526001600160a01b039091169063521d4de990611cf6903390600401614e36565b602060405180830381865afa158015611d13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d379190615813565b611d5457604051632678482f60e21b815260040160405180910390fd5b60398190556040518181527fdd63b3dcdbebad734892f7c7a26d0f647fbc7eec973e0775f5229018ac4ab47a9060200160405180910390a150565b6000611d996137de565b15611db7576040516313d0ff5960e31b815260040160405180910390fd5b6108cc82613af3565b919050565b3382611dd1828261307e565b611dee5760405163c19f17a960e01b815260040160405180910390fd5b611dfa86868686613bb6565b505050505050565b603354604051631c86b03760e31b81526001600160a01b039091169063e43581b890611e32903390600401614e36565b602060405180830381865afa158015611e4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e739190615813565b611e9057604051633b8d9d7560e21b815260040160405180910390fd5b81831115611eb15760405163180d062b60e31b815260040160405180910390fd5b60b49290925560b65560b555565b60335460405163521d4de960e01b81526001600160a01b039091169063521d4de990611eef903390600401614e36565b602060405180830381865afa158015611f0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f309190615813565b611f4d57604051632678482f60e21b815260040160405180910390fd5b603d805460ff60c81b198116600160c81b9182900460ff1615909102179055565b6060611f7982612fa2565b611f965760405163062a39dd60e11b815260040160405180910390fd5b8160005b8115611fbd57611fa981615980565b9050611fb6600a836157ff565b9150611f9a565b6000816001600160401b03811115611fd757611fd7615009565b6040519080825280601f01601f191660200182016040528015612001576020820181803683370190505b5090505b841561206c57612016600183615830565b9150612023600a86615a8e565b61202e90603061594f565b60f81b8183815181106120435761204361588f565b60200101906001600160f81b031916908160001a905350612065600a866157ff565b9450612005565b6046805461207990615766565b1515905061209657604051806020016040528060008152506120ba565b6046816040516020016120aa929190615abe565b6040516020818303038152906040525b95945050505050565b600054610100900460ff16158080156120e35750600054600160ff909116105b8061210457506120f230612f93565b158015612104575060005460ff166001145b6121675760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401611515565b6000805460ff19166001179055801561218a576000805461ff0019166101001790555b6121a586868661219f36889003880188615b5c565b86613bf0565b6121b560e0840160c08501615c1a565b603d805460ff60c81b19921515600160c01b029290921661ffff60c01b1990921691909117600160c81b1790558015611dfa576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050565b612237614df9565b61223f6137de565b1561225d576040516313d0ff5960e31b815260040160405180910390fd5b600260015414156122805760405162461bcd60e51b815260040161151590615905565b60026001558551875114158061229557508651155b156122b3576040516346282e8d60e01b815260040160405180910390fd5b6000806000806000805b8c518110156128165760008d82815181106122da576122da61588f565b60200260200101519050600060078111156122f7576122f7615c37565b81600781111561230957612309615c37565b141561234a576123448d83815181106123245761232461588f565b602002602001015180602001905181019061233f9190615872565b613af3565b50612805565b600281600781111561235e5761235e615c37565b14156123c4578c82815181106123765761237661588f565b60200260200101518060200190518101906123919190615c4d565b95509250826123a05760455492505b6123aa8386613f79565b84886060018181516123bc919061594f565b905250612805565b60078160078111156123d8576123d8615c37565b14156124b15760008060008f85815181106123f5576123f561588f565b60200260200101518060200190518101906124109190615c71565b60345460405163d505accf60e01b81526001600160a01b038089166004830152306024830152604482018890526064820187905260ff8616608483015260a4820185905260c48201849052969f50939d50939b509497509550929350169063d505accf9060e401600060405180830381600087803b15801561249157600080fd5b505af11580156124a5573d6000803e3d6000fd5b50505050505050612805565b866124c1576124be61373d565b96505b60048160078111156124d5576124d5615c37565b141561259d578c82815181106124ed576124ed61588f565b60200260200101518060200190518101906125089190615c4d565b94509250826125175760455492505b6125228385896137ee565b9350600061252e613a27565b612545906001600160401b0316633b9aca00615830565b612553633b9aca00876157ca565b61255d91906157ff565b90506125698582615830565b6041600082825461257a919061594f565b925050819055508089602001818151612593919061594f565b9052506128059050565b8561261c57603660009054906101000a90046001600160a01b03166001600160a01b03166357de26a46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156125f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612619919061579b565b95505b600181600781111561263057612630615c37565b14156126ac578c82815181106126485761264861588f565b6020026020010151806020019051810190612663919061579b565b9250826126705760455492505b61267b838789613fe5565b80965081955050508488604001818151612695919061594f565b9052506020880180518591906123bc90839061594f565b60038160078111156126c0576126c0615c37565b1415612720578c82815181106126d8576126d861588f565b60200260200101518060200190518101906126f39190615c4d565b95509250826127025760455492505b61270e8386888a614102565b84886040018181516123bc919061594f565b600581600781111561273457612734615c37565b1415612796578c828151811061274c5761274c61588f565b60200260200101518060200190518101906127679190615c4d565b94509250826127765760455492505b6127828385888a6141dc565b935083886000018181516123bc919061594f565b60068160078111156127aa576127aa615c37565b1415612805576000808e84815181106127c5576127c561588f565b60200260200101518060200190518101906127e09190615cc4565b985091965092509050846127f45760455494505b612802858383898c8e614277565b50505b5061280f81615980565b90506122bd565b50855160208701511061290d578551602087015160009161283691615830565b9050866060015187604001511061286d576128688760600151886040015161285e9190615830565b828d8d8d8d61391d565b612907565b80156128da57603554604051630d43af8160e21b81526001600160a01b039091169063350ebe04906128a79084908f903390600401615d02565b600060405180830381600087803b1580156128c157600080fd5b505af11580156128d5573d6000803e3d6000fd5b505050505b612907333089604001518a606001516128f39190615830565b6034546001600160a01b03169291906143c7565b50612a99565b6020860151865160009161292091615830565b6035546040516340c10f1960e01b81529192506001600160a01b0316906340c10f1990612953908d908590600401615d21565b600060405180830381600087803b15801561296d57600080fd5b505af1158015612981573d6000803e3d6000fd5b505050508660600151876040015111156129c5576129c08a886060015189604001516129ad9190615830565b6034546001600160a01b03169190614432565b612a97565b6000876040015188606001516129db9190615830565b90508015612a9557885115612a7d57896001600160a01b031663a5d4096b603560009054906101000a90046001600160a01b0316603460009054906101000a90046001600160a01b03163385878f6040518763ffffffff1660e01b8152600401612a4a96959493929190615d3a565b600060405180830381600087803b158015612a6457600080fd5b505af1158015612a78573d6000803e3d6000fd5b505050505b603454612a95906001600160a01b03163330846143c7565b505b505b505060018055509198975050505050505050565b603a8181548110610c9357600080fd5b6001600160a01b039182166000908152604a6020908152604080832093909416825291909152205460011490565b6033546001600160a01b03163314612b165760405163b90cdbb160e01b815260040160405180910390fd5b603380546001600160a01b0319166001600160a01b0383811691909117909155603654604051630787a21360e51b815291169063f0f4426090612b5d908490600401614e36565b600060405180830381600087803b158015612b7757600080fd5b505af1158015610a52573d6000803e3d6000fd5b83421115612bac5760405163f87d927160e01b815260040160405180910390fd5b6fa2a8918ca85bafe22016d0b997e4df60600160ff1b03811180612be357508260ff16601b14158015612be357508260ff16601c14155b15612c0157604051638baa579f60e01b815260040160405180910390fd5b6000612c0b6136d1565b608254898989612c1a8d614451565b6040805160208101969096526001600160a01b03948516908601529290911660608401521515608083015260a082015260c0810187905260e00160405160208183030381529060405280519060200120604051602001612c9192919061190160f01b81526002810192909252602282015260420190565b604051602081830303815290604052805190602001209050612cbb886001600160a01b0316612f93565b15612d9757604080516020810185905280820184905260f886901b6001600160f81b0319166060820152815160418183030181526061820192839052630b135d3f60e11b9092526001600160a01b038a1691631626ba7e91612d21918591606501615d7c565b602060405180830381865afa158015612d3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d629190615d95565b6001600160e01b031916631626ba7e60e01b14612d9257604051638baa579f60e01b815260040160405180910390fd5b612e3f565b6040805160008082526020820180845284905260ff871692820192909252606081018590526080810184905260019060a0016020604051602081039080840390855afa158015612deb573d6000803e3d6000fd5b505050602060405103519050886001600160a01b0316816001600160a01b0316141580612e1f57506001600160a01b038116155b15612e3d57604051638baa579f60e01b815260040160405180910390fd5b505b611c6f888888613a3d565b612e52614d0c565b60408051600080825260208201909252611cb0918791879187918791906114c4565b60335460009081906001600160a01b03163314612ea45760405163b90cdbb160e01b815260040160405180910390fd5b612eac61373d565b505060418054604280546000938490559290559150808210612f4557612ed28183615830565b6035546033546040516340c10f1960e01b8152929450600093506001600160a01b03918216926340c10f1992612f0e9216908690600401615d21565b600060405180830381600087803b158015612f2857600080fd5b505af1158015612f3c573d6000803e3d6000fd5b50505050612f56565b612f4f8282615830565b9050600091505b60408051838152602081018390527ffeb12225c131aab793a00c5239afb778932d170fa28ce6e9d23703e4bd892121910160405180910390a19091565b6001600160a01b03163b151590565b6000908152604760205260409020546001600160a01b0316151590565b6000908152604960205260409020546001600160a01b031690565b6000818152604760205260409020546001600160a01b031680611dc05760405163062a39dd60e11b815260040160405180910390fd5b600081815260496020526040902080546001600160a01b0319166001600160a01b038416908117909155819061304582612fda565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60008061308a83612fda565b9050806001600160a01b0316846001600160a01b031614806130c55750836001600160a01b03166130ba84612fbf565b6001600160a01b0316145b80611cb357506001600160a01b038082166000908152604a6020908152604080832093881683529290522054600114949350505050565b826001600160a01b031661310f82612fda565b6001600160a01b0316146131365760405163c19f17a960e01b815260040160405180910390fd5b6001600160a01b03821661315d5760405163d92e233d60e01b815260040160405180910390fd5b613168600082613010565b6001600160a01b038084166000818152604860209081526040808320805460001901905593861680835284832080546001019055858352604790915283822080546001600160a01b03191682179055925184939291600080516020615eda83398151915291a4505050565b600080603e54426131e49190615830565b603d549091506001600160401b03168115806131fe575080155b1561320d57603f549250505090565b600061321a600184615830565b905060006002841161322d576000613238565b613238600285615830565b90506000676765c793fa10079d601b1b676765c793fa10079d601a1b61325e86806157ca565b613268919061594f565b61327291906157ff565b90506000676765c793fa10079d601b1b676765c793fa10079d601a1b61329887856157ca565b6132a2919061594f565b6132ac91906157ff565b905060006002836132bd878a6157ca565b6132c791906157ca565b6132d191906157ff565b90506000600683866132e3898c6157ca565b6132ed91906157ca565b6132f791906157ca565b61330191906157ff565b9050676765c793fa10079d601b1b818361331b8b8b6157ca565b61333090676765c793fa10079d601b1b61594f565b61333a919061594f565b613344919061594f565b603f5461335191906157ca565b61335b91906157ff565b9850505050505050505090565b613370614d0c565b6000806000613380888787614495565b925092509250633b9aca0083106133aa576040516315fe9b6160e21b815260040160405180910390fd5b6000633b9aca006133bb8582615830565b6133c48a61451e565b6133ce91906157ca565b6133d891906157ff565b603d54909150600160801b90046001600160401b03168110156134085761340381633b9aca00615830565b613429565b603d5461342990600160801b90046001600160401b0316633b9aca00615830565b603d54909150600160401b90046001600160401b03166000806134516002633b9aca00615a7f565b603c5461346791906001600160401b03166157ca565b83613472868a6157ca565b61347c91906157ca565b1061360157603c546001600160401b031661349c6002633b9aca00615a7f565b6134a691906157ca565b603c5485906134c590600160401b90046001600160401b0316866157ca565b6134cf91906157ca565b6134d99190615830565b603c548590633b9aca00906134f7906001600160401b0316896157ca565b603c54613515908b90600160401b90046001600160401b03166157ca565b61351f9190615830565b61352991906157ca565b61353391906157ca565b61353d91906157ff565b60b654909250613551633b9aca00826157ca565b61355b85856157ca565b613565919061594f565b613573633b9aca00896157ca565b116135fb5761358d676765c793fa10079d601b1b856157ca565b633b9aca008b8f602001516135a291906157ca565b6135ac91906157ca565b6135b691906157ff565b6135c190600161594f565b9250808711156135f65783633b9aca006135db838a615830565b6135e591906157ca565b6135ef91906157ff565b91506135fb565b600191505b5061367f565b60385461361290633b9aca006157ca565b8c518b906136219087906157ca565b61362b91906157ca565b61363591906157ff565b61364090600161594f565b915060b55485111561367b57633b9aca008460b554876136609190615830565b61366a91906157ca565b61367491906157ff565b905061367f565b5060015b81885261368c848b6157ca565b60385461369d633b9aca00856157ca565b6136a791906157ca565b6136b191906157ff565b602089015260408801525050606085015250608083015250949350505050565b60808054608154604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f602082015290810192909252606082015246918101919091523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60006137476131d3565b90506000676765c793fa10079d601b1b603f54836137659190615830565b60405461377291906157ca565b61377c91906157ff565b90508060416000828254613790919061594f565b9091555050603f82905542603e8190556040805184815260208101929092527fd1fa8ba00a3bf20274346919dce0de62d2a140af2c71fe7e29fa6472eea3bb9d910160405180910390a15090565b603d54600160c81b900460ff1690565b600081613800576137fd61373d565b91505b60008481526043602052604081206001015490676765c793fa10079d601b1b61382985846157ca565b61383391906157ff565b905080851061384457935080613867565b8361385a676765c793fa10079d601b1b876157ca565b61386491906157ff565b90505b6138718183615830565b915080604060008282546138859190615830565b909155505081158015906138ba5750676765c793fa10079d601b1b60b4546138ad91906157ca565b6138b785846157ca565b11155b156138d85760405163228af07f60e21b815260040160405180910390fd5b60008681526043602052604080822060010184905551600080516020615e9a8339815191529161390b9189918591615967565b60405180910390a15092949350505050565b851561393a5760345461393a906001600160a01b03168488614432565b8415611dfa578051156139b95760345460355460405163a5d4096b60e01b81526001600160a01b038086169363a5d4096b936139869391831692169089908b908d908990600401615d3a565b600060405180830381600087803b1580156139a057600080fd5b505af11580156139b4573d6000803e3d6000fd5b505050505b603554604051630d43af8160e21b81526001600160a01b039091169063350ebe04906139ed90889088903390600401615d02565b600060405180830381600087803b158015613a0757600080fd5b505af1158015613a1b573d6000803e3d6000fd5b50505050505050505050565b603c54600160c01b90046001600160401b031690565b826001600160a01b0316826001600160a01b03161415613a70576040516320c5195360e21b815260040160405180910390fd5b600081613a7e576000613a81565b60015b6001600160a01b038581166000818152604a602090815260408083209489168084529482529182902060ff959095169485905590518615158152939450919290917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a350505050565b60006001600160a01b038216613b1c5760405163d92e233d60e01b815260040160405180910390fd5b5060458054600101908190556001600160a01b038216600081815260486020908152604080832080546001019055848352604790915280822080546001600160a01b031916841790555183929190600080516020615eda833981519152908290a4613b99600083836040518060200160405280600081525061474d565b611dc0576040516320149b4360e21b815260040160405180910390fd5b613bc18484846130fc565b613bcd8484848461474d565b613bea576040516320149b4360e21b815260040160405180910390fd5b50505050565b846001600160a01b0316836001600160a01b03166361d027b36040518163ffffffff1660e01b8152600401602060405180830381865afa158015613c38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c5c9190615872565b6001600160a01b031614613c83576040516302979eb960e31b815260040160405180910390fd5b603380546001600160a01b038088166001600160a01b0319928316179092556034805492871692909116821790556040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa158015613cec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d109190615db2565b613d1b90600a615a7f565b603881905550846001600160a01b031663e9cbd8226040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d839190615872565b603580546001600160a01b03199081166001600160a01b039384161790915560368054909116918516919091179055604051600090613dc6908390602001615dcf565b60408051601f198184030181529190528051909150613dec90607d906020840190614d3b565b50613df681614850565b81604051602001613e079190615e16565b604051602081830303815290604052607e9080519060200190613e2b929190614d3b565b50676765c793fa10079d601b1b603f5542603e55608083015160208401516001600160401b0391821691161180613e725750633b9aca0083608001516001600160401b0316115b80613e8d575082604001516001600160401b0316633b9aca00115b80613ea95750633b9aca008360a001516001600160401b031610155b80613eb6575060e0830151155b15613ed457604051631746545d60e11b815260040160405180910390fd5b8251603955602080840151603c80546040808801516001600160401b039485166001600160801b031993841617600160401b9186168202179093556060880151603d805460808b015160a08c0151938816919095161793861690940292909217600160801b600160c01b031916600160801b92909416919091029290921790558051918201905260e08401518152613f7090603b906001614dbf565b50505050505050565b613f8282612fa2565b613f9f5760405163062a39dd60e11b815260040160405180910390fd5b60008281526043602052604081208054839290613fbd90849061594f565b9091555050604051600080516020615eba833981519152906111809084908490600190615967565b6000803385613ff4828261307e565b6140115760405163c19f17a960e01b815260040160405180910390fd5b600087815260436020908152604080832081518083019092528054825260010154918101919091529080614046838a8a614495565b5091509150633b9aca00821161406f57604051631527804d60e31b815260040160405180910390fd5b8260200151604060008282546140859190615830565b9091555061409490508a614926565b600061409e613a27565b6140b5906001600160401b0316633b9aca00615830565b6140c3633b9aca00846157ca565b6140cd91906157ff565b90506140d98282615830565b604160008282546140ea919061594f565b90915550509251929a92995091975050505050505050565b338461410e828261307e565b61412b5760405163c19f17a960e01b815260040160405180910390fd5b60008681526043602052604081208054879290614149908490615830565b909155505060008681526043602090815260408083208151808301909252805482526001015491810191909152614181908686614495565b50509050633b9aca0081116141a957604051631527804d60e31b815260040160405180910390fd5b600080516020615eba833981519152878760006040516141cb93929190615967565b60405180910390a150505050505050565b600033856141ea828261307e565b6142075760405163c19f17a960e01b815260040160405180910390fd5b614213878787876149a5565b603c54909650600090633b9aca009061423d908990600160801b90046001600160401b03166157ca565b61424791906157ff565b9050806041600082825461425b919061594f565b9091555061426b90508188615830565b98975050505050505050565b3386614283828261307e565b6142a05760405163c19f17a960e01b815260040160405180910390fd5b60408051898152602081018890526001600160a01b038916818301526060810187905290517fddd3b70af631334f7552aadb582ed091018e62e103fa8b150ca66cc700d4dac69181900360800190a16142fb888686866149a5565b94506001600160a01b03871630141561431f576143198686856137ee565b50611c6f565b866001600160a01b031663835986b48787603c60109054906101000a90046001600160401b031661434e613a27565b6040516001600160e01b031960e087901b168152600481019490945260248401929092526001600160401b039081166044840152166064820152608401600060405180830381600087803b1580156143a557600080fd5b505af11580156143b9573d6000803e3d6000fd5b505050505050505050505050565b6040516001600160a01b0380851660248301528316604482015260648101829052613bea9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614b38565b610a198363a9059cbb60e01b84846040516024016143fb929190615d21565b6001600160a01b0381166000908152607f602052604090205461447581600161594f565b6001600160a01b039092166000908152607f602052604090209190915590565b6000806000676765c793fa10079d601b1b8487602001516144b691906157ca565b6144c091906157ff565b91506038548587600001516144d591906157ca565b6144df91906157ff565b9050816144f0576000199250614515565b603c548290614508906001600160401b0316836157ca565b61451291906157ff565b92505b93509350939050565b6037546000906001600160a01b031661455757603b6000815481106145455761454561588f565b90600052602060002001549050919050565b603754604051635dfba04560e11b81526000916001600160a01b03169063bbf7408a90614588908690600401614e36565b602060405180830381865afa1580156145a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145c9919061579b565b9050603a6001815481106145df576145df61588f565b9060005260206000200154811061461757603b6001815481106146045761460461588f565b9060005260206000200154915050919050565b603a60008154811061462b5761462b61588f565b9060005260206000200154811161465057603b6000815481106146045761460461588f565b603a6000815481106146645761466461588f565b9060005260206000200154603a6001815481106146835761468361588f565b90600052602060002001546146989190615830565b603a6000815481106146ac576146ac61588f565b9060005260206000200154826146c29190615830565b603b6000815481106146d6576146d661588f565b9060005260206000200154603b6001815481106146f5576146f561588f565b906000526020600020015461470a9190615830565b61471491906157ca565b61471e91906157ff565b603b6000815481106147325761473261588f565b9060005260206000200154610b04919061594f565b50919050565b6000614761846001600160a01b0316612f93565b1561484857604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290614798903390899088908890600401615e40565b6020604051808303816000875af19250505080156147d3575060408051601f3d908101601f191682019092526147d091810190615d95565b60015b61482e573d808015614801576040519150601f19603f3d011682016040523d82523d6000602084013e614806565b606091505b508051614826576040516320149b4360e21b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611cb3565b506001611cb3565b600054610100900460ff166148bb5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401611515565b7f3f43a9c6bafb5c7aab4e0cfe239dc5d4c15caf0381c6104188191f78a6640bd860825580516020918201206080556040805180820190915260018152603160f81b9101527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6608155565b600061493182612fda565b905061493e600083613010565b6001600160a01b038116600081815260486020908152604080832080546000190190558583526047825280832080546001600160a01b0319169055604390915280822082815560010182905551849290600080516020615eda833981519152908390a45050565b600080826149be676765c793fa10079d601b1b876157ca565b6149c891906157ff565b600087815260436020526040902060010154909150614a035760b4548511614a035760405163228af07f60e21b815260040160405180910390fd5b60008681526043602052604081206001018054839290614a2490849061594f565b925050819055508060406000828254614a3d919061594f565b9091555050603954614a5b90676765c793fa10079d601b1b906157ca565b83604054614a6991906157ca565b1115614a88576040516371239a6160e11b815260040160405180910390fd5b60008681526043602090815260408083208151808301909252805482526001015491810191909152614abb908686614495565b50509050633b9aca008111614ae357604051631527804d60e31b815260040160405180910390fd5b600080516020615e9a83398151915287836001604051614b0593929190615967565b60405180910390a1676765c793fa10079d601b1b614b2385846157ca565b614b2d91906157ff565b979650505050505050565b6000614b8d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614c0a9092919063ffffffff16565b805190915015610a195780806020019051810190614bab9190615813565b610a195760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611515565b6060611cb3848460008585614c1e85612f93565b614c6a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611515565b600080866001600160a01b03168587604051614c869190615e7d565b60006040518083038185875af1925050503d8060008114614cc3576040519150601f19603f3d011682016040523d82523d6000602084013e614cc8565b606091505b5091509150614b2d82828660608315614ce2575081610b04565b825115614cf25782518084602001fd5b8160405162461bcd60e51b81526004016115159190614ed5565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b828054614d4790615766565b90600052602060002090601f016020900481019282614d695760008555614daf565b82601f10614d8257805160ff1916838001178555614daf565b82800160010185558215614daf579182015b82811115614daf578251825591602001919060010190614d94565b50614dbb929150614e21565b5090565b828054828255906000526020600020908101928215614daf5791602002820182811115614daf578251825591602001919060010190614d94565b6040518060800160405280600081526020016000815260200160008152602001600081525090565b5b80821115614dbb5760008155600101614e22565b6001600160a01b0391909116815260200190565b6001600160e01b031981168114610c8057600080fd5b600060208284031215614e7257600080fd5b8135610b0481614e4a565b60005b83811015614e98578181015183820152602001614e80565b83811115613bea5750506000910152565b60008151808452614ec1816020860160208601614e7d565b601f01601f19169290920160200192915050565b602081526000610b046020830184614ea9565b600060208284031215614efa57600080fd5b5035919050565b6001600160a01b0381168114610c8057600080fd5b60008060408385031215614f2957600080fd5b8235614f3481614f01565b946020939093013593505050565b600080600060608486031215614f5757600080fd5b8335614f6281614f01565b92506020840135614f7281614f01565b929592945050506040919091013590565b60008060408385031215614f9657600080fd5b823591506020830135614fa881614f01565b809150509250929050565b60a081016108cc828480518252602081015160208301526040810151604083015260608101516060830152608081015160808301525050565b600060208284031215614ffe57600080fd5b8135610b0481614f01565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561504757615047615009565b604052919050565b600082601f83011261506057600080fd5b81356001600160401b0381111561507957615079615009565b61508c601f8201601f191660200161501f565b8181528460208386010111156150a157600080fd5b816020850160208301376000918101602001919091529392505050565b6000602082840312156150d057600080fd5b81356001600160401b038111156150e657600080fd5b611cb38482850161504f565b80356001600160401b0381168114611dc057600080fd5b6000806040838503121561511c57600080fd5b614f34836150f2565b60006001600160401b0382111561513e5761513e615009565b5060051b60200190565b600082601f83011261515957600080fd5b8135602061516e61516983615125565b61501f565b82815260059290921b8401810191818101908684111561518d57600080fd5b8286015b848110156151a85780358352918301918301615191565b509695505050505050565b6000806000606084860312156151c857600080fd5b83356151d381614f01565b925060208401356001600160401b03808211156151ef57600080fd5b6151fb87838801615148565b9350604086013591508082111561521157600080fd5b5061521e86828701615148565b9150509250925092565b60008060008060008060c0878903121561524157600080fd5b86356001600160401b038082111561525857600080fd5b6152648a838b01615148565b9750602089013591508082111561527a57600080fd5b6152868a838b01615148565b96506040890135915061529882614f01565b9094506060880135906152aa82614f01565b9093506080880135906152bc82614f01565b90925060a088013590808211156152d257600080fd5b506152df89828a0161504f565b9150509295509295509295565b6000806000806080858703121561530257600080fd5b5050823594602084013594506040840135936060013592509050565b600082601f83011261532f57600080fd5b8135602061533f61516983615125565b82815260059290921b8401810191818101908684111561535e57600080fd5b8286015b848110156151a85780356008811061537a5760008081fd5b8352918301918301615362565b600082601f83011261539857600080fd5b813560206153a861516983615125565b82815260059290921b840181019181810190868411156153c757600080fd5b8286015b848110156151a85780356001600160401b038111156153ea5760008081fd5b6153f88986838b010161504f565b8452509183019183016153cb565b6000806000806080858703121561541c57600080fd5b84356001600160401b038082111561543357600080fd5b61543f8883890161531e565b9550602087013591508082111561545557600080fd5b5061546287828801615387565b935050604085013561547381614f01565b9150606085013561548381614f01565b939692955090935050565b8015158114610c8057600080fd5b600080604083850312156154af57600080fd5b82356154ba81614f01565b91506020830135614fa88161548e565b600080600080608085870312156154e057600080fd5b84356154eb81614f01565b935060208501356154fb81614f01565b92506040850135915060608501356001600160401b0381111561551d57600080fd5b6155298782880161504f565b91505092959194509250565b60008060006060848603121561554a57600080fd5b505081359360208301359350604090920135919050565b600080600080600085870361018081121561557b57600080fd5b863561558681614f01565b9550602087013561559681614f01565b945060408701356155a681614f01565b9350610100605f19820112156155bb57600080fd5b506060860191506101608601356001600160401b038111156155dc57600080fd5b6155e88882890161504f565b9150509295509295909350565b60008060008060008060c0878903121561560e57600080fd5b86356001600160401b038082111561562557600080fd5b6156318a838b0161531e565b9750602089013591508082111561564757600080fd5b6152868a838b01615387565b6000806040838503121561566657600080fd5b823561567181614f01565b91506020830135614fa881614f01565b60ff81168114610c8057600080fd5b600080600080600080600060e0888a0312156156ab57600080fd5b87356156b681614f01565b965060208801356156c681614f01565b955060408801356156d68161548e565b94506060880135935060808801356156ed81615681565b9699959850939692959460a0840135945060c09093013592915050565b6000806000806080858703121561572057600080fd5b84356001600160401b038082111561573757600080fd5b61574388838901615148565b9550602087013591508082111561575957600080fd5b5061546287828801615148565b600181811c9082168061577a57607f821691505b6020821081141561474757634e487b7160e01b600052602260045260246000fd5b6000602082840312156157ad57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b60008160001904831182151516156157e4576157e46157b4565b500290565b634e487b7160e01b600052601260045260246000fd5b60008261580e5761580e6157e9565b500490565b60006020828403121561582557600080fd5b8151610b048161548e565b600082821015615842576158426157b4565b500390565b60006001600160401b03828116848216808303821115615869576158696157b4565b01949350505050565b60006020828403121561588457600080fd5b8151610b0481614f01565b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b838110156158d5578151875295820195908201906001016158b9565b509495945050505050565b6040815260006158f360408301856158a5565b82810360208401526120ba81856158a5565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b602081526000610b0460208301846158a5565b60008219821115615962576159626157b4565b500190565b928352602083019190915260ff16604082015260600190565b6000600019821415615994576159946157b4565b5060010190565b600181815b808511156159d65781600019048211156159bc576159bc6157b4565b808516156159c957918102915b93841c93908002906159a0565b509250929050565b6000826159ed575060016108cc565b816159fa575060006108cc565b8160018114615a105760028114615a1a57615a36565b60019150506108cc565b60ff841115615a2b57615a2b6157b4565b50506001821b6108cc565b5060208310610133831016604e8410600b8410161715615a59575081810a6108cc565b615a63838361599b565b8060001904821115615a7757615a776157b4565b029392505050565b6000610b0460ff8416836159de565b600082615a9d57615a9d6157e9565b500690565b60008151615ab4818560208601614e7d565b9290920192915050565b600080845481600182811c915080831680615ada57607f831692505b6020808410821415615afa57634e487b7160e01b86526022600452602486fd5b818015615b0e5760018114615b1f57615b4c565b60ff19861689528489019650615b4c565b60008b81526020902060005b86811015615b445781548b820152908501908301615b2b565b505084890196505b5050505050506120ba8185615aa2565b6000610100808385031215615b7057600080fd5b604051908101906001600160401b0382118183101715615b9257615b92615009565b8160405283358152615ba6602085016150f2565b6020820152615bb7604085016150f2565b6040820152615bc8606085016150f2565b6060820152615bd9608085016150f2565b6080820152615bea60a085016150f2565b60a082015260c08401359150615bff8261548e565b8160c082015260e084013560e0820152809250505092915050565b600060208284031215615c2c57600080fd5b8135610b048161548e565b634e487b7160e01b600052602160045260246000fd5b60008060408385031215615c6057600080fd5b505080516020909101519092909150565b60008060008060008060c08789031215615c8a57600080fd5b8651615c9581614f01565b6020880151604089015160608a015160808b015160a0909b0151939c929b509099909850965090945092505050565b60008060008060808587031215615cda57600080fd5b845193506020850151615cec81614f01565b6040860151606090960151949790965092505050565b9283526001600160a01b03918216602084015216604082015260600190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b038781168252868116602083015285166040820152606081018490526080810183905260c060a0820181905260009061426b90830184614ea9565b828152604060208201526000611cb36040830184614ea9565b600060208284031215615da757600080fd5b8151610b0481614e4a565b600060208284031215615dc457600080fd5b8151610b0481615681565b6e020b733b63290283937ba37b1b7b61608d1b815260008251615df981600f850160208701614e7d565b650815985d5b1d60d21b600f939091019283015250601501919050565b60008251615e28818460208701614e7d565b650b5d985d5b1d60d21b920191825250600601919050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090615e7390830184614ea9565b9695505050505050565b60008251615e8f818460208701614e7d565b919091019291505056fe70cf49afe7355562d5b022e594790f22b71ad8cc7eec902fa5feac7c67f71091722cb71fa87c947148cefc06dd890af5802a6a00207c5ddecf1191bf71ce3cd4ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122078f88412fac305d48d14da508160f0c03b8a2dabd2ce26c193dad112345b201664736f6c634300080c0033" +} \ No newline at end of file diff --git a/deployments/mainnet/VaultManager_USDC_EUR.json b/deployments/mainnet/VaultManager_USDC_EUR.json new file mode 100644 index 00000000..48d577f8 --- /dev/null +++ b/deployments/mainnet/VaultManager_USDC_EUR.json @@ -0,0 +1,247 @@ +{ + "address": "0x96de5c30F2BF4683c7903F3e921F720602F8868A", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_logic", + "type": "address" + }, + { + "internalType": "address", + "name": "admin_", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "admin", + "outputs": [ + { + "internalType": "address", + "name": "admin_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "changeAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "implementation", + "outputs": [ + { + "internalType": "address", + "name": "implementation_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "transactionHash": "0xd4a52e7e67cc4b94ab2d2e7576f17849c698b9c2fc658c3304ce654633364a92", + "receipt": { + "to": null, + "from": "0xfdA462548Ce04282f4B6D6619823a7C64Fdc0185", + "contractAddress": "0x96de5c30F2BF4683c7903F3e921F720602F8868A", + "transactionIndex": 72, + "gasUsed": "1132160", + "logsBloom": "0x00000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000080800000000002000002000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000080000000000000800000000000000400000000000000000400000000000000000000000000000000000000000020000000000000000000040000000000000400000000000000000000000000000000000000000400000000000000000000000000000000000000000000", + "blockHash": "0xda74de13b491b8f24594d59a2fe3a74fb4db6c8062d4225e0acef766f11e7e38", + "transactionHash": "0xd4a52e7e67cc4b94ab2d2e7576f17849c698b9c2fc658c3304ce654633364a92", + "logs": [ + { + "transactionIndex": 72, + "blockNumber": 17228954, + "transactionHash": "0xd4a52e7e67cc4b94ab2d2e7576f17849c698b9c2fc658c3304ce654633364a92", + "address": "0x96de5c30F2BF4683c7903F3e921F720602F8868A", + "topics": [ + "0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b", + "0x0000000000000000000000007e54d1c83fad152b3681b81b7c0be691c6373f77" + ], + "data": "0x", + "logIndex": 139, + "blockHash": "0xda74de13b491b8f24594d59a2fe3a74fb4db6c8062d4225e0acef766f11e7e38" + }, + { + "transactionIndex": 72, + "blockNumber": 17228954, + "transactionHash": "0xd4a52e7e67cc4b94ab2d2e7576f17849c698b9c2fc658c3304ce654633364a92", + "address": "0x96de5c30F2BF4683c7903F3e921F720602F8868A", + "topics": [ + "0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logIndex": 140, + "blockHash": "0xda74de13b491b8f24594d59a2fe3a74fb4db6c8062d4225e0acef766f11e7e38" + }, + { + "transactionIndex": 72, + "blockNumber": 17228954, + "transactionHash": "0xd4a52e7e67cc4b94ab2d2e7576f17849c698b9c2fc658c3304ce654633364a92", + "address": "0x96de5c30F2BF4683c7903F3e921F720602F8868A", + "topics": [ + "0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d941ef0d3bba4ad67dbfbcee5262f4cee53a32b", + "logIndex": 141, + "blockHash": "0xda74de13b491b8f24594d59a2fe3a74fb4db6c8062d4225e0acef766f11e7e38" + } + ], + "blockNumber": 17228954, + "cumulativeGasUsed": "5772624", + "status": 1, + "byzantium": true + }, + "args": [ + "0x7E54d1c83fAD152B3681B81b7c0bE691c6373f77", + "0x1D941EF0D3Bba4ad67DBfBCeE5262F4CEE53A32b", + "0xd9b1cb5b0000000000000000000000008667dbebf68b0bfa6db54f550f41be16c4067d60000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000008c55a4145ca4ff8830f39f74feed9059f1bdce68000000000000000000000000000000000000000000027b46536c66c8e30000000000000000000000000000000000000000000000000000000000000035a4e900000000000000000000000000000000000000000000000000000000003e95ba800000000000000000000000000000000000000000000000000231e02a5754f849000000000000000000000000000000000000000000000000000000003a699d000000000000000000000000000000000000000000000000000000000002faf080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b2d05e0000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000008555344432d455552000000000000000000000000000000000000000000000000" + ], + "numDeployments": 1, + "solcInputHash": "9a2b71309fb0718473c1f135df2b8dfe", + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_logic\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"admin_\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"previousAdmin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"beacon\",\"type\":\"address\"}],\"name\":\"BeaconUpgraded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"admin_\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"changeAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"implementation_\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"upgradeTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"This contract implements a proxy that is upgradeable by an admin. It is fully forked from OpenZeppelin `TransparentUpgradeableProxy` To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector clashing], which can potentially be used in an attack, this contract uses the https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two things that go hand in hand: 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if that call matches one of the admin functions exposed by the proxy itself. 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the implementation. If the admin tries to call a function on the implementation it will fail with an error that says \\\"admin cannot fallback to proxy target\\\". These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due to sudden errors when trying to call a function from the proxy implementation. Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way, you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.\",\"kind\":\"dev\",\"methods\":{\"admin()\":{\"details\":\"Returns the current admin. NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}. TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`\"},\"changeAdmin(address)\":{\"details\":\"Changes the admin of the proxy. Emits an {AdminChanged} event. NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.\"},\"constructor\":{\"details\":\"Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.\"},\"implementation()\":{\"details\":\"Returns the current implementation. NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}. TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`\"},\"upgradeTo(address)\":{\"details\":\"Upgrade the implementation of the proxy. NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.\"},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Upgrade the implementation of the proxy, and then call a function from the new implementation as specified by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the proxied contract. NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/external/TransparentUpgradeableProxy.sol\":\"TransparentUpgradeableProxy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/interfaces/draft-IERC1822.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\\n * proxy whose upgrades are fully controlled by the current implementation.\\n */\\ninterface IERC1822Proxiable {\\n /**\\n * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\\n * address.\\n *\\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\\n * function revert if invoked through a proxy.\\n */\\n function proxiableUUID() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x1d4afe6cb24200cc4545eed814ecf5847277dfe5d613a1707aad5fceecebcfff\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Proxy.sol\\\";\\nimport \\\"./ERC1967Upgrade.sol\\\";\\n\\n/**\\n * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an\\n * implementation address that can be changed. This address is stored in storage in the location specified by\\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the\\n * implementation behind the proxy.\\n */\\ncontract ERC1967Proxy is Proxy, ERC1967Upgrade {\\n /**\\n * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.\\n *\\n * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded\\n * function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n */\\n constructor(address _logic, bytes memory _data) payable {\\n _upgradeToAndCall(_logic, _data, false);\\n }\\n\\n /**\\n * @dev Returns the current implementation address.\\n */\\n function _implementation() internal view virtual override returns (address impl) {\\n return ERC1967Upgrade._getImplementation();\\n }\\n}\\n\",\"keccak256\":\"0xa2b22da3032e50b55f95ec1d13336102d675f341167aa76db571ef7f8bb7975d\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)\\n\\npragma solidity ^0.8.2;\\n\\nimport \\\"../beacon/IBeacon.sol\\\";\\nimport \\\"../../interfaces/draft-IERC1822.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/StorageSlot.sol\\\";\\n\\n/**\\n * @dev This abstract contract provides getters and event emitting update functions for\\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\\n *\\n * _Available since v4.1._\\n *\\n * @custom:oz-upgrades-unsafe-allow delegatecall\\n */\\nabstract contract ERC1967Upgrade {\\n // This is the keccak-256 hash of \\\"eip1967.proxy.rollback\\\" subtracted by 1\\n bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Emitted when the implementation is upgraded.\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @dev Returns the current implementation address.\\n */\\n function _getImplementation() internal view returns (address) {\\n return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new address in the EIP1967 implementation slot.\\n */\\n function _setImplementation(address newImplementation) private {\\n require(Address.isContract(newImplementation), \\\"ERC1967: new implementation is not a contract\\\");\\n StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\\n }\\n\\n /**\\n * @dev Perform implementation upgrade\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeTo(address newImplementation) internal {\\n _setImplementation(newImplementation);\\n emit Upgraded(newImplementation);\\n }\\n\\n /**\\n * @dev Perform implementation upgrade with additional setup call.\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeToAndCall(\\n address newImplementation,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n _upgradeTo(newImplementation);\\n if (data.length > 0 || forceCall) {\\n Address.functionDelegateCall(newImplementation, data);\\n }\\n }\\n\\n /**\\n * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeToAndCallUUPS(\\n address newImplementation,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n // Upgrades from old implementations will perform a rollback test. This test requires the new\\n // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\\n // this special case will break upgrade paths from old UUPS implementation to new ones.\\n if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {\\n _setImplementation(newImplementation);\\n } else {\\n try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\\n require(slot == _IMPLEMENTATION_SLOT, \\\"ERC1967Upgrade: unsupported proxiableUUID\\\");\\n } catch {\\n revert(\\\"ERC1967Upgrade: new implementation is not UUPS\\\");\\n }\\n _upgradeToAndCall(newImplementation, data, forceCall);\\n }\\n }\\n\\n /**\\n * @dev Storage slot with the admin of the contract.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.admin\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\\n\\n /**\\n * @dev Emitted when the admin account has changed.\\n */\\n event AdminChanged(address previousAdmin, address newAdmin);\\n\\n /**\\n * @dev Returns the current admin.\\n */\\n function _getAdmin() internal view returns (address) {\\n return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new address in the EIP1967 admin slot.\\n */\\n function _setAdmin(address newAdmin) private {\\n require(newAdmin != address(0), \\\"ERC1967: new admin is the zero address\\\");\\n StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;\\n }\\n\\n /**\\n * @dev Changes the admin of the proxy.\\n *\\n * Emits an {AdminChanged} event.\\n */\\n function _changeAdmin(address newAdmin) internal {\\n emit AdminChanged(_getAdmin(), newAdmin);\\n _setAdmin(newAdmin);\\n }\\n\\n /**\\n * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\\n * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.\\n */\\n bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\\n\\n /**\\n * @dev Emitted when the beacon is upgraded.\\n */\\n event BeaconUpgraded(address indexed beacon);\\n\\n /**\\n * @dev Returns the current beacon.\\n */\\n function _getBeacon() internal view returns (address) {\\n return StorageSlot.getAddressSlot(_BEACON_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new beacon in the EIP1967 beacon slot.\\n */\\n function _setBeacon(address newBeacon) private {\\n require(Address.isContract(newBeacon), \\\"ERC1967: new beacon is not a contract\\\");\\n require(\\n Address.isContract(IBeacon(newBeacon).implementation()),\\n \\\"ERC1967: beacon implementation is not a contract\\\"\\n );\\n StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;\\n }\\n\\n /**\\n * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does\\n * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).\\n *\\n * Emits a {BeaconUpgraded} event.\\n */\\n function _upgradeBeaconToAndCall(\\n address newBeacon,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n _setBeacon(newBeacon);\\n emit BeaconUpgraded(newBeacon);\\n if (data.length > 0 || forceCall) {\\n Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xabf3f59bc0e5423eae45e459dbe92e7052c6983628d39008590edc852a62f94a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/Proxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM\\n * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to\\n * be specified by overriding the virtual {_implementation} function.\\n *\\n * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a\\n * different contract through the {_delegate} function.\\n *\\n * The success and return data of the delegated call will be returned back to the caller of the proxy.\\n */\\nabstract contract Proxy {\\n /**\\n * @dev Delegates the current call to `implementation`.\\n *\\n * This function does not return to its internal call site, it will return directly to the external caller.\\n */\\n function _delegate(address implementation) internal virtual {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n /**\\n * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function\\n * and {_fallback} should delegate.\\n */\\n function _implementation() internal view virtual returns (address);\\n\\n /**\\n * @dev Delegates the current call to the address returned by `_implementation()`.\\n *\\n * This function does not return to its internal call site, it will return directly to the external caller.\\n */\\n function _fallback() internal virtual {\\n _beforeFallback();\\n _delegate(_implementation());\\n }\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\\n * function in the contract matches the call data.\\n */\\n fallback() external payable virtual {\\n _fallback();\\n }\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data\\n * is empty.\\n */\\n receive() external payable virtual {\\n _fallback();\\n }\\n\\n /**\\n * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`\\n * call, or as part of the Solidity `fallback` or `receive` functions.\\n *\\n * If overridden should call `super._beforeFallback()`.\\n */\\n function _beforeFallback() internal virtual {}\\n}\\n\",\"keccak256\":\"0xc130fe33f1b2132158531a87734153293f6d07bc263ff4ac90e85da9c82c0e27\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/beacon/IBeacon.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\\n */\\ninterface IBeacon {\\n /**\\n * @dev Must return an address that can be used as a delegate call target.\\n *\\n * {BeaconProxy} will check that this address is a contract.\\n */\\n function implementation() external view returns (address);\\n}\\n\",\"keccak256\":\"0xd50a3421ac379ccb1be435fa646d66a65c986b4924f0849839f08692f39dde61\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/StorageSlot.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for reading and writing primitive types to specific storage slots.\\n *\\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\\n * This library helps with reading and writing to such slots without the need for inline assembly.\\n *\\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\\n *\\n * Example usage to set ERC1967 implementation slot:\\n * ```\\n * contract ERC1967 {\\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n *\\n * function _getImplementation() internal view returns (address) {\\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\\n * }\\n *\\n * function _setImplementation(address newImplementation) internal {\\n * require(Address.isContract(newImplementation), \\\"ERC1967: new implementation is not a contract\\\");\\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\\n * }\\n * }\\n * ```\\n *\\n * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._\\n */\\nlibrary StorageSlot {\\n struct AddressSlot {\\n address value;\\n }\\n\\n struct BooleanSlot {\\n bool value;\\n }\\n\\n struct Bytes32Slot {\\n bytes32 value;\\n }\\n\\n struct Uint256Slot {\\n uint256 value;\\n }\\n\\n /**\\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\\n */\\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\\n */\\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\\n */\\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\\n */\\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd5c50c54bf02740ebd122ff06832546cb5fa84486d52695a9ccfd11666e0c81d\",\"license\":\"MIT\"},\"contracts/external/TransparentUpgradeableProxy.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity ^0.8.12;\\n\\nimport \\\"@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol\\\";\\n\\n/**\\n * @dev This contract implements a proxy that is upgradeable by an admin. It is fully forked from OpenZeppelin\\n * `TransparentUpgradeableProxy`\\n *\\n * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector\\n * clashing], which can potentially be used in an attack, this contract uses the\\n * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two\\n * things that go hand in hand:\\n *\\n * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if\\n * that call matches one of the admin functions exposed by the proxy itself.\\n * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the\\n * implementation. If the admin tries to call a function on the implementation it will fail with an error that says\\n * \\\"admin cannot fallback to proxy target\\\".\\n *\\n * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing\\n * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due\\n * to sudden errors when trying to call a function from the proxy implementation.\\n *\\n * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,\\n * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.\\n */\\ncontract TransparentUpgradeableProxy is ERC1967Proxy {\\n /**\\n * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and\\n * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.\\n */\\n constructor(\\n address _logic,\\n address admin_,\\n bytes memory _data\\n ) payable ERC1967Proxy(_logic, _data) {\\n assert(_ADMIN_SLOT == bytes32(uint256(keccak256(\\\"eip1967.proxy.admin\\\")) - 1));\\n _changeAdmin(admin_);\\n }\\n\\n /**\\n * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.\\n */\\n modifier ifAdmin() {\\n if (msg.sender == _getAdmin()) {\\n _;\\n } else {\\n _fallback();\\n }\\n }\\n\\n /**\\n * @dev Returns the current admin.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.\\n *\\n * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the\\n * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.\\n * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`\\n */\\n function admin() external ifAdmin returns (address admin_) {\\n admin_ = _getAdmin();\\n }\\n\\n /**\\n * @dev Returns the current implementation.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.\\n *\\n * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the\\n * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.\\n * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`\\n */\\n function implementation() external ifAdmin returns (address implementation_) {\\n implementation_ = _implementation();\\n }\\n\\n /**\\n * @dev Changes the admin of the proxy.\\n *\\n * Emits an {AdminChanged} event.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.\\n */\\n function changeAdmin(address newAdmin) external virtual ifAdmin {\\n _changeAdmin(newAdmin);\\n }\\n\\n /**\\n * @dev Upgrade the implementation of the proxy.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.\\n */\\n function upgradeTo(address newImplementation) external ifAdmin {\\n _upgradeToAndCall(newImplementation, bytes(\\\"\\\"), false);\\n }\\n\\n /**\\n * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified\\n * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the\\n * proxied contract.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.\\n */\\n function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {\\n _upgradeToAndCall(newImplementation, data, true);\\n }\\n\\n /**\\n * @dev Returns the current admin.\\n */\\n function _admin() internal view virtual returns (address) {\\n return _getAdmin();\\n }\\n\\n /**\\n * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.\\n */\\n function _beforeFallback() internal virtual override {\\n require(msg.sender != _getAdmin(), \\\"TransparentUpgradeableProxy: admin cannot fallback to proxy target\\\");\\n super._beforeFallback();\\n }\\n}\\n\",\"keccak256\":\"0x414cddaeb42e89e2818eab8379a46eb4ae105facec276c336db86b4dd6323e8c\",\"license\":\"GPL-3.0\"}},\"version\":1}", + "bytecode": "0x6080604052604051620010bb380380620010bb8339810160408190526200002691620004d8565b828162000036828260006200009a565b5062000066905060017fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6104620005b8565b6000805160206200107483398151915214620000865762000086620005da565b6200009182620000d7565b50505062000643565b620000a58362000132565b600082511180620000b35750805b15620000d257620000d083836200017460201b6200028c1760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f62000102620001a5565b604080516001600160a01b03928316815291841660208301520160405180910390a16200012f81620001de565b50565b6200013d8162000293565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606200019c8383604051806060016040528060278152602001620010946027913962000347565b90505b92915050565b6000620001cf6000805160206200107483398151915260001b6200042f60201b6200022e1760201c565b546001600160a01b0316919050565b6001600160a01b038116620002495760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b80620002726000805160206200107483398151915260001b6200042f60201b6200022e1760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b620002a9816200043260201b620002b81760201c565b6200030d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840162000240565b80620002727f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b6200042f60201b6200022e1760201c565b60606001600160a01b0384163b620003b15760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b606482015260840162000240565b600080856001600160a01b031685604051620003ce9190620005f0565b600060405180830381855af49150503d80600081146200040b576040519150601f19603f3d011682016040523d82523d6000602084013e62000410565b606091505b5090925090506200042382828662000441565b925050505b9392505050565b90565b6001600160a01b03163b151590565b606083156200045257508162000428565b825115620004635782518084602001fd5b8160405162461bcd60e51b81526004016200024091906200060e565b80516001600160a01b03811681146200049757600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620004cf578181015183820152602001620004b5565b50506000910152565b600080600060608486031215620004ee57600080fd5b620004f9846200047f565b925062000509602085016200047f565b60408501519092506001600160401b03808211156200052757600080fd5b818601915086601f8301126200053c57600080fd5b8151818111156200055157620005516200049c565b604051601f8201601f19908116603f011681019083821181831017156200057c576200057c6200049c565b816040528281528960208487010111156200059657600080fd5b620005a9836020830160208801620004b2565b80955050505050509250925092565b818103818111156200019f57634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052600160045260246000fd5b6000825162000604818460208701620004b2565b9190910192915050565b60208152600082518060208401526200062f816040850160208701620004b2565b601f01601f19169190910160400192915050565b610a2180620006536000396000f3fe60806040526004361061005e5760003560e01c80635c60da1b116100435780635c60da1b146100a85780638f283970146100e6578063f851a440146101065761006d565b80633659cfe6146100755780634f1ef286146100955761006d565b3661006d5761006b61011b565b005b61006b61011b565b34801561008157600080fd5b5061006b610090366004610895565b610135565b61006b6100a33660046108b0565b61017f565b3480156100b457600080fd5b506100bd6101f3565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100f257600080fd5b5061006b610101366004610895565b610231565b34801561011257600080fd5b506100bd61025e565b6101236102d4565b61013361012e6103ab565b6103b5565b565b61013d6103d9565b73ffffffffffffffffffffffffffffffffffffffff1633036101775761017481604051806020016040528060008152506000610419565b50565b61017461011b565b6101876103d9565b73ffffffffffffffffffffffffffffffffffffffff1633036101eb576101e68383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610419915050565b505050565b6101e661011b565b60006101fd6103d9565b73ffffffffffffffffffffffffffffffffffffffff163303610226576102216103ab565b905090565b61022e61011b565b90565b6102396103d9565b73ffffffffffffffffffffffffffffffffffffffff1633036101775761017481610444565b60006102686103d9565b73ffffffffffffffffffffffffffffffffffffffff163303610226576102216103d9565b60606102b183836040518060600160405280602781526020016109c5602791396104a5565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b6102dc6103d9565b73ffffffffffffffffffffffffffffffffffffffff163303610133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f7879207461726760648201527f6574000000000000000000000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b60006102216105cd565b3660008037600080366000845af43d6000803e8080156103d4573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b5473ffffffffffffffffffffffffffffffffffffffff16919050565b610422836105f5565b60008251118061042f5750805b156101e65761043e838361028c565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f61046d6103d9565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301520160405180910390a161017481610642565b606073ffffffffffffffffffffffffffffffffffffffff84163b61054b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e7472616374000000000000000000000000000000000000000000000000000060648201526084016103a2565b6000808573ffffffffffffffffffffffffffffffffffffffff16856040516105739190610957565b600060405180830381855af49150503d80600081146105ae576040519150601f19603f3d011682016040523d82523d6000602084013e6105b3565b606091505b50915091506105c382828661074e565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6103fd565b6105fe816107a1565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b73ffffffffffffffffffffffffffffffffffffffff81166106e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016103a2565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905550565b6060831561075d5750816102b1565b82511561076d5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103a29190610973565b73ffffffffffffffffffffffffffffffffffffffff81163b610845576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e74726163740000000000000000000000000000000000000060648201526084016103a2565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610708565b803573ffffffffffffffffffffffffffffffffffffffff8116811461089057600080fd5b919050565b6000602082840312156108a757600080fd5b6102b18261086c565b6000806000604084860312156108c557600080fd5b6108ce8461086c565b9250602084013567ffffffffffffffff808211156108eb57600080fd5b818601915086601f8301126108ff57600080fd5b81358181111561090e57600080fd5b87602082850101111561092057600080fd5b6020830194508093505050509250925092565b60005b8381101561094e578181015183820152602001610936565b50506000910152565b60008251610969818460208701610933565b9190910192915050565b6020815260008251806020840152610992816040850160208701610933565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212204b89b602dcd071e417000a9fd49a86b76809b9cfc16255d1014d4aa275fbf81264736f6c63430008110033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564", + "deployedBytecode": "0x60806040526004361061005e5760003560e01c80635c60da1b116100435780635c60da1b146100a85780638f283970146100e6578063f851a440146101065761006d565b80633659cfe6146100755780634f1ef286146100955761006d565b3661006d5761006b61011b565b005b61006b61011b565b34801561008157600080fd5b5061006b610090366004610895565b610135565b61006b6100a33660046108b0565b61017f565b3480156100b457600080fd5b506100bd6101f3565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100f257600080fd5b5061006b610101366004610895565b610231565b34801561011257600080fd5b506100bd61025e565b6101236102d4565b61013361012e6103ab565b6103b5565b565b61013d6103d9565b73ffffffffffffffffffffffffffffffffffffffff1633036101775761017481604051806020016040528060008152506000610419565b50565b61017461011b565b6101876103d9565b73ffffffffffffffffffffffffffffffffffffffff1633036101eb576101e68383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610419915050565b505050565b6101e661011b565b60006101fd6103d9565b73ffffffffffffffffffffffffffffffffffffffff163303610226576102216103ab565b905090565b61022e61011b565b90565b6102396103d9565b73ffffffffffffffffffffffffffffffffffffffff1633036101775761017481610444565b60006102686103d9565b73ffffffffffffffffffffffffffffffffffffffff163303610226576102216103d9565b60606102b183836040518060600160405280602781526020016109c5602791396104a5565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b6102dc6103d9565b73ffffffffffffffffffffffffffffffffffffffff163303610133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f7879207461726760648201527f6574000000000000000000000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b60006102216105cd565b3660008037600080366000845af43d6000803e8080156103d4573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b5473ffffffffffffffffffffffffffffffffffffffff16919050565b610422836105f5565b60008251118061042f5750805b156101e65761043e838361028c565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f61046d6103d9565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301520160405180910390a161017481610642565b606073ffffffffffffffffffffffffffffffffffffffff84163b61054b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e7472616374000000000000000000000000000000000000000000000000000060648201526084016103a2565b6000808573ffffffffffffffffffffffffffffffffffffffff16856040516105739190610957565b600060405180830381855af49150503d80600081146105ae576040519150601f19603f3d011682016040523d82523d6000602084013e6105b3565b606091505b50915091506105c382828661074e565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6103fd565b6105fe816107a1565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b73ffffffffffffffffffffffffffffffffffffffff81166106e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016103a2565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905550565b6060831561075d5750816102b1565b82511561076d5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103a29190610973565b73ffffffffffffffffffffffffffffffffffffffff81163b610845576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e74726163740000000000000000000000000000000000000060648201526084016103a2565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610708565b803573ffffffffffffffffffffffffffffffffffffffff8116811461089057600080fd5b919050565b6000602082840312156108a757600080fd5b6102b18261086c565b6000806000604084860312156108c557600080fd5b6108ce8461086c565b9250602084013567ffffffffffffffff808211156108eb57600080fd5b818601915086601f8301126108ff57600080fd5b81358181111561090e57600080fd5b87602082850101111561092057600080fd5b6020830194508093505050509250925092565b60005b8381101561094e578181015183820152602001610936565b50506000910152565b60008251610969818460208701610933565b9190910192915050565b6020815260008251806020840152610992816040850160208701610933565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212204b89b602dcd071e417000a9fd49a86b76809b9cfc16255d1014d4aa275fbf81264736f6c63430008110033", + "devdoc": { + "details": "This contract implements a proxy that is upgradeable by an admin. It is fully forked from OpenZeppelin `TransparentUpgradeableProxy` To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector clashing], which can potentially be used in an attack, this contract uses the https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two things that go hand in hand: 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if that call matches one of the admin functions exposed by the proxy itself. 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the implementation. If the admin tries to call a function on the implementation it will fail with an error that says \"admin cannot fallback to proxy target\". These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due to sudden errors when trying to call a function from the proxy implementation. Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way, you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.", + "kind": "dev", + "methods": { + "admin()": { + "details": "Returns the current admin. NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}. TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`" + }, + "changeAdmin(address)": { + "details": "Changes the admin of the proxy. Emits an {AdminChanged} event. NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}." + }, + "constructor": { + "details": "Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}." + }, + "implementation()": { + "details": "Returns the current implementation. NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}. TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`" + }, + "upgradeTo(address)": { + "details": "Upgrade the implementation of the proxy. NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}." + }, + "upgradeToAndCall(address,bytes)": { + "details": "Upgrade the implementation of the proxy, and then call a function from the new implementation as specified by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the proxied contract. NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} \ No newline at end of file diff --git a/deployments/mainnet/VaultManager_bIB01_EUR.json b/deployments/mainnet/VaultManager_bIB01_EUR.json new file mode 100644 index 00000000..3e0aca3b --- /dev/null +++ b/deployments/mainnet/VaultManager_bIB01_EUR.json @@ -0,0 +1,247 @@ +{ + "address": "0x913E8e1eD659C27613E937a6B6119b91D985094c", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_logic", + "type": "address" + }, + { + "internalType": "address", + "name": "admin_", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "admin", + "outputs": [ + { + "internalType": "address", + "name": "admin_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "changeAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "implementation", + "outputs": [ + { + "internalType": "address", + "name": "implementation_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "transactionHash": "0x463a9c6106f2862388bb20a39ed089a677eb76fa4421ca76d8574f578041e063", + "receipt": { + "to": null, + "from": "0xfdA462548Ce04282f4B6D6619823a7C64Fdc0185", + "contractAddress": "0x913E8e1eD659C27613E937a6B6119b91D985094c", + "transactionIndex": 69, + "gasUsed": "1128464", + "logsBloom": "0x00000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000040000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000080000000000000800000000000000001000000000000000400000000000000000000000000200000081000000020000000000000000000040000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x67d55ff828b6a1220e5168c33107f6bff5f33d7bf9c447e8d96a70e9537eec30", + "transactionHash": "0x463a9c6106f2862388bb20a39ed089a677eb76fa4421ca76d8574f578041e063", + "logs": [ + { + "transactionIndex": 69, + "blockNumber": 17229137, + "transactionHash": "0x463a9c6106f2862388bb20a39ed089a677eb76fa4421ca76d8574f578041e063", + "address": "0x913E8e1eD659C27613E937a6B6119b91D985094c", + "topics": [ + "0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b", + "0x00000000000000000000000088fe06d438f5264da8e2cdcac3daed1ea70f995a" + ], + "data": "0x", + "logIndex": 167, + "blockHash": "0x67d55ff828b6a1220e5168c33107f6bff5f33d7bf9c447e8d96a70e9537eec30" + }, + { + "transactionIndex": 69, + "blockNumber": 17229137, + "transactionHash": "0x463a9c6106f2862388bb20a39ed089a677eb76fa4421ca76d8574f578041e063", + "address": "0x913E8e1eD659C27613E937a6B6119b91D985094c", + "topics": [ + "0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logIndex": 168, + "blockHash": "0x67d55ff828b6a1220e5168c33107f6bff5f33d7bf9c447e8d96a70e9537eec30" + }, + { + "transactionIndex": 69, + "blockNumber": 17229137, + "transactionHash": "0x463a9c6106f2862388bb20a39ed089a677eb76fa4421ca76d8574f578041e063", + "address": "0x913E8e1eD659C27613E937a6B6119b91D985094c", + "topics": [ + "0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d941ef0d3bba4ad67dbfbcee5262f4cee53a32b", + "logIndex": 169, + "blockHash": "0x67d55ff828b6a1220e5168c33107f6bff5f33d7bf9c447e8d96a70e9537eec30" + } + ], + "blockNumber": 17229137, + "cumulativeGasUsed": "6510931", + "status": 1, + "byzantium": true + }, + "args": [ + "0x88fE06D438F5264dA8e2CDCAc3DAED1eA70F995a", + "0x1D941EF0D3Bba4ad67DBfBCeE5262F4CEE53A32b", + "0xd9b1cb5b0000000000000000000000008667dbebf68b0bfa6db54f550f41be16c4067d60000000000000000000000000ca30c93b02514f86d5c86a6e375e3a330b435fb5000000000000000000000000598342fcedb4325b16ae9618e433710070195019000000000000000000000000000000000000000000002a5a058fc295ed000000000000000000000000000000000000000000000000000000000000002faf0800000000000000000000000000000000000000000000000000000000004190ab0000000000000000000000000000000000000000000000000008b6e19be539497c00000000000000000000000000000000000000000000000000000000393870000000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000002540be400000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000056249423031000000000000000000000000000000000000000000000000000000" + ], + "numDeployments": 1, + "solcInputHash": "9a2b71309fb0718473c1f135df2b8dfe", + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_logic\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"admin_\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"previousAdmin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"beacon\",\"type\":\"address\"}],\"name\":\"BeaconUpgraded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"admin_\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"changeAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"implementation_\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"upgradeTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"This contract implements a proxy that is upgradeable by an admin. It is fully forked from OpenZeppelin `TransparentUpgradeableProxy` To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector clashing], which can potentially be used in an attack, this contract uses the https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two things that go hand in hand: 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if that call matches one of the admin functions exposed by the proxy itself. 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the implementation. If the admin tries to call a function on the implementation it will fail with an error that says \\\"admin cannot fallback to proxy target\\\". These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due to sudden errors when trying to call a function from the proxy implementation. Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way, you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.\",\"kind\":\"dev\",\"methods\":{\"admin()\":{\"details\":\"Returns the current admin. NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}. TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`\"},\"changeAdmin(address)\":{\"details\":\"Changes the admin of the proxy. Emits an {AdminChanged} event. NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.\"},\"constructor\":{\"details\":\"Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.\"},\"implementation()\":{\"details\":\"Returns the current implementation. NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}. TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`\"},\"upgradeTo(address)\":{\"details\":\"Upgrade the implementation of the proxy. NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.\"},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Upgrade the implementation of the proxy, and then call a function from the new implementation as specified by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the proxied contract. NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/external/TransparentUpgradeableProxy.sol\":\"TransparentUpgradeableProxy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/interfaces/draft-IERC1822.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\\n * proxy whose upgrades are fully controlled by the current implementation.\\n */\\ninterface IERC1822Proxiable {\\n /**\\n * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\\n * address.\\n *\\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\\n * function revert if invoked through a proxy.\\n */\\n function proxiableUUID() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x1d4afe6cb24200cc4545eed814ecf5847277dfe5d613a1707aad5fceecebcfff\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Proxy.sol\\\";\\nimport \\\"./ERC1967Upgrade.sol\\\";\\n\\n/**\\n * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an\\n * implementation address that can be changed. This address is stored in storage in the location specified by\\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the\\n * implementation behind the proxy.\\n */\\ncontract ERC1967Proxy is Proxy, ERC1967Upgrade {\\n /**\\n * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.\\n *\\n * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded\\n * function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n */\\n constructor(address _logic, bytes memory _data) payable {\\n _upgradeToAndCall(_logic, _data, false);\\n }\\n\\n /**\\n * @dev Returns the current implementation address.\\n */\\n function _implementation() internal view virtual override returns (address impl) {\\n return ERC1967Upgrade._getImplementation();\\n }\\n}\\n\",\"keccak256\":\"0xa2b22da3032e50b55f95ec1d13336102d675f341167aa76db571ef7f8bb7975d\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)\\n\\npragma solidity ^0.8.2;\\n\\nimport \\\"../beacon/IBeacon.sol\\\";\\nimport \\\"../../interfaces/draft-IERC1822.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/StorageSlot.sol\\\";\\n\\n/**\\n * @dev This abstract contract provides getters and event emitting update functions for\\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\\n *\\n * _Available since v4.1._\\n *\\n * @custom:oz-upgrades-unsafe-allow delegatecall\\n */\\nabstract contract ERC1967Upgrade {\\n // This is the keccak-256 hash of \\\"eip1967.proxy.rollback\\\" subtracted by 1\\n bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Emitted when the implementation is upgraded.\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @dev Returns the current implementation address.\\n */\\n function _getImplementation() internal view returns (address) {\\n return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new address in the EIP1967 implementation slot.\\n */\\n function _setImplementation(address newImplementation) private {\\n require(Address.isContract(newImplementation), \\\"ERC1967: new implementation is not a contract\\\");\\n StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\\n }\\n\\n /**\\n * @dev Perform implementation upgrade\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeTo(address newImplementation) internal {\\n _setImplementation(newImplementation);\\n emit Upgraded(newImplementation);\\n }\\n\\n /**\\n * @dev Perform implementation upgrade with additional setup call.\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeToAndCall(\\n address newImplementation,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n _upgradeTo(newImplementation);\\n if (data.length > 0 || forceCall) {\\n Address.functionDelegateCall(newImplementation, data);\\n }\\n }\\n\\n /**\\n * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeToAndCallUUPS(\\n address newImplementation,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n // Upgrades from old implementations will perform a rollback test. This test requires the new\\n // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\\n // this special case will break upgrade paths from old UUPS implementation to new ones.\\n if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {\\n _setImplementation(newImplementation);\\n } else {\\n try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\\n require(slot == _IMPLEMENTATION_SLOT, \\\"ERC1967Upgrade: unsupported proxiableUUID\\\");\\n } catch {\\n revert(\\\"ERC1967Upgrade: new implementation is not UUPS\\\");\\n }\\n _upgradeToAndCall(newImplementation, data, forceCall);\\n }\\n }\\n\\n /**\\n * @dev Storage slot with the admin of the contract.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.admin\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\\n\\n /**\\n * @dev Emitted when the admin account has changed.\\n */\\n event AdminChanged(address previousAdmin, address newAdmin);\\n\\n /**\\n * @dev Returns the current admin.\\n */\\n function _getAdmin() internal view returns (address) {\\n return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new address in the EIP1967 admin slot.\\n */\\n function _setAdmin(address newAdmin) private {\\n require(newAdmin != address(0), \\\"ERC1967: new admin is the zero address\\\");\\n StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;\\n }\\n\\n /**\\n * @dev Changes the admin of the proxy.\\n *\\n * Emits an {AdminChanged} event.\\n */\\n function _changeAdmin(address newAdmin) internal {\\n emit AdminChanged(_getAdmin(), newAdmin);\\n _setAdmin(newAdmin);\\n }\\n\\n /**\\n * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\\n * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.\\n */\\n bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\\n\\n /**\\n * @dev Emitted when the beacon is upgraded.\\n */\\n event BeaconUpgraded(address indexed beacon);\\n\\n /**\\n * @dev Returns the current beacon.\\n */\\n function _getBeacon() internal view returns (address) {\\n return StorageSlot.getAddressSlot(_BEACON_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new beacon in the EIP1967 beacon slot.\\n */\\n function _setBeacon(address newBeacon) private {\\n require(Address.isContract(newBeacon), \\\"ERC1967: new beacon is not a contract\\\");\\n require(\\n Address.isContract(IBeacon(newBeacon).implementation()),\\n \\\"ERC1967: beacon implementation is not a contract\\\"\\n );\\n StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;\\n }\\n\\n /**\\n * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does\\n * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).\\n *\\n * Emits a {BeaconUpgraded} event.\\n */\\n function _upgradeBeaconToAndCall(\\n address newBeacon,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n _setBeacon(newBeacon);\\n emit BeaconUpgraded(newBeacon);\\n if (data.length > 0 || forceCall) {\\n Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xabf3f59bc0e5423eae45e459dbe92e7052c6983628d39008590edc852a62f94a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/Proxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM\\n * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to\\n * be specified by overriding the virtual {_implementation} function.\\n *\\n * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a\\n * different contract through the {_delegate} function.\\n *\\n * The success and return data of the delegated call will be returned back to the caller of the proxy.\\n */\\nabstract contract Proxy {\\n /**\\n * @dev Delegates the current call to `implementation`.\\n *\\n * This function does not return to its internal call site, it will return directly to the external caller.\\n */\\n function _delegate(address implementation) internal virtual {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n /**\\n * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function\\n * and {_fallback} should delegate.\\n */\\n function _implementation() internal view virtual returns (address);\\n\\n /**\\n * @dev Delegates the current call to the address returned by `_implementation()`.\\n *\\n * This function does not return to its internal call site, it will return directly to the external caller.\\n */\\n function _fallback() internal virtual {\\n _beforeFallback();\\n _delegate(_implementation());\\n }\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\\n * function in the contract matches the call data.\\n */\\n fallback() external payable virtual {\\n _fallback();\\n }\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data\\n * is empty.\\n */\\n receive() external payable virtual {\\n _fallback();\\n }\\n\\n /**\\n * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`\\n * call, or as part of the Solidity `fallback` or `receive` functions.\\n *\\n * If overridden should call `super._beforeFallback()`.\\n */\\n function _beforeFallback() internal virtual {}\\n}\\n\",\"keccak256\":\"0xc130fe33f1b2132158531a87734153293f6d07bc263ff4ac90e85da9c82c0e27\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/beacon/IBeacon.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\\n */\\ninterface IBeacon {\\n /**\\n * @dev Must return an address that can be used as a delegate call target.\\n *\\n * {BeaconProxy} will check that this address is a contract.\\n */\\n function implementation() external view returns (address);\\n}\\n\",\"keccak256\":\"0xd50a3421ac379ccb1be435fa646d66a65c986b4924f0849839f08692f39dde61\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/StorageSlot.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for reading and writing primitive types to specific storage slots.\\n *\\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\\n * This library helps with reading and writing to such slots without the need for inline assembly.\\n *\\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\\n *\\n * Example usage to set ERC1967 implementation slot:\\n * ```\\n * contract ERC1967 {\\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n *\\n * function _getImplementation() internal view returns (address) {\\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\\n * }\\n *\\n * function _setImplementation(address newImplementation) internal {\\n * require(Address.isContract(newImplementation), \\\"ERC1967: new implementation is not a contract\\\");\\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\\n * }\\n * }\\n * ```\\n *\\n * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._\\n */\\nlibrary StorageSlot {\\n struct AddressSlot {\\n address value;\\n }\\n\\n struct BooleanSlot {\\n bool value;\\n }\\n\\n struct Bytes32Slot {\\n bytes32 value;\\n }\\n\\n struct Uint256Slot {\\n uint256 value;\\n }\\n\\n /**\\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\\n */\\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\\n */\\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\\n */\\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\\n */\\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd5c50c54bf02740ebd122ff06832546cb5fa84486d52695a9ccfd11666e0c81d\",\"license\":\"MIT\"},\"contracts/external/TransparentUpgradeableProxy.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity ^0.8.12;\\n\\nimport \\\"@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol\\\";\\n\\n/**\\n * @dev This contract implements a proxy that is upgradeable by an admin. It is fully forked from OpenZeppelin\\n * `TransparentUpgradeableProxy`\\n *\\n * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector\\n * clashing], which can potentially be used in an attack, this contract uses the\\n * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two\\n * things that go hand in hand:\\n *\\n * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if\\n * that call matches one of the admin functions exposed by the proxy itself.\\n * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the\\n * implementation. If the admin tries to call a function on the implementation it will fail with an error that says\\n * \\\"admin cannot fallback to proxy target\\\".\\n *\\n * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing\\n * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due\\n * to sudden errors when trying to call a function from the proxy implementation.\\n *\\n * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,\\n * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.\\n */\\ncontract TransparentUpgradeableProxy is ERC1967Proxy {\\n /**\\n * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and\\n * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.\\n */\\n constructor(\\n address _logic,\\n address admin_,\\n bytes memory _data\\n ) payable ERC1967Proxy(_logic, _data) {\\n assert(_ADMIN_SLOT == bytes32(uint256(keccak256(\\\"eip1967.proxy.admin\\\")) - 1));\\n _changeAdmin(admin_);\\n }\\n\\n /**\\n * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.\\n */\\n modifier ifAdmin() {\\n if (msg.sender == _getAdmin()) {\\n _;\\n } else {\\n _fallback();\\n }\\n }\\n\\n /**\\n * @dev Returns the current admin.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.\\n *\\n * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the\\n * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.\\n * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`\\n */\\n function admin() external ifAdmin returns (address admin_) {\\n admin_ = _getAdmin();\\n }\\n\\n /**\\n * @dev Returns the current implementation.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.\\n *\\n * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the\\n * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.\\n * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`\\n */\\n function implementation() external ifAdmin returns (address implementation_) {\\n implementation_ = _implementation();\\n }\\n\\n /**\\n * @dev Changes the admin of the proxy.\\n *\\n * Emits an {AdminChanged} event.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.\\n */\\n function changeAdmin(address newAdmin) external virtual ifAdmin {\\n _changeAdmin(newAdmin);\\n }\\n\\n /**\\n * @dev Upgrade the implementation of the proxy.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.\\n */\\n function upgradeTo(address newImplementation) external ifAdmin {\\n _upgradeToAndCall(newImplementation, bytes(\\\"\\\"), false);\\n }\\n\\n /**\\n * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified\\n * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the\\n * proxied contract.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.\\n */\\n function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {\\n _upgradeToAndCall(newImplementation, data, true);\\n }\\n\\n /**\\n * @dev Returns the current admin.\\n */\\n function _admin() internal view virtual returns (address) {\\n return _getAdmin();\\n }\\n\\n /**\\n * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.\\n */\\n function _beforeFallback() internal virtual override {\\n require(msg.sender != _getAdmin(), \\\"TransparentUpgradeableProxy: admin cannot fallback to proxy target\\\");\\n super._beforeFallback();\\n }\\n}\\n\",\"keccak256\":\"0x414cddaeb42e89e2818eab8379a46eb4ae105facec276c336db86b4dd6323e8c\",\"license\":\"GPL-3.0\"}},\"version\":1}", + "bytecode": "0x6080604052604051620010bb380380620010bb8339810160408190526200002691620004d8565b828162000036828260006200009a565b5062000066905060017fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6104620005b8565b6000805160206200107483398151915214620000865762000086620005da565b6200009182620000d7565b50505062000643565b620000a58362000132565b600082511180620000b35750805b15620000d257620000d083836200017460201b6200028c1760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f62000102620001a5565b604080516001600160a01b03928316815291841660208301520160405180910390a16200012f81620001de565b50565b6200013d8162000293565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606200019c8383604051806060016040528060278152602001620010946027913962000347565b90505b92915050565b6000620001cf6000805160206200107483398151915260001b6200042f60201b6200022e1760201c565b546001600160a01b0316919050565b6001600160a01b038116620002495760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b80620002726000805160206200107483398151915260001b6200042f60201b6200022e1760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b620002a9816200043260201b620002b81760201c565b6200030d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840162000240565b80620002727f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b6200042f60201b6200022e1760201c565b60606001600160a01b0384163b620003b15760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b606482015260840162000240565b600080856001600160a01b031685604051620003ce9190620005f0565b600060405180830381855af49150503d80600081146200040b576040519150601f19603f3d011682016040523d82523d6000602084013e62000410565b606091505b5090925090506200042382828662000441565b925050505b9392505050565b90565b6001600160a01b03163b151590565b606083156200045257508162000428565b825115620004635782518084602001fd5b8160405162461bcd60e51b81526004016200024091906200060e565b80516001600160a01b03811681146200049757600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620004cf578181015183820152602001620004b5565b50506000910152565b600080600060608486031215620004ee57600080fd5b620004f9846200047f565b925062000509602085016200047f565b60408501519092506001600160401b03808211156200052757600080fd5b818601915086601f8301126200053c57600080fd5b8151818111156200055157620005516200049c565b604051601f8201601f19908116603f011681019083821181831017156200057c576200057c6200049c565b816040528281528960208487010111156200059657600080fd5b620005a9836020830160208801620004b2565b80955050505050509250925092565b818103818111156200019f57634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052600160045260246000fd5b6000825162000604818460208701620004b2565b9190910192915050565b60208152600082518060208401526200062f816040850160208701620004b2565b601f01601f19169190910160400192915050565b610a2180620006536000396000f3fe60806040526004361061005e5760003560e01c80635c60da1b116100435780635c60da1b146100a85780638f283970146100e6578063f851a440146101065761006d565b80633659cfe6146100755780634f1ef286146100955761006d565b3661006d5761006b61011b565b005b61006b61011b565b34801561008157600080fd5b5061006b610090366004610895565b610135565b61006b6100a33660046108b0565b61017f565b3480156100b457600080fd5b506100bd6101f3565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100f257600080fd5b5061006b610101366004610895565b610231565b34801561011257600080fd5b506100bd61025e565b6101236102d4565b61013361012e6103ab565b6103b5565b565b61013d6103d9565b73ffffffffffffffffffffffffffffffffffffffff1633036101775761017481604051806020016040528060008152506000610419565b50565b61017461011b565b6101876103d9565b73ffffffffffffffffffffffffffffffffffffffff1633036101eb576101e68383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610419915050565b505050565b6101e661011b565b60006101fd6103d9565b73ffffffffffffffffffffffffffffffffffffffff163303610226576102216103ab565b905090565b61022e61011b565b90565b6102396103d9565b73ffffffffffffffffffffffffffffffffffffffff1633036101775761017481610444565b60006102686103d9565b73ffffffffffffffffffffffffffffffffffffffff163303610226576102216103d9565b60606102b183836040518060600160405280602781526020016109c5602791396104a5565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b6102dc6103d9565b73ffffffffffffffffffffffffffffffffffffffff163303610133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f7879207461726760648201527f6574000000000000000000000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b60006102216105cd565b3660008037600080366000845af43d6000803e8080156103d4573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b5473ffffffffffffffffffffffffffffffffffffffff16919050565b610422836105f5565b60008251118061042f5750805b156101e65761043e838361028c565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f61046d6103d9565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301520160405180910390a161017481610642565b606073ffffffffffffffffffffffffffffffffffffffff84163b61054b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e7472616374000000000000000000000000000000000000000000000000000060648201526084016103a2565b6000808573ffffffffffffffffffffffffffffffffffffffff16856040516105739190610957565b600060405180830381855af49150503d80600081146105ae576040519150601f19603f3d011682016040523d82523d6000602084013e6105b3565b606091505b50915091506105c382828661074e565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6103fd565b6105fe816107a1565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b73ffffffffffffffffffffffffffffffffffffffff81166106e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016103a2565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905550565b6060831561075d5750816102b1565b82511561076d5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103a29190610973565b73ffffffffffffffffffffffffffffffffffffffff81163b610845576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e74726163740000000000000000000000000000000000000060648201526084016103a2565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610708565b803573ffffffffffffffffffffffffffffffffffffffff8116811461089057600080fd5b919050565b6000602082840312156108a757600080fd5b6102b18261086c565b6000806000604084860312156108c557600080fd5b6108ce8461086c565b9250602084013567ffffffffffffffff808211156108eb57600080fd5b818601915086601f8301126108ff57600080fd5b81358181111561090e57600080fd5b87602082850101111561092057600080fd5b6020830194508093505050509250925092565b60005b8381101561094e578181015183820152602001610936565b50506000910152565b60008251610969818460208701610933565b9190910192915050565b6020815260008251806020840152610992816040850160208701610933565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212204b89b602dcd071e417000a9fd49a86b76809b9cfc16255d1014d4aa275fbf81264736f6c63430008110033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564", + "deployedBytecode": "0x60806040526004361061005e5760003560e01c80635c60da1b116100435780635c60da1b146100a85780638f283970146100e6578063f851a440146101065761006d565b80633659cfe6146100755780634f1ef286146100955761006d565b3661006d5761006b61011b565b005b61006b61011b565b34801561008157600080fd5b5061006b610090366004610895565b610135565b61006b6100a33660046108b0565b61017f565b3480156100b457600080fd5b506100bd6101f3565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100f257600080fd5b5061006b610101366004610895565b610231565b34801561011257600080fd5b506100bd61025e565b6101236102d4565b61013361012e6103ab565b6103b5565b565b61013d6103d9565b73ffffffffffffffffffffffffffffffffffffffff1633036101775761017481604051806020016040528060008152506000610419565b50565b61017461011b565b6101876103d9565b73ffffffffffffffffffffffffffffffffffffffff1633036101eb576101e68383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610419915050565b505050565b6101e661011b565b60006101fd6103d9565b73ffffffffffffffffffffffffffffffffffffffff163303610226576102216103ab565b905090565b61022e61011b565b90565b6102396103d9565b73ffffffffffffffffffffffffffffffffffffffff1633036101775761017481610444565b60006102686103d9565b73ffffffffffffffffffffffffffffffffffffffff163303610226576102216103d9565b60606102b183836040518060600160405280602781526020016109c5602791396104a5565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b6102dc6103d9565b73ffffffffffffffffffffffffffffffffffffffff163303610133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f7879207461726760648201527f6574000000000000000000000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b60006102216105cd565b3660008037600080366000845af43d6000803e8080156103d4573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b5473ffffffffffffffffffffffffffffffffffffffff16919050565b610422836105f5565b60008251118061042f5750805b156101e65761043e838361028c565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f61046d6103d9565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301520160405180910390a161017481610642565b606073ffffffffffffffffffffffffffffffffffffffff84163b61054b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e7472616374000000000000000000000000000000000000000000000000000060648201526084016103a2565b6000808573ffffffffffffffffffffffffffffffffffffffff16856040516105739190610957565b600060405180830381855af49150503d80600081146105ae576040519150601f19603f3d011682016040523d82523d6000602084013e6105b3565b606091505b50915091506105c382828661074e565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6103fd565b6105fe816107a1565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b73ffffffffffffffffffffffffffffffffffffffff81166106e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016103a2565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905550565b6060831561075d5750816102b1565b82511561076d5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103a29190610973565b73ffffffffffffffffffffffffffffffffffffffff81163b610845576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e74726163740000000000000000000000000000000000000060648201526084016103a2565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610708565b803573ffffffffffffffffffffffffffffffffffffffff8116811461089057600080fd5b919050565b6000602082840312156108a757600080fd5b6102b18261086c565b6000806000604084860312156108c557600080fd5b6108ce8461086c565b9250602084013567ffffffffffffffff808211156108eb57600080fd5b818601915086601f8301126108ff57600080fd5b81358181111561090e57600080fd5b87602082850101111561092057600080fd5b6020830194508093505050509250925092565b60005b8381101561094e578181015183820152602001610936565b50506000910152565b60008251610969818460208701610933565b9190910192915050565b6020815260008251806020840152610992816040850160208701610933565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212204b89b602dcd071e417000a9fd49a86b76809b9cfc16255d1014d4aa275fbf81264736f6c63430008110033", + "devdoc": { + "details": "This contract implements a proxy that is upgradeable by an admin. It is fully forked from OpenZeppelin `TransparentUpgradeableProxy` To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector clashing], which can potentially be used in an attack, this contract uses the https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two things that go hand in hand: 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if that call matches one of the admin functions exposed by the proxy itself. 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the implementation. If the admin tries to call a function on the implementation it will fail with an error that says \"admin cannot fallback to proxy target\". These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due to sudden errors when trying to call a function from the proxy implementation. Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way, you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.", + "kind": "dev", + "methods": { + "admin()": { + "details": "Returns the current admin. NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}. TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`" + }, + "changeAdmin(address)": { + "details": "Changes the admin of the proxy. Emits an {AdminChanged} event. NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}." + }, + "constructor": { + "details": "Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}." + }, + "implementation()": { + "details": "Returns the current implementation. NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}. TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`" + }, + "upgradeTo(address)": { + "details": "Upgrade the implementation of the proxy. NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}." + }, + "upgradeToAndCall(address,bytes)": { + "details": "Upgrade the implementation of the proxy, and then call a function from the new implementation as specified by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the proxied contract. NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} \ No newline at end of file diff --git a/deployments/mainnet/solcInputs/9a2b71309fb0718473c1f135df2b8dfe.json b/deployments/mainnet/solcInputs/9a2b71309fb0718473c1f135df2b8dfe.json new file mode 100644 index 00000000..63120b97 --- /dev/null +++ b/deployments/mainnet/solcInputs/9a2b71309fb0718473c1f135df2b8dfe.json @@ -0,0 +1,562 @@ +{ + "language": "Solidity", + "sources": { + "contracts/adapters/implementations/SanDAIEURERC4626Adapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.12;\n\nimport \"../SanTokenERC4626Adapter.sol\";\n\n/// @title SanDAIEURERC4626AdapterStakable\n/// @author Angle Labs, Inc.\n/// @notice IERC4626 Adapter for SanTokens of the Angle Protocol\n/// @dev DAI Implementation\ncontract SanDAIEURERC4626Adapter is SanTokenERC4626Adapter {\n /// @inheritdoc SanTokenERC4626Adapter\n function stableMaster() public pure override returns (IStableMaster) {\n return IStableMaster(0x5adDc89785D75C86aB939E9e15bfBBb7Fc086A87);\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function poolManager() public pure override returns (address) {\n return 0xc9daabC677F3d1301006e723bD21C60be57a5915;\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function sanToken() public pure override returns (IERC20MetadataUpgradeable) {\n return IERC20MetadataUpgradeable(0x7B8E89b0cE7BAC2cfEC92A371Da899eA8CBdb450);\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function asset() public pure override returns (address) {\n return 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n }\n}\n" + }, + "contracts/adapters/SanTokenERC4626Adapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\n\n/*\n * █ \n ***** ▓▓▓ \n * ▓▓▓▓▓▓▓ \n * ///. ▓▓▓▓▓▓▓▓▓▓▓▓▓ \n ***** //////// ▓▓▓▓▓▓▓ \n * ///////////// ▓▓▓ \n ▓▓ ////////////////// █ ▓▓ \n ▓▓ ▓▓ /////////////////////// ▓▓ ▓▓ \n ▓▓ ▓▓ //////////////////////////// ▓▓ ▓▓ \n ▓▓ ▓▓ /////////▓▓▓///////▓▓▓///////// ▓▓ ▓▓ \n ▓▓ ,////////////////////////////////////// ▓▓ ▓▓ \n ▓▓ ////////////////////////////////////////// ▓▓ \n ▓▓ //////////////////////▓▓▓▓///////////////////// \n ,//////////////////////////////////////////////////// \n .////////////////////////////////////////////////////////// \n .//////////////////////////██.,//////////////////////////█ \n .//////////////////////████..,./////////////////////██ \n ...////////////////███████.....,.////////////////███ \n ,.,////////////████████ ........,///////////████ \n .,.,//////█████████ ,.......///////████ \n ,..//████████ ........./████ \n ..,██████ .....,███ \n .██ ,.,█ \n \n \n \n ▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓ \n ▓▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓ ▓▓▓▓ \n ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓▓▓▓ \n ▓▓▓ ▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ \n*/\n\npragma solidity ^0.8.12;\n\nimport \"../interfaces/ICoreBorrow.sol\";\nimport \"../interfaces/coreModule/ILiquidityGauge.sol\";\nimport \"../interfaces/coreModule/IPoolManager.sol\";\nimport \"../interfaces/coreModule/IStableMaster.sol\";\nimport \"../utils/Constants.sol\";\n\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/interfaces/IERC20MetadataUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/interfaces/IERC4626Upgradeable.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/// @title SanTokenERC4626Adapter\n/// @author Angle Labs, Inc.\n/// @notice IERC4626 Adapter for SanTokens of the Angle Protocol\nabstract contract SanTokenERC4626Adapter is Initializable, ERC20Upgradeable, IERC4626Upgradeable, Constants {\n using MathUpgradeable for uint256;\n using SafeERC20 for IERC20;\n\n uint256[50] private __gap;\n\n // =============================== INITIALIZATION ==============================\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() initializer {}\n\n /// @notice Initializes the contract\n function initialize() public initializer {\n __ERC20_init_unchained(\n string(abi.encodePacked(\"Angle \", sanToken().name(), \" Wrapper\")),\n string(abi.encodePacked(\"ag-wrapper-\", sanToken().symbol()))\n );\n IERC20(asset()).safeIncreaseAllowance(address(stableMaster()), type(uint256).max);\n if (address(gauge()) != address(0))\n IERC20(address(sanToken())).safeIncreaseAllowance(address(gauge()), type(uint256).max);\n }\n\n // ============================= VIRTUAL FUNCTIONS =============================\n\n /// @notice Address of the `StableMaster` in the Core module of the protocol\n function stableMaster() public view virtual returns (IStableMaster);\n\n /// @notice Address of the corresponding poolManager\n function poolManager() public view virtual returns (address);\n\n /// @notice Address of the associated sanToken\n function sanToken() public view virtual returns (IERC20MetadataUpgradeable);\n\n /// @inheritdoc IERC4626Upgradeable\n function asset() public view virtual returns (address);\n\n /// @inheritdoc IERC4626Upgradeable\n function totalAssets() public view virtual returns (uint256) {\n return _convertToAssetsWithSlippage(sanToken().balanceOf(address(this)));\n }\n\n /// @notice Returns the gauge address\n /// @dev This function is only useful in the stakable implementation\n function gauge() public view virtual returns (ILiquidityGauge) {\n return ILiquidityGauge(address(0));\n }\n\n // ========================== IERC4626 VIEW FUNCTIONS ==========================\n\n /// @inheritdoc IERC20MetadataUpgradeable\n function decimals() public view override(ERC20Upgradeable, IERC20MetadataUpgradeable) returns (uint8) {\n return IERC20MetadataUpgradeable(asset()).decimals();\n }\n\n /// @notice Returns the available balance of the token in the associated `PoolManager`\n function availableBalance() public view returns (uint256) {\n return IERC20(asset()).balanceOf(poolManager());\n }\n\n /// @inheritdoc IERC4626Upgradeable\n function convertToShares(uint256 assets) public view returns (uint256 shares) {\n return _convertToShares(assets);\n }\n\n /// @inheritdoc IERC4626Upgradeable\n function convertToAssets(uint256 shares) public view returns (uint256 assets) {\n return _convertToAssets(shares, MathUpgradeable.Rounding.Down);\n }\n\n /// @inheritdoc IERC4626Upgradeable\n function maxDeposit(address) public pure returns (uint256) {\n return type(uint256).max;\n }\n\n /// @inheritdoc IERC4626Upgradeable\n function maxMint(address) public pure returns (uint256) {\n return type(uint256).max;\n }\n\n /// @inheritdoc IERC4626Upgradeable\n function previewDeposit(uint256 assets) public view returns (uint256) {\n return _convertToShares(assets);\n }\n\n /// @inheritdoc IERC4626Upgradeable\n function previewMint(uint256 shares) public view returns (uint256) {\n return _convertToAssets(shares, MathUpgradeable.Rounding.Up);\n }\n\n /// @inheritdoc IERC4626Upgradeable\n function maxWithdraw(address owner) public view returns (uint256) {\n return MathUpgradeable.min(_convertToAssetsWithSlippage(balanceOf(owner)), availableBalance());\n }\n\n /// @inheritdoc IERC4626Upgradeable\n function maxRedeem(address owner) public view returns (uint256 redeemable) {\n return MathUpgradeable.min(balanceOf(owner), _convertToSharesWithSlippage(availableBalance()));\n }\n\n /// @inheritdoc IERC4626Upgradeable\n function previewWithdraw(uint256 assets) public view returns (uint256) {\n if (assets > availableBalance()) return type(uint256).max;\n return _convertToSharesWithSlippage(assets);\n }\n\n /// @inheritdoc IERC4626Upgradeable\n function previewRedeem(uint256 shares) public view returns (uint256) {\n uint256 assets = _convertToAssetsWithSlippage(shares);\n if (assets > availableBalance()) return 0;\n else return assets;\n }\n\n // ========================= IERC4626 ACTION FUNCTIONS =========================\n\n /// @inheritdoc IERC4626Upgradeable\n function deposit(uint256 assets, address receiver) public returns (uint256) {\n uint256 shares = previewDeposit(assets);\n _deposit(msg.sender, receiver, assets, shares);\n return shares;\n }\n\n /// @inheritdoc IERC4626Upgradeable\n function mint(uint256 shares, address receiver) public returns (uint256) {\n uint256 assets = previewMint(shares);\n _deposit(msg.sender, receiver, assets, shares);\n return assets;\n }\n\n /// @inheritdoc IERC4626Upgradeable\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) public returns (uint256) {\n uint256 shares = previewWithdraw(assets);\n _withdraw(msg.sender, receiver, owner, assets, shares);\n return shares;\n }\n\n /// @inheritdoc IERC4626Upgradeable\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) public returns (uint256) {\n uint256 assets = previewRedeem(shares);\n // This means that there are in fact not enough assets to cover for the shares that are being burnt\n if (assets == 0) revert InsufficientAssets();\n _withdraw(msg.sender, receiver, owner, assets, shares);\n return assets;\n }\n\n // ============================== INTERNAL HELPERS =============================\n\n /// @notice Estimates the current version of the sanRate for this collateral asset and the slippage value\n function _estimateSanRate() internal view returns (uint256, uint256) {\n (, , , , , uint256 sanRate, , SLPData memory slpData, ) = stableMaster().collateralMap(poolManager());\n if (block.timestamp != slpData.lastBlockUpdated && slpData.lockedInterests > 0) {\n uint256 sanMint = sanToken().totalSupply();\n if (sanMint != 0) {\n if (slpData.lockedInterests > slpData.maxInterestsDistributed) {\n sanRate += (slpData.maxInterestsDistributed * _BASE_18) / sanMint;\n } else {\n sanRate += (slpData.lockedInterests * _BASE_18) / sanMint;\n }\n }\n }\n return (sanRate, slpData.slippage);\n }\n\n /// @notice Deposit/mint common workflow\n function _deposit(\n address caller,\n address receiver,\n uint256 assets,\n uint256 shares\n ) internal {\n IERC20(asset()).safeTransferFrom(caller, address(this), assets);\n // It is expected that calling `stableMaster.deposit` will mint exactly `shares`\n // This assumption may no longer be valid if the `stableMaster` contract is upgraded\n stableMaster().deposit(assets, address(this), poolManager());\n _mint(receiver, shares);\n emit Deposit(caller, receiver, assets, shares);\n }\n\n /// @notice Withdraw/redeem common workflow\n function _withdraw(\n address caller,\n address receiver,\n address owner,\n uint256 assets,\n uint256 shares\n ) internal {\n if (caller != owner) {\n _spendAllowance(owner, caller, shares);\n }\n _burn(owner, shares);\n // Like for the `_deposit` function, this function is built under the assumption that\n // `stableMaster.withdraw` will return either `assets` or `assets+1`. It may no longer\n // hold if the `stableMaster` contract is upgraded.\n // Performing two transfers here to be sure that `receiver` exactly receives assets and not\n // `assets+1`\n stableMaster().withdraw(shares, address(this), address(this), poolManager());\n IERC20(asset()).safeTransfer(receiver, assets);\n emit Withdraw(caller, receiver, owner, assets, shares);\n }\n\n /// @notice Internal version of the `convertToShares` function\n /// @dev We round down by default\n function _convertToShares(uint256 assets) internal view returns (uint256 shares) {\n (uint256 sanRate, ) = _estimateSanRate();\n return assets.mulDiv(_BASE_18, sanRate, MathUpgradeable.Rounding.Down);\n }\n\n /// @notice Internal version of the `convertToAssets` function\n function _convertToAssets(uint256 shares, MathUpgradeable.Rounding rounding)\n internal\n view\n returns (uint256 assets)\n {\n (uint256 sanRate, ) = _estimateSanRate();\n return shares.mulDiv(sanRate, _BASE_18, rounding);\n }\n\n /// @notice Converts an amount of `assets` to a shares amount with potential exit slippage taken into account\n function _convertToSharesWithSlippage(uint256 assets) internal view returns (uint256 shares) {\n (uint256 sanRate, uint256 slippage) = _estimateSanRate();\n shares = assets.mulDiv(_BASE_27, (_BASE_9 - slippage) * sanRate, MathUpgradeable.Rounding.Up);\n }\n\n /// @notice Converts an amount of `shares` to an assets amount with potential exit slippage taken into account\n function _convertToAssetsWithSlippage(uint256 shares) internal view returns (uint256 assets) {\n (uint256 sanRate, uint256 slippage) = _estimateSanRate();\n assets = shares.mulDiv((_BASE_9 - slippage) * sanRate, _BASE_27, MathUpgradeable.Rounding.Down);\n }\n}\n" + }, + "contracts/interfaces/ICoreBorrow.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\n/// @title ICoreBorrow\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `CoreBorrow` contract\n/// @dev This interface only contains functions of the `CoreBorrow` contract which are called by other contracts\n/// of this module\ninterface ICoreBorrow {\n /// @notice Checks if an address corresponds to a treasury of a stablecoin with a flash loan\n /// module initialized on it\n /// @param treasury Address to check\n /// @return Whether the address has the `FLASHLOANER_TREASURY_ROLE` or not\n function isFlashLoanerTreasury(address treasury) external view returns (bool);\n\n /// @notice Checks whether an address is governor of the Angle Protocol or not\n /// @param admin Address to check\n /// @return Whether the address has the `GOVERNOR_ROLE` or not\n function isGovernor(address admin) external view returns (bool);\n\n /// @notice Checks whether an address is governor or a guardian of the Angle Protocol or not\n /// @param admin Address to check\n /// @return Whether the address has the `GUARDIAN_ROLE` or not\n /// @dev Governance should make sure when adding a governor to also give this governor the guardian\n /// role by calling the `addGovernor` function\n function isGovernorOrGuardian(address admin) external view returns (bool);\n}\n" + }, + "contracts/interfaces/coreModule/ILiquidityGauge.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\ninterface ILiquidityGauge {\n function deposit(\n uint256 _value,\n address _addr,\n // solhint-disable-next-line\n bool _claim_rewards\n ) external;\n\n function withdraw(\n uint256 _value,\n // solhint-disable-next-line\n bool _claim_rewards\n ) external;\n\n // solhint-disable-next-line\n function claim_rewards(address _addr, address _receiver) external;\n\n // solhint-disable-next-line\n function claimable_reward(address _addr, address _reward_token) external view returns (uint256 amount);\n}\n" + }, + "contracts/interfaces/coreModule/IPoolManager.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\n/// @title IPoolManager\n/// @author Angle Labs, Inc.\ninterface IPoolManager {\n function feeManager() external view returns (address);\n\n function strategyList(uint256) external view returns (address);\n}\n" + }, + "contracts/interfaces/coreModule/IStableMaster.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"./IPerpetualManager.sol\";\nimport \"./IOracleCore.sol\";\n\n// Struct to handle all the parameters to manage the fees\n// related to a given collateral pool (associated to the stablecoin)\nstruct MintBurnData {\n // Values of the thresholds to compute the minting fees\n // depending on HA hedge (scaled by `BASE_PARAMS`)\n uint64[] xFeeMint;\n // Values of the fees at thresholds (scaled by `BASE_PARAMS`)\n uint64[] yFeeMint;\n // Values of the thresholds to compute the burning fees\n // depending on HA hedge (scaled by `BASE_PARAMS`)\n uint64[] xFeeBurn;\n // Values of the fees at thresholds (scaled by `BASE_PARAMS`)\n uint64[] yFeeBurn;\n // Max proportion of collateral from users that can be covered by HAs\n // It is exactly the same as the parameter of the same name in `PerpetualManager`, whenever one is updated\n // the other changes accordingly\n uint64 targetHAHedge;\n // Minting fees correction set by the `FeeManager` contract: they are going to be multiplied\n // to the value of the fees computed using the hedge curve\n // Scaled by `BASE_PARAMS`\n uint64 bonusMalusMint;\n // Burning fees correction set by the `FeeManager` contract: they are going to be multiplied\n // to the value of the fees computed using the hedge curve\n // Scaled by `BASE_PARAMS`\n uint64 bonusMalusBurn;\n // Parameter used to limit the number of stablecoins that can be issued using the concerned collateral\n uint256 capOnStableMinted;\n}\n\n// Struct to handle all the variables and parameters to handle SLPs in the protocol\n// including the fraction of interests they receive or the fees to be distributed to\n// them\nstruct SLPData {\n // Last timestamp at which the `sanRate` has been updated for SLPs\n uint256 lastBlockUpdated;\n // Fees accumulated from previous blocks and to be distributed to SLPs\n uint256 lockedInterests;\n // Max interests used to update the `sanRate` in a single block\n // Should be in collateral token base\n uint256 maxInterestsDistributed;\n // Amount of fees left aside for SLPs and that will be distributed\n // when the protocol is collateralized back again\n uint256 feesAside;\n // Part of the fees normally going to SLPs that is left aside\n // before the protocol is collateralized back again (depends on collateral ratio)\n // Updated by keepers and scaled by `BASE_PARAMS`\n uint64 slippageFee;\n // Portion of the fees from users minting and burning\n // that goes to SLPs (the rest goes to surplus)\n uint64 feesForSLPs;\n // Slippage factor that's applied to SLPs exiting (depends on collateral ratio)\n // If `slippage = BASE_PARAMS`, SLPs can get nothing, if `slippage = 0` they get their full claim\n // Updated by keepers and scaled by `BASE_PARAMS`\n uint64 slippage;\n // Portion of the interests from lending\n // that goes to SLPs (the rest goes to surplus)\n uint64 interestsForSLPs;\n}\n\n/// @title IStableMaster\n/// @author Angle Labs, Inc.\ninterface IStableMaster {\n function agToken() external view returns (address);\n\n function updateStocksUsers(uint256 amount, address poolManager) external;\n\n function collateralMap(address poolManager)\n external\n view\n returns (\n address token,\n address sanToken,\n IPerpetualManager perpetualManager,\n IOracleCore oracle,\n uint256 stocksUsers,\n uint256 sanRate,\n uint256 collatBase,\n SLPData memory slpData,\n MintBurnData memory feeData\n );\n\n function paused(bytes32) external view returns (bool);\n\n function deposit(\n uint256 amount,\n address user,\n address poolManager\n ) external;\n\n function withdraw(\n uint256 amount,\n address burner,\n address dest,\n address poolManager\n ) external;\n}\n" + }, + "contracts/utils/Constants.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nerror InsufficientAssets();\n\n/// @title Constants\n/// @author Angle Labs, Inc.\n/// @notice Constants and errors for Angle Protocol contracts\ncontract Constants {\n uint256 internal constant _BASE_9 = 1e9;\n uint256 internal constant _BASE_18 = 1e18;\n uint256 internal constant _BASE_27 = 1e27;\n uint256 internal constant _BASE_36 = 1e36;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n * @custom:oz-retyped-from bool\n */\n uint8 private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint8 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.\n */\n modifier initializer() {\n bool isTopLevelCall = !_initializing;\n require(\n (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n \"Initializable: contract is already initialized\"\n );\n _initialized = 1;\n if (isTopLevelCall) {\n _initializing = true;\n }\n _;\n if (isTopLevelCall) {\n _initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n * initialization step. This is essential to configure modules that are added through upgrades and that require\n * initialization.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n */\n modifier reinitializer(uint8 version) {\n require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n _initialized = version;\n _initializing = true;\n _;\n _initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n require(_initializing, \"Initializable: contract is not initializing\");\n _;\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n */\n function _disableInitializers() internal virtual {\n require(!_initializing, \"Initializable: contract is initializing\");\n if (_initialized < type(uint8).max) {\n _initialized = type(uint8).max;\n emit Initialized(type(uint8).max);\n }\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20Upgradeable.sol\";\nimport \"./extensions/IERC20MetadataUpgradeable.sol\";\nimport \"../../utils/ContextUpgradeable.sol\";\nimport \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {\n __ERC20_init_unchained(name_, symbol_);\n }\n\n function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[45] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary MathUpgradeable {\n enum Rounding {\n Down, // Toward negative infinity\n Up, // Toward infinity\n Zero // Toward zero\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a >= b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a == 0 ? 0 : (a - 1) / b + 1;\n }\n\n /**\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n * with further edits by Uniswap Labs also under MIT license.\n */\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator\n ) internal pure returns (uint256 result) {\n unchecked {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n return prod0 / denominator;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n require(denominator > prod1);\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 twos = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [prod1 prod0] by twos.\n prod0 := div(prod0, twos)\n\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n\n /**\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator,\n Rounding rounding\n ) internal pure returns (uint256) {\n uint256 result = mulDiv(x, y, denominator);\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n result += 1;\n }\n return result;\n }\n\n /**\n * @dev Returns the square root of a number. It the number is not a perfect square, the value is rounded down.\n *\n * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n if (a == 0) {\n return 0;\n }\n\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n // `msb(a) <= a < 2*msb(a)`.\n // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`.\n // This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`.\n // Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a\n // good first aproximation of `sqrt(a)` with at least 1 correct bit.\n uint256 result = 1;\n uint256 x = a;\n if (x >> 128 > 0) {\n x >>= 128;\n result <<= 64;\n }\n if (x >> 64 > 0) {\n x >>= 64;\n result <<= 32;\n }\n if (x >> 32 > 0) {\n x >>= 32;\n result <<= 16;\n }\n if (x >> 16 > 0) {\n x >>= 16;\n result <<= 8;\n }\n if (x >> 8 > 0) {\n x >>= 8;\n result <<= 4;\n }\n if (x >> 4 > 0) {\n x >>= 4;\n result <<= 2;\n }\n if (x >> 2 > 0) {\n result <<= 1;\n }\n\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n // into the expected uint128 result.\n unchecked {\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n return min(result, a / result);\n }\n }\n\n /**\n * @notice Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n uint256 result = sqrt(a);\n if (rounding == Rounding.Up && result * result < a) {\n result += 1;\n }\n return result;\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/interfaces/IERC20MetadataUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../token/ERC20/extensions/IERC20MetadataUpgradeable.sol\";\n" + }, + "@openzeppelin/contracts-upgradeable/interfaces/IERC4626Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (interfaces/IERC4626.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../token/ERC20/IERC20Upgradeable.sol\";\nimport \"../token/ERC20/extensions/IERC20MetadataUpgradeable.sol\";\n\n/**\n * @dev Interface of the ERC4626 \"Tokenized Vault Standard\", as defined in\n * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].\n *\n * _Available since v4.7._\n */\ninterface IERC4626Upgradeable is IERC20Upgradeable, IERC20MetadataUpgradeable {\n event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);\n\n event Withdraw(\n address indexed caller,\n address indexed receiver,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n\n /**\n * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function asset() external view returns (address assetTokenAddress);\n\n /**\n * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n *\n * - SHOULD include any compounding that occurs from yield.\n * - MUST be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT revert.\n */\n function totalAssets() external view returns (uint256 totalManagedAssets);\n\n /**\n * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n * through a deposit call.\n *\n * - MUST return a limited value if receiver is subject to some deposit limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n * - MUST NOT revert.\n */\n function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n * in the same transaction.\n * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n * deposit would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * deposit execution, and are accounted for during deposit.\n * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n * - MUST return a limited value if receiver is subject to some mint limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n * - MUST NOT revert.\n */\n function maxMint(address receiver) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n * same transaction.\n * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n * would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by minting.\n */\n function previewMint(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n * execution, and are accounted for during mint.\n * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n * Vault, through a withdraw call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n * called\n * in the same transaction.\n * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n * the withdrawal would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * withdraw execution, and are accounted for during withdraw.\n * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n * through a redeem call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n * same transaction.\n * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n * redemption would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n */\n function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * redeem execution, and are accounted for during redeem.\n * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) external returns (uint256 assets);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n function safePermit(\n IERC20Permit token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "contracts/interfaces/coreModule/IPerpetualManager.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\n/// @title IPerpetualManager\n/// @author Angle Labs, Inc.\ninterface IPerpetualManager {\n function totalHedgeAmount() external view returns (uint256);\n\n function maintenanceMargin() external view returns (uint64);\n\n function maxLeverage() external view returns (uint64);\n\n function targetHAHedge() external view returns (uint64);\n\n function limitHAHedge() external view returns (uint64);\n\n function lockTime() external view returns (uint64);\n\n function haBonusMalusDeposit() external view returns (uint64);\n\n function haBonusMalusWithdraw() external view returns (uint64);\n\n function xHAFeesDeposit(uint256) external view returns (uint64);\n\n function yHAFeesDeposit(uint256) external view returns (uint64);\n\n function xHAFeesWithdraw(uint256) external view returns (uint64);\n\n function yHAFeesWithdraw(uint256) external view returns (uint64);\n}\n" + }, + "contracts/interfaces/coreModule/IOracleCore.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\n/// @title IOracleCore\n/// @author Angle Labs, Inc.\ninterface IOracleCore {\n function readUpper() external view returns (uint256);\n\n function readQuoteLower(uint256 baseAmount) external view returns (uint256);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20Upgradeable {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20MetadataUpgradeable is IERC20Upgradeable {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n function __Context_init() internal onlyInitializing {\n }\n\n function __Context_init_unchained() internal onlyInitializing {\n }\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" + }, + "contracts/mock/MockSanTokenERC4626Adapter.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.12;\n\nimport \"../adapters/SanTokenERC4626Adapter.sol\";\nimport { SanTokenERC4626AdapterStakable } from \"../adapters/SanTokenERC4626AdapterStakable.sol\";\n\ncontract MockSanTokenERC4626Adapter is SanTokenERC4626Adapter {\n IStableMaster internal _stableMaster;\n address internal _poolManager;\n IERC20MetadataUpgradeable internal _sanToken;\n address internal _asset;\n\n /// @notice Address of the `StableMaster` in the Core module of the protocol\n function stableMaster() public view override returns (IStableMaster) {\n return _stableMaster;\n }\n\n /// @notice Address of the corresponding poolManager\n function poolManager() public view override returns (address) {\n return _poolManager;\n }\n\n /// @notice Address of the associated sanToken\n function sanToken() public view override returns (IERC20MetadataUpgradeable) {\n return _sanToken;\n }\n\n /// @inheritdoc IERC4626Upgradeable\n function asset() public view override returns (address) {\n return _asset;\n }\n\n // ================================== SETTERS ==================================\n\n /// @notice Address of the `StableMaster` in the Core module of the protocol\n function setStableMaster(address stableMaster_) public virtual {\n _stableMaster = IStableMaster(stableMaster_);\n }\n\n /// @notice Address of the corresponding poolManager\n function setPoolManager(address poolManager_) public virtual {\n _poolManager = poolManager_;\n }\n\n /// @notice Address of the associated sanToken\n function setSanToken(address sanToken_) public virtual {\n _sanToken = IERC20MetadataUpgradeable(sanToken_);\n }\n\n function setAsset(address asset_) public virtual {\n _asset = asset_;\n }\n}\n\ncontract MockSanTokenERC4626AdapterStakable is SanTokenERC4626AdapterStakable {\n ILiquidityGauge internal _gauge;\n IStableMaster internal _stableMaster;\n address internal _poolManager;\n IERC20MetadataUpgradeable internal _sanToken;\n address internal _asset;\n\n /// @notice Address of the `StableMaster` in the Core module of the protocol\n function stableMaster() public view override returns (IStableMaster) {\n return _stableMaster;\n }\n\n /// @notice Address of the corresponding poolManager\n function poolManager() public view override returns (address) {\n return _poolManager;\n }\n\n /// @notice Address of the associated sanToken\n function sanToken() public view override returns (IERC20MetadataUpgradeable) {\n return _sanToken;\n }\n\n /// @inheritdoc IERC4626Upgradeable\n function asset() public view override returns (address) {\n return _asset;\n }\n\n // ================================== SETTERS ==================================\n\n /// @notice Address of the `StableMaster` in the Core module of the protocol\n function setStableMaster(address stableMaster_) public virtual {\n _stableMaster = IStableMaster(stableMaster_);\n }\n\n /// @notice Address of the corresponding poolManager\n function setPoolManager(address poolManager_) public virtual {\n _poolManager = poolManager_;\n }\n\n /// @notice Address of the associated sanToken\n function setSanToken(address sanToken_) public virtual {\n _sanToken = IERC20MetadataUpgradeable(sanToken_);\n }\n\n function setAsset(address asset_) public virtual {\n _asset = asset_;\n }\n\n /// @notice Address of the corresponding poolManager\n function gauge() public view override returns (ILiquidityGauge) {\n return _gauge;\n }\n\n function setLiquidityGauge(address gauge_) public virtual {\n _gauge = ILiquidityGauge(gauge_);\n }\n}\n" + }, + "contracts/adapters/SanTokenERC4626AdapterStakable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.12;\n\nimport \"./SanTokenERC4626Adapter.sol\";\n\n/// @title SanTokenERC4626AdapterStakable\n/// @author Angle Labs, Inc.\n/// @notice IERC4626 Adapter for SanTokens of the Angle Protocol\n/// @dev In this implementation, sanTokens are staked and accumulate ANGLE rewards on top of the native rewards\n/// @dev Rewards are claimed at every transfer or withdrawal\n/// @dev This implementation could be generalized if multiple reward tokens are sent in the liquidity gauge contract\nabstract contract SanTokenERC4626AdapterStakable is SanTokenERC4626Adapter {\n using MathUpgradeable for uint256;\n using SafeERC20 for IERC20;\n\n /// @notice Angle-related constants\n IERC20 private constant _ANGLE = IERC20(0x31429d1856aD1377A8A0079410B297e1a9e214c2);\n\n // ================================= REFERENCES ================================\n\n /// @notice Maps each reward token to a track record of cumulated rewards\n mapping(IERC20 => uint256) public integral;\n /// @notice Maps pairs of `(token,user)` to the currently pending claimable rewards\n mapping(IERC20 => mapping(address => uint256)) public pendingRewardsOf;\n /// @notice Maps pairs of `(token,user)` to a track record of cumulated personal rewards\n mapping(IERC20 => mapping(address => uint256)) public integralOf;\n\n uint256[47] private __gapStakable;\n\n /// @inheritdoc SanTokenERC4626Adapter\n function totalAssets() public view override returns (uint256) {\n return _convertToAssetsWithSlippage(IERC20(address(gauge())).balanceOf(address(this)));\n }\n\n // ================================ ERC20 LOGIC ================================\n\n /// @inheritdoc ERC20Upgradeable\n function _beforeTokenTransfer(\n address _from,\n address _to,\n uint256 amount\n ) internal override {\n // Not claiming only if it is a deposit\n bool _claim = !(_from == address(0));\n _claimContractRewards();\n _checkpointRewardsUser(_from, _claim);\n _checkpointRewardsUser(_to, _claim);\n // If the user is withdrawing, we need to unstake from the gauge\n if (_to == address(0)) gauge().withdraw(amount, false);\n if (_from == address(0)) gauge().deposit(amount, address(this), false);\n }\n\n // ================================ USER ACTIONS ===============================\n\n /// @notice Claims earned rewards for user `from`\n /// @param from Address to claim for\n /// @return rewardAmounts Amounts of each reward token claimed by the user\n //solhint-disable-next-line\n function claim_rewards(address from) public returns (uint256[] memory) {\n _claimContractRewards();\n return _checkpointRewardsUser(from, true);\n }\n\n /// @notice Same as the function above\n function claimRewards(address from) external returns (uint256[] memory) {\n return claim_rewards(from);\n }\n\n /// @notice Returns the exact amount that will be received if calling `claim_rewards(from)` for a specific reward token\n /// @param user Address to claim for\n /// @param _rewardToken Token to get rewards for\n function claimableRewards(address user, IERC20 _rewardToken) external view returns (uint256) {\n uint256 _totalSupply = totalSupply();\n uint256 newIntegral = _totalSupply != 0\n ? integral[_rewardToken] + (_rewardsToBeClaimed(_rewardToken) * _BASE_36) / _totalSupply\n : integral[_rewardToken];\n uint256 newClaimable = (balanceOf(user) * (newIntegral - integralOf[_rewardToken][user])) / _BASE_36;\n return pendingRewardsOf[_rewardToken][user] + newClaimable;\n }\n\n // ======================== INTERNAL ACCOUNTING HELPERS ========================\n\n /// @notice Checkpoints rewards earned by a user\n /// @param user Address to claim rewards for\n /// @param _claim Whether to claim or not the rewards\n /// @return rewardAmounts Amounts of the different reward tokens earned by the user\n function _checkpointRewardsUser(address user, bool _claim) internal returns (uint256[] memory rewardAmounts) {\n IERC20[] memory rewardTokens = _getRewards();\n uint256 rewardTokensLength = rewardTokens.length;\n rewardAmounts = new uint256[](rewardTokensLength);\n if (user == address(0)) return rewardAmounts;\n uint256 userBalance = balanceOf(user);\n for (uint256 i; i < rewardTokensLength; ++i) {\n uint256 totalClaimable = (userBalance * (integral[rewardTokens[i]] - integralOf[rewardTokens[i]][user])) /\n _BASE_36 +\n pendingRewardsOf[rewardTokens[i]][user];\n if (totalClaimable != 0) {\n if (_claim) {\n pendingRewardsOf[rewardTokens[i]][user] = 0;\n rewardTokens[i].safeTransfer(user, totalClaimable);\n } else {\n pendingRewardsOf[rewardTokens[i]][user] = totalClaimable;\n }\n rewardAmounts[i] = totalClaimable;\n }\n integralOf[rewardTokens[i]][user] = integral[rewardTokens[i]];\n }\n }\n\n /// @notice Claims all available rewards and increases the associated integral\n function _claimContractRewards() internal virtual {\n IERC20[] memory rewardTokens = _getRewards();\n uint256 rewardTokensLength = rewardTokens.length;\n uint256[] memory prevBalances = new uint256[](rewardTokensLength);\n for (uint256 i; i < rewardTokensLength; ++i) {\n prevBalances[i] = rewardTokens[i].balanceOf(address(this));\n }\n gauge().claim_rewards(address(this), address(0));\n for (uint256 i; i < rewardTokensLength; ++i) {\n IERC20 rewardToken = rewardTokens[i];\n uint256 rewards = rewardToken.balanceOf(address(this)) - prevBalances[i];\n _updateRewards(rewardToken, rewards);\n }\n }\n\n /// @notice Adds the contract claimed rewards to the distributed rewards\n /// @param rewardToken Reward token that must be updated\n /// @param amount Amount to add to the claimable rewards\n function _updateRewards(IERC20 rewardToken, uint256 amount) internal {\n uint256 _totalSupply = totalSupply();\n if (_totalSupply != 0) integral[rewardToken] += (amount * _BASE_36) / _totalSupply;\n }\n\n /// @notice Gets the reward tokens given in the liquidity gauge\n function _getRewards() internal pure virtual returns (IERC20[] memory rewards) {\n rewards = new IERC20[](1);\n rewards[0] = _ANGLE;\n return rewards;\n }\n\n /// @notice Checks all unclaimed rewards in `rewardToken`\n function _rewardsToBeClaimed(IERC20 rewardToken) internal view virtual returns (uint256 amount) {\n return gauge().claimable_reward(address(this), address(rewardToken));\n }\n}\n" + }, + "contracts/adapters/implementations/Stakable/SanUSDCEURERC4626AdapterStakable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.12;\n\nimport \"../../SanTokenERC4626AdapterStakable.sol\";\n\n/// @title SanUSDCEURERC4626AdapterStakable\n/// @author Angle Labs, Inc.\n/// @notice IERC4626 Adapter for SanTokens of the Angle Protocol\n/// @dev USDC stakable implementation\ncontract SanUSDCEURERC4626AdapterStakable is SanTokenERC4626AdapterStakable {\n /// @inheritdoc SanTokenERC4626Adapter\n function stableMaster() public pure override returns (IStableMaster) {\n return IStableMaster(0x5adDc89785D75C86aB939E9e15bfBBb7Fc086A87);\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function poolManager() public pure override returns (address) {\n return 0xe9f183FC656656f1F17af1F2b0dF79b8fF9ad8eD;\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function sanToken() public pure override returns (IERC20MetadataUpgradeable) {\n return IERC20MetadataUpgradeable(0x9C215206Da4bf108aE5aEEf9dA7caD3352A36Dad);\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function asset() public pure override returns (address) {\n return 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function gauge() public pure override returns (ILiquidityGauge) {\n return ILiquidityGauge(0x51fE22abAF4a26631b2913E417c0560D547797a7);\n }\n}\n" + }, + "contracts/adapters/implementations/Stakable/SanFRAXEURERC4626AdapterStakable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.12;\n\nimport \"../../SanTokenERC4626AdapterStakable.sol\";\n\n/// @title SanFRAXEURERC4626AdapterStakable\n/// @author Angle Labs, Inc.\n/// @notice IERC4626 Adapter for SanTokens of the Angle Protocol\n/// @dev FRAX stakable implementation\ncontract SanFRAXEURERC4626AdapterStakable is SanTokenERC4626AdapterStakable {\n /// @inheritdoc SanTokenERC4626Adapter\n function stableMaster() public pure override returns (IStableMaster) {\n return IStableMaster(0x5adDc89785D75C86aB939E9e15bfBBb7Fc086A87);\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function poolManager() public pure override returns (address) {\n return 0x6b4eE7352406707003bC6f6b96595FD35925af48;\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function sanToken() public pure override returns (IERC20MetadataUpgradeable) {\n return IERC20MetadataUpgradeable(0xb3B209Bb213A5Da5B947C56f2C770b3E1015f1FE);\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function asset() public pure override returns (address) {\n return 0x853d955aCEf822Db058eb8505911ED77F175b99e;\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function gauge() public pure override returns (ILiquidityGauge) {\n return ILiquidityGauge(0xb40432243E4F317cE287398e72Ab8f0312fc2FE8);\n }\n}\n" + }, + "contracts/adapters/implementations/Stakable/SanDAIEURERC4626AdapterStakable.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.12;\n\nimport \"../../SanTokenERC4626AdapterStakable.sol\";\n\n/// @title SanDAIEURERC4626AdapterStakable\n/// @author Angle Labs, Inc.\n/// @notice IERC4626 Adapter for SanTokens of the Angle Protocol\n/// @dev DAI stakable implementation\ncontract SanDAIEURERC4626AdapterStakable is SanTokenERC4626AdapterStakable {\n /// @inheritdoc SanTokenERC4626Adapter\n function stableMaster() public pure override returns (IStableMaster) {\n return IStableMaster(0x5adDc89785D75C86aB939E9e15bfBBb7Fc086A87);\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function poolManager() public pure override returns (address) {\n return 0xc9daabC677F3d1301006e723bD21C60be57a5915;\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function sanToken() public pure override returns (IERC20MetadataUpgradeable) {\n return IERC20MetadataUpgradeable(0x7B8E89b0cE7BAC2cfEC92A371Da899eA8CBdb450);\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function asset() public pure override returns (address) {\n return 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function gauge() public pure override returns (ILiquidityGauge) {\n return ILiquidityGauge(0x8E2c0CbDa6bA7B65dbcA333798A3949B07638026);\n }\n}\n" + }, + "contracts/adapters/implementations/SanUSDCEURERC4626Adapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.12;\n\nimport \"../SanTokenERC4626Adapter.sol\";\n\n/// @title SanUSDCEURERC4626Adapter\n/// @author Angle Labs, Inc.\n/// @notice IERC4626 Adapter for SanTokens of the Angle Protocol\n/// @dev USDC Implementation\ncontract SanUSDCEURERC4626Adapter is SanTokenERC4626Adapter {\n /// @inheritdoc SanTokenERC4626Adapter\n function stableMaster() public pure override returns (IStableMaster) {\n return IStableMaster(0x5adDc89785D75C86aB939E9e15bfBBb7Fc086A87);\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function poolManager() public pure override returns (address) {\n return 0xe9f183FC656656f1F17af1F2b0dF79b8fF9ad8eD;\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function sanToken() public pure override returns (IERC20MetadataUpgradeable) {\n return IERC20MetadataUpgradeable(0x9C215206Da4bf108aE5aEEf9dA7caD3352A36Dad);\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function asset() public pure override returns (address) {\n return 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;\n }\n}\n" + }, + "contracts/adapters/implementations/SanFRAXEURERC4626Adapter.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.12;\n\nimport \"../SanTokenERC4626Adapter.sol\";\n\n/// @title SanFRAXEURERC4626Adapter\n/// @author Angle Labs, Inc.\n/// @notice IERC4626 Adapter for SanTokens of the Angle Protocol\n/// @dev FRAX Implementation\ncontract SanFRAXEURERC4626Adapter is SanTokenERC4626Adapter {\n /// @inheritdoc SanTokenERC4626Adapter\n function stableMaster() public pure override returns (IStableMaster) {\n return IStableMaster(0x5adDc89785D75C86aB939E9e15bfBBb7Fc086A87);\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function poolManager() public pure override returns (address) {\n return 0x6b4eE7352406707003bC6f6b96595FD35925af48;\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function sanToken() public pure override returns (IERC20MetadataUpgradeable) {\n return IERC20MetadataUpgradeable(0xb3B209Bb213A5Da5B947C56f2C770b3E1015f1FE);\n }\n\n /// @inheritdoc SanTokenERC4626Adapter\n function asset() public pure override returns (address) {\n return 0x853d955aCEf822Db058eb8505911ED77F175b99e;\n }\n}\n" + }, + "contracts/vaultManager/VaultManagerStorage.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/interfaces/IERC721MetadataUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport \"../interfaces/IAgToken.sol\";\nimport \"../interfaces/IOracle.sol\";\nimport \"../interfaces/ISwapper.sol\";\nimport \"../interfaces/ITreasury.sol\";\nimport \"../interfaces/IVaultManager.sol\";\nimport \"../interfaces/governance/IVeBoostProxy.sol\";\n\n/// @title VaultManagerStorage\n/// @author Angle Labs, Inc.\n/// @dev Variables, references, parameters and events needed in the `VaultManager` contract\n// solhint-disable-next-line max-states-count\ncontract VaultManagerStorage is IVaultManagerStorage, Initializable, ReentrancyGuardUpgradeable {\n /// @notice Base used for parameter computation: almost all the parameters of this contract are set in `BASE_PARAMS`\n uint256 public constant BASE_PARAMS = 10**9;\n /// @notice Base used for interest rate computation\n uint256 public constant BASE_INTEREST = 10**27;\n /// @notice Used for interest rate computation\n uint256 public constant HALF_BASE_INTEREST = 10**27 / 2;\n\n // ================================= REFERENCES ================================\n\n /// @inheritdoc IVaultManagerStorage\n ITreasury public treasury;\n /// @inheritdoc IVaultManagerStorage\n IERC20 public collateral;\n /// @inheritdoc IVaultManagerStorage\n IAgToken public stablecoin;\n /// @inheritdoc IVaultManagerStorage\n IOracle public oracle;\n /// @notice Reference to the contract which computes adjusted veANGLE balances for liquidators boosts\n IVeBoostProxy public veBoostProxy;\n /// @notice Base of the collateral\n uint256 internal _collatBase;\n\n // ================================= PARAMETERS ================================\n // Unless specified otherwise, parameters of this contract are expressed in `BASE_PARAMS`\n\n /// @notice Maximum amount of stablecoins that can be issued with this contract (in `BASE_TOKENS`). This parameter should\n /// not be bigger than `type(uint256).max / BASE_INTEREST` otherwise there may be some overflows in the `increaseDebt` function\n uint256 public debtCeiling;\n /// @notice Threshold veANGLE balance values for the computation of the boost for liquidators: the length of this array\n /// should normally be 2. The base of the x-values in this array should be `BASE_TOKENS`\n uint256[] public xLiquidationBoost;\n /// @notice Values of the liquidation boost at the threshold values of x\n uint256[] public yLiquidationBoost;\n /// @inheritdoc IVaultManagerStorage\n uint64 public collateralFactor;\n /// @notice Maximum Health factor at which a vault can end up after a liquidation (unless it's fully liquidated)\n uint64 public targetHealthFactor;\n /// @notice Upfront fee taken when borrowing stablecoins: this fee is optional and should in practice not be used\n uint64 public borrowFee;\n /// @notice Upfront fee taken when repaying stablecoins: this fee is optional as well. It should be smaller\n /// than the liquidation surcharge (cf below) to avoid exploits where people voluntarily get liquidated at a 0\n /// discount to pay smaller repaying fees\n uint64 public repayFee;\n /// @notice Per second interest taken to borrowers taking agToken loans. Contrarily to other parameters, it is set in `BASE_INTEREST`\n /// that is to say in base 10**27\n uint64 public interestRate;\n /// @notice Fee taken by the protocol during a liquidation. Technically, this value is not the fee per se, it's 1 - fee.\n /// For instance for a 2% fee, `liquidationSurcharge` should be 98%\n uint64 public liquidationSurcharge;\n /// @notice Maximum discount given to liquidators\n uint64 public maxLiquidationDiscount;\n /// @notice Whether whitelisting is required to own a vault or not\n bool public whitelistingActivated;\n /// @notice Whether the contract is paused or not\n bool public paused;\n\n // ================================= VARIABLES =================================\n\n /// @notice Timestamp at which the `interestAccumulator` was updated\n uint256 public lastInterestAccumulatorUpdated;\n /// @inheritdoc IVaultManagerStorage\n uint256 public interestAccumulator;\n /// @inheritdoc IVaultManagerStorage\n uint256 public totalNormalizedDebt;\n /// @notice Surplus accumulated by the contract: surplus is always in stablecoins, and is then reset\n /// when the value is communicated to the treasury contract\n uint256 public surplus;\n /// @notice Bad debt made from liquidated vaults which ended up having no collateral and a positive amount\n /// of stablecoins\n uint256 public badDebt;\n\n // ================================== MAPPINGS =================================\n\n /// @inheritdoc IVaultManagerStorage\n mapping(uint256 => Vault) public vaultData;\n /// @notice Maps an address to 1 if it's whitelisted and can open or own a vault\n mapping(address => uint256) public isWhitelisted;\n\n // ================================ ERC721 DATA ================================\n\n /// @inheritdoc IVaultManagerStorage\n uint256 public vaultIDCount;\n\n /// @notice URI\n string internal _baseURI;\n\n // Mapping from `vaultID` to owner address\n mapping(uint256 => address) internal _owners;\n\n // Mapping from owner address to vault owned count\n mapping(address => uint256) internal _balances;\n\n // Mapping from `vaultID` to approved address\n mapping(uint256 => address) internal _vaultApprovals;\n\n // Mapping from owner to operator approvals\n mapping(address => mapping(address => uint256)) internal _operatorApprovals;\n\n uint256[50] private __gap;\n\n // =================================== EVENTS ==================================\n\n event AccruedToTreasury(uint256 surplusEndValue, uint256 badDebtEndValue);\n event CollateralAmountUpdated(uint256 vaultID, uint256 collateralAmount, uint8 isIncrease);\n event InterestAccumulatorUpdated(uint256 value, uint256 timestamp);\n event InternalDebtUpdated(uint256 vaultID, uint256 internalAmount, uint8 isIncrease);\n event FiledUint64(uint64 param, bytes32 what);\n event DebtCeilingUpdated(uint256 debtCeiling);\n event LiquidationBoostParametersUpdated(address indexed _veBoostProxy, uint256[] xBoost, uint256[] yBoost);\n event LiquidatedVaults(uint256[] vaultIDs);\n event DebtTransferred(uint256 srcVaultID, uint256 dstVaultID, address dstVaultManager, uint256 amount);\n\n // =================================== ERRORS ==================================\n\n error ApprovalToOwner();\n error ApprovalToCaller();\n error DustyLeftoverAmount();\n error DebtCeilingExceeded();\n error HealthyVault();\n error IncompatibleLengths();\n error InsolventVault();\n error InvalidParameterValue();\n error InvalidParameterType();\n error InvalidSetOfParameters();\n error InvalidTreasury();\n error NonERC721Receiver();\n error NonexistentVault();\n error NotApproved();\n error NotGovernor();\n error NotGovernorOrGuardian();\n error NotTreasury();\n error NotWhitelisted();\n error NotVaultManager();\n error Paused();\n error TooHighParameterValue();\n error TooSmallParameterValue();\n error ZeroAddress();\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() initializer {}\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20PermitUpgradeable {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721ReceiverUpgradeable {\n /**\n * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n * by `operator` from `from`, this function is called.\n *\n * It must return its Solidity selector to confirm the token transfer.\n * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.\n *\n * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.\n */\n function onERC721Received(\n address operator,\n address from,\n uint256 tokenId,\n bytes calldata data\n ) external returns (bytes4);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/interfaces/IERC721MetadataUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../token/ERC721/extensions/IERC721MetadataUpgradeable.sol\";\n" + }, + "@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165Upgradeable {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n function __ReentrancyGuard_init() internal onlyInitializing {\n __ReentrancyGuard_init_unchained();\n }\n\n function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n // On the first call to nonReentrant, _notEntered will be true\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n\n _;\n\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "contracts/interfaces/IAgToken.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\n\n/// @title IAgToken\n/// @author Angle Labs, Inc.\n/// @notice Interface for the stablecoins `AgToken` contracts\n/// @dev This interface only contains functions of the `AgToken` contract which are called by other contracts\n/// of this module or of the first module of the Angle Protocol\ninterface IAgToken is IERC20Upgradeable {\n // ======================= Minter Role Only Functions ===========================\n\n /// @notice Lets the `StableMaster` contract or another whitelisted contract mint agTokens\n /// @param account Address to mint to\n /// @param amount Amount to mint\n /// @dev The contracts allowed to issue agTokens are the `StableMaster` contract, `VaultManager` contracts\n /// associated to this stablecoin as well as the flash loan module (if activated) and potentially contracts\n /// whitelisted by governance\n function mint(address account, uint256 amount) external;\n\n /// @notice Burns `amount` tokens from a `burner` address after being asked to by `sender`\n /// @param amount Amount of tokens to burn\n /// @param burner Address to burn from\n /// @param sender Address which requested the burn from `burner`\n /// @dev This method is to be called by a contract with the minter right after being requested\n /// to do so by a `sender` address willing to burn tokens from another `burner` address\n /// @dev The method checks the allowance between the `sender` and the `burner`\n function burnFrom(\n uint256 amount,\n address burner,\n address sender\n ) external;\n\n /// @notice Burns `amount` tokens from a `burner` address\n /// @param amount Amount of tokens to burn\n /// @param burner Address to burn from\n /// @dev This method is to be called by a contract with a minter right on the AgToken after being\n /// requested to do so by an address willing to burn tokens from its address\n function burnSelf(uint256 amount, address burner) external;\n\n // ========================= Treasury Only Functions ===========================\n\n /// @notice Adds a minter in the contract\n /// @param minter Minter address to add\n /// @dev Zero address checks are performed directly in the `Treasury` contract\n function addMinter(address minter) external;\n\n /// @notice Removes a minter from the contract\n /// @param minter Minter address to remove\n /// @dev This function can also be called by a minter wishing to revoke itself\n function removeMinter(address minter) external;\n\n /// @notice Sets a new treasury contract\n /// @param _treasury New treasury address\n function setTreasury(address _treasury) external;\n\n // ========================= External functions ================================\n\n /// @notice Checks whether an address has the right to mint agTokens\n /// @param minter Address for which the minting right should be checked\n /// @return Whether the address has the right to mint agTokens or not\n function isMinter(address minter) external view returns (bool);\n\n /// @notice Get the associated treasury\n function treasury() external view returns (address);\n}\n" + }, + "contracts/interfaces/IOracle.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"./ITreasury.sol\";\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\n/// @title IOracle\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `Oracle` contract\n/// @dev This interface only contains functions of the contract which are called by other contracts\n/// of this module\ninterface IOracle {\n /// @notice Reads the rate from the Chainlink circuit and other data provided\n /// @return quoteAmount The current rate between the in-currency and out-currency in the base\n /// of the out currency\n /// @dev For instance if the out currency is EUR (and hence agEUR), then the base of the returned\n /// value is 10**18\n function read() external view returns (uint256);\n\n /// @notice Changes the treasury contract\n /// @param _treasury Address of the new treasury contract\n /// @dev This function can be called by an approved `VaultManager` contract which can call\n /// this function after being requested to do so by a `treasury` contract\n /// @dev In some situations (like reactor contracts), the `VaultManager` may not directly be linked\n /// to the `oracle` contract and as such we may need governors to be able to call this function as well\n function setTreasury(address _treasury) external;\n\n /// @notice Reference to the `treasury` contract handling this `VaultManager`\n function treasury() external view returns (ITreasury treasury);\n\n /// @notice Array with the list of Chainlink feeds in the order in which they are read\n function circuitChainlink() external view returns (AggregatorV3Interface[] memory);\n}\n" + }, + "contracts/interfaces/ISwapper.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/// @title ISwapper\n/// @author Angle Labs, Inc.\n/// @notice Interface for Swapper contracts\n/// @dev This interface defines the key functions `Swapper` contracts should have when interacting with\n/// Angle\ninterface ISwapper {\n /// @notice Notifies a contract that an address should be given `outToken` from `inToken`\n /// @param inToken Address of the token received\n /// @param outToken Address of the token to obtain\n /// @param outTokenRecipient Address to which the outToken should be sent\n /// @param outTokenOwed Minimum amount of outToken the `outTokenRecipient` address should have at the end of the call\n /// @param inTokenObtained Amount of collateral obtained by a related address prior\n /// to the call to this function\n /// @param data Extra data needed (to encode Uniswap swaps for instance)\n function swap(\n IERC20 inToken,\n IERC20 outToken,\n address outTokenRecipient,\n uint256 outTokenOwed,\n uint256 inTokenObtained,\n bytes calldata data\n ) external;\n}\n" + }, + "contracts/interfaces/ITreasury.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"./IAgToken.sol\";\nimport \"./ICoreBorrow.sol\";\nimport \"./IFlashAngle.sol\";\n\n/// @title ITreasury\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `Treasury` contract\n/// @dev This interface only contains functions of the `Treasury` which are called by other contracts\n/// of this module\ninterface ITreasury {\n /// @notice Stablecoin handled by this `treasury` contract\n function stablecoin() external view returns (IAgToken);\n\n /// @notice Checks whether a given address has the governor role\n /// @param admin Address to check\n /// @return Whether the address has the governor role\n /// @dev Access control is only kept in the `CoreBorrow` contract\n function isGovernor(address admin) external view returns (bool);\n\n /// @notice Checks whether a given address has the guardian or the governor role\n /// @param admin Address to check\n /// @return Whether the address has the guardian or the governor role\n /// @dev Access control is only kept in the `CoreBorrow` contract which means that this function\n /// queries the `CoreBorrow` contract\n function isGovernorOrGuardian(address admin) external view returns (bool);\n\n /// @notice Checks whether a given address has well been initialized in this contract\n /// as a `VaultManager`\n /// @param _vaultManager Address to check\n /// @return Whether the address has been initialized or not\n function isVaultManager(address _vaultManager) external view returns (bool);\n\n /// @notice Sets a new flash loan module for this stablecoin\n /// @param _flashLoanModule Reference to the new flash loan module\n /// @dev This function removes the minting right to the old flash loan module and grants\n /// it to the new module\n function setFlashLoanModule(address _flashLoanModule) external;\n}\n" + }, + "contracts/interfaces/IVaultManager.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts/interfaces/IERC721Metadata.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./ITreasury.sol\";\nimport \"./IOracle.sol\";\n\n// ========================= Key Structs and Enums =============================\n\n/// @notice Parameters associated to a given `VaultManager` contract: these all correspond\n/// to parameters which signification is detailed in the `VaultManagerStorage` file\nstruct VaultParameters {\n uint256 debtCeiling;\n uint64 collateralFactor;\n uint64 targetHealthFactor;\n uint64 interestRate;\n uint64 liquidationSurcharge;\n uint64 maxLiquidationDiscount;\n bool whitelistingActivated;\n uint256 baseBoost;\n}\n\n/// @notice Data stored to track someone's loan (or equivalently called position)\nstruct Vault {\n // Amount of collateral deposited in the vault, in collateral decimals. For example, if the collateral\n // is USDC with 6 decimals, then `collateralAmount` will be in base 10**6\n uint256 collateralAmount;\n // Normalized value of the debt (that is to say of the stablecoins borrowed). It is expressed\n // in the base of Angle stablecoins (i.e. `BASE_TOKENS = 10**18`)\n uint256 normalizedDebt;\n}\n\n/// @notice For a given `vaultID`, this encodes a liquidation opportunity that is to say details about the maximum\n/// amount that could be repaid by liquidating the position\n/// @dev All the values are null in the case of a vault which cannot be liquidated under these conditions\nstruct LiquidationOpportunity {\n // Maximum stablecoin amount that can be repaid upon liquidating the vault\n uint256 maxStablecoinAmountToRepay;\n // Collateral amount given to the person in the case where the maximum amount to repay is given\n uint256 maxCollateralAmountGiven;\n // Threshold value of stablecoin amount to repay: it is ok for a liquidator to repay below threshold,\n // but if this threshold is non null and the liquidator wants to repay more than threshold, it should repay\n // the max stablecoin amount given in this vault\n uint256 thresholdRepayAmount;\n // Discount proposed to the liquidator on the collateral\n uint256 discount;\n // Amount of debt in the vault\n uint256 currentDebt;\n}\n\n/// @notice Data stored during a liquidation process to keep in memory what's due to a liquidator and some\n/// essential data for vaults being liquidated\nstruct LiquidatorData {\n // Current amount of stablecoins the liquidator should give to the contract\n uint256 stablecoinAmountToReceive;\n // Current amount of collateral the contract should give to the liquidator\n uint256 collateralAmountToGive;\n // Bad debt accrued across the liquidation process\n uint256 badDebtFromLiquidation;\n // Oracle value (in stablecoin base) at the time of the liquidation\n uint256 oracleValue;\n // Value of the `interestAccumulator` at the time of the call\n uint256 newInterestAccumulator;\n}\n\n/// @notice Data to track during a series of action the amount to give or receive in stablecoins and collateral\n/// to the caller or associated addresses\nstruct PaymentData {\n // Stablecoin amount the contract should give\n uint256 stablecoinAmountToGive;\n // Stablecoin amount owed to the contract\n uint256 stablecoinAmountToReceive;\n // Collateral amount the contract should give\n uint256 collateralAmountToGive;\n // Collateral amount owed to the contract\n uint256 collateralAmountToReceive;\n}\n\n/// @notice Actions possible when composing calls to the different entry functions proposed\nenum ActionType {\n createVault,\n closeVault,\n addCollateral,\n removeCollateral,\n repayDebt,\n borrow,\n getDebtIn,\n permit\n}\n\n// ========================= Interfaces =============================\n\n/// @title IVaultManagerFunctions\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `VaultManager` contract\n/// @dev This interface only contains functions of the contract which are called by other contracts\n/// of this module (without getters)\ninterface IVaultManagerFunctions {\n /// @notice Accrues interest accumulated across all vaults to the surplus and sends the surplus to the treasury\n /// @return surplusValue Value of the surplus communicated to the `Treasury`\n /// @return badDebtValue Value of the bad debt communicated to the `Treasury`\n /// @dev `surplus` and `badDebt` should be reset to 0 once their current value have been given to the `treasury` contract\n function accrueInterestToTreasury() external returns (uint256 surplusValue, uint256 badDebtValue);\n\n /// @notice Removes debt from a vault after being requested to do so by another `VaultManager` contract\n /// @param vaultID ID of the vault to remove debt from\n /// @param amountStablecoins Amount of stablecoins to remove from the debt: this amount is to be converted to an\n /// internal debt amount\n /// @param senderBorrowFee Borrowing fees from the contract which requested this: this is to make sure that people are not\n /// arbitraging difference in minting fees\n /// @param senderRepayFee Repay fees from the contract which requested this: this is to make sure that people are not arbitraging\n /// differences in repay fees\n /// @dev This function can only be called from a vaultManager registered in the same Treasury\n function getDebtOut(\n uint256 vaultID,\n uint256 amountStablecoins,\n uint256 senderBorrowFee,\n uint256 senderRepayFee\n ) external;\n\n /// @notice Gets the current debt of a vault\n /// @param vaultID ID of the vault to check\n /// @return Debt of the vault\n function getVaultDebt(uint256 vaultID) external view returns (uint256);\n\n /// @notice Gets the total debt across all vaults\n /// @return Total debt across all vaults, taking into account the interest accumulated\n /// over time\n function getTotalDebt() external view returns (uint256);\n\n /// @notice Sets the treasury contract\n /// @param _treasury New treasury contract\n /// @dev All required checks when setting up a treasury contract are performed in the contract\n /// calling this function\n function setTreasury(address _treasury) external;\n\n /// @notice Creates a vault\n /// @param toVault Address for which the va\n /// @return vaultID ID of the vault created\n /// @dev This function just creates the vault without doing any collateral or\n function createVault(address toVault) external returns (uint256);\n\n /// @notice Allows composability between calls to the different entry points of this module. Any user calling\n /// this function can perform any of the allowed actions in the order of their choice\n /// @param actions Set of actions to perform\n /// @param datas Data to be decoded for each action: it can include like the `vaultID` or the `stablecoinAmount` to borrow\n /// @param from Address from which stablecoins will be taken if one action includes burning stablecoins. This address\n /// should either be the `msg.sender` or be approved by the latter\n /// @param to Address to which stablecoins and/or collateral will be sent in case of\n /// @param who Address of the contract to handle in case of repayment of stablecoins from received collateral\n /// @param repayData Data to pass to the repayment contract in case of\n /// @return paymentData Struct containing the accounting changes from the protocol's perspective (like how much of collateral\n /// or how much has been received). Note that the values in the struct are not aggregated and you could have in the output\n /// a positive amount of stablecoins to receive as well as a positive amount of stablecoins to give\n /// @dev This function is optimized to reduce gas cost due to payment from or to the user and that expensive calls\n /// or computations (like `oracleValue`) are done only once\n /// @dev When specifying `vaultID` in `data`, it is important to know that if you specify `vaultID = 0`, it will simply\n /// use the latest `vaultID`. This is the default behavior, and unless you're engaging into some complex protocol actions\n /// it is encouraged to use `vaultID = 0` only when the first action of the batch is `createVault`\n function angle(\n ActionType[] memory actions,\n bytes[] memory datas,\n address from,\n address to,\n address who,\n bytes memory repayData\n ) external returns (PaymentData memory paymentData);\n\n /// @notice This function is a wrapper built on top of the function above. It enables users to interact with the contract\n /// without having to provide `who` and `repayData` parameters\n function angle(\n ActionType[] memory actions,\n bytes[] memory datas,\n address from,\n address to\n ) external returns (PaymentData memory paymentData);\n\n /// @notice Initializes the `VaultManager` contract\n /// @param _treasury Treasury address handling the contract\n /// @param _collateral Collateral supported by this contract\n /// @param _oracle Oracle contract used\n /// @param _symbol Symbol used to define the `VaultManager` name and symbol\n /// @dev The parameters and the oracle are the only elements which could be modified once the\n /// contract has been initialized\n /// @dev For the contract to be fully initialized, governance needs to set the parameters for the liquidation\n /// boost\n function initialize(\n ITreasury _treasury,\n IERC20 _collateral,\n IOracle _oracle,\n VaultParameters calldata params,\n string memory _symbol\n ) external;\n\n /// @notice Minimum amount of debt a vault can have, expressed in `BASE_TOKENS` that is to say the base of the agTokens\n function dust() external view returns (uint256);\n}\n\n/// @title IVaultManagerStorage\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `VaultManager` contract\n/// @dev This interface contains getters of the contract's public variables used by other contracts\n/// of this module\ninterface IVaultManagerStorage {\n /// @notice Encodes the maximum ratio stablecoin/collateral a vault can have before being liquidated. It's what\n /// determines the minimum collateral ratio of a position\n function collateralFactor() external view returns (uint64);\n\n /// @notice Stablecoin handled by this contract. Another `VaultManager` contract could have\n /// the same rights as this `VaultManager` on the stablecoin contract\n function stablecoin() external view returns (IAgToken);\n\n /// @notice Reference to the `treasury` contract handling this `VaultManager`\n function treasury() external view returns (ITreasury);\n\n /// @notice Oracle contract to get access to the price of the collateral with respect to the stablecoin\n function oracle() external view returns (IOracle);\n\n /// @notice The `interestAccumulator` variable keeps track of the interest that should accrue to the protocol.\n /// The stored value is not necessarily the true value: this one is recomputed every time an action takes place\n /// within the protocol. It is in base `BASE_INTEREST`\n function interestAccumulator() external view returns (uint256);\n\n /// @notice Reference to the collateral handled by this `VaultManager`\n function collateral() external view returns (IERC20);\n\n /// @notice Total normalized amount of stablecoins borrowed, not taking into account the potential bad debt accumulated\n /// This value is expressed in the base of Angle stablecoins (`BASE_TOKENS = 10**18`)\n function totalNormalizedDebt() external view returns (uint256);\n\n /// @notice Maximum amount of stablecoins that can be issued with this contract. It is expressed in `BASE_TOKENS`\n function debtCeiling() external view returns (uint256);\n\n /// @notice Maps a `vaultID` to its data (namely collateral amount and normalized debt)\n function vaultData(uint256 vaultID) external view returns (uint256 collateralAmount, uint256 normalizedDebt);\n\n /// @notice ID of the last vault created. The `vaultIDCount` variables serves as a counter to generate a unique\n /// `vaultID` for each vault: it is like `tokenID` in basic ERC721 contracts\n function vaultIDCount() external view returns (uint256);\n}\n\n/// @title IVaultManager\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `VaultManager` contract\ninterface IVaultManager is IVaultManagerFunctions, IVaultManagerStorage, IERC721Metadata {\n function isApprovedOrOwner(address spender, uint256 vaultID) external view returns (bool);\n}\n\n/// @title IVaultManagerListing\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `VaultManagerListing` contract\ninterface IVaultManagerListing is IVaultManager {\n /// @notice Get the collateral owned by `user` in the contract\n /// @dev This function effectively sums the collateral amounts of all the vaults owned by `user`\n function getUserCollateral(address user) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/governance/IVeBoostProxy.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\n/// @title IVeBoostProxy\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `VeBoostProxy` contract\n/// @dev This interface only contains functions of the contract which are called by other contracts\n/// of this module\n/// @dev The `veBoostProxy` contract used by Angle is a full fork of Curve Finance implementation\ninterface IVeBoostProxy {\n /// @notice Reads the adjusted veANGLE balance of an address (adjusted by delegation)\n //solhint-disable-next-line\n function adjusted_balance_of(address) external view returns (uint256);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/IERC721MetadataUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721Upgradeable.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721MetadataUpgradeable is IERC721Upgradeable {\n /**\n * @dev Returns the token collection name.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the token collection symbol.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n */\n function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165Upgradeable.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721Upgradeable is IERC165Upgradeable {\n /**\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n */\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n */\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n */\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /**\n * @dev Returns the number of tokens in ``owner``'s account.\n */\n function balanceOf(address owner) external view returns (uint256 balance);\n\n /**\n * @dev Returns the owner of the `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes calldata data\n ) external;\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Transfers `tokenId` token from `from` to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n * The approval is cleared when the token is transferred.\n *\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n *\n * Requirements:\n *\n * - The caller must own the token or be an approved operator.\n * - `tokenId` must exist.\n *\n * Emits an {Approval} event.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev Approve or remove `operator` as an operator for the caller.\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n *\n * Requirements:\n *\n * - The `operator` cannot be the caller.\n *\n * Emits an {ApprovalForAll} event.\n */\n function setApprovalForAll(address operator, bool _approved) external;\n\n /**\n * @dev Returns the account approved for `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function getApproved(uint256 tokenId) external view returns (address operator);\n\n /**\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n *\n * See {setApprovalForAll}\n */\n function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n" + }, + "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n\n function decimals()\n external\n view\n returns (\n uint8\n );\n\n function description()\n external\n view\n returns (\n string memory\n );\n\n function version()\n external\n view\n returns (\n uint256\n );\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(\n uint80 _roundId\n )\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n}\n" + }, + "contracts/interfaces/IFlashAngle.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"./IAgToken.sol\";\nimport \"./ICoreBorrow.sol\";\n\n/// @title IFlashAngle\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `FlashAngle` contract\n/// @dev This interface only contains functions of the contract which are called by other contracts\n/// of this module\ninterface IFlashAngle {\n /// @notice Reference to the `CoreBorrow` contract managing the FlashLoan module\n function core() external view returns (ICoreBorrow);\n\n /// @notice Sends the fees taken from flash loans to the treasury contract associated to the stablecoin\n /// @param stablecoin Stablecoin from which profits should be sent\n /// @return balance Amount of profits sent\n /// @dev This function can only be called by the treasury contract\n function accrueInterestToTreasury(IAgToken stablecoin) external returns (uint256 balance);\n\n /// @notice Adds support for a stablecoin\n /// @param _treasury Treasury associated to the stablecoin to add support for\n /// @dev This function can only be called by the `CoreBorrow` contract\n function addStablecoinSupport(address _treasury) external;\n\n /// @notice Removes support for a stablecoin\n /// @param _treasury Treasury associated to the stablecoin to remove support for\n /// @dev This function can only be called by the `CoreBorrow` contract\n function removeStablecoinSupport(address _treasury) external;\n\n /// @notice Sets a new core contract\n /// @param _core Core contract address to set\n /// @dev This function can only be called by the `CoreBorrow` contract\n function setCore(address _core) external;\n}\n" + }, + "@openzeppelin/contracts/interfaces/IERC721Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../token/ERC721/extensions/IERC721Metadata.sol\";\n" + }, + "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721Metadata is IERC721 {\n /**\n * @dev Returns the token collection name.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the token collection symbol.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n */\n function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/IERC721.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n /**\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n */\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n */\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n */\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /**\n * @dev Returns the number of tokens in ``owner``'s account.\n */\n function balanceOf(address owner) external view returns (uint256 balance);\n\n /**\n * @dev Returns the owner of the `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes calldata data\n ) external;\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Transfers `tokenId` token from `from` to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n * The approval is cleared when the token is transferred.\n *\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n *\n * Requirements:\n *\n * - The caller must own the token or be an approved operator.\n * - `tokenId` must exist.\n *\n * Emits an {Approval} event.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev Approve or remove `operator` as an operator for the caller.\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n *\n * Requirements:\n *\n * - The `operator` cannot be the caller.\n *\n * Emits an {ApprovalForAll} event.\n */\n function setApprovalForAll(address operator, bool _approved) external;\n\n /**\n * @dev Returns the account approved for `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function getApproved(uint256 tokenId) external view returns (address operator);\n\n /**\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n *\n * See {setApprovalForAll}\n */\n function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "contracts/mock/MockVeBoostProxy.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"../interfaces/governance/IVeBoostProxy.sol\";\n\ncontract MockVeBoostProxy is IVeBoostProxy {\n //solhint-disable-next-line\n mapping(address => uint256) public adjusted_balance_of;\n\n constructor() {}\n\n function setBalance(address concerned, uint256 balance) external {\n adjusted_balance_of[concerned] = balance;\n }\n}\n" + }, + "contracts/deprecated/vaultManager/OldVaultManagerStorage.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/interfaces/IERC721MetadataUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport \"../../interfaces/IAgToken.sol\";\nimport \"../../interfaces/IOracle.sol\";\nimport \"../../interfaces/ISwapper.sol\";\nimport \"../../interfaces/ITreasury.sol\";\nimport \"../../interfaces/IVaultManager.sol\";\nimport \"../../interfaces/governance/IVeBoostProxy.sol\";\n\n/// @title VaultManagerStorage\n/// @author Angle Labs, Inc.\n/// @dev Variables, references, parameters and events needed in the `VaultManager` contract\n// solhint-disable-next-line max-states-count\ncontract OldVaultManagerStorage is IVaultManagerStorage, Initializable, ReentrancyGuardUpgradeable {\n /// @notice Base used for parameter computation: almost all the parameters of this contract are set in `BASE_PARAMS`\n uint256 public constant BASE_PARAMS = 10**9;\n /// @notice Base used for interest rate computation\n uint256 public constant BASE_INTEREST = 10**27;\n /// @notice Used for interest rate computation\n uint256 public constant HALF_BASE_INTEREST = 10**27 / 2;\n\n // ================================= REFERENCES ================================\n\n /// @inheritdoc IVaultManagerStorage\n ITreasury public treasury;\n /// @inheritdoc IVaultManagerStorage\n IERC20 public collateral;\n /// @inheritdoc IVaultManagerStorage\n IAgToken public stablecoin;\n /// @inheritdoc IVaultManagerStorage\n IOracle public oracle;\n /// @notice Reference to the contract which computes adjusted veANGLE balances for liquidators boosts\n IVeBoostProxy public veBoostProxy;\n /// @notice Base of the collateral\n uint256 internal _collatBase;\n\n // ================================= PARAMETERS ================================\n // Unless specified otherwise, parameters of this contract are expressed in `BASE_PARAMS`\n\n /// @notice Maximum amount of stablecoins that can be issued with this contract (in `BASE_TOKENS`). This parameter should\n /// not be bigger than `type(uint256).max / BASE_INTEREST` otherwise there may be some overflows in the `increaseDebt` function\n uint256 public debtCeiling;\n /// @notice Threshold veANGLE balance values for the computation of the boost for liquidators: the length of this array\n /// should normally be 2. The base of the x-values in this array should be `BASE_TOKENS`\n uint256[] public xLiquidationBoost;\n /// @notice Values of the liquidation boost at the threshold values of x\n uint256[] public yLiquidationBoost;\n /// @inheritdoc IVaultManagerStorage\n uint64 public collateralFactor;\n /// @notice Maximum Health factor at which a vault can end up after a liquidation (unless it's fully liquidated)\n uint64 public targetHealthFactor;\n /// @notice Upfront fee taken when borrowing stablecoins: this fee is optional and should in practice not be used\n uint64 public borrowFee;\n /// @notice Upfront fee taken when repaying stablecoins: this fee is optional as well. It should be smaller\n /// than the liquidation surcharge (cf below) to avoid exploits where people voluntarily get liquidated at a 0\n /// discount to pay smaller repaying fees\n uint64 public repayFee;\n /// @notice Per second interest taken to borrowers taking agToken loans. Contrarily to other parameters, it is set in `BASE_INTEREST`\n /// that is to say in base 10**27\n uint64 public interestRate;\n /// @notice Fee taken by the protocol during a liquidation. Technically, this value is not the fee per se, it's 1 - fee.\n /// For instance for a 2% fee, `liquidationSurcharge` should be 98%\n uint64 public liquidationSurcharge;\n /// @notice Maximum discount given to liquidators\n uint64 public maxLiquidationDiscount;\n /// @notice Whether whitelisting is required to own a vault or not\n bool public whitelistingActivated;\n /// @notice Whether the contract is paused or not\n bool public paused;\n\n // ================================= VARIABLES =================================\n\n /// @notice Timestamp at which the `interestAccumulator` was updated\n uint256 public lastInterestAccumulatorUpdated;\n /// @inheritdoc IVaultManagerStorage\n uint256 public interestAccumulator;\n /// @inheritdoc IVaultManagerStorage\n uint256 public totalNormalizedDebt;\n /// @notice Surplus accumulated by the contract: surplus is always in stablecoins, and is then reset\n /// when the value is communicated to the treasury contract\n uint256 public surplus;\n /// @notice Bad debt made from liquidated vaults which ended up having no collateral and a positive amount\n /// of stablecoins\n uint256 public badDebt;\n\n // ================================== MAPPINGS =================================\n\n /// @inheritdoc IVaultManagerStorage\n mapping(uint256 => Vault) public vaultData;\n /// @notice Maps an address to 1 if it's whitelisted and can open or own a vault\n mapping(address => uint256) public isWhitelisted;\n\n // ================================ ERC721 DATA ================================\n\n /// @inheritdoc IVaultManagerStorage\n uint256 public vaultIDCount;\n\n /// @notice URI\n string internal _baseURI;\n\n // Mapping from `vaultID` to owner address\n mapping(uint256 => address) internal _owners;\n\n // Mapping from owner address to vault owned count\n mapping(address => uint256) internal _balances;\n\n // Mapping from `vaultID` to approved address\n mapping(uint256 => address) internal _vaultApprovals;\n\n // Mapping from owner to operator approvals\n mapping(address => mapping(address => uint256)) internal _operatorApprovals;\n\n uint256[50] private __gap;\n\n // =================================== EVENTS ==================================\n\n event AccruedToTreasury(uint256 surplusEndValue, uint256 badDebtEndValue);\n event CollateralAmountUpdated(uint256 vaultID, uint256 collateralAmount, uint8 isIncrease);\n event InterestAccumulatorUpdated(uint256 value, uint256 timestamp);\n event InternalDebtUpdated(uint256 vaultID, uint256 internalAmount, uint8 isIncrease);\n event FiledUint64(uint64 param, bytes32 what);\n event DebtCeilingUpdated(uint256 debtCeiling);\n event LiquidationBoostParametersUpdated(address indexed _veBoostProxy, uint256[] xBoost, uint256[] yBoost);\n event LiquidatedVaults(uint256[] vaultIDs);\n event DebtTransferred(uint256 srcVaultID, uint256 dstVaultID, address dstVaultManager, uint256 amount);\n\n // =================================== ERRORS ==================================\n\n error ApprovalToOwner();\n error ApprovalToCaller();\n error DustyLeftoverAmount();\n error DebtCeilingExceeded();\n error HealthyVault();\n error IncompatibleLengths();\n error InsolventVault();\n error InvalidParameterValue();\n error InvalidParameterType();\n error InvalidSetOfParameters();\n error InvalidTreasury();\n error NonERC721Receiver();\n error NonexistentVault();\n error NotApproved();\n error NotGovernor();\n error NotGovernorOrGuardian();\n error NotTreasury();\n error NotWhitelisted();\n error NotVaultManager();\n error Paused();\n error TooHighParameterValue();\n error TooSmallParameterValue();\n error ZeroAddress();\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() initializer {}\n}\n" + }, + "contracts/ui-helpers/AngleBorrowHelpers.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n * █ \n ***** ▓▓▓ \n * ▓▓▓▓▓▓▓ \n * ///. ▓▓▓▓▓▓▓▓▓▓▓▓▓ \n ***** //////// ▓▓▓▓▓▓▓ \n * ///////////// ▓▓▓ \n ▓▓ ////////////////// █ ▓▓ \n ▓▓ ▓▓ /////////////////////// ▓▓ ▓▓ \n ▓▓ ▓▓ //////////////////////////// ▓▓ ▓▓ \n ▓▓ ▓▓ /////////▓▓▓///////▓▓▓///////// ▓▓ ▓▓ \n ▓▓ ,////////////////////////////////////// ▓▓ ▓▓ \n ▓▓ ////////////////////////////////////////// ▓▓ \n ▓▓ //////////////////////▓▓▓▓///////////////////// \n ,//////////////////////////////////////////////////// \n .////////////////////////////////////////////////////////// \n .//////////////////////////██.,//////////////////////////█ \n .//////////////////////████..,./////////////////////██ \n ...////////////////███████.....,.////////////////███ \n ,.,////////////████████ ........,///////////████ \n .,.,//////█████████ ,.......///////████ \n ,..//████████ ........./████ \n ..,██████ .....,███ \n .██ ,.,█ \n \n \n \n ▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓ \n ▓▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓ ▓▓▓▓ \n ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓▓▓▓ \n ▓▓▓ ▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ \n*/\n\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"../interfaces/IVaultManager.sol\";\n\npragma solidity ^0.8.12;\n\n/// @title AngleBorrowHelpers\n/// @author Angle Labs, Inc.\n/// @notice Contract with view functions designed to facilitate integrations on the Borrow module of the Angle Protocol\n/// @dev This contract only contains view functions to be queried off-chain. It was thus not optimized for gas consumption\ncontract AngleBorrowHelpers is Initializable {\n /// @notice Returns all the vaults owned or controlled (under the form of approval) by an address\n /// @param vaultManager VaultManager address to query vaultIDs on\n /// @param spender Address for which vault ownerships should be checked\n /// @return List of `vaultID` controlled by this address\n /// @return Count of vaults owned by the address\n /// @dev This function is never to be called on-chain since it iterates over all vaultIDs. It is here\n /// to reduce dependency on an external graph to link an ID to its owner\n function getControlledVaults(IVaultManager vaultManager, address spender)\n external\n view\n returns (uint256[] memory, uint256)\n {\n uint256 arraySize = vaultManager.vaultIDCount();\n uint256[] memory vaultsControlled = new uint256[](arraySize);\n uint256 count;\n for (uint256 i = 1; i <= arraySize; ++i) {\n try vaultManager.isApprovedOrOwner(spender, i) returns (bool _isApprovedOrOwner) {\n if (_isApprovedOrOwner) {\n vaultsControlled[count] = i;\n count += 1;\n }\n } catch {\n continue;\n } // This happens if nobody owns the vaultID=i (if there has been a burn)\n }\n return (vaultsControlled, count);\n }\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() initializer {}\n}\n" + }, + "contracts/ui-helpers/AngleHelpers.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\nimport \"../interfaces/IAngleRouter.sol\";\nimport \"../interfaces/coreModule/IAgTokenMainnet.sol\";\nimport \"../interfaces/coreModule/ICore.sol\";\nimport \"../interfaces/coreModule/IOracleCore.sol\";\nimport \"../interfaces/coreModule/IPerpetualManager.sol\";\nimport \"../interfaces/coreModule/IPoolManager.sol\";\nimport \"../interfaces/coreModule/IStableMaster.sol\";\nimport \"./AngleBorrowHelpers.sol\";\n\npragma solidity ^0.8.12;\n\nstruct Parameters {\n SLPData slpData;\n MintBurnData feeData;\n PerpetualManagerFeeData perpFeeData;\n PerpetualManagerParamData perpParam;\n}\n\nstruct PerpetualManagerFeeData {\n uint64[] xHAFeesDeposit;\n uint64[] yHAFeesDeposit;\n uint64[] xHAFeesWithdraw;\n uint64[] yHAFeesWithdraw;\n uint64 haBonusMalusDeposit;\n uint64 haBonusMalusWithdraw;\n}\n\nstruct PerpetualManagerParamData {\n uint64 maintenanceMargin;\n uint64 maxLeverage;\n uint64 targetHAHedge;\n uint64 limitHAHedge;\n uint64 lockTime;\n}\n\nstruct CollateralAddresses {\n address stableMaster;\n address poolManager;\n address perpetualManager;\n address sanToken;\n address oracle;\n address gauge;\n address feeManager;\n address[] strategies;\n}\n\n/// @title AngleHelpers\n/// @author Angle Labs, Inc.\n/// @notice Contract with view functions designed to facilitate integrations on the Core and Borrow module of the Angle Protocol\n/// @dev This contract only contains view functions to be queried off-chain. It was thus not optimized for gas consumption\ncontract AngleHelpers is AngleBorrowHelpers {\n // =========================== HELPER VIEW FUNCTIONS ===========================\n\n /// @notice Gives the amount of `agToken` you'd be getting if you were executing in the same block a mint transaction\n /// with `amount` of `collateral` in the Core module of the Angle protocol as well as the value of the fees\n /// (in `BASE_PARAMS`) that would be applied during the mint\n /// @return Amount of `agToken` that would be obtained with a mint transaction in the same block\n /// @return Percentage of fees that would be taken during a mint transaction in the same block\n /// @dev This function reverts if the mint transaction was to revert in the same conditions (without taking into account\n /// potential approval problems to the `StableMaster` contract)\n function previewMintAndFees(\n uint256 amount,\n address agToken,\n address collateral\n ) external view returns (uint256, uint256) {\n return _previewMintAndFees(amount, agToken, collateral);\n }\n\n /// @notice Gives the amount of `collateral` you'd be getting if you were executing in the same block a burn transaction\n /// with `amount` of `agToken` in the Core module of the Angle protocol as well as the value of the fees\n /// (in `BASE_PARAMS`) that would be applied during the burn\n /// @return Amount of `collateral` that would be obtained with a burn transaction in the same block\n /// @return Percentage of fees that would be taken during a burn transaction in the same block\n /// @dev This function reverts if the burn transaction was to revert in the same conditions (without taking into account\n /// potential approval problems to the `StableMaster` contract or agToken balance prior to the call)\n function previewBurnAndFees(\n uint256 amount,\n address agToken,\n address collateral\n ) external view returns (uint256, uint256) {\n return _previewBurnAndFees(amount, agToken, collateral);\n }\n\n /// @notice Returns all the addresses associated to the (`agToken`,`collateral`) pair given\n /// @return addresses A struct with all the addresses associated in the Core module\n function getCollateralAddresses(address agToken, address collateral)\n external\n view\n returns (CollateralAddresses memory addresses)\n {\n address stableMaster = IAgTokenMainnet(agToken).stableMaster();\n (address poolManager, address perpetualManager, address sanToken, address gauge) = ROUTER.mapPoolManagers(\n stableMaster,\n collateral\n );\n (, , , IOracleCore oracle, , , , , ) = IStableMaster(stableMaster).collateralMap(poolManager);\n addresses.stableMaster = stableMaster;\n addresses.poolManager = poolManager;\n addresses.perpetualManager = perpetualManager;\n addresses.sanToken = sanToken;\n addresses.gauge = gauge;\n addresses.oracle = address(oracle);\n addresses.feeManager = IPoolManager(poolManager).feeManager();\n\n uint256 length;\n while (true) {\n try IPoolManager(poolManager).strategyList(length) returns (address) {\n length += 1;\n } catch {\n break;\n }\n }\n address[] memory strategies = new address[](length);\n for (uint256 i; i < length; ++i) {\n strategies[i] = IPoolManager(poolManager).strategyList(i);\n }\n addresses.strategies = strategies;\n }\n\n /// @notice Gets the addresses of all the `StableMaster` contracts and their associated `AgToken` addresses\n /// @return List of the `StableMaster` addresses of the Angle protocol\n /// @return List of the `AgToken` addresses of the protocol\n /// @dev The place of an agToken address in the list is the same as the corresponding `StableMaster` address\n function getStablecoinAddresses() external view returns (address[] memory, address[] memory) {\n address[] memory stableMasterAddresses = CORE.stablecoinList();\n address[] memory agTokenAddresses = new address[](stableMasterAddresses.length);\n for (uint256 i; i < stableMasterAddresses.length; ++i) {\n agTokenAddresses[i] = IStableMaster(stableMasterAddresses[i]).agToken();\n }\n return (stableMasterAddresses, agTokenAddresses);\n }\n\n /// @notice Returns most of the governance parameters associated to the (`agToken`,`collateral`) pair given\n /// @return params Struct with most of the parameters in the `StableMaster` and `PerpetualManager` contracts\n /// @dev Check out the struct `Parameters` for the meaning of the return values\n function getCollateralParameters(address agToken, address collateral)\n external\n view\n returns (Parameters memory params)\n {\n (address stableMaster, address poolManager) = _getStableMasterAndPoolManager(agToken, collateral);\n (\n ,\n ,\n IPerpetualManager perpetualManager,\n ,\n ,\n ,\n ,\n SLPData memory slpData,\n MintBurnData memory feeData\n ) = IStableMaster(stableMaster).collateralMap(poolManager);\n\n params.slpData = slpData;\n params.feeData = feeData;\n params.perpParam.maintenanceMargin = perpetualManager.maintenanceMargin();\n params.perpParam.maxLeverage = perpetualManager.maxLeverage();\n params.perpParam.targetHAHedge = perpetualManager.targetHAHedge();\n params.perpParam.limitHAHedge = perpetualManager.limitHAHedge();\n params.perpParam.lockTime = perpetualManager.lockTime();\n\n params.perpFeeData.haBonusMalusDeposit = perpetualManager.haBonusMalusDeposit();\n params.perpFeeData.haBonusMalusWithdraw = perpetualManager.haBonusMalusWithdraw();\n\n uint256 length;\n while (true) {\n try perpetualManager.xHAFeesDeposit(length) returns (uint64) {\n length += 1;\n } catch {\n break;\n }\n }\n uint64[] memory data = new uint64[](length);\n uint64[] memory data2 = new uint64[](length);\n for (uint256 i; i < length; ++i) {\n data[i] = perpetualManager.xHAFeesDeposit(i);\n data2[i] = perpetualManager.yHAFeesDeposit(i);\n }\n params.perpFeeData.xHAFeesDeposit = data;\n params.perpFeeData.yHAFeesDeposit = data2;\n\n length = 0;\n while (true) {\n try perpetualManager.xHAFeesWithdraw(length) returns (uint64) {\n length += 1;\n } catch {\n break;\n }\n }\n data = new uint64[](length);\n data2 = new uint64[](length);\n for (uint256 i; i < length; ++i) {\n data[i] = perpetualManager.xHAFeesWithdraw(i);\n data2[i] = perpetualManager.yHAFeesWithdraw(i);\n }\n params.perpFeeData.xHAFeesWithdraw = data;\n params.perpFeeData.yHAFeesWithdraw = data2;\n }\n\n /// @notice Returns the address of the poolManager associated to an (`agToken`, `collateral`) pair\n /// in the Core module of the protocol\n function getPoolManager(address agToken, address collateral) public view returns (address poolManager) {\n (, poolManager) = _getStableMasterAndPoolManager(agToken, collateral);\n }\n\n // ============================= REPLICA FUNCTIONS =============================\n // These replicate what is done in the other contracts of the protocol\n\n function _previewBurnAndFees(\n uint256 amount,\n address agToken,\n address collateral\n ) internal view returns (uint256 amountForUserInCollat, uint256 feePercent) {\n (address stableMaster, address poolManager) = _getStableMasterAndPoolManager(agToken, collateral);\n (\n address token,\n ,\n IPerpetualManager perpetualManager,\n IOracleCore oracle,\n uint256 stocksUsers,\n ,\n uint256 collatBase,\n ,\n MintBurnData memory feeData\n ) = IStableMaster(stableMaster).collateralMap(poolManager);\n if (token == address(0) || IStableMaster(stableMaster).paused(keccak256(abi.encodePacked(STABLE, poolManager))))\n revert NotInitialized();\n if (amount > stocksUsers) revert InvalidAmount();\n\n if (feeData.xFeeBurn.length == 1) {\n feePercent = feeData.yFeeBurn[0];\n } else {\n bytes memory data = abi.encode(address(perpetualManager), feeData.targetHAHedge);\n uint64 hedgeRatio = _computeHedgeRatio(stocksUsers - amount, data);\n feePercent = _piecewiseLinear(hedgeRatio, feeData.xFeeBurn, feeData.yFeeBurn);\n }\n feePercent = (feePercent * feeData.bonusMalusBurn) / BASE_PARAMS;\n\n amountForUserInCollat = (amount * (BASE_PARAMS - feePercent) * collatBase) / (oracle.readUpper() * BASE_PARAMS);\n }\n\n function _previewMintAndFees(\n uint256 amount,\n address agToken,\n address collateral\n ) internal view returns (uint256 amountForUserInStable, uint256 feePercent) {\n (address stableMaster, address poolManager) = _getStableMasterAndPoolManager(agToken, collateral);\n (\n address token,\n ,\n IPerpetualManager perpetualManager,\n IOracleCore oracle,\n uint256 stocksUsers,\n ,\n ,\n ,\n MintBurnData memory feeData\n ) = IStableMaster(stableMaster).collateralMap(poolManager);\n if (token == address(0) || IStableMaster(stableMaster).paused(keccak256(abi.encodePacked(STABLE, poolManager))))\n revert NotInitialized();\n\n amountForUserInStable = oracle.readQuoteLower(amount);\n\n if (feeData.xFeeMint.length == 1) feePercent = feeData.yFeeMint[0];\n else {\n bytes memory data = abi.encode(address(perpetualManager), feeData.targetHAHedge);\n uint64 hedgeRatio = _computeHedgeRatio(amountForUserInStable + stocksUsers, data);\n feePercent = _piecewiseLinear(hedgeRatio, feeData.xFeeMint, feeData.yFeeMint);\n }\n feePercent = (feePercent * feeData.bonusMalusMint) / BASE_PARAMS;\n\n amountForUserInStable = (amountForUserInStable * (BASE_PARAMS - feePercent)) / BASE_PARAMS;\n if (stocksUsers + amountForUserInStable > feeData.capOnStableMinted) revert InvalidAmount();\n }\n\n // ============================= UTILITY FUNCTIONS =============================\n // These utility functions are taken from other contracts of the protocol\n\n function _computeHedgeRatio(uint256 newStocksUsers, bytes memory data) internal view returns (uint64 ratio) {\n (address perpetualManager, uint64 targetHAHedge) = abi.decode(data, (address, uint64));\n uint256 totalHedgeAmount = IPerpetualManager(perpetualManager).totalHedgeAmount();\n newStocksUsers = (targetHAHedge * newStocksUsers) / BASE_PARAMS;\n if (newStocksUsers > totalHedgeAmount) ratio = uint64((totalHedgeAmount * BASE_PARAMS) / newStocksUsers);\n else ratio = uint64(BASE_PARAMS);\n }\n\n function _piecewiseLinear(\n uint64 x,\n uint64[] memory xArray,\n uint64[] memory yArray\n ) internal pure returns (uint64) {\n if (x >= xArray[xArray.length - 1]) {\n return yArray[xArray.length - 1];\n } else if (x <= xArray[0]) {\n return yArray[0];\n } else {\n uint256 lower;\n uint256 upper = xArray.length - 1;\n uint256 mid;\n while (upper - lower > 1) {\n mid = lower + (upper - lower) / 2;\n if (xArray[mid] <= x) {\n lower = mid;\n } else {\n upper = mid;\n }\n }\n if (yArray[upper] > yArray[lower]) {\n return\n yArray[lower] +\n ((yArray[upper] - yArray[lower]) * (x - xArray[lower])) /\n (xArray[upper] - xArray[lower]);\n } else {\n return\n yArray[lower] -\n ((yArray[lower] - yArray[upper]) * (x - xArray[lower])) /\n (xArray[upper] - xArray[lower]);\n }\n }\n }\n\n function _getStableMasterAndPoolManager(address agToken, address collateral)\n internal\n view\n returns (address stableMaster, address poolManager)\n {\n stableMaster = IAgTokenMainnet(agToken).stableMaster();\n (poolManager, , , ) = ROUTER.mapPoolManagers(stableMaster, collateral);\n }\n\n // ========================= CONSTANTS AND INITIALIZERS ========================\n\n IAngleRouter public constant ROUTER = IAngleRouter(0xBB755240596530be0c1DE5DFD77ec6398471561d);\n ICore public constant CORE = ICore(0x61ed74de9Ca5796cF2F8fD60D54160D47E30B7c3);\n\n bytes32 public constant STABLE = keccak256(\"STABLE\");\n uint256 public constant BASE_PARAMS = 10**9;\n\n error NotInitialized();\n error InvalidAmount();\n}\n" + }, + "contracts/interfaces/IAngleRouter.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\n/// @title IAngleRouter\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `AngleRouter` contract\n/// @dev This interface only contains functions of the `AngleRouter01` contract which are called by other contracts\n/// of this module\ninterface IAngleRouter {\n function mint(\n address user,\n uint256 amount,\n uint256 minStableAmount,\n address stablecoin,\n address collateral\n ) external;\n\n function burn(\n address user,\n uint256 amount,\n uint256 minAmountOut,\n address stablecoin,\n address collateral\n ) external;\n\n function mapPoolManagers(address stableMaster, address collateral)\n external\n view\n returns (\n address poolManager,\n address perpetualManager,\n address sanToken,\n address gauge\n );\n}\n" + }, + "contracts/interfaces/coreModule/IAgTokenMainnet.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\n/// @title IAgTokenMainnet\n/// @author Angle Labs, Inc.\ninterface IAgTokenMainnet {\n function stableMaster() external view returns (address);\n}\n" + }, + "contracts/interfaces/coreModule/ICore.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\n/// @title ICore\n/// @author Angle Labs, Inc.\ninterface ICore {\n function stablecoinList() external view returns (address[] memory);\n}\n" + }, + "contracts/mock/MockStableMaster.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"../interfaces/IAgToken.sol\";\nimport \"./MockToken.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { SLPData, MintBurnData } from \"../interfaces/coreModule/IStableMaster.sol\";\n\n// All the details about a collateral that are going to be stored in `StableMaster`\nstruct Collateral {\n // Interface for the token accepted by the underlying `PoolManager` contract\n IERC20 token;\n // Reference to the `SanToken` for the pool\n MockToken sanToken;\n // Reference to the `PerpetualManager` for the pool\n address perpetualManager;\n // Adress of the oracle for the change rate between\n // collateral and the corresponding stablecoin\n address oracle;\n // Amount of collateral in the reserves that comes from users\n // converted in stablecoin value. Updated at minting and burning.\n // A `stocksUsers` of 10 for a collateral type means that overall the balance of the collateral from users\n // that minted/burnt stablecoins using this collateral is worth 10 of stablecoins\n uint256 stocksUsers;\n // Exchange rate between sanToken and collateral\n uint256 sanRate;\n // Base used in the collateral implementation (ERC20 decimal)\n uint256 collatBase;\n // Parameters for SLPs and update of the `sanRate`\n SLPData slpData;\n // All the fees parameters\n MintBurnData feeData;\n}\n\ncontract MockStableMaster {\n mapping(address => uint256) public poolManagerMap;\n\n constructor() {}\n\n function updateStocksUsers(uint256 amount, address poolManager) external {\n poolManagerMap[poolManager] += amount;\n }\n\n function burnSelf(\n IAgToken agToken,\n uint256 amount,\n address burner\n ) external {\n agToken.burnSelf(amount, burner);\n }\n\n function burnFrom(\n IAgToken agToken,\n uint256 amount,\n address burner,\n address sender\n ) external {\n agToken.burnFrom(amount, burner, sender);\n }\n\n function mint(\n IAgToken agToken,\n address account,\n uint256 amount\n ) external {\n agToken.mint(account, amount);\n }\n}\n\ncontract MockStableMasterSanWrapper is MockStableMaster {\n using SafeERC20 for IERC20;\n\n /// @notice Maps a `PoolManager` contract handling a collateral for this stablecoin to the properties of the struct above\n mapping(address => Collateral) public collateralMap;\n\n constructor() MockStableMaster() {}\n\n uint256 internal constant _BASE_TOKENS = 10**18;\n uint256 internal constant _BASE_PARAMS = 10**9;\n IERC20 public token;\n\n function deposit(\n uint256 assets,\n address receiver,\n address poolManager\n ) external {\n token.safeTransferFrom(msg.sender, address(this), assets);\n Collateral storage col = collateralMap[poolManager];\n _updateSanRate(col);\n uint256 amount = (assets * _BASE_TOKENS) / col.sanRate;\n col.sanToken.mint(receiver, amount);\n }\n\n function withdraw(\n uint256 assets,\n address sender,\n address receiver,\n address poolManager\n ) external {\n Collateral storage col = collateralMap[poolManager];\n _updateSanRate(col);\n col.sanToken.burn(sender, assets);\n // Computing the amount of collateral to give back to the SLP depending on slippage and on the `sanRate`\n uint256 redeemInC = (assets * (_BASE_PARAMS - col.slpData.slippage) * col.sanRate) /\n (_BASE_TOKENS * _BASE_PARAMS);\n token.safeTransfer(receiver, redeemInC);\n }\n\n function setPoolManagerToken(address, address token_) external {\n token = MockToken(token_);\n }\n\n function setPoolManagerSanToken(address poolManager, address sanToken_) external {\n Collateral storage col = collateralMap[poolManager];\n col.sanToken = MockToken(sanToken_);\n }\n\n function setSanRate(address poolManager, uint256 sanRate_) external {\n Collateral storage col = collateralMap[poolManager];\n col.sanRate = sanRate_;\n }\n\n function _updateSanRate(Collateral storage col) internal {\n uint256 _lockedInterests = col.slpData.lockedInterests;\n // Checking if the `sanRate` has been updated in the current block using past block fees\n // This is a way to prevent flash loans attacks when an important amount of fees are going to be distributed\n // in a block: fees are stored but will just be distributed to SLPs who will be here during next blocks\n if (block.timestamp != col.slpData.lastBlockUpdated && _lockedInterests > 0) {\n uint256 sanMint = col.sanToken.totalSupply();\n if (sanMint != 0) {\n // Checking if the update is too important and should be made in multiple blocks\n if (_lockedInterests > col.slpData.maxInterestsDistributed) {\n // `sanRate` is expressed in `BASE_TOKENS`\n col.sanRate += (col.slpData.maxInterestsDistributed * 10**18) / sanMint;\n _lockedInterests -= col.slpData.maxInterestsDistributed;\n } else {\n col.sanRate += (_lockedInterests * 10**18) / sanMint;\n _lockedInterests = 0;\n }\n } else {\n _lockedInterests = 0;\n }\n }\n col.slpData.lockedInterests = _lockedInterests;\n col.slpData.lastBlockUpdated = block.timestamp;\n }\n\n // copy paste from the deployed contract\n function estimateSanRate(address poolManager) external view returns (uint256 sanRate, uint64 slippage) {\n Collateral memory col = collateralMap[poolManager];\n uint256 _lockedInterests = col.slpData.lockedInterests;\n // Checking if the `sanRate` has been updated in the current block using past block fees\n // This is a way to prevent flash loans attacks when an important amount of fees are going to be distributed\n // in a block: fees are stored but will just be distributed to SLPs who will be here during next blocks\n if (block.timestamp != col.slpData.lastBlockUpdated && _lockedInterests > 0) {\n uint256 sanMint = col.sanToken.totalSupply();\n if (sanMint != 0) {\n // Checking if the update is too important and should be made in multiple blocks\n if (_lockedInterests > col.slpData.maxInterestsDistributed) {\n // `sanRate` is expressed in `BASE_TOKENS`\n col.sanRate += (col.slpData.maxInterestsDistributed * 10**18) / sanMint;\n _lockedInterests -= col.slpData.maxInterestsDistributed;\n } else {\n col.sanRate += (_lockedInterests * 10**18) / sanMint;\n _lockedInterests = 0;\n }\n } else {\n _lockedInterests = 0;\n }\n }\n return (col.sanRate, col.slpData.slippage);\n }\n\n function setSLPData(\n address poolManager,\n uint256 lockedInterests,\n uint256 maxInterestsDistributed,\n uint64 slippage\n ) external {\n Collateral storage col = collateralMap[poolManager];\n col.slpData.lockedInterests = lockedInterests;\n col.slpData.maxInterestsDistributed = maxInterestsDistributed;\n col.slpData.slippage = slippage;\n }\n}\n" + }, + "contracts/mock/MockToken.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.7;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockToken is ERC20 {\n event Minting(address indexed _to, address indexed _minter, uint256 _amount);\n\n event Burning(address indexed _from, address indexed _burner, uint256 _amount);\n\n uint8 internal _decimal;\n mapping(address => bool) public minters;\n address public treasury;\n\n constructor(\n string memory name_,\n string memory symbol_,\n uint8 decimal_\n ) ERC20(name_, symbol_) {\n _decimal = decimal_;\n }\n\n function decimals() public view override returns (uint8) {\n return _decimal;\n }\n\n function mint(address account, uint256 amount) external {\n _mint(account, amount);\n emit Minting(account, msg.sender, amount);\n }\n\n function burn(address account, uint256 amount) public {\n _burn(account, amount);\n emit Burning(account, msg.sender, amount);\n }\n\n function setAllowance(address from, address to) public {\n _approve(from, to, type(uint256).max);\n }\n\n function burnSelf(uint256 amount, address account) public {\n _burn(account, amount);\n emit Burning(account, msg.sender, amount);\n }\n\n function addMinter(address minter) public {\n minters[minter] = true;\n }\n\n function removeMinter(address minter) public {\n minters[minter] = false;\n }\n\n function setTreasury(address _treasury) public {\n treasury = _treasury;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n }\n _balances[to] += amount;\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" + }, + "contracts/settlement/Settlement.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\nimport \"../interfaces/IAgToken.sol\";\nimport \"../interfaces/ISwapper.sol\";\nimport \"../interfaces/IVaultManager.sol\";\n\n/// @title Settlement\n/// @author Angle Labs, Inc.\n/// @notice Settlement Contract for a VaultManager\n/// @dev This settlement contract should be activated by a careful governance which needs to have performed\n/// some key operations before activating this contract\n/// @dev In case of global settlement, there should be one settlement contract per `VaultManager`\ncontract Settlement {\n using SafeERC20 for IERC20;\n\n /// @notice Base used for parameter computation\n uint256 public constant BASE_PARAMS = 10**9;\n /// @notice Base used for interest computation\n uint256 public constant BASE_INTEREST = 10**27;\n /// @notice Base used for exchange rate computation. It is assumed\n /// that stablecoins have this base\n uint256 public constant BASE_STABLECOIN = 10**18;\n /// @notice Duration of the claim period for over-collateralized vaults\n uint256 public constant OVER_COLLATERALIZED_CLAIM_DURATION = 3 * 24 * 3600;\n\n // =============== Immutable references set in the constructor =================\n\n /// @notice `VaultManager` of this settlement contract\n IVaultManager public immutable vaultManager;\n /// @notice Reference to the stablecoin supported by the `VaultManager` contract\n IAgToken public immutable stablecoin;\n /// @notice Reference to the collateral supported by the `VaultManager`\n IERC20 public immutable collateral;\n /// @notice Base of the collateral\n uint256 internal immutable _collatBase;\n\n // ================ Variables frozen at settlement activation ==================\n\n /// @notice Value of the oracle for the collateral/stablecoin pair\n uint256 public oracleValue;\n /// @notice Value of the interest accumulator at settlement activation\n uint256 public interestAccumulator;\n /// @notice Timestamp at which settlement was activated\n uint256 public activationTimestamp;\n /// @notice Collateral factor of the `VaultManager`\n uint64 public collateralFactor;\n\n // =================== Variables updated during the process ====================\n\n /// @notice How much collateral you can get from stablecoins\n uint256 public collateralStablecoinExchangeRate;\n /// @notice Amount of collateral that will be left over at the end of the process\n uint256 public leftOverCollateral;\n /// @notice Whether the `collateralStablecoinExchangeRate` has been computed\n bool public exchangeRateComputed;\n /// @notice Maps a vault to 1 if it was claimed by its owner\n mapping(uint256 => uint256) public vaultCheck;\n\n // ================================ Events =====================================\n\n event GlobalClaimPeriodActivated(uint256 _collateralStablecoinExchangeRate);\n event Recovered(address indexed tokenAddress, address indexed to, uint256 amount);\n event SettlementActivated(uint256 startTimestamp);\n event VaultClaimed(uint256 vaultID, uint256 stablecoinAmount, uint256 collateralAmount);\n\n // ================================ Errors =====================================\n\n error GlobalClaimPeriodNotStarted();\n error InsolventVault();\n error NotGovernor();\n error NotOwner();\n error RestrictedClaimPeriodNotEnded();\n error SettlementNotInitialized();\n error VaultAlreadyClaimed();\n\n /// @notice Constructor of the contract\n /// @param _vaultManager Address of the `VaultManager` associated to this `Settlement` contract\n /// @dev Out of safety, this constructor reads values from the `VaultManager` contract directly\n constructor(IVaultManager _vaultManager) {\n vaultManager = _vaultManager;\n stablecoin = _vaultManager.stablecoin();\n collateral = _vaultManager.collateral();\n _collatBase = 10**(IERC20Metadata(address(collateral)).decimals());\n }\n\n /// @notice Checks whether the `msg.sender` has the governor role or not\n modifier onlyGovernor() {\n if (!(vaultManager.treasury().isGovernor(msg.sender))) revert NotGovernor();\n _;\n }\n\n /// @notice Activates the settlement contract\n /// @dev When calling this function governance should make sure to have:\n /// 1. Accrued the interest rate on the contract\n /// 2. Paused the contract\n /// 3. Recovered all the collateral available in the `VaultManager` contract either\n /// by doing a contract upgrade or by calling a `recoverERC20` method if supported\n function activateSettlement() external onlyGovernor {\n oracleValue = (vaultManager.oracle()).read();\n interestAccumulator = vaultManager.interestAccumulator();\n activationTimestamp = block.timestamp;\n collateralFactor = vaultManager.collateralFactor();\n emit SettlementActivated(block.timestamp);\n }\n\n /// @notice Allows the owner of an over-collateralized vault to claim its collateral upon bringing back all owed stablecoins\n /// @param vaultID ID of the vault to claim\n /// @param to Address to which collateral should be sent\n /// @param who Address which should be notified if needed of the transfer of stablecoins and collateral\n /// @param data Data to pass to the `who` contract for it to successfully give the correct amount of stablecoins\n /// to the `msg.sender` address\n /// @return Amount of collateral sent to the `to` address\n /// @return Amount of stablecoins sent to the contract\n /// @dev Claiming can only happen short after settlement activation\n /// @dev A vault cannot be claimed twice and only the owner of the vault can claim it (regardless of the approval logic)\n /// @dev Only over-collateralized vaults can be claimed from this medium\n function claimOverCollateralizedVault(\n uint256 vaultID,\n address to,\n address who,\n bytes memory data\n ) external returns (uint256, uint256) {\n if (activationTimestamp == 0 || block.timestamp > activationTimestamp + OVER_COLLATERALIZED_CLAIM_DURATION)\n revert SettlementNotInitialized();\n if (vaultCheck[vaultID] == 1) revert VaultAlreadyClaimed();\n if (vaultManager.ownerOf(vaultID) != msg.sender) revert NotOwner();\n (uint256 collateralAmount, uint256 normalizedDebt) = vaultManager.vaultData(vaultID);\n uint256 vaultDebt = (normalizedDebt * interestAccumulator) / BASE_INTEREST;\n if (collateralAmount * oracleValue * collateralFactor < vaultDebt * BASE_PARAMS * _collatBase)\n revert InsolventVault();\n vaultCheck[vaultID] = 1;\n emit VaultClaimed(vaultID, vaultDebt, collateralAmount);\n return _handleRepay(collateralAmount, vaultDebt, to, who, data);\n }\n\n /// @notice Activates the global claim period by setting the `collateralStablecoinExchangeRate` which is going to\n /// dictate how much of collateral will be recoverable for each stablecoin\n /// @dev This function can only be called by the governor in order to allow it in case multiple settlements happen across\n /// different `VaultManager` to rebalance the amount of stablecoins on each to make sure that across all settlement contracts\n /// a similar value of collateral can be obtained against a similar value of stablecoins\n function activateGlobalClaimPeriod() external onlyGovernor {\n if (activationTimestamp == 0 || block.timestamp <= activationTimestamp + OVER_COLLATERALIZED_CLAIM_DURATION)\n revert RestrictedClaimPeriodNotEnded();\n uint256 collateralBalance = collateral.balanceOf(address(this));\n uint256 leftOverDebt = (vaultManager.totalNormalizedDebt() * interestAccumulator) / BASE_INTEREST;\n uint256 stablecoinBalance = stablecoin.balanceOf(address(this));\n // How much 1 of stablecoin will give you in collateral\n uint256 _collateralStablecoinExchangeRate;\n\n if (stablecoinBalance < leftOverDebt) {\n // The left over debt is the total debt minus the stablecoins which have already been accumulated\n // in the first phase\n leftOverDebt -= stablecoinBalance;\n // If you control all the debt, then you are entitled to get all the collateral left in the protocol\n _collateralStablecoinExchangeRate = (collateralBalance * BASE_STABLECOIN) / leftOverDebt;\n // But at the same time, you cannot get more collateral than the value of the stablecoins you brought\n uint256 maxExchangeRate = (BASE_STABLECOIN * _collatBase) / oracleValue;\n if (_collateralStablecoinExchangeRate >= maxExchangeRate) {\n // In this situation, we're sure that `leftOverCollateral` will be positive: governance should be wary\n // to call `recoverERC20` short after though as there's nothing that is going to prevent people to redeem\n // more stablecoins than the `leftOverDebt`\n leftOverCollateral = collateralBalance - (leftOverDebt * _collatBase) / oracleValue;\n _collateralStablecoinExchangeRate = maxExchangeRate;\n }\n }\n exchangeRateComputed = true;\n // In the else case where there is no debt left, you cannot get anything from your stablecoins\n // and so the `collateralStablecoinExchangeRate` is null\n collateralStablecoinExchangeRate = _collateralStablecoinExchangeRate;\n emit GlobalClaimPeriodActivated(_collateralStablecoinExchangeRate);\n }\n\n /// @notice Allows to claim collateral from stablecoins\n /// @param to Address to which collateral should be sent\n /// @param who Address which should be notified if needed of the transfer of stablecoins and collateral\n /// @param data Data to pass to the `who` contract for it to successfully give the correct amount of stablecoins\n /// to the `msg.sender` address\n /// @return Amount of collateral sent to the `to` address\n /// @return Amount of stablecoins sent to the contract\n /// @dev This function reverts if the `collateralStablecoinExchangeRate` is null and hence if the global claim period has\n /// not been activated\n function claimCollateralFromStablecoins(\n uint256 stablecoinAmount,\n address to,\n address who,\n bytes memory data\n ) external returns (uint256, uint256) {\n if (!exchangeRateComputed) revert GlobalClaimPeriodNotStarted();\n return\n _handleRepay(\n (stablecoinAmount * collateralStablecoinExchangeRate) / BASE_STABLECOIN,\n stablecoinAmount,\n to,\n who,\n data\n );\n }\n\n /// @notice Handles the simultaneous repayment of stablecoins with a transfer of collateral\n /// @param collateralAmountToGive Amount of collateral the contract should give\n /// @param stableAmountToRepay Amount of stablecoins the contract should burn from the call\n /// @param to Address to which stablecoins should be sent\n /// @param who Address which should be notified if needed of the transfer\n /// @param data Data to pass to the `who` contract for it to successfully give the correct amount of stablecoins\n /// to the `msg.sender` address\n /// @dev This function allows for capital-efficient claims of collateral from stablecoins\n function _handleRepay(\n uint256 collateralAmountToGive,\n uint256 stableAmountToRepay,\n address to,\n address who,\n bytes memory data\n ) internal returns (uint256, uint256) {\n collateral.safeTransfer(to, collateralAmountToGive);\n if (data.length != 0) {\n ISwapper(who).swap(\n collateral,\n IERC20(address(stablecoin)),\n msg.sender,\n stableAmountToRepay,\n collateralAmountToGive,\n data\n );\n }\n stablecoin.transferFrom(msg.sender, address(this), stableAmountToRepay);\n return (collateralAmountToGive, stableAmountToRepay);\n }\n\n /// @notice Recovers leftover tokens from the contract or tokens that were mistakenly sent to the contract\n /// @param tokenAddress Address of the token to recover\n /// @param to Address to send the remaining tokens to\n /// @param amountToRecover Amount to recover from the contract\n /// @dev Governors cannot recover more collateral than what would be leftover from the contract\n /// @dev This function can be used to rebalance stablecoin balances across different settlement contracts\n /// to make sure every stablecoin can be redeemed for the same value of collateral\n /// @dev It can also be used to recover tokens that are mistakenly sent to this contract\n function recoverERC20(\n address tokenAddress,\n address to,\n uint256 amountToRecover\n ) external onlyGovernor {\n if (tokenAddress == address(collateral)) {\n if (!exchangeRateComputed) revert GlobalClaimPeriodNotStarted();\n leftOverCollateral -= amountToRecover;\n collateral.safeTransfer(to, amountToRecover);\n } else {\n IERC20(tokenAddress).safeTransfer(to, amountToRecover);\n }\n emit Recovered(tokenAddress, to, amountToRecover);\n }\n}\n" + }, + "contracts/swapper/Swapper.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n * █ \n ***** ▓▓▓ \n * ▓▓▓▓▓▓▓ \n * ///. ▓▓▓▓▓▓▓▓▓▓▓▓▓ \n ***** //////// ▓▓▓▓▓▓▓ \n * ///////////// ▓▓▓ \n ▓▓ ////////////////// █ ▓▓ \n ▓▓ ▓▓ /////////////////////// ▓▓ ▓▓ \n ▓▓ ▓▓ //////////////////////////// ▓▓ ▓▓ \n ▓▓ ▓▓ /////////▓▓▓///////▓▓▓///////// ▓▓ ▓▓ \n ▓▓ ,////////////////////////////////////// ▓▓ ▓▓ \n ▓▓ ////////////////////////////////////////// ▓▓ \n ▓▓ //////////////////////▓▓▓▓///////////////////// \n ,//////////////////////////////////////////////////// \n .////////////////////////////////////////////////////////// \n .//////////////////////////██.,//////////////////////////█ \n .//////////////////////████..,./////////////////////██ \n ...////////////////███████.....,.////////////////███ \n ,.,////////////████████ ........,///////////████ \n .,.,//////█████████ ,.......///////████ \n ,..//████████ ........./████ \n ..,██████ .....,███ \n .██ ,.,█ \n \n \n \n ▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓ \n ▓▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓ ▓▓▓▓ \n ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓▓▓▓ \n ▓▓▓ ▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ \n*/\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport \"../interfaces/IAngleRouterSidechain.sol\";\nimport \"../interfaces/ICoreBorrow.sol\";\nimport \"../interfaces/ISwapper.sol\";\nimport \"../interfaces/external/lido/IWStETH.sol\";\nimport \"../interfaces/external/uniswap/IUniswapRouter.sol\";\n\n// ==================================== ENUM ===================================\n\n/// @notice All possible swaps\nenum SwapType {\n UniswapV3,\n oneInch,\n AngleRouter,\n Leverage,\n None\n}\n\n/// @title Swapper\n/// @author Angle Labs, Inc.\n/// @notice Swapper contract facilitating interactions with Angle VaultManager contracts, notably\n/// liquidation and leverage transactions\ncontract Swapper is ISwapper {\n using SafeERC20 for IERC20;\n\n // ===================== CONSTANTS AND IMMUTABLE VARIABLES =====================\n\n /// @notice Reference to the `CoreBorrow` contract of the module which handles all AccessControl logic\n ICoreBorrow public immutable core;\n /// @notice Uniswap Router contract\n IUniswapV3Router public immutable uniV3Router;\n /// @notice 1inch Router\n address public immutable oneInch;\n /// @notice AngleRouter\n IAngleRouterSidechain public immutable angleRouter;\n\n // =================================== ERRORS ==================================\n\n error EmptyReturnMessage();\n error IncompatibleLengths();\n error NotGovernorOrGuardian();\n error TooSmallAmountOut();\n error ZeroAddress();\n\n /// @notice Constructor of the contract\n /// @param _core Core address\n /// @param _uniV3Router UniswapV3 Router address\n /// @param _oneInch 1inch Router address\n /// @param _angleRouter AngleRouter contract address\n constructor(\n ICoreBorrow _core,\n IUniswapV3Router _uniV3Router,\n address _oneInch,\n IAngleRouterSidechain _angleRouter\n ) {\n if (address(_core) == address(0) || _oneInch == address(0) || address(_angleRouter) == address(0))\n revert ZeroAddress();\n core = _core;\n uniV3Router = _uniV3Router;\n oneInch = _oneInch;\n angleRouter = _angleRouter;\n }\n\n // ========================= EXTERNAL ACCESS FUNCTIONS =========================\n\n /// @inheritdoc ISwapper\n /// @dev This function swaps the `inToken` to the `outToken` by doing a UniV3 swap, a 1inch swap or by interacting\n /// with the `AngleRouter` contract\n /// @dev One slippage check is performed at the end of the call\n /// @dev In this implementation, the function tries to make sure that the `outTokenRecipient` address has at the end\n /// of the call `outTokenOwed`, leftover tokens are sent to a `to` address which by default is the `outTokenRecipient`\n function swap(\n IERC20 inToken,\n IERC20 outToken,\n address outTokenRecipient,\n uint256 outTokenOwed,\n uint256 inTokenObtained,\n bytes memory data\n ) external {\n // Address to receive the surplus amount of token at the end of the call\n address to;\n // For slippage protection, it is checked at the end of the call\n uint256 minAmountOut;\n // Type of the swap to execute: if `swapType == 4`, then it is optional to swap\n uint256 swapType;\n // We're reusing the `data` variable (it can be `path` on UniswapV3, a payload for 1inch or like encoded actions\n // for a router call)\n (to, minAmountOut, swapType, data) = abi.decode(data, (address, uint256, uint256, bytes));\n\n to = (to == address(0)) ? outTokenRecipient : to;\n\n _swap(inToken, inTokenObtained, SwapType(swapType), data);\n\n // A final slippage check is performed after the swaps\n uint256 outTokenBalance = outToken.balanceOf(address(this));\n if (outTokenBalance < minAmountOut) revert TooSmallAmountOut();\n\n // The `outTokenRecipient` may already have enough in balance, in which case there's no need to transfer\n // to this address the token and everything can be given to the `to` address\n uint256 outTokenBalanceRecipient = outToken.balanceOf(outTokenRecipient);\n if (outTokenBalanceRecipient >= outTokenOwed || to == outTokenRecipient)\n outToken.safeTransfer(to, outTokenBalance);\n else {\n // The `outTokenRecipient` should receive the delta to make sure its end balance is equal to `outTokenOwed`\n // Any leftover in this case is sent to the `to` address\n // The function reverts if it did not obtain more than `outTokenOwed - outTokenBalanceRecipient` from the swap\n outToken.safeTransfer(outTokenRecipient, outTokenOwed - outTokenBalanceRecipient);\n outToken.safeTransfer(to, outTokenBalanceRecipient + outTokenBalance - outTokenOwed);\n }\n // Reusing the `inTokenObtained` variable for the `inToken` balance\n // Sending back the remaining amount of inTokens to the `to` address: it is possible that not the full `inTokenObtained`\n // is swapped to `outToken` if we're using the `1inch` payload\n inTokenObtained = inToken.balanceOf(address(this));\n if (inTokenObtained != 0) inToken.safeTransfer(to, inTokenObtained);\n }\n\n // ============================ GOVERNANCE FUNCTION ============================\n\n /// @notice Changes allowances of this contract for different tokens\n /// @param tokens Addresses of the tokens to allow\n /// @param spenders Addresses to allow transfer\n /// @param amounts Amounts to allow\n function changeAllowance(\n IERC20[] calldata tokens,\n address[] calldata spenders,\n uint256[] calldata amounts\n ) external {\n if (!core.isGovernorOrGuardian(msg.sender)) revert NotGovernorOrGuardian();\n uint256 tokensLength = tokens.length;\n if (tokensLength != spenders.length || tokensLength != amounts.length) revert IncompatibleLengths();\n for (uint256 i; i < tokensLength; ++i) {\n _changeAllowance(tokens[i], spenders[i], amounts[i]);\n }\n }\n\n // ========================= INTERNAL UTILITY FUNCTIONS ========================\n\n /// @notice Internal version of the `_changeAllowance` function\n function _changeAllowance(\n IERC20 token,\n address spender,\n uint256 amount\n ) internal {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance < amount) {\n token.safeIncreaseAllowance(spender, amount - currentAllowance);\n } else if (currentAllowance > amount) {\n token.safeDecreaseAllowance(spender, currentAllowance - amount);\n }\n }\n\n /// @notice Checks the allowance for a contract and updates it to the max if it is not big enough\n /// @param token Token for which allowance should be checked\n /// @param spender Address to grant allowance to\n /// @param amount Minimum amount of tokens needed for the allowance\n function _checkAllowance(\n IERC20 token,\n address spender,\n uint256 amount\n ) internal {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance < amount) token.safeIncreaseAllowance(spender, type(uint256).max - currentAllowance);\n }\n\n /// @notice Performs a swap using either Uniswap, 1inch. This function can also stake stETH to wstETH\n /// @param inToken Token to swap\n /// @param amount Amount of tokens to swap\n /// @param swapType Type of the swap to perform\n /// @param args Extra args for the swap: in the case of Uniswap it should be a path, for 1inch it should be\n /// a payload\n /// @dev This function does nothing if `swapType` is None and it simply passes on the `amount` it received\n /// @dev No slippage is specified in the actions given here as a final slippage check is performed\n /// after the call to this function\n function _swap(\n IERC20 inToken,\n uint256 amount,\n SwapType swapType,\n bytes memory args\n ) internal {\n if (swapType == SwapType.UniswapV3) _swapOnUniswapV3(inToken, amount, args);\n else if (swapType == SwapType.oneInch) _swapOn1inch(inToken, args);\n else if (swapType == SwapType.AngleRouter) _angleRouterActions(inToken, args);\n else if (swapType == SwapType.Leverage) _swapLeverage(args);\n }\n\n /// @notice Performs a UniswapV3 swap\n /// @param inToken Token to swap\n /// @param amount Amount of tokens to swap\n /// @param path Path for the UniswapV3 swap: this encodes the out token that is going to be obtained\n /// @dev This function does not check the out token obtained here: if it is wrongly specified, either\n /// the `swap` function could fail or these tokens could stay on the contract\n function _swapOnUniswapV3(\n IERC20 inToken,\n uint256 amount,\n bytes memory path\n ) internal returns (uint256 amountOut) {\n // We need more than `amount` of allowance to the contract\n _checkAllowance(inToken, address(uniV3Router), amount);\n amountOut = uniV3Router.exactInput(ExactInputParams(path, address(this), block.timestamp, amount, 0));\n }\n\n /// @notice Allows to swap any token to an accepted collateral via 1inch API\n /// @param inToken Token received for the 1inch swap\n /// @param payload Bytes needed for 1inch API\n function _swapOn1inch(IERC20 inToken, bytes memory payload) internal returns (uint256 amountOut) {\n _changeAllowance(inToken, oneInch, type(uint256).max);\n //solhint-disable-next-line\n (bool success, bytes memory result) = oneInch.call(payload);\n if (!success) _revertBytes(result);\n amountOut = abi.decode(result, (uint256));\n }\n\n /// @notice Performs actions with the router contract of the protocol on the corresponding chain\n /// @param inToken Token concerned by the action and for which\n function _angleRouterActions(IERC20 inToken, bytes memory args) internal {\n (ActionType[] memory actions, bytes[] memory actionData) = abi.decode(args, (ActionType[], bytes[]));\n _changeAllowance(inToken, address(angleRouter), type(uint256).max);\n PermitType[] memory permits;\n angleRouter.mixer(permits, actions, actionData);\n }\n\n /// @notice Allows to take leverage or deleverage via a specific contract\n /// @param payload Bytes needed for 1inch API\n /// @dev This function is to be implemented if the swapper concerns a token that requires some actions\n /// not supported by 1inch or UniV3\n function _swapLeverage(bytes memory payload) internal virtual returns (uint256 amountOut) {}\n\n /// @notice Internal function used for error handling\n /// @param errMsg Error message received\n function _revertBytes(bytes memory errMsg) internal pure {\n if (errMsg.length != 0) {\n //solhint-disable-next-line\n assembly {\n revert(add(32, errMsg), mload(errMsg))\n }\n }\n revert EmptyReturnMessage();\n }\n}\n" + }, + "contracts/interfaces/IAngleRouterSidechain.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\n/// @notice Action types\nenum ActionType {\n transfer,\n wrap,\n wrapNative,\n sweep,\n sweepNative,\n unwrap,\n unwrapNative,\n swapIn,\n swapOut,\n uniswapV3,\n oneInch,\n claimRewards,\n gaugeDeposit,\n borrower\n}\n\n/// @notice Data needed to get permits\nstruct PermitType {\n address token;\n address owner;\n uint256 value;\n uint256 deadline;\n uint8 v;\n bytes32 r;\n bytes32 s;\n}\n\n/// @title IAngleRouterSidechain\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `AngleRouter` contract on other chains\ninterface IAngleRouterSidechain {\n function mixer(\n PermitType[] memory paramsPermit,\n ActionType[] memory actions,\n bytes[] calldata data\n ) external;\n}\n" + }, + "contracts/interfaces/external/lido/IWStETH.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\n/// @title IWStETH\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `WStETH` contract\n/// @dev This interface only contains functions of the `WStETH` which are called by other contracts\n/// of this module\ninterface IWStETH {\n function wrap(uint256 _stETHAmount) external returns (uint256);\n\n function stETH() external view returns (address);\n}\n" + }, + "contracts/interfaces/external/uniswap/IUniswapRouter.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nstruct ExactInputParams {\n bytes path;\n address recipient;\n uint256 deadline;\n uint256 amountIn;\n uint256 amountOutMinimum;\n}\n\n/// @title Router token swapping functionality\n/// @notice Functions for swapping tokens via Uniswap V3\ninterface IUniswapV3Router {\n /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path\n /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata\n /// @return amountOut The amount of the received token\n function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);\n}\n\n/// @title Router for price estimation functionality\n/// @notice Functions for getting the price of one token with respect to another using Uniswap V2\n/// @dev This interface is only used for non critical elements of the protocol\ninterface IUniswapV2Router {\n /// @notice Given an input asset amount, returns the maximum output amount of the\n /// other asset (accounting for fees) given reserves.\n /// @param path Addresses of the pools used to get prices\n function getAmountsOut(uint256 amountIn, address[] calldata path) external view returns (uint256[] memory amounts);\n\n function swapExactTokensForTokens(\n uint256 swapAmount,\n uint256 minExpected,\n address[] calldata path,\n address receiver,\n uint256 swapDeadline\n ) external;\n}\n" + }, + "contracts/mock/MockRouter.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport \"../interfaces/IAngleRouter.sol\";\nimport \"../interfaces/external/uniswap/IUniswapRouter.sol\";\nimport \"../interfaces/external/lido/IWStETH.sol\";\n\ncontract MockRouter is IUniswapV3Router, IWStETH {\n using SafeERC20 for IERC20;\n\n uint256 public counterAngleMint;\n uint256 public counterAngleBurn;\n uint256 public counter1Inch;\n uint256 public counterUni;\n uint256 public counterWrap;\n uint256 public counterMixer;\n uint256 public amountOutUni;\n uint256 public multiplierMintBurn;\n uint256 public stETHMultiplier;\n address public inToken;\n address public outToken;\n\n address public stETH;\n\n /// @notice Action types\n enum ActionType {\n transfer,\n wrap,\n wrapNative,\n sweep,\n sweepNative,\n unwrap,\n unwrapNative,\n swapIn,\n swapOut,\n uniswapV3,\n oneInch,\n claimRewards,\n gaugeDeposit,\n borrower\n }\n\n /// @notice Data needed to get permits\n struct PermitType {\n address token;\n address owner;\n uint256 value;\n uint256 deadline;\n uint8 v;\n bytes32 r;\n bytes32 s;\n }\n\n constructor() {}\n\n function mint(\n address user,\n uint256 amount,\n uint256,\n address stablecoin,\n address collateral\n ) external {\n counterAngleMint += 1;\n IERC20(collateral).safeTransferFrom(msg.sender, address(this), amount);\n IERC20(stablecoin).safeTransfer(user, (amount * 10**9) / multiplierMintBurn);\n }\n\n function setStETH(address _stETH) external {\n stETH = _stETH;\n }\n\n function burn(\n address user,\n uint256 amount,\n uint256,\n address stablecoin,\n address collateral\n ) external {\n counterAngleBurn += 1;\n IERC20(stablecoin).safeTransferFrom(msg.sender, address(this), amount);\n IERC20(collateral).safeTransfer(user, (amount * multiplierMintBurn) / 10**9);\n }\n\n function mixer(\n PermitType[] memory paramsPermit,\n ActionType[] memory actions,\n bytes[] calldata data\n ) public payable virtual {\n paramsPermit;\n counterMixer += 1;\n for (uint256 i; i < actions.length; ++i) {\n if (actions[i] == ActionType.transfer) {\n (address transferToken, uint256 amount) = abi.decode(data[i], (address, uint256));\n IERC20(transferToken).safeTransferFrom(msg.sender, address(this), amount);\n }\n }\n }\n\n function wrap(uint256 amount) external returns (uint256 amountOut) {\n amountOut = (amount * stETHMultiplier) / 10**9;\n counterWrap += 1;\n IERC20(stETH).safeTransferFrom(msg.sender, address(this), amount);\n IERC20(outToken).safeTransfer(msg.sender, amountOut);\n }\n\n function oneInch(uint256 amountIn) external returns (uint256 amountOut) {\n counter1Inch += 1;\n amountOut = (amountOutUni * amountIn) / 10**9;\n IERC20(inToken).safeTransferFrom(msg.sender, address(this), amountIn);\n IERC20(outToken).safeTransfer(msg.sender, amountOut);\n }\n\n function oneInchReverts() external {\n counter1Inch += 1;\n revert(\"wrong swap\");\n }\n\n function oneInchRevertsWithoutMessage() external {\n counter1Inch += 1;\n require(false);\n }\n\n function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut) {\n counterUni += 1;\n amountOut = (params.amountIn * amountOutUni) / 10**9;\n IERC20(inToken).safeTransferFrom(msg.sender, address(this), params.amountIn);\n IERC20(outToken).safeTransfer(params.recipient, amountOut);\n require(amountOut >= params.amountOutMinimum);\n }\n\n function setMultipliers(uint256 a, uint256 b) external {\n amountOutUni = a;\n multiplierMintBurn = b;\n }\n\n function setStETHMultiplier(uint256 value) external {\n stETHMultiplier = value;\n }\n\n function setInOut(address _collateral, address _stablecoin) external {\n inToken = _collateral;\n outToken = _stablecoin;\n }\n}\n" + }, + "contracts/deprecated/OldAngleHelpers.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\nimport \"../interfaces/IAngleRouter.sol\";\nimport \"../interfaces/coreModule/IAgTokenMainnet.sol\";\nimport \"../interfaces/coreModule/ICore.sol\";\nimport \"../interfaces/coreModule/IOracleCore.sol\";\nimport \"../interfaces/coreModule/IPerpetualManager.sol\";\nimport \"../interfaces/coreModule/IPoolManager.sol\";\nimport \"../interfaces/coreModule/IStableMaster.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"../interfaces/IVaultManager.sol\";\n\npragma solidity ^0.8.12;\n\nstruct Parameters {\n SLPData slpData;\n MintBurnData feeData;\n PerpetualManagerFeeData perpFeeData;\n PerpetualManagerParamData perpParam;\n}\n\nstruct PerpetualManagerFeeData {\n uint64[] xHAFeesDeposit;\n uint64[] yHAFeesDeposit;\n uint64[] xHAFeesWithdraw;\n uint64[] yHAFeesWithdraw;\n uint64 haBonusMalusDeposit;\n uint64 haBonusMalusWithdraw;\n}\n\nstruct PerpetualManagerParamData {\n uint64 maintenanceMargin;\n uint64 maxLeverage;\n uint64 targetHAHedge;\n uint64 limitHAHedge;\n uint64 lockTime;\n}\n\nstruct CollateralAddresses {\n address stableMaster;\n address poolManager;\n address perpetualManager;\n address sanToken;\n address oracle;\n address gauge;\n address feeManager;\n address[] strategies;\n}\n\n/// @title AngleHelpers\n/// @author Angle Labs, Inc.\n/// @notice Contract with view functions designed to facilitate integrations on the Core module of the Angle Protocol\n/// @dev This contract only contains view functions to be queried off-chain. It was thus not optimized for gas consumption\ncontract OldAngleHelpers is Initializable {\n // ======================== Helper View Functions ==============================\n\n /// @notice Gives the amount of `agToken` you'd be getting if you were executing in the same block a mint transaction\n /// with `amount` of `collateral` in the Core module of the Angle protocol as well as the value of the fees\n /// (in `BASE_PARAMS`) that would be applied during the mint\n /// @return Amount of `agToken` that would be obtained with a mint transaction in the same block\n /// @return Percentage of fees that would be taken during a mint transaction in the same block\n /// @dev This function reverts if the mint transaction was to revert in the same conditions (without taking into account\n /// potential approval problems to the `StableMaster` contract)\n function previewMintAndFees(\n uint256 amount,\n address agToken,\n address collateral\n ) external view returns (uint256, uint256) {\n return _previewMintAndFees(amount, agToken, collateral);\n }\n\n /// @notice Gives the amount of `collateral` you'd be getting if you were executing in the same block a burn transaction\n /// with `amount` of `agToken` in the Core module of the Angle protocol as well as the value of the fees\n /// (in `BASE_PARAMS`) that would be applied during the burn\n /// @return Amount of `collateral` that would be obtained with a burn transaction in the same block\n /// @return Percentage of fees that would be taken during a burn transaction in the same block\n /// @dev This function reverts if the burn transaction was to revert in the same conditions (without taking into account\n /// potential approval problems to the `StableMaster` contract or agToken balance prior to the call)\n function previewBurnAndFees(\n uint256 amount,\n address agToken,\n address collateral\n ) external view returns (uint256, uint256) {\n return _previewBurnAndFees(amount, agToken, collateral);\n }\n\n /// @notice Returns all the addresses associated to the (`agToken`,`collateral`) pair given\n /// @return addresses A struct with all the addresses associated in the Core module\n function getCollateralAddresses(address agToken, address collateral)\n external\n view\n returns (CollateralAddresses memory addresses)\n {\n address stableMaster = IAgTokenMainnet(agToken).stableMaster();\n (address poolManager, address perpetualManager, address sanToken, address gauge) = ROUTER.mapPoolManagers(\n stableMaster,\n collateral\n );\n (, , , IOracleCore oracle, , , , , ) = IStableMaster(stableMaster).collateralMap(poolManager);\n addresses.stableMaster = stableMaster;\n addresses.poolManager = poolManager;\n addresses.perpetualManager = perpetualManager;\n addresses.sanToken = sanToken;\n addresses.gauge = gauge;\n addresses.oracle = address(oracle);\n addresses.feeManager = IPoolManager(poolManager).feeManager();\n\n uint256 length = 0;\n while (true) {\n try IPoolManager(poolManager).strategyList(length) returns (address) {\n length += 1;\n } catch {\n break;\n }\n }\n address[] memory strategies = new address[](length);\n for (uint256 i; i < length; ++i) {\n strategies[i] = IPoolManager(poolManager).strategyList(i);\n }\n addresses.strategies = strategies;\n }\n\n /// @notice Gets the addresses of all the `StableMaster` contracts and their associated `AgToken` addresses\n /// @return List of the `StableMaster` addresses of the Angle protocol\n /// @return List of the `AgToken` addresses of the protocol\n /// @dev The place of an agToken address in the list is the same as the corresponding `StableMaster` address\n function getStablecoinAddresses() external view returns (address[] memory, address[] memory) {\n address[] memory stableMasterAddresses = CORE.stablecoinList();\n address[] memory agTokenAddresses = new address[](stableMasterAddresses.length);\n for (uint256 i; i < stableMasterAddresses.length; ++i) {\n agTokenAddresses[i] = IStableMaster(stableMasterAddresses[i]).agToken();\n }\n return (stableMasterAddresses, agTokenAddresses);\n }\n\n /// @notice Returns most of the governance parameters associated to the (`agToken`,`collateral`) pair given\n /// @return params Struct with most of the parameters in the `StableMaster` and `PerpetualManager` contracts\n /// @dev Check out the struct `Parameters` for the meaning of the return values\n function getCollateralParameters(address agToken, address collateral)\n external\n view\n returns (Parameters memory params)\n {\n (address stableMaster, address poolManager) = _getStableMasterAndPoolManager(agToken, collateral);\n (\n ,\n ,\n IPerpetualManager perpetualManager,\n ,\n ,\n ,\n ,\n SLPData memory slpData,\n MintBurnData memory feeData\n ) = IStableMaster(stableMaster).collateralMap(poolManager);\n\n params.slpData = slpData;\n params.feeData = feeData;\n params.perpParam.maintenanceMargin = perpetualManager.maintenanceMargin();\n params.perpParam.maxLeverage = perpetualManager.maxLeverage();\n params.perpParam.targetHAHedge = perpetualManager.targetHAHedge();\n params.perpParam.limitHAHedge = perpetualManager.limitHAHedge();\n params.perpParam.lockTime = perpetualManager.lockTime();\n\n params.perpFeeData.haBonusMalusDeposit = perpetualManager.haBonusMalusDeposit();\n params.perpFeeData.haBonusMalusWithdraw = perpetualManager.haBonusMalusWithdraw();\n\n uint256 length = 0;\n while (true) {\n try perpetualManager.xHAFeesDeposit(length) returns (uint64) {\n length += 1;\n } catch {\n break;\n }\n }\n uint64[] memory data = new uint64[](length);\n uint64[] memory data2 = new uint64[](length);\n for (uint256 i; i < length; ++i) {\n data[i] = perpetualManager.xHAFeesDeposit(i);\n data2[i] = perpetualManager.yHAFeesDeposit(i);\n }\n params.perpFeeData.xHAFeesDeposit = data;\n params.perpFeeData.yHAFeesDeposit = data2;\n\n length = 0;\n while (true) {\n try perpetualManager.xHAFeesWithdraw(length) returns (uint64) {\n length += 1;\n } catch {\n break;\n }\n }\n data = new uint64[](length);\n data2 = new uint64[](length);\n for (uint256 i; i < length; ++i) {\n data[i] = perpetualManager.xHAFeesWithdraw(i);\n data2[i] = perpetualManager.yHAFeesWithdraw(i);\n }\n params.perpFeeData.xHAFeesWithdraw = data;\n params.perpFeeData.yHAFeesWithdraw = data2;\n }\n\n /// @notice Returns the address of the poolManager associated to an (`agToken`, `collateral`) pair\n /// in the Core module of the protocol\n function getPoolManager(address agToken, address collateral) public view returns (address poolManager) {\n (, poolManager) = _getStableMasterAndPoolManager(agToken, collateral);\n }\n\n // ======================== Replica Functions ==================================\n // These replicate what is done in the other contracts of the protocol\n\n function _previewBurnAndFees(\n uint256 amount,\n address agToken,\n address collateral\n ) internal view returns (uint256 amountForUserInCollat, uint256 feePercent) {\n (address stableMaster, address poolManager) = _getStableMasterAndPoolManager(agToken, collateral);\n (\n address token,\n ,\n IPerpetualManager perpetualManager,\n IOracleCore oracle,\n uint256 stocksUsers,\n ,\n uint256 collatBase,\n ,\n MintBurnData memory feeData\n ) = IStableMaster(stableMaster).collateralMap(poolManager);\n if (token == address(0) || IStableMaster(stableMaster).paused(keccak256(abi.encodePacked(STABLE, poolManager))))\n revert NotInitialized();\n if (amount > stocksUsers) revert InvalidAmount();\n\n if (feeData.xFeeBurn.length == 1) {\n feePercent = feeData.yFeeBurn[0];\n } else {\n bytes memory data = abi.encode(address(perpetualManager), feeData.targetHAHedge);\n uint64 hedgeRatio = _computeHedgeRatio(stocksUsers - amount, data);\n feePercent = _piecewiseLinear(hedgeRatio, feeData.xFeeBurn, feeData.yFeeBurn);\n }\n feePercent = (feePercent * feeData.bonusMalusBurn) / BASE_PARAMS;\n\n amountForUserInCollat = (amount * (BASE_PARAMS - feePercent) * collatBase) / (oracle.readUpper() * BASE_PARAMS);\n }\n\n function _previewMintAndFees(\n uint256 amount,\n address agToken,\n address collateral\n ) internal view returns (uint256 amountForUserInStable, uint256 feePercent) {\n (address stableMaster, address poolManager) = _getStableMasterAndPoolManager(agToken, collateral);\n (\n address token,\n ,\n IPerpetualManager perpetualManager,\n IOracleCore oracle,\n uint256 stocksUsers,\n ,\n ,\n ,\n MintBurnData memory feeData\n ) = IStableMaster(stableMaster).collateralMap(poolManager);\n if (token == address(0) || IStableMaster(stableMaster).paused(keccak256(abi.encodePacked(STABLE, poolManager))))\n revert NotInitialized();\n\n amountForUserInStable = oracle.readQuoteLower(amount);\n\n if (feeData.xFeeMint.length == 1) feePercent = feeData.yFeeMint[0];\n else {\n bytes memory data = abi.encode(address(perpetualManager), feeData.targetHAHedge);\n uint64 hedgeRatio = _computeHedgeRatio(amountForUserInStable + stocksUsers, data);\n feePercent = _piecewiseLinear(hedgeRatio, feeData.xFeeMint, feeData.yFeeMint);\n }\n feePercent = (feePercent * feeData.bonusMalusMint) / BASE_PARAMS;\n\n amountForUserInStable = (amountForUserInStable * (BASE_PARAMS - feePercent)) / BASE_PARAMS;\n if (stocksUsers + amountForUserInStable > feeData.capOnStableMinted) revert InvalidAmount();\n }\n\n // ======================== Utility Functions ==================================\n // These utility functions are taken from other contracts of the protocol\n\n function _computeHedgeRatio(uint256 newStocksUsers, bytes memory data) internal view returns (uint64 ratio) {\n (address perpetualManager, uint64 targetHAHedge) = abi.decode(data, (address, uint64));\n uint256 totalHedgeAmount = IPerpetualManager(perpetualManager).totalHedgeAmount();\n newStocksUsers = (targetHAHedge * newStocksUsers) / BASE_PARAMS;\n if (newStocksUsers > totalHedgeAmount) ratio = uint64((totalHedgeAmount * BASE_PARAMS) / newStocksUsers);\n else ratio = uint64(BASE_PARAMS);\n }\n\n function _piecewiseLinear(\n uint64 x,\n uint64[] memory xArray,\n uint64[] memory yArray\n ) internal pure returns (uint64) {\n if (x >= xArray[xArray.length - 1]) {\n return yArray[xArray.length - 1];\n } else if (x <= xArray[0]) {\n return yArray[0];\n } else {\n uint256 lower;\n uint256 upper = xArray.length - 1;\n uint256 mid;\n while (upper - lower > 1) {\n mid = lower + (upper - lower) / 2;\n if (xArray[mid] <= x) {\n lower = mid;\n } else {\n upper = mid;\n }\n }\n if (yArray[upper] > yArray[lower]) {\n return\n yArray[lower] +\n ((yArray[upper] - yArray[lower]) * (x - xArray[lower])) /\n (xArray[upper] - xArray[lower]);\n } else {\n return\n yArray[lower] -\n ((yArray[lower] - yArray[upper]) * (x - xArray[lower])) /\n (xArray[upper] - xArray[lower]);\n }\n }\n }\n\n function _getStableMasterAndPoolManager(address agToken, address collateral)\n internal\n view\n returns (address stableMaster, address poolManager)\n {\n stableMaster = IAgTokenMainnet(agToken).stableMaster();\n (poolManager, , , ) = ROUTER.mapPoolManagers(stableMaster, collateral);\n }\n\n // ====================== Constants and Initializers ===========================\n\n IAngleRouter public constant ROUTER = IAngleRouter(0xBB755240596530be0c1DE5DFD77ec6398471561d);\n ICore public constant CORE = ICore(0x61ed74de9Ca5796cF2F8fD60D54160D47E30B7c3);\n\n bytes32 public constant STABLE = keccak256(\"STABLE\");\n uint256 public constant BASE_PARAMS = 10**9;\n\n error NotInitialized();\n error InvalidAmount();\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() initializer {}\n}\n" + }, + "contracts/oracle/KeeperRegistry.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport \"../interfaces/ICoreBorrow.sol\";\nimport \"../interfaces/IKeeperRegistry.sol\";\n\n/// @title KeeperRegistry\n/// @notice Maintains a mapping of keepers authorized to use the core module just after oracle updates\n/// @author Angle Labs, Inc.\ncontract KeeperRegistry is Initializable, IKeeperRegistry {\n using SafeERC20 for IERC20;\n\n /// @notice Contract handling access control\n ICoreBorrow public coreBorrow;\n\n /// @notice Trusted EOAs - needs to be tx.origin\n mapping(address => uint256) public trusted;\n\n uint256[48] private __gap;\n\n // =================================== EVENTS ==================================\n\n event TrustedToggled(address indexed wallet, bool trust);\n\n // =================================== ERRORS ==================================\n\n error NotGovernorOrGuardian();\n error NotTrusted();\n error ZeroAddress();\n\n // ================================= MODIFIERS =================================\n\n /// @notice Checks whether the `msg.sender` has the governor role or the guardian role\n modifier onlyGovernorOrGuardian() {\n if (!coreBorrow.isGovernorOrGuardian(msg.sender)) revert NotGovernorOrGuardian();\n _;\n }\n\n // ================================ CONSTRUCTOR ================================\n\n constructor() initializer {}\n\n function initialize(ICoreBorrow _coreBorrow) public initializer {\n if (address(_coreBorrow) == address(0)) revert ZeroAddress();\n coreBorrow = _coreBorrow;\n }\n\n // =============================== MAIN FUNCTIONS ==============================\n\n /// @notice Adds or removes a trusted keeper bot\n function toggleTrusted(address eoa) external onlyGovernorOrGuardian {\n uint256 trustedStatus = 1 - trusted[eoa];\n trusted[eoa] = trustedStatus;\n emit TrustedToggled(eoa, trustedStatus == 1);\n }\n\n /// @inheritdoc IKeeperRegistry\n function isTrusted(address caller) external view returns (bool) {\n return trusted[caller] == 1;\n }\n}\n" + }, + "contracts/interfaces/IKeeperRegistry.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\n\n/// @title IKeeperRegistry\n/// @author Angle Labs, Inc.\ninterface IKeeperRegistry {\n /// @notice Checks whether an address is whitelisted during oracle updates\n /// @param caller Address for which the whitelist should be checked\n /// @return Whether the address is trusted or not\n function isTrusted(address caller) external view returns (bool);\n}\n" + }, + "contracts/agToken/polygon/utils/ERC20UpgradeableCustom.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface modified by Angle Labs, Inc.\n *\n * This implementation has a custom burn function to avoid having a {Transfer} event to the zero address\n * in some specific burn cases to avoid having Polygon PoS bridge catching this event\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20UpgradeableCustom is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n //solhint-disable-next-line\n function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {\n __Context_init_unchained();\n __ERC20_init_unchained(name_, symbol_);\n }\n\n //solhint-disable-next-line\n function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public virtual override returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * Requirements:\n *\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for `sender`'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public virtual override returns (bool) {\n _transfer(sender, recipient, amount);\n\n uint256 currentAllowance = _allowances[sender][_msgSender()];\n require(currentAllowance >= amount, \"ERC20: transfer amount exceeds allowance\");\n unchecked {\n _approve(sender, _msgSender(), currentAllowance - amount);\n }\n\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n uint256 currentAllowance = _allowances[_msgSender()][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(_msgSender(), spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(\n address sender,\n address recipient,\n uint256 amount\n ) internal virtual {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(sender, recipient, amount);\n\n uint256 senderBalance = _balances[sender];\n require(senderBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[sender] = senderBalance - amount;\n }\n _balances[recipient] += amount;\n\n emit Transfer(sender, recipient, amount);\n\n _afterTokenTransfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Contrary to the other `burn` function, the {Transfer} event is not to the zero address\n * but rather to this address: the reason is that not all burn events should be caught up\n * by the PoS bridge\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burnCustom(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(this), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of `from`'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of `from`'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of `from`'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of `from`'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n uint256[45] private __gap;\n}\n" + }, + "contracts/mock/MockPolygonAgEUR.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.12;\n\nimport \"../agToken/polygon/utils/ERC20UpgradeableCustom.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport \"../interfaces/IAgToken.sol\";\nimport \"../interfaces/ITreasury.sol\";\n\ninterface IChildToken {\n function deposit(address user, bytes calldata depositData) external;\n\n function withdraw(uint256 amount) external;\n}\n\ncontract MockPolygonAgEUR is\n Initializable,\n ERC20UpgradeableCustom,\n AccessControlUpgradeable,\n EIP712Upgradeable,\n IChildToken\n{\n bytes32 public constant DEPOSITOR_ROLE = keccak256(\"DEPOSITOR_ROLE\");\n\n /// @dev Emitted when the child chain manager changes\n event ChildChainManagerAdded(address newAddress);\n event ChildChainManagerRevoked(address oldAddress);\n\n constructor() initializer {}\n\n function initialize(\n string memory _name,\n string memory _symbol,\n address childChainManager,\n address guardian\n ) public initializer {\n __ERC20_init(_name, _symbol);\n __AccessControl_init();\n _setupRole(DEFAULT_ADMIN_ROLE, guardian);\n _setupRole(DEPOSITOR_ROLE, childChainManager);\n __EIP712_init(_name, \"1\");\n }\n\n /**\n * @notice Called when the bridge has tokens to mint\n * @param user Address to mint the token to\n * @param depositData Encoded amount to mint\n */\n function deposit(address user, bytes calldata depositData) external override {\n require(hasRole(DEPOSITOR_ROLE, msg.sender));\n uint256 amount = abi.decode(depositData, (uint256));\n _mint(user, amount);\n }\n\n /**\n * @notice Called when user wants to withdraw tokens back to root chain\n * @dev Should burn user's tokens. This transaction will be verified when exiting on root chain\n * @param amount Amount of tokens to withdraw\n */\n function withdraw(uint256 amount) external override {\n _burn(_msgSender(), amount);\n }\n\n // =============================================================================\n // ======================= New data added for the upgrade ======================\n // =============================================================================\n\n mapping(address => bool) public isMinter;\n /// @notice Reference to the treasury contract which can grant minting rights\n address public treasury;\n /// @notice Boolean to check whether the contract has been reinitialized after its upgrade\n bool public treasuryInitialized;\n\n using SafeERC20 for IERC20;\n\n /// @notice Base used for fee computation\n uint256 public constant BASE_PARAMS = 10**9;\n\n // =============================== Bridging Data ===============================\n\n /// @notice Struct with some data about a specific bridge token\n struct BridgeDetails {\n // Limit on the balance of bridge token held by the contract: it is designed\n // to reduce the exposure of the system to hacks\n uint256 limit;\n // Limit on the hourly volume of token minted through this bridge\n // Technically the limit over a rolling hour is hourlyLimit x2 as hourly limit\n // is enforced only between x:00 and x+1:00\n uint256 hourlyLimit;\n // Fee taken for swapping in and out the token\n uint64 fee;\n // Whether the associated token is allowed or not\n bool allowed;\n // Whether swapping in and out from the associated token is paused or not\n bool paused;\n }\n\n /// @notice Maps a bridge token to data\n mapping(address => BridgeDetails) public bridges;\n /// @notice List of all bridge tokens\n address[] public bridgeTokensList;\n /// @notice Maps a bridge token to the associated hourly volume\n mapping(address => mapping(uint256 => uint256)) public usage;\n /// @notice Maps an address to whether it is exempt of fees for when it comes to swapping in and out\n mapping(address => uint256) public isFeeExempt;\n\n uint256[44] private __gap;\n\n // ================================== Events ===================================\n\n event BridgeTokenAdded(address indexed bridgeToken, uint256 limit, uint256 hourlyLimit, uint64 fee, bool paused);\n event BridgeTokenToggled(address indexed bridgeToken, bool toggleStatus);\n event BridgeTokenRemoved(address indexed bridgeToken);\n event BridgeTokenFeeUpdated(address indexed bridgeToken, uint64 fee);\n event BridgeTokenLimitUpdated(address indexed bridgeToken, uint256 limit);\n event BridgeTokenHourlyLimitUpdated(address indexed bridgeToken, uint256 hourlyLimit);\n event HourlyLimitUpdated(uint256 hourlyLimit);\n event FeeToggled(address indexed theAddress, uint256 toggleStatus);\n event KeeperToggled(address indexed keeper, bool toggleStatus);\n event MinterToggled(address indexed minter);\n event Recovered(address indexed token, address indexed to, uint256 amount);\n event TreasuryUpdated(address indexed _treasury);\n\n // ================================== Errors ===================================\n\n error AssetStillControlledInReserves();\n error BurnAmountExceedsAllowance();\n error HourlyLimitExceeded();\n error InvalidSender();\n error InvalidToken();\n error InvalidTreasury();\n error NotGovernor();\n error NotGovernorOrGuardian();\n error NotMinter();\n error NotTreasury();\n error TooBigAmount();\n error TooHighParameterValue();\n error TreasuryAlreadyInitialized();\n error ZeroAddress();\n\n /// @notice Checks to see if it is the `Treasury` calling this contract\n /// @dev There is no Access Control here, because it can be handled cheaply through this modifier\n modifier onlyTreasury() {\n if (msg.sender != treasury) revert NotTreasury();\n _;\n }\n\n /// @notice Checks whether the sender has the minting right\n modifier onlyMinter() {\n if (!isMinter[msg.sender]) revert NotMinter();\n _;\n }\n\n /// @notice Checks whether the `msg.sender` has the governor role or not\n modifier onlyGovernor() {\n if (!ITreasury(treasury).isGovernor(msg.sender)) revert NotGovernor();\n _;\n }\n\n /// @notice Checks whether the `msg.sender` has the governor role or the guardian role\n modifier onlyGovernorOrGuardian() {\n if (!ITreasury(treasury).isGovernorOrGuardian(msg.sender)) revert NotGovernorOrGuardian();\n _;\n }\n\n /// @notice Sets up the treasury contract on Polygon after the upgrade\n /// @param _treasury Address of the treasury contract\n function setUpTreasury(address _treasury) external {\n // Only governor on Polygon\n if (msg.sender != 0xdA2D2f638D6fcbE306236583845e5822554c02EA) revert NotGovernor();\n if (address(ITreasury(_treasury).stablecoin()) != address(this)) revert InvalidTreasury();\n if (treasuryInitialized) revert TreasuryAlreadyInitialized();\n treasury = _treasury;\n treasuryInitialized = true;\n emit TreasuryUpdated(_treasury);\n }\n\n // =========================== External Function ===============================\n\n /// @notice Allows anyone to burn agToken without redeeming collateral back\n /// @param amount Amount of stablecoins to burn\n /// @dev This function can typically be called if there is a settlement mechanism to burn stablecoins\n function burnStablecoin(uint256 amount) external {\n _burnCustom(msg.sender, amount);\n }\n\n // ======================= Minter Role Only Functions ==========================\n\n function burnSelf(uint256 amount, address burner) external onlyMinter {\n _burnCustom(burner, amount);\n }\n\n function burnFrom(\n uint256 amount,\n address burner,\n address sender\n ) external onlyMinter {\n _burnFromNoRedeem(amount, burner, sender);\n }\n\n function mint(address account, uint256 amount) external onlyMinter {\n _mint(account, amount);\n }\n\n // ======================= Treasury Only Functions =============================\n\n function addMinter(address minter) external onlyTreasury {\n isMinter[minter] = true;\n emit MinterToggled(minter);\n }\n\n function removeMinter(address minter) external {\n if (msg.sender != address(treasury) && msg.sender != minter) revert InvalidSender();\n isMinter[minter] = false;\n emit MinterToggled(minter);\n }\n\n function setTreasury(address _treasury) external onlyTreasury {\n treasury = _treasury;\n emit TreasuryUpdated(_treasury);\n }\n\n // ============================ Internal Function ==============================\n\n /// @notice Internal version of the function `burnFromNoRedeem`\n /// @param amount Amount to burn\n /// @dev It is at the level of this function that allowance checks are performed\n function _burnFromNoRedeem(\n uint256 amount,\n address burner,\n address sender\n ) internal {\n if (burner != sender) {\n uint256 currentAllowance = allowance(burner, sender);\n if (currentAllowance < amount) revert BurnAmountExceedsAllowance();\n _approve(burner, sender, currentAllowance - amount);\n }\n _burnCustom(burner, amount);\n }\n\n // ==================== External Permissionless Functions ======================\n\n /// @notice Returns the list of all supported bridge tokens\n /// @dev Helpful for UIs\n function allBridgeTokens() external view returns (address[] memory) {\n return bridgeTokensList;\n }\n\n /// @notice Returns the current volume for a bridge, for the current hour\n /// @dev Helpful for UIs\n function currentUsage(address bridge) external view returns (uint256) {\n return usage[bridge][block.timestamp / 3600];\n }\n\n /// @notice Mints the canonical token from a supported bridge token\n /// @param bridgeToken Bridge token to use to mint\n /// @param amount Amount of bridge tokens to send\n /// @param to Address to which the stablecoin should be sent\n /// @dev Some fees may be taken by the protocol depending on the token used and on the address calling\n function swapIn(\n address bridgeToken,\n uint256 amount,\n address to\n ) external returns (uint256) {\n BridgeDetails memory bridgeDetails = bridges[bridgeToken];\n if (!bridgeDetails.allowed || bridgeDetails.paused) revert InvalidToken();\n uint256 balance = IERC20(bridgeToken).balanceOf(address(this));\n if (balance + amount > bridgeDetails.limit) {\n // In case someone maliciously sends tokens to this contract\n // Or the limit changes\n if (bridgeDetails.limit > balance) amount = bridgeDetails.limit - balance;\n else {\n amount = 0;\n }\n }\n\n // Checking requirement on the hourly volume\n uint256 hour = block.timestamp / 3600;\n uint256 hourlyUsage = usage[bridgeToken][hour] + amount;\n if (hourlyUsage > bridgeDetails.hourlyLimit) {\n // Edge case when the hourly limit changes\n if (bridgeDetails.hourlyLimit > usage[bridgeToken][hour])\n amount = bridgeDetails.hourlyLimit - usage[bridgeToken][hour];\n else {\n amount = 0;\n }\n }\n usage[bridgeToken][hour] = usage[bridgeToken][hour] + amount;\n\n IERC20(bridgeToken).safeTransferFrom(msg.sender, address(this), amount);\n uint256 canonicalOut = amount;\n // Computing fees\n if (isFeeExempt[msg.sender] == 0) {\n canonicalOut -= (canonicalOut * bridgeDetails.fee) / BASE_PARAMS;\n }\n _mint(to, canonicalOut);\n return canonicalOut;\n }\n\n /// @notice Burns the canonical token in exchange for a bridge token\n /// @param bridgeToken Bridge token required\n /// @param amount Amount of canonical tokens to burn\n /// @param to Address to which the bridge token should be sent\n /// @dev Some fees may be taken by the protocol depending on the token used and on the address calling\n function swapOut(\n address bridgeToken,\n uint256 amount,\n address to\n ) external returns (uint256) {\n BridgeDetails memory bridgeDetails = bridges[bridgeToken];\n if (!bridgeDetails.allowed || bridgeDetails.paused) revert InvalidToken();\n\n _burnCustom(msg.sender, amount);\n uint256 bridgeOut = amount;\n if (isFeeExempt[msg.sender] == 0) {\n bridgeOut -= (bridgeOut * bridgeDetails.fee) / BASE_PARAMS;\n }\n IERC20(bridgeToken).safeTransfer(to, bridgeOut);\n return bridgeOut;\n }\n\n // ======================= Governance Functions ================================\n\n /// @notice Adds support for a bridge token\n /// @param bridgeToken Bridge token to add: it should be a version of the stablecoin from another bridge\n /// @param limit Limit on the balance of bridge token this contract could hold\n /// @param hourlyLimit Limit on the hourly volume for this bridge\n /// @param paused Whether swapping for this token should be paused or not\n /// @param fee Fee taken upon swapping for or against this token\n function addBridgeToken(\n address bridgeToken,\n uint256 limit,\n uint256 hourlyLimit,\n uint64 fee,\n bool paused\n ) external onlyGovernor {\n if (bridges[bridgeToken].allowed || bridgeToken == address(0)) revert InvalidToken();\n if (fee > BASE_PARAMS) revert TooHighParameterValue();\n BridgeDetails memory _bridge;\n _bridge.limit = limit;\n _bridge.hourlyLimit = hourlyLimit;\n _bridge.paused = paused;\n _bridge.fee = fee;\n _bridge.allowed = true;\n bridges[bridgeToken] = _bridge;\n bridgeTokensList.push(bridgeToken);\n emit BridgeTokenAdded(bridgeToken, limit, hourlyLimit, fee, paused);\n }\n\n /// @notice Removes support for a token\n /// @param bridgeToken Address of the bridge token to remove support for\n function removeBridgeToken(address bridgeToken) external onlyGovernor {\n if (IERC20(bridgeToken).balanceOf(address(this)) != 0) revert AssetStillControlledInReserves();\n delete bridges[bridgeToken];\n // Deletion from `bridgeTokensList` loop\n uint256 bridgeTokensListLength = bridgeTokensList.length;\n for (uint256 i; i < bridgeTokensListLength - 1; ++i) {\n if (bridgeTokensList[i] == bridgeToken) {\n // Replace the `bridgeToken` to remove with the last of the list\n bridgeTokensList[i] = bridgeTokensList[bridgeTokensListLength - 1];\n break;\n }\n }\n // Remove last element in array\n bridgeTokensList.pop();\n emit BridgeTokenRemoved(bridgeToken);\n }\n\n /// @notice Recovers any ERC20 token\n /// @dev Can be used to withdraw bridge tokens for them to be de-bridged on mainnet\n function recoverERC20(\n address tokenAddress,\n address to,\n uint256 amountToRecover\n ) external onlyGovernor {\n IERC20(tokenAddress).safeTransfer(to, amountToRecover);\n emit Recovered(tokenAddress, to, amountToRecover);\n }\n\n /// @notice Updates the `limit` amount for `bridgeToken`\n function setLimit(address bridgeToken, uint256 limit) external onlyGovernorOrGuardian {\n if (!bridges[bridgeToken].allowed) revert InvalidToken();\n bridges[bridgeToken].limit = limit;\n emit BridgeTokenLimitUpdated(bridgeToken, limit);\n }\n\n /// @notice Updates the `hourlyLimit` amount for `bridgeToken`\n function setHourlyLimit(address bridgeToken, uint256 hourlyLimit) external onlyGovernorOrGuardian {\n if (!bridges[bridgeToken].allowed) revert InvalidToken();\n bridges[bridgeToken].hourlyLimit = hourlyLimit;\n emit BridgeTokenHourlyLimitUpdated(bridgeToken, hourlyLimit);\n }\n\n /// @notice Updates the `fee` value for `bridgeToken`\n function setSwapFee(address bridgeToken, uint64 fee) external onlyGovernorOrGuardian {\n if (!bridges[bridgeToken].allowed) revert InvalidToken();\n if (fee > BASE_PARAMS) revert TooHighParameterValue();\n bridges[bridgeToken].fee = fee;\n emit BridgeTokenFeeUpdated(bridgeToken, fee);\n }\n\n /// @notice Pauses or unpauses swapping in and out for a token\n function toggleBridge(address bridgeToken) external onlyGovernorOrGuardian {\n if (!bridges[bridgeToken].allowed) revert InvalidToken();\n bool pausedStatus = bridges[bridgeToken].paused;\n bridges[bridgeToken].paused = !pausedStatus;\n emit BridgeTokenToggled(bridgeToken, !pausedStatus);\n }\n\n /// @notice Toggles fees for the address `theAddress`\n function toggleFeesForAddress(address theAddress) external onlyGovernorOrGuardian {\n uint256 feeExemptStatus = 1 - isFeeExempt[theAddress];\n isFeeExempt[theAddress] = feeExemptStatus;\n emit FeeToggled(theAddress, feeExemptStatus);\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControlUpgradeable.sol\";\nimport \"../utils/ContextUpgradeable.sol\";\nimport \"../utils/StringsUpgradeable.sol\";\nimport \"../utils/introspection/ERC165Upgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it.\n */\nabstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {\n function __AccessControl_init() internal onlyInitializing {\n }\n\n function __AccessControl_init_unchained() internal onlyInitializing {\n }\n struct RoleData {\n mapping(address => bool) members;\n bytes32 adminRole;\n }\n\n mapping(bytes32 => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with a standardized message including the required role.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n *\n * _Available since v4.1._\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\n return _roles[role].members[account];\n }\n\n /**\n * @dev Revert with a standard message if `_msgSender()` is missing `role`.\n * Overriding this function changes the behavior of the {onlyRole} modifier.\n *\n * Format of the revert message is described in {_checkRole}.\n *\n * _Available since v4.6._\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Revert with a standard message if `account` is missing `role`.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert(\n string(\n abi.encodePacked(\n \"AccessControl: account \",\n StringsUpgradeable.toHexString(uint160(account), 20),\n \" is missing role \",\n StringsUpgradeable.toHexString(uint256(role), 32)\n )\n )\n );\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address account) public virtual override {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn't perform any\n * checks on the calling account.\n *\n * May emit a {RoleGranted} event.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n *\n * NOTE: This function is deprecated in favor of {_grantRole}.\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual {\n if (!hasRole(role, account)) {\n _roles[role].members[account] = true;\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual {\n if (hasRole(role, account)) {\n _roles[role].members[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/cryptography/draft-EIP712.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./ECDSAUpgradeable.sol\";\nimport \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,\n * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding\n * they need in their contracts using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * _Available since v3.4._\n *\n * @custom:storage-size 52\n */\nabstract contract EIP712Upgradeable is Initializable {\n /* solhint-disable var-name-mixedcase */\n bytes32 private _HASHED_NAME;\n bytes32 private _HASHED_VERSION;\n bytes32 private constant _TYPE_HASH = keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\");\n\n /* solhint-enable var-name-mixedcase */\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n function __EIP712_init(string memory name, string memory version) internal onlyInitializing {\n __EIP712_init_unchained(name, version);\n }\n\n function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {\n bytes32 hashedName = keccak256(bytes(name));\n bytes32 hashedVersion = keccak256(bytes(version));\n _HASHED_NAME = hashedName;\n _HASHED_VERSION = hashedVersion;\n }\n\n /**\n * @dev Returns the domain separator for the current chain.\n */\n function _domainSeparatorV4() internal view returns (bytes32) {\n return _buildDomainSeparator(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash());\n }\n\n function _buildDomainSeparator(\n bytes32 typeHash,\n bytes32 nameHash,\n bytes32 versionHash\n ) private view returns (bytes32) {\n return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * )));\n * address signer = ECDSA.recover(digest, signature);\n * ```\n */\n function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(), structHash);\n }\n\n /**\n * @dev The hash of the name parameter for the EIP712 domain.\n *\n * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs\n * are a concern.\n */\n function _EIP712NameHash() internal virtual view returns (bytes32) {\n return _HASHED_NAME;\n }\n\n /**\n * @dev The hash of the version parameter for the EIP712 domain.\n *\n * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs\n * are a concern.\n */\n function _EIP712VersionHash() internal virtual view returns (bytes32) {\n return _HASHED_VERSION;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/access/IAccessControlUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControlUpgradeable {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary StringsUpgradeable {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165Upgradeable.sol\";\nimport \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {\n function __ERC165_init() internal onlyInitializing {\n }\n\n function __ERC165_init_unchained() internal onlyInitializing {\n }\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165Upgradeable).interfaceId;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../StringsUpgradeable.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSAUpgradeable {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", StringsUpgradeable.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" + }, + "contracts/oracle/BaseOracleChainlinkMulti.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n * █ \n ***** ▓▓▓ \n * ▓▓▓▓▓▓▓ \n * ///. ▓▓▓▓▓▓▓▓▓▓▓▓▓ \n ***** //////// ▓▓▓▓▓▓▓ \n * ///////////// ▓▓▓ \n ▓▓ ////////////////// █ ▓▓ \n ▓▓ ▓▓ /////////////////////// ▓▓ ▓▓ \n ▓▓ ▓▓ //////////////////////////// ▓▓ ▓▓ \n ▓▓ ▓▓ /////////▓▓▓///////▓▓▓///////// ▓▓ ▓▓ \n ▓▓ ,////////////////////////////////////// ▓▓ ▓▓ \n ▓▓ ////////////////////////////////////////// ▓▓ \n ▓▓ //////////////////////▓▓▓▓///////////////////// \n ,//////////////////////////////////////////////////// \n .////////////////////////////////////////////////////////// \n .//////////////////////////██.,//////////////////////////█ \n .//////////////////////████..,./////////////////////██ \n ...////////////////███████.....,.////////////////███ \n ,.,////////////████████ ........,///////////████ \n .,.,//////█████████ ,.......///////████ \n ,..//████████ ........./████ \n ..,██████ .....,███ \n .██ ,.,█ \n \n \n \n ▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓ \n ▓▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓ ▓▓▓▓ \n ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓▓▓▓ \n ▓▓▓ ▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ \n*/\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../interfaces/IOracle.sol\";\nimport \"../interfaces/ITreasury.sol\";\n\n/// @title BaseOracleChainlinkMulti\n/// @author Angle Labs, Inc.\n/// @notice Base Contract to be overriden by all contracts of the protocol\n/// @dev This base contract concerns an oracle that uses Chainlink with multiple pools to read from\n/// @dev All gas-efficient implementation of the `OracleChainlinkMulti` contract should inherit from this\nabstract contract BaseOracleChainlinkMulti is IOracle {\n // ========================= Parameters and References =========================\n\n /// @inheritdoc IOracle\n ITreasury public override treasury;\n /// @notice Represent the maximum amount of time (in seconds) between each Chainlink update\n /// before the price feed is considered stale\n uint32 public stalePeriod;\n\n // =================================== Event ===================================\n\n event StalePeriodUpdated(uint32 _stalePeriod);\n\n // =================================== Errors ===================================\n\n error InvalidChainlinkRate();\n error NotGovernorOrGuardian();\n error NotVaultManagerOrGovernor();\n\n /// @notice Constructor for an oracle using Chainlink with multiple pools to read from\n /// @param _stalePeriod Minimum feed update frequency for the oracle to not revert\n /// @param _treasury Treasury associated to the VaultManager which reads from this feed\n constructor(uint32 _stalePeriod, address _treasury) {\n stalePeriod = _stalePeriod;\n treasury = ITreasury(_treasury);\n }\n\n // ============================= Reading Oracles ===============================\n\n /// @inheritdoc IOracle\n function read() external view virtual override returns (uint256 quoteAmount);\n\n /// @inheritdoc IOracle\n function circuitChainlink() public view virtual returns (AggregatorV3Interface[] memory);\n\n /// @notice Reads a Chainlink feed using a quote amount and converts the quote amount to\n /// the out-currency\n /// @param quoteAmount The amount for which to compute the price expressed with base decimal\n /// @param feed Chainlink feed to query\n /// @param multiplied Whether the ratio outputted by Chainlink should be multiplied or divided\n /// to the `quoteAmount`\n /// @param decimals Number of decimals of the corresponding Chainlink pair\n /// @return The `quoteAmount` converted in out-currency\n function _readChainlinkFeed(\n uint256 quoteAmount,\n AggregatorV3Interface feed,\n uint8 multiplied,\n uint256 decimals\n ) internal view returns (uint256) {\n (uint80 roundId, int256 ratio, , uint256 updatedAt, uint80 answeredInRound) = feed.latestRoundData();\n if (ratio <= 0 || roundId > answeredInRound || block.timestamp - updatedAt > stalePeriod)\n revert InvalidChainlinkRate();\n uint256 castedRatio = uint256(ratio);\n // Checking whether we should multiply or divide by the ratio computed\n if (multiplied == 1) return (quoteAmount * castedRatio) / (10 ** decimals);\n else return (quoteAmount * (10 ** decimals)) / castedRatio;\n }\n\n // ======================= Governance Related Functions ========================\n\n /// @notice Changes the stale period\n /// @param _stalePeriod New stale period (in seconds)\n function changeStalePeriod(uint32 _stalePeriod) external {\n if (!treasury.isGovernorOrGuardian(msg.sender)) revert NotGovernorOrGuardian();\n stalePeriod = _stalePeriod;\n emit StalePeriodUpdated(_stalePeriod);\n }\n\n /// @inheritdoc IOracle\n function setTreasury(address _treasury) external override {\n if (!treasury.isVaultManager(msg.sender) && !treasury.isGovernor(msg.sender))\n revert NotVaultManagerOrGovernor();\n treasury = ITreasury(_treasury);\n }\n}\n" + }, + "contracts/oracle/OracleChainlinkMultiTemplate.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"./BaseOracleChainlinkMulti.sol\";\n\n/// @title OracleChainlinkMultiTemplate\n/// @author Angle Labs, Inc.\n/// @notice Oracle contract, one contract is deployed per collateral/stablecoin pair\n/// @dev This contract concerns an oracle that uses Chainlink with multiple pools to read from\n/// @dev This is a template and a more gas-efficient implementation of the `OracleChainlinkMulti` contract\ncontract OracleChainlinkMultiTemplate is BaseOracleChainlinkMulti {\n // ===================== To be modified before deployment ======================\n uint256 public constant OUTBASE = 10**18;\n string public constant DESCRIPTION = \"ETH/EUR Oracle\";\n\n // =============================================================================\n\n /// @notice Constructor for an oracle using Chainlink with multiple pools to read from\n /// @param _stalePeriod Minimum feed update frequency for the oracle to not revert\n /// @param _treasury Treasury associated to the VaultManager which reads from this feed\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMulti(_stalePeriod, _treasury) {}\n\n // ============================= Reading Oracles ===============================\n\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n _circuitChainlink[0] = AggregatorV3Interface(address(0));\n _circuitChainlink[1] = AggregatorV3Interface(address(0));\n return _circuitChainlink;\n }\n\n /// @inheritdoc IOracle\n function read() external view override returns (uint256 quoteAmount) {\n quoteAmount = OUTBASE;\n // ===================== To be modified before deployment ==================\n AggregatorV3Interface[] memory _circuitChainlink = circuitChainlink();\n uint8[2] memory circuitChainIsMultiplied = [0, 0];\n uint8[2] memory chainlinkDecimals = [0, 0];\n // =========================================================================\n uint256 circuitLength = _circuitChainlink.length;\n for (uint256 i; i < circuitLength; ++i) {\n quoteAmount = _readChainlinkFeed(\n quoteAmount,\n _circuitChainlink[i],\n circuitChainIsMultiplied[i],\n chainlinkDecimals[i]\n );\n }\n }\n}\n" + }, + "contracts/oracle/OracleChainlinkMulti.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"./BaseOracleChainlinkMulti.sol\";\n\n/// @title OracleChainlinkMulti\n/// @author Angle Labs, Inc.\n/// @notice Oracle contract, one contract is deployed per collateral/stablecoin pair\n/// @dev This contract concerns an oracle that uses Chainlink with multiple pools to read from\n/// @dev Typically we expect to use this contract to read like the ETH/USD and then USD/EUR feed\ncontract OracleChainlinkMulti is BaseOracleChainlinkMulti {\n // ========================= Parameters and References =========================\n\n /// @notice Chainlink pools, the order of the pools has to be the order in which they are read for the computation\n /// of the price\n AggregatorV3Interface[] internal _circuitChainlink;\n /// @notice Whether each rate for the pairs in `circuitChainlink` should be multiplied or divided\n uint8[] public circuitChainIsMultiplied;\n /// @notice Decimals for each Chainlink pairs\n uint8[] public chainlinkDecimals;\n /// @notice Unit of the stablecoin\n uint256 public immutable outBase;\n /// @notice Description of the assets concerned by the oracle and the price outputted\n string public description;\n\n // ===================================== Error =================================\n\n error IncompatibleLengths();\n\n /// @notice Constructor for an oracle using Chainlink with multiple pools to read from\n /// @param circuitChainlink_ Chainlink pool addresses (in order)\n /// @param _circuitChainIsMultiplied Whether we should multiply or divide by this rate\n /// @param _outBase Unit of the stablecoin (or the out asset) associated to the oracle\n /// @param _stalePeriod Minimum feed update frequency for the oracle to not revert\n /// @param _treasury Treasury associated to the VaultManager which reads from this feed\n /// @param _description Description of the assets concerned by the oracle\n /// @dev For instance, if this oracle is supposed to give the price of ETH in EUR, and if the agEUR\n /// stablecoin associated to EUR has 18 decimals, then `outBase` should be 10**18\n constructor(\n address[] memory circuitChainlink_,\n uint8[] memory _circuitChainIsMultiplied,\n uint256 _outBase,\n uint32 _stalePeriod,\n address _treasury,\n string memory _description\n ) BaseOracleChainlinkMulti(_stalePeriod, _treasury) {\n outBase = _outBase;\n description = _description;\n uint256 circuitLength = circuitChainlink_.length;\n if (circuitLength == 0 || circuitLength != _circuitChainIsMultiplied.length) revert IncompatibleLengths();\n for (uint256 i; i < circuitLength; ++i) {\n AggregatorV3Interface _pool = AggregatorV3Interface(circuitChainlink_[i]);\n _circuitChainlink.push(_pool);\n chainlinkDecimals.push(_pool.decimals());\n }\n circuitChainIsMultiplied = _circuitChainIsMultiplied;\n }\n\n // ============================= Reading Oracles ===============================\n\n /// @inheritdoc IOracle\n function circuitChainlink() public view override returns (AggregatorV3Interface[] memory) {\n return _circuitChainlink;\n }\n\n /// @inheritdoc IOracle\n function read() external view override returns (uint256 quoteAmount) {\n quoteAmount = outBase;\n uint256 circuitLength = _circuitChainlink.length;\n for (uint256 i; i < circuitLength; ++i) {\n quoteAmount = _readChainlinkFeed(\n quoteAmount,\n _circuitChainlink[i],\n circuitChainIsMultiplied[i],\n chainlinkDecimals[i]\n );\n }\n }\n}\n" + }, + "contracts/oracle/implementations/polygon/XAU/OracleETHXAUChainlinkPolygon.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleETHXAUChainlinkPolygon\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of ETH in XAU in base 18\n/// @dev This contract is built to be deployed on Polygon\ncontract OracleETHXAUChainlinkPolygon is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"ETH/GOLD Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle ETH/USD\n _circuitChainlink[0] = AggregatorV3Interface(0xF9680D99D6C9589e2a93a78A04A279e509205945);\n // Oracle XAU/USD\n _circuitChainlink[1] = AggregatorV3Interface(0x0C466540B2ee1a31b441671eac0ca886e051E410);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/BaseOracleChainlinkMultiTwoFeeds.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"./BaseOracleChainlinkMulti.sol\";\n\n/// @title BaseOracleChainlinkMultiTwoFeeds\n/// @author Angle Labs, Inc.\n/// @notice Base contract for an oracle that reads into two Chainlink feeds (including an EUR/USD feed) which both have\n/// 8 decimals\nabstract contract BaseOracleChainlinkMultiTwoFeeds is BaseOracleChainlinkMulti {\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMulti(_stalePeriod, _treasury) {}\n\n /// @notice Returns the quote amount of the oracle contract\n function _getQuoteAmount() internal view virtual returns (uint256) {\n return 10**18;\n }\n\n /// @inheritdoc IOracle\n function read() external view virtual override returns (uint256 quoteAmount) {\n quoteAmount = _getQuoteAmount();\n AggregatorV3Interface[] memory _circuitChainlink = circuitChainlink();\n uint8[2] memory circuitChainIsMultiplied = [1, 0];\n uint8[2] memory chainlinkDecimals = [8, 8];\n uint256 circuitLength = _circuitChainlink.length;\n for (uint256 i; i < circuitLength; ++i) {\n quoteAmount = _readChainlinkFeed(\n quoteAmount,\n _circuitChainlink[i],\n circuitChainIsMultiplied[i],\n chainlinkDecimals[i]\n );\n }\n }\n}\n" + }, + "contracts/oracle/implementations/polygon/EUR/OracleUSDCEURChainlinkPolygon.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleUSDCEURChainlinkPolygon\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of USDC in Euro in base 18\n/// @dev This contract is built to be deployed on Polygon\ncontract OracleUSDCEURChainlinkPolygon is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"USDC/EUR Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle USDC/USD\n _circuitChainlink[0] = AggregatorV3Interface(0xfE4A8cc5b5B2366C1B58Bea3858e81843581b2F7);\n // Oracle EUR/USD\n _circuitChainlink[1] = AggregatorV3Interface(0x73366Fe0AA0Ded304479862808e02506FE556a98);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/implementations/polygon/EUR/OracleMATICEURChainlinkPolygon.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleMATICEURChainlinkPolygon\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of MATIC in Euro in base 18\n/// @dev This contract is built to be deployed on Polygon\ncontract OracleMATICEURChainlinkPolygon is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"MATIC/EUR Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle MATIC/USD\n _circuitChainlink[0] = AggregatorV3Interface(0xAB594600376Ec9fD91F8e885dADF0CE036862dE0);\n // Oracle EUR/USD\n _circuitChainlink[1] = AggregatorV3Interface(0x73366Fe0AA0Ded304479862808e02506FE556a98);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/implementations/polygon/EUR/OracleMAIEURChainlinkPolygon.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleMAIEURChainlinkPolygon\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of MAI in Euro in base 18\n/// @dev This contract is built to be deployed on Polygon\ncontract OracleMAIEURChainlinkPolygon is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"MAI/EUR Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle MAI/USD\n _circuitChainlink[0] = AggregatorV3Interface(0xd8d483d813547CfB624b8Dc33a00F2fcbCd2D428);\n // Oracle EUR/USD\n _circuitChainlink[1] = AggregatorV3Interface(0x73366Fe0AA0Ded304479862808e02506FE556a98);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/implementations/polygon/EUR/OracleETHEURChainlinkPolygon.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleETHEURChainlinkPolygon\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of ETH in Euro in base 18\n/// @dev This contract is built to be deployed on Polygon\ncontract OracleETHEURChainlinkPolygon is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"ETH/EUR Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle ETH/USD\n _circuitChainlink[0] = AggregatorV3Interface(0xF9680D99D6C9589e2a93a78A04A279e509205945);\n // Oracle EUR/USD\n _circuitChainlink[1] = AggregatorV3Interface(0x73366Fe0AA0Ded304479862808e02506FE556a98);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/implementations/polygon/EUR/OracleBTCEURChainlinkPolygon.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleBTCEURChainlinkPolygon\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of BTC in Euro in base 18\n/// @dev This contract is built to be deployed on Polygon\ncontract OracleBTCEURChainlinkPolygon is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"BTC/EUR Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle BTC/USD\n _circuitChainlink[0] = AggregatorV3Interface(0xc907E116054Ad103354f2D350FD2514433D57F6f);\n // Oracle EUR/USD\n _circuitChainlink[1] = AggregatorV3Interface(0x73366Fe0AA0Ded304479862808e02506FE556a98);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/implementations/optimism/EUR/OracleUSDCEURChainlinkOptimism.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleUSDCEURChainlinkOptimism\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of USDC in Euro in base 18\n/// @dev This contract is built to be deployed on Optimism\ncontract OracleUSDCEURChainlinkOptimism is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"USDC/EUR Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle USDC/USD\n _circuitChainlink[0] = AggregatorV3Interface(0x16a9FA2FDa030272Ce99B29CF780dFA30361E0f3);\n // Oracle EUR/USD\n _circuitChainlink[1] = AggregatorV3Interface(0x3626369857A10CcC6cc3A6e4f5C2f5984a519F20);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/implementations/optimism/EUR/OracleOPEURChainlinkOptimism.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleOPEURChainlinkOptimism\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of OP in Euro in base 18\n/// @dev This contract is built to be deployed on Optimism\ncontract OracleOPEURChainlinkOptimism is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"OP/EUR Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle OP/USD\n _circuitChainlink[0] = AggregatorV3Interface(0x0D276FC14719f9292D5C1eA2198673d1f4269246);\n // Oracle EUR/USD\n _circuitChainlink[1] = AggregatorV3Interface(0x3626369857A10CcC6cc3A6e4f5C2f5984a519F20);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/implementations/optimism/EUR/OracleETHEURChainlinkOptimism.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleETHEURChainlinkOptimism\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of ETH in Euro in base 18\n/// @dev This contract is built to be deployed on Optimism\ncontract OracleETHEURChainlinkOptimism is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"ETH/EUR Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle ETH/USD\n _circuitChainlink[0] = AggregatorV3Interface(0x13e3Ee699D1909E989722E753853AE30b17e08c5);\n // Oracle EUR/USD\n _circuitChainlink[1] = AggregatorV3Interface(0x3626369857A10CcC6cc3A6e4f5C2f5984a519F20);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/implementations/mainnet/XAU/OracleWSTETHXAUChainlink.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\nimport \"../../../../interfaces/external/lido/IStETH.sol\";\n\n/// @title OracleWSTETHXAUChainlink\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of wSTETH in XAU in base 18\ncontract OracleWSTETHXAUChainlink is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"wSTETH/XAU Oracle\";\n IStETH public constant STETH = IStETH(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84);\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle stETH/USD\n _circuitChainlink[0] = AggregatorV3Interface(0xCfE54B5cD566aB89272946F602D76Ea879CAb4a8);\n // Oracle XAU/USD\n _circuitChainlink[1] = AggregatorV3Interface(0x214eD9Da11D2fbe465a6fc601a91E62EbEc1a0D6);\n return _circuitChainlink;\n }\n\n /// @inheritdoc BaseOracleChainlinkMultiTwoFeeds\n function _getQuoteAmount() internal view override returns (uint256) {\n return STETH.getPooledEthByShares(1 ether);\n }\n}\n" + }, + "contracts/interfaces/external/lido/IStETH.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\n/// @title IStETH\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `StETH` contract\n/// @dev This interface only contains functions of the `StETH` which are called by other contracts\n/// of this module\ninterface IStETH {\n function getPooledEthByShares(uint256 _sharesAmount) external view returns (uint256);\n\n event Submitted(address sender, uint256 amount, address referral);\n\n function submit(address) external payable returns (uint256);\n\n function getSharesByPooledEth(uint256 _ethAmount) external view returns (uint256);\n}\n" + }, + "contracts/oracle/implementations/mainnet/EUR/OracleWSTETHEURChainlink.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\nimport \"../../../../interfaces/external/lido/IStETH.sol\";\n\n/// @title OracleWSTETHEURChainlink\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of wSTETH in Euro in base 18\ncontract OracleWSTETHEURChainlink is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"wSTETH/EUR Oracle\";\n IStETH public constant STETH = IStETH(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84);\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle stETH/USD\n _circuitChainlink[0] = AggregatorV3Interface(0xCfE54B5cD566aB89272946F602D76Ea879CAb4a8);\n // Oracle EUR/USD\n _circuitChainlink[1] = AggregatorV3Interface(0xb49f677943BC038e9857d61E7d053CaA2C1734C1);\n return _circuitChainlink;\n }\n\n /// @inheritdoc BaseOracleChainlinkMultiTwoFeeds\n function _getQuoteAmount() internal view override returns (uint256) {\n return STETH.getPooledEthByShares(1 ether);\n }\n}\n" + }, + "contracts/oracle/implementations/mainnet/XAU/OracleUSDCXAUChainlink.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleUSDCXAUChainlink\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of USDC in XAU in base 18\ncontract OracleUSDCXAUChainlink is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"USDC/GOLD Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle USDC/USD\n _circuitChainlink[0] = AggregatorV3Interface(0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6);\n // Oracle XAU/USD\n _circuitChainlink[1] = AggregatorV3Interface(0x214eD9Da11D2fbe465a6fc601a91E62EbEc1a0D6);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/implementations/mainnet/XAU/OracleLUSDXAUChainlink.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleLUSDXAUChainlink\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of LUSD in XAU in base 18\ncontract OracleLUSDXAUChainlink is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"LUSD/GOLD Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle LUSD/USD\n _circuitChainlink[0] = AggregatorV3Interface(0x3D7aE7E594f2f2091Ad8798313450130d0Aba3a0);\n // Oracle XAU/USD\n _circuitChainlink[1] = AggregatorV3Interface(0x214eD9Da11D2fbe465a6fc601a91E62EbEc1a0D6);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/implementations/mainnet/XAU/OracleETHXAUChainlink.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleETHXAUChainlink\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of ETH in XAU in base 18\ncontract OracleETHXAUChainlink is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"ETH/GOLD Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle ETH/USD\n _circuitChainlink[0] = AggregatorV3Interface(0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419);\n // Oracle XAU/USD\n _circuitChainlink[1] = AggregatorV3Interface(0x214eD9Da11D2fbe465a6fc601a91E62EbEc1a0D6);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/implementations/mainnet/EUR/OracleUSDCEURChainlink.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleUSDCEURChainlink\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of USDC in Euro in base 18\ncontract OracleUSDCEURChainlink is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"USDC/EUR Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle USDC/USD\n _circuitChainlink[0] = AggregatorV3Interface(0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6);\n // Oracle EUR/USD\n _circuitChainlink[1] = AggregatorV3Interface(0xb49f677943BC038e9857d61E7d053CaA2C1734C1);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/implementations/mainnet/EUR/OracleLUSDEURChainlink.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleLUSDEURChainlink\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of LUSD in Euro in base 18\ncontract OracleLUSDEURChainlink is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"LUSD/EUR Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle LUSD/USD\n _circuitChainlink[0] = AggregatorV3Interface(0x3D7aE7E594f2f2091Ad8798313450130d0Aba3a0);\n // Oracle EUR/USD\n _circuitChainlink[1] = AggregatorV3Interface(0xb49f677943BC038e9857d61E7d053CaA2C1734C1);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/implementations/mainnet/EUR/OracleIB01EURChainlink.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleIB01EURChainlink\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of IB01 in Euro in base 18\ncontract OracleIB01EURChainlink is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"IB01/EUR Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle IB01/USD\n _circuitChainlink[0] = AggregatorV3Interface(0x788D911ae7c95121A89A0f0306db65D87422E1de);\n // Oracle EUR/USD\n _circuitChainlink[1] = AggregatorV3Interface(0xb49f677943BC038e9857d61E7d053CaA2C1734C1);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/implementations/mainnet/EUR/OracleETHEURChainlink.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleETHEURChainlink\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of ETH in Euro in base 18\ncontract OracleETHEURChainlink is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"ETH/EUR Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle ETH/USD\n _circuitChainlink[0] = AggregatorV3Interface(0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419);\n // Oracle EUR/USD\n _circuitChainlink[1] = AggregatorV3Interface(0xb49f677943BC038e9857d61E7d053CaA2C1734C1);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/implementations/mainnet/EUR/OracleCBETHEURChainlink.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleCBETHEURChainlink\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of cbETH in Euro in base 18\ncontract OracleCBETHEURChainlink is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"cbETH/EUR Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](3);\n // Oracle cbETH/ETH\n _circuitChainlink[0] = AggregatorV3Interface(0xF017fcB346A1885194689bA23Eff2fE6fA5C483b);\n // Oracle ETH/USD\n _circuitChainlink[1] = AggregatorV3Interface(0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419);\n // Oracle EUR/USD\n _circuitChainlink[2] = AggregatorV3Interface(0xb49f677943BC038e9857d61E7d053CaA2C1734C1);\n return _circuitChainlink;\n }\n\n /// @inheritdoc BaseOracleChainlinkMultiTwoFeeds\n function read() external view virtual override returns (uint256 quoteAmount) {\n quoteAmount = _getQuoteAmount();\n AggregatorV3Interface[] memory _circuitChainlink = circuitChainlink();\n uint8[3] memory circuitChainIsMultiplied = [1, 1, 0];\n uint8[3] memory chainlinkDecimals = [18, 8, 8];\n uint256 circuitLength = _circuitChainlink.length;\n for (uint256 i; i < circuitLength; ++i) {\n quoteAmount = _readChainlinkFeed(\n quoteAmount,\n _circuitChainlink[i],\n circuitChainIsMultiplied[i],\n chainlinkDecimals[i]\n );\n }\n }\n}\n" + }, + "contracts/oracle/implementations/mainnet/EUR/OracleBTCEURChainlink.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleBTCEURChainlink\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of BTC in Euro in base 18\ncontract OracleBTCEURChainlink is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"BTC/EUR Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle BTC/USD\n _circuitChainlink[0] = AggregatorV3Interface(0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c);\n // Oracle EUR/USD\n _circuitChainlink[1] = AggregatorV3Interface(0xb49f677943BC038e9857d61E7d053CaA2C1734C1);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/implementations/avalanche/EUR/OracleUSDCEURChainlinkAvalanche.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleUSDCEURChainlinkAvalanche\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of USDC in Euro in base 18\n/// @dev This contract is built to be deployed on Avalanche\ncontract OracleUSDCEURChainlinkAvalanche is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"USDC/EUR Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle USDC/USD\n _circuitChainlink[0] = AggregatorV3Interface(0xF096872672F44d6EBA71458D74fe67F9a77a23B9);\n // Oracle EUR/USD\n _circuitChainlink[1] = AggregatorV3Interface(0x192f2DBA961Bb0277520C082d6bfa87D5961333E);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/implementations/avalanche/EUR/OracleAVAXEURChainlinkAvalanche.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleAVAXEURChainlinkAvalanche\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of AVAX in Euro in base 18\n/// @dev This contract is built to be deployed on Avalanche\ncontract OracleAVAXEURChainlinkAvalanche is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"AVAX/EUR Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle AVAX/USD\n _circuitChainlink[0] = AggregatorV3Interface(0x0A77230d17318075983913bC2145DB16C7366156);\n // Oracle EUR/USD\n _circuitChainlink[1] = AggregatorV3Interface(0x192f2DBA961Bb0277520C082d6bfa87D5961333E);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/implementations/arbitrum/EUR/OracleUSDCEURChainlinkArbitrum.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleUSDCEURChainlinkArbitrum\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of USDC in Euro in base 18\n/// @dev This contract is built to be deployed on Arbitrum\ncontract OracleUSDCEURChainlinkArbitrum is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"USDC/EUR Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle ETH/USD\n _circuitChainlink[0] = AggregatorV3Interface(0x50834F3163758fcC1Df9973b6e91f0F0F0434aD3);\n // Oracle EUR/USD\n _circuitChainlink[1] = AggregatorV3Interface(0xA14d53bC1F1c0F31B4aA3BD109344E5009051a84);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/implementations/arbitrum/EUR/OracleETHEURChainlinkArbitrum.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleETHEURChainlinkArbitrum\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of ETH in Euro in base 18\n/// @dev This contract is built to be deployed on Arbitrum\ncontract OracleETHEURChainlinkArbitrum is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"ETH/EUR Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle ETH/USD\n _circuitChainlink[0] = AggregatorV3Interface(0x639Fe6ab55C921f74e7fac1ee960C0B6293ba612);\n // Oracle EUR/USD\n _circuitChainlink[1] = AggregatorV3Interface(0xA14d53bC1F1c0F31B4aA3BD109344E5009051a84);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/oracle/implementations/arbitrum/EUR/OracleBTCEURChainlinkArbitrum.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\nimport \"../../../BaseOracleChainlinkMultiTwoFeeds.sol\";\n\n/// @title OracleBTCEURChainlinkArbitrum\n/// @author Angle Labs, Inc.\n/// @notice Gives the price of BTC in Euro in base 18\n/// @dev This contract is built to be deployed on Arbitrum\ncontract OracleBTCEURChainlinkArbitrum is BaseOracleChainlinkMultiTwoFeeds {\n string public constant DESCRIPTION = \"BTC/EUR Oracle\";\n\n constructor(uint32 _stalePeriod, address _treasury) BaseOracleChainlinkMultiTwoFeeds(_stalePeriod, _treasury) {}\n\n /// @inheritdoc IOracle\n function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {\n AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);\n // Oracle BTC/USD\n _circuitChainlink[0] = AggregatorV3Interface(0x6ce185860a4963106506C203335A2910413708e9);\n // Oracle EUR/USD\n _circuitChainlink[1] = AggregatorV3Interface(0xA14d53bC1F1c0F31B4aA3BD109344E5009051a84);\n return _circuitChainlink;\n }\n}\n" + }, + "contracts/mock/MockOracle.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.7;\n\nimport \"../interfaces/IOracle.sol\";\n\ncontract MockOracle is IOracle {\n event Update(uint256 _peg);\n\n ITreasury public treasury;\n\n uint256 public base = 1 ether;\n uint256 public precision = 1 ether;\n uint256 public rate;\n bool public outdated;\n\n /// @notice Initiate with a fixe change rate\n constructor(uint256 rate_, ITreasury _treasury) {\n rate = rate_;\n treasury = _treasury;\n }\n\n /// @notice Mock read\n function read() external view override returns (uint256) {\n return rate;\n }\n\n /// @notice change oracle rate\n function update(uint256 newRate) external {\n rate = newRate;\n }\n\n function setTreasury(address _treasury) external override {\n treasury = ITreasury(_treasury);\n }\n\n function circuitChainlink() external pure override returns (AggregatorV3Interface[] memory) {}\n}\n" + }, + "contracts/mock/MockVaultManager.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"../interfaces/IVaultManager.sol\";\nimport \"../interfaces/ITreasury.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockVaultManager {\n ITreasury public treasury;\n mapping(uint256 => Vault) public vaultData;\n mapping(uint256 => address) public ownerOf;\n uint256 public surplus;\n uint256 public badDebt;\n IAgToken public token;\n address public oracle = address(this);\n\n address public governor;\n address public collateral;\n address public stablecoin;\n uint256 public oracleValue;\n uint256 public interestAccumulator;\n uint256 public collateralFactor;\n uint256 public totalNormalizedDebt;\n\n constructor(address _treasury) {\n treasury = ITreasury(_treasury);\n }\n\n function accrueInterestToTreasury() external returns (uint256, uint256) {\n // Avoid the function to be view\n if (surplus >= badDebt) {\n token.mint(msg.sender, surplus - badDebt);\n }\n return (surplus, badDebt);\n }\n\n function read() external view returns (uint256) {\n return oracleValue;\n }\n\n function setParams(\n address _governor,\n address _collateral,\n address _stablecoin,\n uint256 _oracleValue,\n uint256 _interestAccumulator,\n uint256 _collateralFactor,\n uint256 _totalNormalizedDebt\n ) external {\n governor = _governor;\n collateral = _collateral;\n stablecoin = _stablecoin;\n interestAccumulator = _interestAccumulator;\n collateralFactor = _collateralFactor;\n totalNormalizedDebt = _totalNormalizedDebt;\n oracleValue = _oracleValue;\n }\n\n function setOwner(uint256 vaultID, address owner) external virtual {\n ownerOf[vaultID] = owner;\n }\n\n function setVaultData(\n uint256 normalizedDebt,\n uint256 collateralAmount,\n uint256 vaultID\n ) external {\n vaultData[vaultID].normalizedDebt = normalizedDebt;\n vaultData[vaultID].collateralAmount = collateralAmount;\n }\n\n function isGovernor(address admin) external view returns (bool) {\n return admin == governor;\n }\n\n function setSurplusBadDebt(\n uint256 _surplus,\n uint256 _badDebt,\n IAgToken _token\n ) external {\n surplus = _surplus;\n badDebt = _badDebt;\n token = _token;\n }\n\n function getDebtOut(\n uint256 vaultID,\n uint256 amountStablecoins,\n uint256 senderBorrowFee\n ) external {}\n\n function setTreasury(address _treasury) external {\n treasury = ITreasury(_treasury);\n }\n\n function getVaultDebt(uint256 vaultID) external view returns (uint256) {\n vaultID;\n token;\n return 0;\n }\n\n function createVault(address toVault) external view returns (uint256) {\n toVault;\n token;\n return 0;\n }\n}\n\ncontract MockVaultManagerListing is MockVaultManager {\n // @notice Mapping from owner address to all his vaults\n mapping(address => uint256[]) internal _ownerListVaults;\n\n constructor(address _treasury) MockVaultManager(_treasury) {}\n\n function getUserVaults(address owner) public view returns (uint256[] memory) {\n return _ownerListVaults[owner];\n }\n\n function getUserCollateral(address owner) public view returns (uint256 totalCollateral) {\n uint256[] memory vaultList = _ownerListVaults[owner];\n uint256 vaultListLength = vaultList.length;\n for (uint256 k; k < vaultListLength; ++k) {\n totalCollateral += vaultData[vaultList[k]].collateralAmount;\n }\n return totalCollateral;\n }\n\n function setOwner(uint256 vaultID, address owner) external override {\n if (ownerOf[vaultID] != address(0)) _removeVaultFromList(ownerOf[vaultID], vaultID);\n _ownerListVaults[owner].push(vaultID);\n ownerOf[vaultID] = owner;\n }\n\n /// @notice Remove `vaultID` from `user` stroed vault list\n /// @param user Address to look out for the vault list\n /// @param vaultID VaultId to remove from the list\n /// @dev The vault is necessarily in the list\n function _removeVaultFromList(address user, uint256 vaultID) internal {\n uint256[] storage vaultList = _ownerListVaults[user];\n uint256 vaultListLength = vaultList.length;\n for (uint256 i; i < vaultListLength - 1; ++i) {\n if (vaultList[i] == vaultID) {\n vaultList[i] = vaultList[vaultListLength - 1];\n break;\n }\n }\n vaultList.pop();\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/extensions/draft-ERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./draft-IERC20Permit.sol\";\nimport \"../ERC20.sol\";\nimport \"../../../utils/cryptography/draft-EIP712.sol\";\nimport \"../../../utils/cryptography/ECDSA.sol\";\nimport \"../../../utils/Counters.sol\";\n\n/**\n * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * _Available since v3.4._\n */\nabstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {\n using Counters for Counters.Counter;\n\n mapping(address => Counters.Counter) private _nonces;\n\n // solhint-disable-next-line var-name-mixedcase\n bytes32 private constant _PERMIT_TYPEHASH =\n keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n /**\n * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`.\n * However, to ensure consistency with the upgradeable transpiler, we will continue\n * to reserve a slot.\n * @custom:oz-renamed-from _PERMIT_TYPEHASH\n */\n // solhint-disable-next-line var-name-mixedcase\n bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;\n\n /**\n * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\"1\"`.\n *\n * It's a good idea to use the same `name` that is defined as the ERC20 token name.\n */\n constructor(string memory name) EIP712(name, \"1\") {}\n\n /**\n * @dev See {IERC20Permit-permit}.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual override {\n require(block.timestamp <= deadline, \"ERC20Permit: expired deadline\");\n\n bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));\n\n bytes32 hash = _hashTypedDataV4(structHash);\n\n address signer = ECDSA.recover(hash, v, r, s);\n require(signer == owner, \"ERC20Permit: invalid signature\");\n\n _approve(owner, spender, value);\n }\n\n /**\n * @dev See {IERC20Permit-nonces}.\n */\n function nonces(address owner) public view virtual override returns (uint256) {\n return _nonces[owner].current();\n }\n\n /**\n * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view override returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /**\n * @dev \"Consume a nonce\": return the current value and increment.\n *\n * _Available since v4.1._\n */\n function _useNonce(address owner) internal virtual returns (uint256 current) {\n Counters.Counter storage nonce = _nonces[owner];\n current = nonce.current();\n nonce.increment();\n }\n}\n" + }, + "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/cryptography/draft-EIP712.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./ECDSA.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,\n * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding\n * they need in their contracts using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * _Available since v3.4._\n */\nabstract contract EIP712 {\n /* solhint-disable var-name-mixedcase */\n // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to\n // invalidate the cached domain separator if the chain id changes.\n bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;\n uint256 private immutable _CACHED_CHAIN_ID;\n address private immutable _CACHED_THIS;\n\n bytes32 private immutable _HASHED_NAME;\n bytes32 private immutable _HASHED_VERSION;\n bytes32 private immutable _TYPE_HASH;\n\n /* solhint-enable var-name-mixedcase */\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n constructor(string memory name, string memory version) {\n bytes32 hashedName = keccak256(bytes(name));\n bytes32 hashedVersion = keccak256(bytes(version));\n bytes32 typeHash = keccak256(\n \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"\n );\n _HASHED_NAME = hashedName;\n _HASHED_VERSION = hashedVersion;\n _CACHED_CHAIN_ID = block.chainid;\n _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);\n _CACHED_THIS = address(this);\n _TYPE_HASH = typeHash;\n }\n\n /**\n * @dev Returns the domain separator for the current chain.\n */\n function _domainSeparatorV4() internal view returns (bytes32) {\n if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {\n return _CACHED_DOMAIN_SEPARATOR;\n } else {\n return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);\n }\n }\n\n function _buildDomainSeparator(\n bytes32 typeHash,\n bytes32 nameHash,\n bytes32 versionHash\n ) private view returns (bytes32) {\n return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * )));\n * address signer = ECDSA.recover(digest, signature);\n * ```\n */\n function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n /// @solidity memory-safe-assembly\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Counters.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title Counters\n * @author Matt Condon (@shrugs)\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\n *\n * Include with `using Counters for Counters.Counter;`\n */\nlibrary Counters {\n struct Counter {\n // This variable should never be directly accessed by users of the library: interactions must be restricted to\n // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\n // this feature: see https://github.com/ethereum/solidity/issues/4637\n uint256 _value; // default: 0\n }\n\n function current(Counter storage counter) internal view returns (uint256) {\n return counter._value;\n }\n\n function increment(Counter storage counter) internal {\n unchecked {\n counter._value += 1;\n }\n }\n\n function decrement(Counter storage counter) internal {\n uint256 value = counter._value;\n require(value > 0, \"Counter: decrement overflow\");\n unchecked {\n counter._value = value - 1;\n }\n }\n\n function reset(Counter storage counter) internal {\n counter._value = 0;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" + }, + "contracts/agToken/layerZero/LayerZeroBridge.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.12;\n\nimport \"./utils/OFTCore.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\";\n\n/// @title LayerZeroBridge\n/// @author Angle Labs, Inc., forked from https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/token/oft/OFT.sol\n/// @notice Contract to be deployed on Ethereum for bridging an AgToken using a bridge intermediate token and LayerZero\ncontract LayerZeroBridge is OFTCore, PausableUpgradeable {\n /// @notice Name of the contract for indexing purposes\n string public name;\n\n /// @notice Address of the bridgeable token\n /// @dev Immutable\n IERC20 public canonicalToken;\n\n /// @notice Maps an address to the amount of token bridged but not received\n mapping(address => uint256) public balanceOf;\n\n // ============================= Constructor ===================================\n\n /// @notice Initializes the contract\n /// @param _name Name of the token corresponding to this contract\n /// @param _lzEndpoint Layer zero endpoint to pass messages\n /// @param _treasury Address of the treasury contract used for access control\n function initialize(\n string memory _name,\n address _lzEndpoint,\n address _treasury\n ) external initializer {\n __LzAppUpgradeable_init(_lzEndpoint, _treasury);\n name = _name;\n canonicalToken = IERC20(address(ITreasury(_treasury).stablecoin()));\n }\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() initializer {}\n\n // ==================== External Permissionless Functions ======================\n\n /// @inheritdoc OFTCore\n function sendWithPermit(\n uint16 _dstChainId,\n bytes memory _toAddress,\n uint256 _amount,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes memory _adapterParams,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public payable override {\n IERC20Permit(address(canonicalToken)).permit(msg.sender, address(this), _amount, deadline, v, r, s);\n send(_dstChainId, _toAddress, _amount, _refundAddress, _zroPaymentAddress, _adapterParams);\n }\n\n /// @inheritdoc OFTCore\n function withdraw(uint256 amount, address recipient) external override returns (uint256) {\n return _withdraw(amount, msg.sender, recipient);\n }\n\n /// @notice Withdraws amount of `token` from the contract and sends it to the recipient\n /// @param amount Amount to withdraw\n /// @param recipient Address to withdraw for\n /// @return The amount of canonical token sent\n function withdrawFor(uint256 amount, address recipient) external returns (uint256) {\n return _withdraw(amount, recipient, recipient);\n }\n\n // ========================== Internal Functions ===============================\n\n /// @notice Withdraws `amount` from the balance of the `from` address and sends these tokens to the `to` address\n /// @dev It's important to make sure that `from` is either the `msg.sender` or that `from` and `to` are the same\n /// addresses\n function _withdraw(\n uint256 amount,\n address from,\n address to\n ) internal whenNotPaused returns (uint256) {\n balanceOf[from] -= amount; // Will overflow if the amount is too big\n canonicalToken.transfer(to, amount);\n return amount;\n }\n\n /// @inheritdoc OFTCore\n function _debitFrom(\n uint16,\n bytes memory,\n uint256 _amount\n ) internal override whenNotPaused returns (uint256) {\n // No need to use safeTransferFrom as we know this implementation reverts on failure\n canonicalToken.transferFrom(msg.sender, address(this), _amount);\n return _amount;\n }\n\n /// @inheritdoc OFTCore\n function _debitCreditFrom(\n uint16,\n bytes memory,\n uint256 _amount\n ) internal override whenNotPaused returns (uint256) {\n balanceOf[msg.sender] -= _amount;\n return _amount;\n }\n\n /// @inheritdoc OFTCore\n function _creditTo(\n uint16,\n address _toAddress,\n uint256 _amount\n ) internal override whenNotPaused returns (uint256) {\n // Should never revert as all the LayerZero bridge tokens come from\n // this contract\n uint256 balance = canonicalToken.balanceOf(address(this));\n if (balance < _amount) {\n balanceOf[_toAddress] = _amount - balance;\n if (balance != 0) canonicalToken.transfer(_toAddress, balance);\n } else {\n canonicalToken.transfer(_toAddress, _amount);\n }\n return _amount;\n }\n\n // ========================= View Functions ====================================\n\n /// @inheritdoc ERC165Upgradeable\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IOFTCore).interfaceId || super.supportsInterface(interfaceId);\n }\n\n // ======================= Governance Functions ================================\n\n /// @notice Pauses bridging through the contract\n /// @param pause Future pause status\n function pauseSendTokens(bool pause) external onlyGovernorOrGuardian {\n pause ? _pause() : _unpause();\n }\n\n /// @notice Decreases the balance of an address\n /// @param amount Amount to withdraw from balance\n /// @param recipient Address to withdraw from\n function sweep(uint256 amount, address recipient) external onlyGovernorOrGuardian {\n balanceOf[recipient] -= amount; // Will overflow if the amount is too big\n }\n\n uint256[47] private __gap;\n}\n" + }, + "contracts/agToken/layerZero/utils/OFTCore.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.12;\n\nimport \"./NonblockingLzApp.sol\";\nimport \"./IOFTCore.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol\";\n\n/// @title OFTCore\n/// @author Forked from https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/token/oft/OFTCore.sol\n/// but with slight modifications from the Angle Labs, Inc. which added return values to the `_creditTo` and `_debitFrom` functions\n/// @notice Base contract for bridging using LayerZero\nabstract contract OFTCore is NonblockingLzApp, ERC165Upgradeable, IOFTCore {\n // ==================== External Permissionless Functions ======================\n\n /// @inheritdoc IOFTCore\n function sendWithPermit(\n uint16 _dstChainId,\n bytes memory _toAddress,\n uint256 _amount,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes memory _adapterParams,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public payable virtual;\n\n /// @inheritdoc IOFTCore\n function send(\n uint16 _dstChainId,\n bytes memory _toAddress,\n uint256 _amount,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes memory _adapterParams\n ) public payable virtual {\n _amount = _debitFrom(_dstChainId, _toAddress, _amount);\n\n bytes memory payload = abi.encode(_toAddress, _amount);\n _lzSend(_dstChainId, payload, _refundAddress, _zroPaymentAddress, _adapterParams);\n\n uint64 nonce = lzEndpoint.getOutboundNonce(_dstChainId, address(this));\n emit SendToChain(msg.sender, _dstChainId, _toAddress, _amount, nonce);\n }\n\n /// @inheritdoc IOFTCore\n function sendCredit(\n uint16 _dstChainId,\n bytes memory _toAddress,\n uint256 _amount,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes memory _adapterParams\n ) public payable virtual {\n _amount = _debitCreditFrom(_dstChainId, _toAddress, _amount);\n\n _send(_dstChainId, _toAddress, _amount, _refundAddress, _zroPaymentAddress, _adapterParams);\n }\n\n /// @inheritdoc IOFTCore\n function withdraw(uint256 amount, address recipient) external virtual returns (uint256);\n\n // =========================== Internal Functions ==============================\n\n /// @notice Internal function to send `_amount` amount of token to (`_dstChainId`, `_toAddress`)\n /// @param _dstChainId the destination chain identifier\n /// @param _toAddress can be any size depending on the `dstChainId`.\n /// @param _amount the quantity of tokens in wei\n /// @param _refundAddress the address LayerZero refunds if too much message fee is sent\n /// @param _zroPaymentAddress set to address(0x0) if not paying in ZRO (LayerZero Token)\n /// @param _adapterParams is a flexible bytes array to indicate messaging adapter services\n /// @dev Accounting and checks should be performed beforehand\n function _send(\n uint16 _dstChainId,\n bytes memory _toAddress,\n uint256 _amount,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes memory _adapterParams\n ) internal {\n bytes memory payload = abi.encode(_toAddress, _amount);\n _lzSend(_dstChainId, payload, _refundAddress, _zroPaymentAddress, _adapterParams);\n\n uint64 nonce = lzEndpoint.getOutboundNonce(_dstChainId, address(this));\n emit SendToChain(msg.sender, _dstChainId, _toAddress, _amount, nonce);\n }\n\n /// @inheritdoc NonblockingLzApp\n function _nonblockingLzReceive(\n uint16 _srcChainId,\n bytes memory _srcAddress,\n uint64 _nonce,\n bytes memory _payload\n ) internal virtual override {\n // decode and load the toAddress\n (bytes memory toAddressBytes, uint256 amount) = abi.decode(_payload, (bytes, uint256));\n address toAddress;\n //solhint-disable-next-line\n assembly {\n toAddress := mload(add(toAddressBytes, 20))\n }\n amount = _creditTo(_srcChainId, toAddress, amount);\n\n emit ReceiveFromChain(_srcChainId, _srcAddress, toAddress, amount, _nonce);\n }\n\n /// @notice Makes accountability when bridging from this contract using canonical token\n /// @param _dstChainId ChainId of the destination chain - LayerZero standard\n /// @param _toAddress Recipient on the destination chain\n /// @param _amount Amount to bridge\n function _debitFrom(\n uint16 _dstChainId,\n bytes memory _toAddress,\n uint256 _amount\n ) internal virtual returns (uint256);\n\n /// @notice Makes accountability when bridging from this contract's credit\n /// @param _dstChainId ChainId of the destination chain - LayerZero standard\n /// @param _toAddress Recipient on the destination chain\n /// @param _amount Amount to bridge\n function _debitCreditFrom(\n uint16 _dstChainId,\n bytes memory _toAddress,\n uint256 _amount\n ) internal virtual returns (uint256);\n\n /// @notice Makes accountability when bridging to this contract\n /// @param _srcChainId ChainId of the source chain - LayerZero standard\n /// @param _toAddress Recipient on this chain\n /// @param _amount Amount to bridge\n function _creditTo(\n uint16 _srcChainId,\n address _toAddress,\n uint256 _amount\n ) internal virtual returns (uint256);\n\n // ========================== View Functions ===================================\n\n /// @inheritdoc ERC165Upgradeable\n function supportsInterface(bytes4 interfaceId)\n public\n view\n virtual\n override(ERC165Upgradeable, IERC165)\n returns (bool)\n {\n return interfaceId == type(IOFTCore).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /// @inheritdoc IOFTCore\n function estimateSendFee(\n uint16 _dstChainId,\n bytes memory _toAddress,\n uint256 _amount,\n bool _useZro,\n bytes memory _adapterParams\n ) public view virtual override returns (uint256 nativeFee, uint256 zroFee) {\n // mock the payload for send()\n bytes memory payload = abi.encode(_toAddress, _amount);\n return lzEndpoint.estimateFees(_dstChainId, address(this), payload, _useZro, _adapterParams);\n }\n\n uint256[50] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract PausableUpgradeable is Initializable, ContextUpgradeable {\n /**\n * @dev Emitted when the pause is triggered by `account`.\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by `account`.\n */\n event Unpaused(address account);\n\n bool private _paused;\n\n /**\n * @dev Initializes the contract in unpaused state.\n */\n function __Pausable_init() internal onlyInitializing {\n __Pausable_init_unchained();\n }\n\n function __Pausable_init_unchained() internal onlyInitializing {\n _paused = false;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n modifier whenNotPaused() {\n _requireNotPaused();\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n modifier whenPaused() {\n _requirePaused();\n _;\n }\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view virtual returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Throws if the contract is paused.\n */\n function _requireNotPaused() internal view virtual {\n require(!paused(), \"Pausable: paused\");\n }\n\n /**\n * @dev Throws if the contract is not paused.\n */\n function _requirePaused() internal view virtual {\n require(paused(), \"Pausable: not paused\");\n }\n\n /**\n * @dev Triggers stopped state.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n function _pause() internal virtual whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Returns to normal state.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n function _unpause() internal virtual whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "contracts/agToken/layerZero/utils/NonblockingLzApp.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"../../../interfaces/external/layerZero/ILayerZeroReceiver.sol\";\nimport \"../../../interfaces/external/layerZero/ILayerZeroUserApplicationConfig.sol\";\nimport \"../../../interfaces/external/layerZero/ILayerZeroEndpoint.sol\";\nimport \"../../../interfaces/ITreasury.sol\";\n\n/// @title NonblockingLzApp\n/// @author Angle Labs, Inc., forked from https://github.com/LayerZero-Labs/solidity-examples/\n/// @notice Base contract for bridging using LayerZero\nabstract contract NonblockingLzApp is Initializable, ILayerZeroReceiver, ILayerZeroUserApplicationConfig {\n /// @notice Layer Zero endpoint\n ILayerZeroEndpoint public lzEndpoint;\n\n /// @notice Maps chainIds to failed messages to retry them\n mapping(uint16 => mapping(bytes => mapping(uint64 => bytes32))) public failedMessages;\n\n /// @notice Maps chainIds to their OFT address\n mapping(uint16 => bytes) public trustedRemoteLookup;\n\n /// @notice Reference to the treasury contract to fetch access control\n address public treasury;\n\n // ================================== Events ===================================\n\n event SetTrustedRemote(uint16 _srcChainId, bytes _srcAddress);\n event MessageFailed(uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes _payload);\n\n // =============================== Errors ================================\n\n error NotGovernor();\n error NotGovernorOrGuardian();\n error InvalidEndpoint();\n error InvalidSource();\n error InvalidCaller();\n error InvalidPayload();\n error ZeroAddress();\n\n // ============================= Constructor ===================================\n\n //solhint-disable-next-line\n function __LzAppUpgradeable_init(address _endpoint, address _treasury) internal {\n if (_endpoint == address(0) || _treasury == address(0)) revert ZeroAddress();\n lzEndpoint = ILayerZeroEndpoint(_endpoint);\n treasury = _treasury;\n }\n\n // =============================== Modifiers ===================================\n\n /// @notice Checks whether the `msg.sender` has the governor role or the guardian role\n modifier onlyGovernorOrGuardian() {\n if (!ITreasury(treasury).isGovernorOrGuardian(msg.sender)) revert NotGovernorOrGuardian();\n _;\n }\n\n // ==================== External Permissionless Functions ======================\n\n /// @notice Receives a message from the LZ endpoint and process it\n /// @param _srcChainId ChainId of the source chain - LayerZero standard\n /// @param _srcAddress Sender of the source chain\n /// @param _nonce Nounce of the message\n /// @param _payload Data: recipient address and amount\n function lzReceive(\n uint16 _srcChainId,\n bytes memory _srcAddress,\n uint64 _nonce,\n bytes memory _payload\n ) public virtual override {\n // lzReceive must be called by the endpoint for security\n if (msg.sender != address(lzEndpoint)) revert InvalidEndpoint();\n\n bytes memory trustedRemote = trustedRemoteLookup[_srcChainId];\n // if will still block the message pathway from (srcChainId, srcAddress). should not receive message from untrusted remote.\n if (_srcAddress.length != trustedRemote.length || keccak256(_srcAddress) != keccak256(trustedRemote))\n revert InvalidSource();\n\n _blockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);\n }\n\n /// @notice Retries a message that previously failed and was stored\n /// @param _srcChainId ChainId of the source chain - LayerZero standard\n /// @param _srcAddress Sender of the source chain\n /// @param _nonce Nounce of the message\n /// @param _payload Data: recipient address and amount\n function retryMessage(\n uint16 _srcChainId,\n bytes memory _srcAddress,\n uint64 _nonce,\n bytes memory _payload\n ) public payable virtual {\n // assert there is message to retry\n bytes32 payloadHash = failedMessages[_srcChainId][_srcAddress][_nonce];\n if (payloadHash == bytes32(0) || keccak256(_payload) != payloadHash) revert InvalidPayload();\n // clear the stored message\n failedMessages[_srcChainId][_srcAddress][_nonce] = bytes32(0);\n // execute the message. revert if it fails again\n _nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);\n }\n\n // ============================= Internal Functions ===================================\n\n /// @notice Handles message receptions in a non blocking way\n /// @param _srcChainId ChainId of the source chain - LayerZero standard\n /// @param _srcAddress Sender of the source chain\n /// @param _nonce Nounce of the message\n /// @param _payload Data: recipient address and amount\n /// @dev public for the needs of try / catch but effectively internal\n function nonblockingLzReceive(\n uint16 _srcChainId,\n bytes memory _srcAddress,\n uint64 _nonce,\n bytes memory _payload\n ) public virtual {\n // only internal transaction\n if (msg.sender != address(this)) revert InvalidCaller();\n _nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);\n }\n\n /// @notice Handles message receptions in a non blocking way\n /// @param _srcChainId ChainId of the source chain - LayerZero standard\n /// @param _srcAddress Sender of the source chain\n /// @param _nonce Nounce of the message\n /// @param _payload Data: recipient address and amount\n function _nonblockingLzReceive(\n uint16 _srcChainId,\n bytes memory _srcAddress,\n uint64 _nonce,\n bytes memory _payload\n ) internal virtual;\n\n /// @notice Handles message receptions in a blocking way\n /// @param _srcChainId ChainId of the source chain - LayerZero standard\n /// @param _srcAddress Sender of the source chain\n /// @param _nonce Nounce of the message\n /// @param _payload Data: recipient address and amount\n function _blockingLzReceive(\n uint16 _srcChainId,\n bytes memory _srcAddress,\n uint64 _nonce,\n bytes memory _payload\n ) internal {\n // try-catch all errors/exceptions\n try this.nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload) {\n // do nothing\n } catch {\n // error / exception\n failedMessages[_srcChainId][_srcAddress][_nonce] = keccak256(_payload);\n emit MessageFailed(_srcChainId, _srcAddress, _nonce, _payload);\n }\n }\n\n /// @notice Sends a message to the LZ endpoint and process it\n /// @param _dstChainId L0 defined chain id to send tokens too\n /// @param _payload Data: recipient address and amount\n /// @param _refundAddress Address LayerZero refunds if too much message fee is sent\n /// @param _zroPaymentAddress Set to address(0x0) if not paying in ZRO (LayerZero Token)\n /// @param _adapterParams Flexible bytes array to indicate messaging adapter services in L0\n function _lzSend(\n uint16 _dstChainId,\n bytes memory _payload,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes memory _adapterParams\n ) internal virtual {\n bytes memory trustedRemote = trustedRemoteLookup[_dstChainId];\n if (trustedRemote.length == 0) revert InvalidSource();\n //solhint-disable-next-line\n lzEndpoint.send{ value: msg.value }(\n _dstChainId,\n trustedRemote,\n _payload,\n _refundAddress,\n _zroPaymentAddress,\n _adapterParams\n );\n }\n\n // ======================= Governance Functions ================================\n\n /// @notice Sets the corresponding address on an other chain.\n /// @param _srcChainId ChainId of the source chain - LayerZero standard\n /// @param _srcAddress Address on the source chain\n /// @dev Used for both receiving and sending message\n /// @dev There can only be one trusted source per chain\n /// @dev Allows owner to set it multiple times.\n function setTrustedRemote(uint16 _srcChainId, bytes calldata _srcAddress) external onlyGovernorOrGuardian {\n trustedRemoteLookup[_srcChainId] = _srcAddress;\n emit SetTrustedRemote(_srcChainId, _srcAddress);\n }\n\n /// @notice Fetches the default LZ config\n function getConfig(\n uint16 _version,\n uint16 _chainId,\n address,\n uint256 _configType\n ) external view returns (bytes memory) {\n return lzEndpoint.getConfig(_version, _chainId, address(this), _configType);\n }\n\n /// @notice Overrides the default LZ config\n function setConfig(\n uint16 _version,\n uint16 _chainId,\n uint256 _configType,\n bytes calldata _config\n ) external override onlyGovernorOrGuardian {\n lzEndpoint.setConfig(_version, _chainId, _configType, _config);\n }\n\n /// @notice Overrides the default LZ config\n function setSendVersion(uint16 _version) external override onlyGovernorOrGuardian {\n lzEndpoint.setSendVersion(_version);\n }\n\n /// @notice Overrides the default LZ config\n function setReceiveVersion(uint16 _version) external override onlyGovernorOrGuardian {\n lzEndpoint.setReceiveVersion(_version);\n }\n\n /// @notice Unpauses the receive functionalities\n function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress)\n external\n override\n onlyGovernorOrGuardian\n {\n lzEndpoint.forceResumeReceive(_srcChainId, _srcAddress);\n }\n\n // ======================= View Functions ================================\n\n /// @notice Checks if the `_srcAddress` corresponds to the trusted source\n function isTrustedRemote(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool) {\n bytes memory trustedSource = trustedRemoteLookup[_srcChainId];\n return keccak256(trustedSource) == keccak256(_srcAddress);\n }\n\n uint256[46] private __gap;\n}\n" + }, + "contracts/agToken/layerZero/utils/IOFTCore.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\n\n/**\n * @dev Interface of the IOFT core standard\n * @dev Forked from https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/token/oft/IOFTCore.sol\n */\ninterface IOFTCore is IERC165 {\n /// @notice Estimates send token `_tokenId` to (`_dstChainId`, `_toAddress`)\n /// @param _dstChainId L0 defined chain id to send tokens too\n /// @param _toAddress dynamic bytes array which contains the address to whom you are sending tokens to on the dstChain\n /// @param _amount amount of the tokens to transfer\n /// @param _useZro indicates to use zro to pay L0 fees\n /// @param _adapterParams flexible bytes array to indicate messaging adapter services in L0\n function estimateSendFee(\n uint16 _dstChainId,\n bytes calldata _toAddress,\n uint256 _amount,\n bool _useZro,\n bytes calldata _adapterParams\n ) external view returns (uint256 nativeFee, uint256 zroFee);\n\n /// @notice Sends `_amount` amount of token to (`_dstChainId`, `_toAddress`)\n /// @param _dstChainId the destination chain identifier\n /// @param _toAddress can be any size depending on the `dstChainId`.\n /// @param _amount the quantity of tokens in wei\n /// @param _refundAddress the address LayerZero refunds if too much message fee is sent\n /// @param _zroPaymentAddress set to address(0x0) if not paying in ZRO (LayerZero Token)\n /// @param _adapterParams is a flexible bytes array to indicate messaging adapter services\n function send(\n uint16 _dstChainId,\n bytes calldata _toAddress,\n uint256 _amount,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes calldata _adapterParams\n ) external payable;\n\n /// @notice Sends `_amount` amount of credit to (`_dstChainId`, `_toAddress`)\n /// @param _dstChainId the destination chain identifier\n /// @param _toAddress can be any size depending on the `dstChainId`.\n /// @param _amount the quantity of credit to send in wei\n /// @param _refundAddress the address LayerZero refunds if too much message fee is sent\n /// @param _zroPaymentAddress set to address(0x0) if not paying in ZRO (LayerZero Token)\n /// @param _adapterParams is a flexible bytes array to indicate messaging adapter services\n function sendCredit(\n uint16 _dstChainId,\n bytes calldata _toAddress,\n uint256 _amount,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes calldata _adapterParams\n ) external payable;\n\n /// @notice Sends `_amount` amount of token to (`_dstChainId`, `_toAddress`)\n /// @param _dstChainId The destination chain identifier\n /// @param _toAddress Can be any size depending on the `dstChainId`.\n /// @param _amount Quantity of tokens in wei\n /// @param _refundAddress Address LayerZero refunds if too much message fee is sent\n /// @param _zroPaymentAddress Set to address(0x0) if not paying in ZRO (LayerZero Token)\n /// @param _adapterParams Flexible bytes array to indicate messaging adapter services\n /// @param deadline Deadline parameter for the signature to be valid\n /// @dev The `v`, `r`, and `s` parameters are used as signature data\n function sendWithPermit(\n uint16 _dstChainId,\n bytes memory _toAddress,\n uint256 _amount,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes memory _adapterParams,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external payable;\n\n /// @notice Withdraws amount of canonical token from the `msg.sender` balance and sends it to the recipient\n /// @param amount Amount to withdraw\n /// @param recipient Address to send the canonical token to\n /// @return The amount of canonical token sent\n function withdraw(uint256 amount, address recipient) external returns (uint256);\n\n /// @dev Emitted when `_amount` tokens are moved from the `_sender` to (`_dstChainId`, `_toAddress`)\n /// `_nonce` is the outbound nonce\n event SendToChain(\n address indexed _sender,\n uint16 indexed _dstChainId,\n bytes indexed _toAddress,\n uint256 _amount,\n uint64 _nonce\n );\n\n /// @dev Emitted when `_amount` tokens are received from `_srcChainId` into the `_toAddress` on the local chain.\n /// `_nonce` is the inbound nonce.\n event ReceiveFromChain(\n uint16 indexed _srcChainId,\n bytes indexed _srcAddress,\n address indexed _toAddress,\n uint256 _amount,\n uint64 _nonce\n );\n}\n\n/// @dev Interface of the OFT standard\ninterface IOFT is IOFTCore, IERC20 {\n\n}\n" + }, + "contracts/interfaces/external/layerZero/ILayerZeroReceiver.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.5.0;\n\ninterface ILayerZeroReceiver {\n // @notice LayerZero endpoint will invoke this function to deliver the message on the destination\n // @param _srcChainId - the source endpoint identifier\n // @param _srcAddress - the source sending contract address from the source chain\n // @param _nonce - the ordered message nonce\n // @param _payload - the signed payload is the UA bytes has encoded to be sent\n function lzReceive(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n uint64 _nonce,\n bytes calldata _payload\n ) external;\n}\n" + }, + "contracts/interfaces/external/layerZero/ILayerZeroUserApplicationConfig.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.5.0;\n\ninterface ILayerZeroUserApplicationConfig {\n // @notice set the configuration of the LayerZero messaging library of the specified version\n // @param _version - messaging library version\n // @param _chainId - the chainId for the pending config change\n // @param _configType - type of configuration. every messaging library has its own convention.\n // @param _config - configuration in the bytes. can encode arbitrary content.\n function setConfig(\n uint16 _version,\n uint16 _chainId,\n uint256 _configType,\n bytes calldata _config\n ) external;\n\n // @notice set the send() LayerZero messaging library version to _version\n // @param _version - new messaging library version\n function setSendVersion(uint16 _version) external;\n\n // @notice set the lzReceive() LayerZero messaging library version to _version\n // @param _version - new messaging library version\n function setReceiveVersion(uint16 _version) external;\n\n // @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload\n // @param _srcChainId - the chainId of the source chain\n // @param _srcAddress - the contract address of the source contract at the source chain\n function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external;\n}\n" + }, + "contracts/interfaces/external/layerZero/ILayerZeroEndpoint.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.5.0;\n\nimport \"./ILayerZeroUserApplicationConfig.sol\";\n\ninterface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig {\n // @notice send a LayerZero message to the specified address at a LayerZero endpoint.\n // @param _dstChainId - the destination chain identifier\n // @param _destination - the address on destination chain (in bytes). address length/format may vary by chains\n // @param _payload - a custom bytes payload to send to the destination contract\n // @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address\n // @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction\n // @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination\n function send(\n uint16 _dstChainId,\n bytes calldata _destination,\n bytes calldata _payload,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes calldata _adapterParams\n ) external payable;\n\n // @notice used by the messaging library to publish verified payload\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source contract (as bytes) at the source chain\n // @param _dstAddress - the address on destination chain\n // @param _nonce - the unbound message ordering nonce\n // @param _gasLimit - the gas limit for external contract execution\n // @param _payload - verified payload to send to the destination contract\n function receivePayload(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n address _dstAddress,\n uint64 _nonce,\n uint256 _gasLimit,\n bytes calldata _payload\n ) external;\n\n // @notice get the inboundNonce of a lzApp from a source chain which could be EVM or non-EVM chain\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source chain contract address\n function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64);\n\n // @notice get the outboundNonce from this source chain which, consequently, is always an EVM\n // @param _srcAddress - the source chain contract address\n function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64);\n\n // @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery\n // @param _dstChainId - the destination chain identifier\n // @param _userApplication - the user app address on this EVM chain\n // @param _payload - the custom message to send over LayerZero\n // @param _payInZRO - if false, user app pays the protocol fee in native token\n // @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain\n function estimateFees(\n uint16 _dstChainId,\n address _userApplication,\n bytes calldata _payload,\n bool _payInZRO,\n bytes calldata _adapterParam\n ) external view returns (uint256 nativeFee, uint256 zroFee);\n\n // @notice get this Endpoint's immutable source identifier\n function getChainId() external view returns (uint16);\n\n // @notice the interface to retry failed message on this Endpoint destination\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source chain contract address\n // @param _payload - the payload to be retried\n function retryPayload(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n bytes calldata _payload\n ) external;\n\n // @notice query if any STORED payload (message blocking) at the endpoint.\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source chain contract address\n function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool);\n\n // @notice query if the _libraryAddress is valid for sending msgs.\n // @param _userApplication - the user app address on this EVM chain\n function getSendLibraryAddress(address _userApplication) external view returns (address);\n\n // @notice query if the _libraryAddress is valid for receiving msgs.\n // @param _userApplication - the user app address on this EVM chain\n function getReceiveLibraryAddress(address _userApplication) external view returns (address);\n\n // @notice query if the non-reentrancy guard for send() is on\n // @return true if the guard is on. false otherwise\n function isSendingPayload() external view returns (bool);\n\n // @notice query if the non-reentrancy guard for receive() is on\n // @return true if the guard is on. false otherwise\n function isReceivingPayload() external view returns (bool);\n\n // @notice get the configuration of the LayerZero messaging library of the specified version\n // @param _version - messaging library version\n // @param _chainId - the chainId for the pending config change\n // @param _userApplication - the contract address of the user application\n // @param _configType - type of configuration. every messaging library has its own convention.\n function getConfig(\n uint16 _version,\n uint16 _chainId,\n address _userApplication,\n uint256 _configType\n ) external view returns (bytes memory);\n\n // @notice get the send() LayerZero messaging library version\n // @param _userApplication - the contract address of the user application\n function getSendVersion(address _userApplication) external view returns (uint16);\n\n // @notice get the lzReceive() LayerZero messaging library version\n // @param _userApplication - the contract address of the user application\n function getReceiveVersion(address _userApplication) external view returns (uint16);\n}\n" + }, + "contracts/agToken/layerZero/LayerZeroBridgeToken.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.12;\n\nimport \"./utils/OFTCore.sol\";\nimport \"../../interfaces/IAgTokenSideChainMultiBridge.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol\";\n\n/// @title LayerZeroBridgeToken\n/// @author Angle Labs, Inc., forked from https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/token/oft/OFT.sol\n/// @notice Contract to be deployed on a L2/sidechain for bridging an AgToken using a bridge intermediate token and LayerZero\ncontract LayerZeroBridgeToken is OFTCore, ERC20Upgradeable, PausableUpgradeable {\n /// @notice Address of the bridgeable token\n /// @dev Immutable\n IAgTokenSideChainMultiBridge public canonicalToken;\n\n // =============================== Errors ================================\n\n error InvalidAllowance();\n\n // ============================= Constructor ===================================\n\n /// @notice Initializes the contract\n /// @param _name Name of the token corresponding to this contract\n /// @param _symbol Symbol of the token corresponding to this contract\n /// @param _lzEndpoint Layer zero endpoint to pass messages\n /// @param _treasury Address of the treasury contract used for access control\n /// @param initialSupply Initial supply to mint to the canonical token address\n /// @dev The initial supply corresponds to the initial amount that could be bridged using this OFT\n function initialize(\n string memory _name,\n string memory _symbol,\n address _lzEndpoint,\n address _treasury,\n uint256 initialSupply\n ) external initializer {\n __ERC20_init_unchained(_name, _symbol);\n __LzAppUpgradeable_init(_lzEndpoint, _treasury);\n\n canonicalToken = IAgTokenSideChainMultiBridge(address(ITreasury(_treasury).stablecoin()));\n _approve(address(this), address(canonicalToken), type(uint256).max);\n _mint(address(canonicalToken), initialSupply);\n }\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() initializer {}\n\n // ==================== External Permissionless Functions ======================\n\n /// @inheritdoc OFTCore\n function sendWithPermit(\n uint16 _dstChainId,\n bytes memory _toAddress,\n uint256 _amount,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes memory _adapterParams,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public payable override {\n canonicalToken.permit(msg.sender, address(this), _amount, deadline, v, r, s);\n send(_dstChainId, _toAddress, _amount, _refundAddress, _zroPaymentAddress, _adapterParams);\n }\n\n /// @inheritdoc OFTCore\n function withdraw(uint256 amount, address recipient) external override returns (uint256 amountMinted) {\n // Does not check allowances as transfers from `msg.sender`\n _transfer(msg.sender, address(this), amount);\n amountMinted = canonicalToken.swapIn(address(this), amount, recipient);\n uint256 leftover = balanceOf(address(this));\n if (leftover != 0) {\n _transfer(address(this), msg.sender, leftover);\n }\n }\n\n // ============================= Internal Functions ===================================\n\n /// @inheritdoc OFTCore\n function _debitFrom(\n uint16,\n bytes memory,\n uint256 _amount\n ) internal override whenNotPaused returns (uint256 amountSwapped) {\n // No need to use safeTransferFrom as we know this implementation reverts on failure\n canonicalToken.transferFrom(msg.sender, address(this), _amount);\n\n // Swap canonical for this bridge token. There may be some fees\n amountSwapped = canonicalToken.swapOut(address(this), _amount, address(this));\n _burn(address(this), amountSwapped);\n }\n\n /// @inheritdoc OFTCore\n function _debitCreditFrom(\n uint16,\n bytes memory,\n uint256 _amount\n ) internal override whenNotPaused returns (uint256) {\n _burn(msg.sender, _amount);\n return _amount;\n }\n\n /// @inheritdoc OFTCore\n function _creditTo(\n uint16,\n address _toAddress,\n uint256 _amount\n ) internal override whenNotPaused returns (uint256 amountMinted) {\n _mint(address(this), _amount);\n amountMinted = canonicalToken.swapIn(address(this), _amount, _toAddress);\n uint256 leftover = balanceOf(address(this));\n if (leftover != 0) {\n _transfer(address(this), _toAddress, leftover);\n }\n }\n\n // ======================= View Functions ================================\n\n /// @inheritdoc ERC165Upgradeable\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return\n interfaceId == type(IOFT).interfaceId ||\n interfaceId == type(IERC20).interfaceId ||\n super.supportsInterface(interfaceId);\n }\n\n // ======================= Governance Functions ================================\n\n /// @notice Mints the intermediate contract to the `canonicalToken`\n /// @dev Used to increase the bridging capacity\n function mint(uint256 amount) external onlyGovernorOrGuardian {\n _mint(address(canonicalToken), amount);\n }\n\n /// @notice Burns the intermediate contract from the `canonicalToken`\n /// @dev Used to decrease the bridging capacity\n function burn(uint256 amount) external onlyGovernorOrGuardian {\n _burn(address(canonicalToken), amount);\n }\n\n /// @notice Increases allowance of the `canonicalToken`\n function setupAllowance() public onlyGovernorOrGuardian {\n _approve(address(this), address(canonicalToken), type(uint256).max);\n }\n\n /// @notice Pauses bridging through the contract\n /// @param pause Future pause status\n function pauseSendTokens(bool pause) external onlyGovernorOrGuardian {\n pause ? _pause() : _unpause();\n }\n\n uint256[49] private __gap;\n}\n" + }, + "contracts/interfaces/IAgTokenSideChainMultiBridge.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\n\n/// @title IAgTokenSideChainMultiBridge\n/// @author Angle Labs, Inc.\n/// @notice Interface for the canonical `AgToken` contracts\n/// @dev This interface only contains functions useful for bridge tokens to interact with the canonical token\ninterface IAgTokenSideChainMultiBridge is IERC20PermitUpgradeable, IERC20Upgradeable {\n /// @notice Mints the canonical token from a supported bridge token\n /// @param bridgeToken Bridge token to use to mint\n /// @param amount Amount of bridge tokens to send\n /// @param to Address to which the stablecoin should be sent\n /// @return Amount of the canonical stablecoin actually minted\n /// @dev Some fees may be taken by the protocol depending on the token used and on the address calling\n function swapIn(\n address bridgeToken,\n uint256 amount,\n address to\n ) external returns (uint256);\n\n /// @notice Burns the canonical token in exchange for a bridge token\n /// @param bridgeToken Bridge token required\n /// @param amount Amount of canonical tokens to burn\n /// @param to Address to which the bridge token should be sent\n /// @return Amount of bridge tokens actually sent back\n /// @dev Some fees may be taken by the protocol depending on the token used and on the address calling\n function swapOut(\n address bridgeToken,\n uint256 amount,\n address to\n ) external returns (uint256);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/extensions/draft-ERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./draft-IERC20PermitUpgradeable.sol\";\nimport \"../ERC20Upgradeable.sol\";\nimport \"../../../utils/cryptography/draft-EIP712Upgradeable.sol\";\nimport \"../../../utils/cryptography/ECDSAUpgradeable.sol\";\nimport \"../../../utils/CountersUpgradeable.sol\";\nimport \"../../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * _Available since v3.4._\n *\n * @custom:storage-size 51\n */\nabstract contract ERC20PermitUpgradeable is Initializable, ERC20Upgradeable, IERC20PermitUpgradeable, EIP712Upgradeable {\n using CountersUpgradeable for CountersUpgradeable.Counter;\n\n mapping(address => CountersUpgradeable.Counter) private _nonces;\n\n // solhint-disable-next-line var-name-mixedcase\n bytes32 private constant _PERMIT_TYPEHASH =\n keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n /**\n * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`.\n * However, to ensure consistency with the upgradeable transpiler, we will continue\n * to reserve a slot.\n * @custom:oz-renamed-from _PERMIT_TYPEHASH\n */\n // solhint-disable-next-line var-name-mixedcase\n bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;\n\n /**\n * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\"1\"`.\n *\n * It's a good idea to use the same `name` that is defined as the ERC20 token name.\n */\n function __ERC20Permit_init(string memory name) internal onlyInitializing {\n __EIP712_init_unchained(name, \"1\");\n }\n\n function __ERC20Permit_init_unchained(string memory) internal onlyInitializing {}\n\n /**\n * @dev See {IERC20Permit-permit}.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual override {\n require(block.timestamp <= deadline, \"ERC20Permit: expired deadline\");\n\n bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));\n\n bytes32 hash = _hashTypedDataV4(structHash);\n\n address signer = ECDSAUpgradeable.recover(hash, v, r, s);\n require(signer == owner, \"ERC20Permit: invalid signature\");\n\n _approve(owner, spender, value);\n }\n\n /**\n * @dev See {IERC20Permit-nonces}.\n */\n function nonces(address owner) public view virtual override returns (uint256) {\n return _nonces[owner].current();\n }\n\n /**\n * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view override returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /**\n * @dev \"Consume a nonce\": return the current value and increment.\n *\n * _Available since v4.1._\n */\n function _useNonce(address owner) internal virtual returns (uint256 current) {\n CountersUpgradeable.Counter storage nonce = _nonces[owner];\n current = nonce.current();\n nonce.increment();\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title Counters\n * @author Matt Condon (@shrugs)\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\n *\n * Include with `using Counters for Counters.Counter;`\n */\nlibrary CountersUpgradeable {\n struct Counter {\n // This variable should never be directly accessed by users of the library: interactions must be restricted to\n // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\n // this feature: see https://github.com/ethereum/solidity/issues/4637\n uint256 _value; // default: 0\n }\n\n function current(Counter storage counter) internal view returns (uint256) {\n return counter._value;\n }\n\n function increment(Counter storage counter) internal {\n unchecked {\n counter._value += 1;\n }\n }\n\n function decrement(Counter storage counter) internal {\n uint256 value = counter._value;\n require(value > 0, \"Counter: decrement overflow\");\n unchecked {\n counter._value = value - 1;\n }\n }\n\n function reset(Counter storage counter) internal {\n counter._value = 0;\n }\n}\n" + }, + "contracts/deprecated/AgTokenIntermediateUpgrade.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"../interfaces/IAgToken.sol\";\nimport \"../interfaces/coreModule/IStableMaster.sol\";\n// OpenZeppelin may update its version of the ERC20PermitUpgradeable token\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol\";\n\n/// @title AgTokenIntermediateUpgrade\n/// @author Angle Labs, Inc.\n/// @notice Base contract for agToken, that is to say Angle's stablecoins\n/// @dev This contract is used to create and handle the stablecoins of Angle protocol\n/// @dev It is still possible for any address to burn its agTokens without redeeming collateral in exchange\n/// @dev This contract is the upgraded version of the AgToken that was first deployed on Ethereum mainnet and is used to\n/// add other minters as needed by AMOs\ncontract AgTokenIntermediateUpgrade is ERC20PermitUpgradeable {\n // ========================= References to other contracts =====================\n\n /// @notice Reference to the `StableMaster` contract associated to this `AgToken`\n address public stableMaster;\n\n // ============================= Constructor ===================================\n\n /// @notice Initializes the `AgToken` contract\n /// @param name_ Name of the token\n /// @param symbol_ Symbol of the token\n /// @param stableMaster_ Reference to the `StableMaster` contract associated to this agToken\n /// @dev By default, agTokens are ERC-20 tokens with 18 decimals\n function initialize(\n string memory name_,\n string memory symbol_,\n address stableMaster_\n ) external initializer {\n __ERC20Permit_init(name_);\n __ERC20_init(name_, symbol_);\n require(stableMaster_ != address(0), \"0\");\n stableMaster = stableMaster_;\n }\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() initializer {}\n\n // ======= Added Parameters and Variables from the first implementation ========\n\n /// @notice Checks whether an address has the right to mint agTokens\n mapping(address => bool) public isMinter;\n\n // =============================== Added Events ================================\n\n event MinterToggled(address indexed minter);\n\n // =============================== Setup Function ==============================\n\n /// @notice Sets up the minter role and gives it to the governor\n /// @dev This function just has to be called once\n function setUpMinter() external {\n address governor = 0xdC4e6DFe07EFCa50a197DF15D9200883eF4Eb1c8;\n require(msg.sender == governor);\n isMinter[governor] = true;\n emit MinterToggled(governor);\n }\n\n // =============================== Modifiers ===================================\n\n /// @notice Checks whether the sender has the minting right\n modifier onlyMinter() {\n require(isMinter[msg.sender] || msg.sender == stableMaster, \"35\");\n _;\n }\n\n // ========================= External Functions ================================\n // The following functions allow anyone to burn stablecoins without redeeming collateral\n // in exchange for that\n\n /// @notice Destroys `amount` token from the caller without giving collateral back\n /// @param amount Amount to burn\n /// @param poolManager Reference to the `PoolManager` contract for which the `stocksUsers` will\n /// need to be updated\n /// @dev When calling this function, people should specify the `poolManager` for which they want to decrease\n /// the `stocksUsers`: this is a way for the protocol to maintain healthy accounting variables\n function burnNoRedeem(uint256 amount, address poolManager) external {\n _burn(msg.sender, amount);\n IStableMaster(stableMaster).updateStocksUsers(amount, poolManager);\n }\n\n /// @notice Burns `amount` of agToken on behalf of another account without redeeming collateral back\n /// @param account Account to burn on behalf of\n /// @param amount Amount to burn\n /// @param poolManager Reference to the `PoolManager` contract for which the `stocksUsers` will need to be updated\n function burnFromNoRedeem(\n address account,\n uint256 amount,\n address poolManager\n ) external {\n _burnFromNoRedeem(amount, account, msg.sender);\n IStableMaster(stableMaster).updateStocksUsers(amount, poolManager);\n }\n\n // ======================= Minter Role Only Functions ==========================\n\n /// @notice Burns `amount` tokens from a `burner` address\n /// @param amount Amount of tokens to burn\n /// @param burner Address to burn from\n /// @dev This method is to be called by a contract with a minter right on the AgToken after being\n /// requested to do so by an address willing to burn tokens from its address\n function burnSelf(uint256 amount, address burner) external onlyMinter {\n _burn(burner, amount);\n }\n\n /// @notice Burns `amount` tokens from a `burner` address after being asked to by `sender`\n /// @param amount Amount of tokens to burn\n /// @param burner Address to burn from\n /// @param sender Address which requested the burn from `burner`\n /// @dev This method is to be called by a contract with the minter right after being requested\n /// to do so by a `sender` address willing to burn tokens from another `burner` address\n /// @dev The method checks the allowance between the `sender` and the `burner`\n function burnFrom(\n uint256 amount,\n address burner,\n address sender\n ) external onlyMinter {\n _burnFromNoRedeem(amount, burner, sender);\n }\n\n /// @notice Lets the `StableMaster` contract or another whitelisted contract mint agTokens\n /// @param account Address to mint to\n /// @param amount Amount to mint\n /// @dev The contracts allowed to issue agTokens are the `StableMaster` contract, `VaultManager` contracts\n /// associated to this stablecoin as well as the flash loan module (if activated) and potentially contracts\n /// whitelisted by governance\n function mint(address account, uint256 amount) external onlyMinter {\n _mint(account, amount);\n }\n\n // ======================= Minter Only Functions ===============================\n\n /// @notice Adds a minter in the contract\n /// @param minter Minter address to add\n function addMinter(address minter) external onlyMinter {\n isMinter[minter] = true;\n emit MinterToggled(minter);\n }\n\n /// @notice Removes a minter from the contract\n /// @param minter Minter address to remove\n /// @dev This function can at the moment only be called by a minter wishing to revoke itself\n function removeMinter(address minter) external {\n require(msg.sender == minter && isMinter[msg.sender], \"36\");\n isMinter[minter] = false;\n emit MinterToggled(minter);\n }\n\n // ============================ Internal Function ==============================\n\n /// @notice Internal version of the function `burnFromNoRedeem`\n /// @param amount Amount to burn\n /// @dev It is at the level of this function that allowance checks are performed\n function _burnFromNoRedeem(\n uint256 amount,\n address burner,\n address sender\n ) internal {\n if (burner != sender) {\n uint256 currentAllowance = allowance(burner, sender);\n require(currentAllowance >= amount, \"23\");\n _approve(burner, sender, currentAllowance - amount);\n }\n _burn(burner, amount);\n }\n}\n" + }, + "contracts/treasury/Treasury.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n * █ \n ***** ▓▓▓ \n * ▓▓▓▓▓▓▓ \n * ///. ▓▓▓▓▓▓▓▓▓▓▓▓▓ \n ***** //////// ▓▓▓▓▓▓▓ \n * ///////////// ▓▓▓ \n ▓▓ ////////////////// █ ▓▓ \n ▓▓ ▓▓ /////////////////////// ▓▓ ▓▓ \n ▓▓ ▓▓ //////////////////////////// ▓▓ ▓▓ \n ▓▓ ▓▓ /////////▓▓▓///////▓▓▓///////// ▓▓ ▓▓ \n ▓▓ ,////////////////////////////////////// ▓▓ ▓▓ \n ▓▓ ////////////////////////////////////////// ▓▓ \n ▓▓ //////////////////////▓▓▓▓///////////////////// \n ,//////////////////////////////////////////////////// \n .////////////////////////////////////////////////////////// \n .//////////////////////////██.,//////////////////////////█ \n .//////////////////////████..,./////////////////////██ \n ...////////////////███████.....,.////////////////███ \n ,.,////////////████████ ........,///////////████ \n .,.,//////█████████ ,.......///////████ \n ,..//████████ ........./████ \n ..,██████ .....,███ \n .██ ,.,█ \n \n \n \n ▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓ \n ▓▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓ ▓▓▓▓ \n ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓▓▓▓ \n ▓▓▓ ▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ \n*/\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport \"../interfaces/IAgToken.sol\";\nimport \"../interfaces/ICoreBorrow.sol\";\nimport \"../interfaces/IFlashAngle.sol\";\nimport \"../interfaces/ITreasury.sol\";\nimport \"../interfaces/IVaultManager.sol\";\n\n/// @title Treasury\n/// @author Angle Labs, Inc.\n/// @notice Treasury of Angle Borrowing Module doing the accounting across all VaultManagers for\n/// a given stablecoin\ncontract Treasury is ITreasury, Initializable {\n using SafeERC20 for IERC20;\n\n /// @notice Base used for parameter computation\n uint256 public constant BASE_9 = 1e9;\n\n // ================================= REFERENCES ================================\n\n /// @notice Reference to the `CoreBorrow` contract of the module which handles all AccessControl logic\n ICoreBorrow public core;\n /// @notice Flash Loan Module with a minter right on the stablecoin\n IFlashAngle public flashLoanModule;\n /// @inheritdoc ITreasury\n IAgToken public stablecoin;\n /// @notice Address responsible for handling the surplus made by the treasury\n address public surplusManager;\n /// @notice List of the accepted `VaultManager` of the protocol\n address[] public vaultManagerList;\n /// @notice Maps an address to 1 if it was initialized as a `VaultManager` contract\n mapping(address => uint256) public vaultManagerMap;\n\n // ================================= VARIABLES =================================\n\n /// @notice Amount of bad debt (unbacked stablecoin) accumulated across all `VaultManager` contracts\n /// linked to this stablecoin\n uint256 public badDebt;\n /// @notice Surplus amount accumulated by the contract waiting to be distributed to governance. Technically\n /// only a share of this `surplusBuffer` will go to governance. Once a share of the surplus buffer has been\n /// given to governance, then this surplus is reset\n uint256 public surplusBuffer;\n\n // ================================= PARAMETER =================================\n\n /// @notice Share of the `surplusBuffer` distributed to governance (in `BASE_9`)\n uint64 public surplusForGovernance;\n\n // =================================== EVENTS ==================================\n\n event BadDebtUpdated(uint256 badDebtValue);\n event CoreUpdated(address indexed _core);\n event NewTreasurySet(address indexed _treasury);\n event Recovered(address indexed token, address indexed to, uint256 amount);\n event SurplusBufferUpdated(uint256 surplusBufferValue);\n event SurplusForGovernanceUpdated(uint64 _surplusForGovernance);\n event SurplusManagerUpdated(address indexed _surplusManager);\n event VaultManagerToggled(address indexed vaultManager);\n\n // =================================== ERRORS ==================================\n\n error AlreadyVaultManager();\n error InvalidAddress();\n error InvalidTreasury();\n error NotCore();\n error NotGovernor();\n error NotVaultManager();\n error RightsNotRemoved();\n error TooBigAmount();\n error TooHighParameterValue();\n error ZeroAddress();\n\n // ================================== MODIFIER =================================\n\n /// @notice Checks whether the `msg.sender` has the governor role or not\n modifier onlyGovernor() {\n if (!core.isGovernor(msg.sender)) revert NotGovernor();\n _;\n }\n\n /// @notice Initializes the treasury contract\n /// @param _core Address of the `CoreBorrow` contract of the module\n /// @param _stablecoin Address of the stablecoin\n function initialize(ICoreBorrow _core, IAgToken _stablecoin) public virtual initializer {\n if (address(_stablecoin) == address(0) || address(_core) == address(0)) revert ZeroAddress();\n core = _core;\n stablecoin = _stablecoin;\n }\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() initializer {}\n\n // =============================== VIEW FUNCTIONS ==============================\n\n /// @inheritdoc ITreasury\n function isGovernor(address admin) external view returns (bool) {\n return core.isGovernor(admin);\n }\n\n /// @inheritdoc ITreasury\n function isGovernorOrGuardian(address admin) external view returns (bool) {\n return core.isGovernorOrGuardian(admin);\n }\n\n /// @inheritdoc ITreasury\n function isVaultManager(address _vaultManager) external view returns (bool) {\n return vaultManagerMap[_vaultManager] == 1;\n }\n\n // ===================== EXTERNAL PERMISSIONLESS FUNCTIONS =====================\n\n /// @notice Fetches the surplus accrued across all the `VaultManager` contracts controlled by this\n /// `Treasury` contract as well as from the fees of the `FlashLoan` module\n /// @return Surplus buffer value at the end of the call\n /// @return Bad debt value at the end of the call\n /// @dev This function pools surplus and bad debt across all contracts and then updates the `surplusBuffer`\n /// (or the `badDebt` if more losses were made than profits)\n function fetchSurplusFromAll() external returns (uint256, uint256) {\n return _fetchSurplusFromAll();\n }\n\n /// @notice Fetches the surplus accrued in the flash loan module and updates the `surplusBuffer`\n /// @return Surplus buffer value at the end of the call\n /// @return Bad debt value at the end of the call\n /// @dev This function fails if the `flashLoanModule` has not been initialized yet\n function fetchSurplusFromFlashLoan() external returns (uint256, uint256) {\n uint256 surplusBufferValue = surplusBuffer + flashLoanModule.accrueInterestToTreasury(stablecoin);\n return _updateSurplusAndBadDebt(surplusBufferValue, badDebt);\n }\n\n /// @notice Pushes the surplus buffer to the `surplusManager` contract\n /// @return governanceAllocation Amount transferred to governance\n /// @dev It makes sure to fetch the surplus from all the contracts handled by this treasury to avoid\n /// the situation where rewards are still distributed to governance even though a `VaultManager` has made\n /// a big loss\n /// @dev Typically this function is to be called once every week by a keeper to distribute rewards to veANGLE\n /// holders\n /// @dev `stablecoin` must be an AgToken and hence `transfer` reverts if the call is not successful\n function pushSurplus() external returns (uint256 governanceAllocation) {\n address _surplusManager = surplusManager;\n if (_surplusManager == address(0)) {\n revert ZeroAddress();\n }\n (uint256 surplusBufferValue, ) = _fetchSurplusFromAll();\n surplusBuffer = 0;\n emit SurplusBufferUpdated(0);\n governanceAllocation = (surplusForGovernance * surplusBufferValue) / BASE_9;\n stablecoin.transfer(_surplusManager, governanceAllocation);\n }\n\n /// @notice Updates the bad debt of the protocol in case where the protocol has accumulated some revenue\n /// from an external source\n /// @param amount Amount to reduce the bad debt of\n /// @return badDebtValue Value of the bad debt at the end of the call\n /// @dev If the protocol has made a loss and managed to make some profits to recover for this loss (through\n /// a program like Olympus Pro), then this function needs to be called\n /// @dev `badDebt` is simply reduced here by burning stablecoins\n /// @dev It is impossible to burn more than the `badDebt` otherwise this function could be used to manipulate\n /// the `surplusBuffer` and hence the amount going to governance\n function updateBadDebt(uint256 amount) external returns (uint256 badDebtValue) {\n stablecoin.burnSelf(amount, address(this));\n badDebtValue = badDebt - amount;\n badDebt = badDebtValue;\n emit BadDebtUpdated(badDebtValue);\n }\n\n // ========================= INTERNAL UTILITY FUNCTIONS ========================\n\n /// @notice Internal version of the `fetchSurplusFromAll` function\n function _fetchSurplusFromAll() internal returns (uint256 surplusBufferValue, uint256 badDebtValue) {\n (surplusBufferValue, badDebtValue) = _fetchSurplusFromList(vaultManagerList);\n // It will fail anyway if the `flashLoanModule` is the zero address\n if (address(flashLoanModule) != address(0))\n surplusBufferValue += flashLoanModule.accrueInterestToTreasury(stablecoin);\n (surplusBufferValue, badDebtValue) = _updateSurplusAndBadDebt(surplusBufferValue, badDebtValue);\n }\n\n /// @notice Fetches the surplus from a list of `VaultManager` addresses without modifying the\n /// `surplusBuffer` and `badDebtValue`\n /// @return surplusBufferValue Value the `surplusBuffer` should have after the call if it was updated\n /// @return badDebtValue Value the `badDebt` should have after the call if it was updated\n /// @dev This internal function is never to be called alone, and should always be called in conjunction\n /// with the `_updateSurplusAndBadDebt` function\n function _fetchSurplusFromList(\n address[] memory vaultManagers\n ) internal returns (uint256 surplusBufferValue, uint256 badDebtValue) {\n badDebtValue = badDebt;\n surplusBufferValue = surplusBuffer;\n uint256 newSurplus;\n uint256 newBadDebt;\n uint256 vaultManagersLength = vaultManagers.length;\n for (uint256 i; i < vaultManagersLength; ++i) {\n (newSurplus, newBadDebt) = IVaultManager(vaultManagers[i]).accrueInterestToTreasury();\n surplusBufferValue += newSurplus;\n badDebtValue += newBadDebt;\n }\n }\n\n /// @notice Updates the `surplusBuffer` and the `badDebt` from updated values after calling the flash loan module\n /// and/or a list of `VaultManager` contracts\n /// @param surplusBufferValue Value of the surplus buffer after the calls to the different modules\n /// @param badDebtValue Value of the bad debt after the calls to the different modules\n /// @return Value of the `surplusBuffer` corrected from the `badDebt`\n /// @return Value of the `badDebt` corrected from the `surplusBuffer` and from the surplus the treasury had accumulated\n /// previously\n /// @dev When calling this function, it is possible that there is a positive `surplusBufferValue` and `badDebtValue`,\n /// this function tries to reconcile both values and makes sure that we either have surplus or bad debt but not both\n /// at the same time\n function _updateSurplusAndBadDebt(\n uint256 surplusBufferValue,\n uint256 badDebtValue\n ) internal returns (uint256, uint256) {\n if (badDebtValue != 0) {\n // If we have bad debt we need to burn stablecoins that accrued to the protocol\n // We still need to make sure that we're not burning too much or as much as we can if the debt is big\n uint256 balance = stablecoin.balanceOf(address(this));\n // We are going to burn `min(balance, badDebtValue)`\n uint256 toBurn = balance <= badDebtValue ? balance : badDebtValue;\n stablecoin.burnSelf(toBurn, address(this));\n // If we burned more than `surplusBuffer`, we set surplus to 0. It means we had to tap into Treasury reserve\n surplusBufferValue = toBurn >= surplusBufferValue ? 0 : surplusBufferValue - toBurn;\n badDebtValue -= toBurn;\n // Note here that the stablecoin balance is necessarily greater than the surplus buffer, and so if\n // `surplusBuffer >= toBurn`, then `badDebtValue = toBurn`\n }\n surplusBuffer = surplusBufferValue;\n badDebt = badDebtValue;\n emit SurplusBufferUpdated(surplusBufferValue);\n emit BadDebtUpdated(badDebtValue);\n return (surplusBufferValue, badDebtValue);\n }\n\n /// @notice Adds a new `VaultManager`\n /// @param vaultManager `VaultManager` contract to add\n /// @dev This contract should have already been initialized with a correct treasury address\n /// @dev It's this function that gives the minter right to the `VaultManager`\n function _addVaultManager(address vaultManager) internal virtual {\n if (vaultManagerMap[vaultManager] == 1) revert AlreadyVaultManager();\n if (address(IVaultManager(vaultManager).treasury()) != address(this)) revert InvalidTreasury();\n vaultManagerMap[vaultManager] = 1;\n vaultManagerList.push(vaultManager);\n emit VaultManagerToggled(vaultManager);\n stablecoin.addMinter(vaultManager);\n }\n\n // ============================= GOVERNOR FUNCTIONS ============================\n\n /// @notice Adds a new minter for the stablecoin\n /// @param minter Minter address to add\n function addMinter(address minter) external virtual onlyGovernor {\n if (minter == address(0)) revert ZeroAddress();\n stablecoin.addMinter(minter);\n }\n\n /// @notice External wrapper for `_addVaultManager`\n function addVaultManager(address vaultManager) external virtual onlyGovernor {\n _addVaultManager(vaultManager);\n }\n\n /// @notice Removes a minter from the stablecoin contract\n /// @param minter Minter address to remove\n function removeMinter(address minter) external virtual onlyGovernor {\n // To remove the minter role to a `VaultManager` you have to go through the `removeVaultManager` function\n if (vaultManagerMap[minter] == 1) revert InvalidAddress();\n stablecoin.removeMinter(minter);\n }\n\n /// @notice Removes a `VaultManager`\n /// @param vaultManager `VaultManager` contract to remove\n /// @dev A removed `VaultManager` loses its minter right on the stablecoin\n function removeVaultManager(address vaultManager) external onlyGovernor {\n if (vaultManagerMap[vaultManager] != 1) revert NotVaultManager();\n delete vaultManagerMap[vaultManager];\n // deletion from `vaultManagerList` loop\n uint256 vaultManagerListLength = vaultManagerList.length;\n for (uint256 i; i < vaultManagerListLength - 1; ++i) {\n if (vaultManagerList[i] == vaultManager) {\n // replace the `VaultManager` to remove with the last of the list\n vaultManagerList[i] = vaultManagerList[vaultManagerListLength - 1];\n break;\n }\n }\n // remove last element in array\n vaultManagerList.pop();\n emit VaultManagerToggled(vaultManager);\n stablecoin.removeMinter(vaultManager);\n }\n\n /// @notice Allows to recover any ERC20 token, including the stablecoin handled by this contract, and to send it\n /// to a contract\n /// @param tokenAddress Address of the token to recover\n /// @param to Address of the contract to send collateral to\n /// @param amountToRecover Amount of collateral to transfer\n /// @dev It is impossible to recover the stablecoin of the protocol if there is some bad debt for it\n /// @dev In this case, the function makes sure to fetch the surplus/bad debt from all the `VaultManager` contracts\n /// and from the flash loan module\n /// @dev If the token to recover is the stablecoin, tokens recovered are fetched\n /// from the surplus and not from the `surplusBuffer`\n function recoverERC20(address tokenAddress, address to, uint256 amountToRecover) external onlyGovernor {\n // Cannot recover stablecoin if badDebt or tap into the surplus buffer\n if (tokenAddress == address(stablecoin)) {\n _fetchSurplusFromAll();\n // If balance is non zero then this means, after the call to `fetchSurplusFromAll` that\n // bad debt is necessarily null\n uint256 balance = stablecoin.balanceOf(address(this));\n if (amountToRecover + surplusBuffer > balance) revert TooBigAmount();\n stablecoin.transfer(to, amountToRecover);\n } else {\n IERC20(tokenAddress).safeTransfer(to, amountToRecover);\n }\n emit Recovered(tokenAddress, to, amountToRecover);\n }\n\n /// @notice Changes the treasury contract and communicates this change to all `VaultManager` contract\n /// @param _treasury New treasury address for this stablecoin\n /// @dev This function is basically a way to remove rights to this contract and grant them to a new one\n /// @dev It could be used to set a new core contract\n function setTreasury(address _treasury) external virtual onlyGovernor {\n if (ITreasury(_treasury).stablecoin() != stablecoin) revert InvalidTreasury();\n // Flash loan role should be removed before calling this function\n if (core.isFlashLoanerTreasury(address(this))) revert RightsNotRemoved();\n emit NewTreasurySet(_treasury);\n uint256 vaultManagerListLength = vaultManagerList.length;\n for (uint256 i; i < vaultManagerListLength; ++i) {\n IVaultManager(vaultManagerList[i]).setTreasury(_treasury);\n }\n // A `TreasuryUpdated` event is triggered in the stablecoin\n stablecoin.setTreasury(_treasury);\n }\n\n /// @notice Sets the `surplusForGovernance` parameter\n /// @param _surplusForGovernance New value of the parameter\n /// @dev To pause surplus distribution, governance needs to set a zero value for `surplusForGovernance`\n /// which means\n function setSurplusForGovernance(uint64 _surplusForGovernance) external onlyGovernor {\n if (_surplusForGovernance > BASE_9) revert TooHighParameterValue();\n surplusForGovernance = _surplusForGovernance;\n emit SurplusForGovernanceUpdated(_surplusForGovernance);\n }\n\n /// @notice Sets the `surplusManager` contract responsible for handling the surplus of the\n /// protocol\n /// @param _surplusManager New address responsible for handling the surplus\n function setSurplusManager(address _surplusManager) external onlyGovernor {\n if (_surplusManager == address(0)) revert ZeroAddress();\n surplusManager = _surplusManager;\n emit SurplusManagerUpdated(_surplusManager);\n }\n\n /// @notice Sets a new `core` contract\n /// @dev This function should typically be called on all treasury contracts after the `setCore`\n /// function has been called on the `CoreBorrow` contract\n /// @dev One sanity check that can be performed here is to verify whether at least the governor\n /// calling the contract is still a governor in the new core\n function setCore(ICoreBorrow _core) external onlyGovernor {\n if (!_core.isGovernor(msg.sender)) revert NotGovernor();\n core = ICoreBorrow(_core);\n emit CoreUpdated(address(_core));\n }\n\n /// @inheritdoc ITreasury\n function setFlashLoanModule(address _flashLoanModule) external {\n if (msg.sender != address(core)) revert NotCore();\n address oldFlashLoanModule = address(flashLoanModule);\n flashLoanModule = IFlashAngle(_flashLoanModule);\n if (oldFlashLoanModule != address(0)) {\n stablecoin.removeMinter(oldFlashLoanModule);\n }\n // We may want to cancel the module\n if (_flashLoanModule != address(0)) {\n stablecoin.addMinter(_flashLoanModule);\n }\n }\n}\n" + }, + "contracts/mock/MockTreasury.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"../interfaces/ITreasury.sol\";\nimport \"../interfaces/IFlashAngle.sol\";\nimport \"../interfaces/IVaultManager.sol\";\n\ncontract MockTreasury is ITreasury {\n IAgToken public override stablecoin;\n address public governor;\n address public guardian;\n address public vaultManager1;\n address public vaultManager2;\n address public flashLoanModule;\n\n constructor(\n IAgToken _stablecoin,\n address _governor,\n address _guardian,\n address _vaultManager1,\n address _vaultManager2,\n address _flashLoanModule\n ) {\n stablecoin = _stablecoin;\n governor = _governor;\n guardian = _guardian;\n vaultManager1 = _vaultManager1;\n vaultManager2 = _vaultManager2;\n flashLoanModule = _flashLoanModule;\n }\n\n function isGovernor(address admin) external view override returns (bool) {\n return (admin == governor);\n }\n\n function isGovernorOrGuardian(address admin) external view override returns (bool) {\n return (admin == governor || admin == guardian);\n }\n\n function isVaultManager(address _vaultManager) external view override returns (bool) {\n return (_vaultManager == vaultManager1 || _vaultManager == vaultManager2);\n }\n\n function setStablecoin(IAgToken _stablecoin) external {\n stablecoin = _stablecoin;\n }\n\n function setFlashLoanModule(address _flashLoanModule) external override {\n flashLoanModule = _flashLoanModule;\n }\n\n function setGovernor(address _governor) external {\n governor = _governor;\n }\n\n function setVaultManager(address _vaultManager) external {\n vaultManager1 = _vaultManager;\n }\n\n function setVaultManager2(address _vaultManager) external {\n vaultManager2 = _vaultManager;\n }\n\n function setTreasury(address _agTokenOrVaultManager, address _treasury) external {\n IAgToken(_agTokenOrVaultManager).setTreasury(_treasury);\n }\n\n function addMinter(IAgToken _agToken, address _minter) external {\n _agToken.addMinter(_minter);\n }\n\n function removeMinter(IAgToken _agToken, address _minter) external {\n _agToken.removeMinter(_minter);\n }\n\n function accrueInterestToTreasury(IFlashAngle flashAngle) external returns (uint256 balance) {\n balance = flashAngle.accrueInterestToTreasury(stablecoin);\n }\n\n function accrueInterestToTreasuryVaultManager(IVaultManager _vaultManager) external returns (uint256, uint256) {\n return _vaultManager.accrueInterestToTreasury();\n }\n}\n" + }, + "contracts/mock/MockFlashLoanModule.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"../interfaces/IFlashAngle.sol\";\nimport \"../interfaces/ICoreBorrow.sol\";\n\ncontract MockFlashLoanModule is IFlashAngle {\n ICoreBorrow public override core;\n mapping(address => bool) public stablecoinsSupported;\n mapping(IAgToken => uint256) public interestAccrued;\n uint256 public surplusValue;\n\n constructor(ICoreBorrow _core) {\n core = _core;\n }\n\n function accrueInterestToTreasury(IAgToken stablecoin) external override returns (uint256 balance) {\n balance = surplusValue;\n interestAccrued[stablecoin] += balance;\n }\n\n function addStablecoinSupport(address _treasury) external override {\n stablecoinsSupported[_treasury] = true;\n }\n\n function removeStablecoinSupport(address _treasury) external override {\n stablecoinsSupported[_treasury] = false;\n }\n\n function setCore(address _core) external override {\n core = ICoreBorrow(_core);\n }\n\n function setSurplusValue(uint256 _surplusValue) external {\n surplusValue = _surplusValue;\n }\n}\n" + }, + "contracts/mock/MockCoreBorrow.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"../interfaces/ICoreBorrow.sol\";\nimport \"../interfaces/IFlashAngle.sol\";\nimport \"../interfaces/ITreasury.sol\";\n\ncontract MockCoreBorrow is ICoreBorrow {\n mapping(address => bool) public flashLoaners;\n mapping(address => bool) public governors;\n mapping(address => bool) public guardians;\n\n function isFlashLoanerTreasury(address treasury) external view override returns (bool) {\n return flashLoaners[treasury];\n }\n\n function isGovernor(address admin) external view override returns (bool) {\n return governors[admin];\n }\n\n function isGovernorOrGuardian(address admin) external view override returns (bool) {\n return governors[admin] || guardians[admin];\n }\n\n function toggleGovernor(address admin) external {\n governors[admin] = !governors[admin];\n }\n\n function toggleGuardian(address admin) external {\n guardians[admin] = !guardians[admin];\n }\n\n function toggleFlashLoaners(address admin) external {\n flashLoaners[admin] = !flashLoaners[admin];\n }\n\n function addStablecoinSupport(IFlashAngle flashAngle, address _treasury) external {\n flashAngle.addStablecoinSupport(_treasury);\n }\n\n function removeStablecoinSupport(IFlashAngle flashAngle, address _treasury) external {\n flashAngle.removeStablecoinSupport(_treasury);\n }\n\n function setCore(IFlashAngle flashAngle, address _core) external {\n flashAngle.setCore(_core);\n }\n\n function setFlashLoanModule(ITreasury _treasury, address _flashLoanModule) external {\n _treasury.setFlashLoanModule(_flashLoanModule);\n }\n}\n" + }, + "contracts/flashloan/FlashAngle.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol\";\nimport \"@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport \"../interfaces/IAgToken.sol\";\nimport \"../interfaces/ICoreBorrow.sol\";\nimport \"../interfaces/IFlashAngle.sol\";\nimport \"../interfaces/ITreasury.sol\";\n\n/// @title FlashAngle\n/// @author Angle Labs, Inc.\n/// @notice Contract to take flash loans on top of several AgToken contracts\ncontract FlashAngle is IERC3156FlashLender, IFlashAngle, Initializable, ReentrancyGuardUpgradeable {\n using SafeERC20 for IERC20;\n /// @notice Base used for parameter computation\n uint256 public constant BASE_PARAMS = 10**9;\n /// @notice Success message received when calling a `FlashBorrower` contract\n bytes32 public constant CALLBACK_SUCCESS = keccak256(\"ERC3156FlashBorrower.onFlashLoan\");\n\n /// @notice Struct encoding for a given stablecoin the parameters\n struct StablecoinData {\n // Maximum amount borrowable for this stablecoin\n uint256 maxBorrowable;\n // Flash loan fee taken by the protocol for a flash loan on this stablecoin\n uint64 flashLoanFee;\n // Treasury address responsible of the stablecoin\n address treasury;\n }\n\n // ======================= Parameters and References ===========================\n\n /// @notice Maps a stablecoin to the data and parameters for flash loans\n mapping(IAgToken => StablecoinData) public stablecoinMap;\n /// @inheritdoc IFlashAngle\n ICoreBorrow public core;\n\n // =============================== Event =======================================\n\n event FlashLoan(address indexed stablecoin, uint256 amount, IERC3156FlashBorrower indexed receiver);\n event FlashLoanParametersUpdated(IAgToken indexed stablecoin, uint64 _flashLoanFee, uint256 _maxBorrowable);\n\n // =============================== Errors ======================================\n\n error InvalidReturnMessage();\n error NotCore();\n error NotGovernorOrGuardian();\n error NotTreasury();\n error TooBigAmount();\n error TooHighParameterValue();\n error UnsupportedStablecoin();\n error ZeroAddress();\n\n /// @notice Initializes the contract\n /// @param _core Core address handling this module\n function initialize(ICoreBorrow _core) public initializer {\n if (address(_core) == address(0)) revert ZeroAddress();\n core = _core;\n }\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() initializer {}\n\n // =================================== Modifiers ===============================\n\n /// @notice Checks whether the sender is the core contract\n modifier onlyCore() {\n if (msg.sender != address(core)) revert NotCore();\n _;\n }\n\n /// @notice Checks whether a given stablecoin has been initialized in this contract\n /// @param stablecoin Stablecoin to check\n /// @dev To check whether a stablecoin has been initialized, we just need to check whether its associated\n /// `treasury` address is not null in the `stablecoinMap`. This is what's checked in the `CoreBorrow` contract\n /// when adding support for a stablecoin\n modifier onlyExistingStablecoin(IAgToken stablecoin) {\n if (stablecoinMap[stablecoin].treasury == address(0)) revert UnsupportedStablecoin();\n _;\n }\n\n // ================================ ERC3156 Spec ===============================\n\n /// @inheritdoc IERC3156FlashLender\n function flashFee(address token, uint256 amount) external view returns (uint256) {\n return _flashFee(token, amount);\n }\n\n /// @inheritdoc IERC3156FlashLender\n function maxFlashLoan(address token) external view returns (uint256) {\n // It will be 0 anyway if the token was not added\n return stablecoinMap[IAgToken(token)].maxBorrowable;\n }\n\n /// @inheritdoc IERC3156FlashLender\n function flashLoan(\n IERC3156FlashBorrower receiver,\n address token,\n uint256 amount,\n bytes calldata data\n ) external nonReentrant returns (bool) {\n uint256 fee = _flashFee(token, amount);\n if (amount > stablecoinMap[IAgToken(token)].maxBorrowable) revert TooBigAmount();\n IAgToken(token).mint(address(receiver), amount);\n if (receiver.onFlashLoan(msg.sender, token, amount, fee, data) != CALLBACK_SUCCESS)\n revert InvalidReturnMessage();\n // Token must be an agToken here so normally no need to use `safeTransferFrom`, but out of safety\n // and in case governance whitelists an agToken which does not have a correct implementation, we prefer\n // to use `safeTransferFrom` here\n IERC20(token).safeTransferFrom(address(receiver), address(this), amount + fee);\n IAgToken(token).burnSelf(amount, address(this));\n emit FlashLoan(token, amount, receiver);\n return true;\n }\n\n /// @notice Internal function to compute the fee induced for taking a flash loan of `amount` of `token`\n /// @param token The loan currency\n /// @param amount The amount of tokens lent\n /// @dev This function will revert if the `token` requested is not whitelisted here\n function _flashFee(address token, uint256 amount)\n internal\n view\n onlyExistingStablecoin(IAgToken(token))\n returns (uint256)\n {\n return (amount * stablecoinMap[IAgToken(token)].flashLoanFee) / BASE_PARAMS;\n }\n\n // ============================ Treasury Only Function =========================\n\n /// @inheritdoc IFlashAngle\n function accrueInterestToTreasury(IAgToken stablecoin) external returns (uint256 balance) {\n address treasury = stablecoinMap[stablecoin].treasury;\n if (msg.sender != treasury) revert NotTreasury();\n balance = stablecoin.balanceOf(address(this));\n IERC20(address(stablecoin)).safeTransfer(treasury, balance);\n }\n\n // =========================== Governance Only Function ========================\n\n /// @notice Sets the parameters for a given stablecoin\n /// @param stablecoin Stablecoin to change the parameters for\n /// @param _flashLoanFee New flash loan fee for this stablecoin\n /// @param _maxBorrowable Maximum amount that can be borrowed in a single flash loan\n /// @dev Setting a `maxBorrowable` parameter equal to 0 is a way to pause the functionality\n /// @dev Parameters can only be modified for whitelisted stablecoins\n function setFlashLoanParameters(\n IAgToken stablecoin,\n uint64 _flashLoanFee,\n uint256 _maxBorrowable\n ) external onlyExistingStablecoin(stablecoin) {\n if (!core.isGovernorOrGuardian(msg.sender)) revert NotGovernorOrGuardian();\n if (_flashLoanFee > BASE_PARAMS) revert TooHighParameterValue();\n stablecoinMap[stablecoin].flashLoanFee = _flashLoanFee;\n stablecoinMap[stablecoin].maxBorrowable = _maxBorrowable;\n emit FlashLoanParametersUpdated(stablecoin, _flashLoanFee, _maxBorrowable);\n }\n\n // =========================== CoreBorrow Only Functions =======================\n\n /// @inheritdoc IFlashAngle\n function addStablecoinSupport(address _treasury) external onlyCore {\n stablecoinMap[IAgToken(ITreasury(_treasury).stablecoin())].treasury = _treasury;\n }\n\n /// @inheritdoc IFlashAngle\n function removeStablecoinSupport(address _treasury) external onlyCore {\n delete stablecoinMap[IAgToken(ITreasury(_treasury).stablecoin())];\n }\n\n /// @inheritdoc IFlashAngle\n function setCore(address _core) external onlyCore {\n core = ICoreBorrow(_core);\n }\n}\n" + }, + "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (interfaces/IERC3156FlashBorrower.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC3156 FlashBorrower, as defined in\n * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].\n *\n * _Available since v4.1._\n */\ninterface IERC3156FlashBorrower {\n /**\n * @dev Receive a flash loan.\n * @param initiator The initiator of the loan.\n * @param token The loan currency.\n * @param amount The amount of tokens lent.\n * @param fee The additional amount of tokens to repay.\n * @param data Arbitrary data structure, intended to contain user-defined parameters.\n * @return The keccak256 hash of \"IERC3156FlashBorrower.onFlashLoan\"\n */\n function onFlashLoan(\n address initiator,\n address token,\n uint256 amount,\n uint256 fee,\n bytes calldata data\n ) external returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC3156FlashLender.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC3156FlashBorrower.sol\";\n\n/**\n * @dev Interface of the ERC3156 FlashLender, as defined in\n * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].\n *\n * _Available since v4.1._\n */\ninterface IERC3156FlashLender {\n /**\n * @dev The amount of currency available to be lended.\n * @param token The loan currency.\n * @return The amount of `token` that can be borrowed.\n */\n function maxFlashLoan(address token) external view returns (uint256);\n\n /**\n * @dev The fee to be charged for a given loan.\n * @param token The loan currency.\n * @param amount The amount of tokens lent.\n * @return The amount of `token` to be charged for the loan, on top of the returned principal.\n */\n function flashFee(address token, uint256 amount) external view returns (uint256);\n\n /**\n * @dev Initiate a flash loan.\n * @param receiver The receiver of the tokens in the loan, and the receiver of the callback.\n * @param token The loan currency.\n * @param amount The amount of tokens lent.\n * @param data Arbitrary data structure, intended to contain user-defined parameters.\n */\n function flashLoan(\n IERC3156FlashBorrower receiver,\n address token,\n uint256 amount,\n bytes calldata data\n ) external returns (bool);\n}\n" + }, + "contracts/mock/MockFlashLoanReceiver.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.7;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\nimport \"@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol\";\n\nimport \"@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol\";\n\ncontract MockFlashLoanReceiver is IERC3156FlashBorrower {\n bytes32 public constant CALLBACK_SUCCESS = keccak256(\"ERC3156FlashBorrower.onFlashLoan\");\n\n constructor() {}\n\n function onFlashLoan(\n address,\n address token,\n uint256 amount,\n uint256 fee,\n bytes calldata data\n ) external override returns (bytes32) {\n IERC20(token).approve(msg.sender, amount + fee);\n if (amount >= 10**21) return keccak256(\"error\");\n if (amount == 2 * 10**18) {\n IERC3156FlashLender(msg.sender).flashLoan(IERC3156FlashBorrower(address(this)), token, amount, data);\n return keccak256(\"reentrant\");\n } else return CALLBACK_SUCCESS;\n }\n}\n" + }, + "contracts/coreBorrow/CoreBorrow.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n * █ \n ***** ▓▓▓ \n * ▓▓▓▓▓▓▓ \n * ///. ▓▓▓▓▓▓▓▓▓▓▓▓▓ \n ***** //////// ▓▓▓▓▓▓▓ \n * ///////////// ▓▓▓ \n ▓▓ ////////////////// █ ▓▓ \n ▓▓ ▓▓ /////////////////////// ▓▓ ▓▓ \n ▓▓ ▓▓ //////////////////////////// ▓▓ ▓▓ \n ▓▓ ▓▓ /////////▓▓▓///////▓▓▓///////// ▓▓ ▓▓ \n ▓▓ ,////////////////////////////////////// ▓▓ ▓▓ \n ▓▓ ////////////////////////////////////////// ▓▓ \n ▓▓ //////////////////////▓▓▓▓///////////////////// \n ,//////////////////////////////////////////////////// \n .////////////////////////////////////////////////////////// \n .//////////////////////////██.,//////////////////////////█ \n .//////////////////////████..,./////////////////////██ \n ...////////////////███████.....,.////////////////███ \n ,.,////////////████████ ........,///////////████ \n .,.,//////█████████ ,.......///////████ \n ,..//████████ ........./████ \n ..,██████ .....,███ \n .██ ,.,█ \n \n \n \n ▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓ \n ▓▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓ ▓▓▓▓ \n ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓▓▓▓ \n ▓▓▓ ▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ \n*/\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\n\nimport \"../interfaces/ICoreBorrow.sol\";\nimport \"../interfaces/IFlashAngle.sol\";\nimport \"../interfaces/ITreasury.sol\";\n\n/// @title CoreBorrow\n/// @author Angle Labs, Inc.\n/// @notice Core contract of the borrowing module. This contract handles the access control across all contracts\n/// (it is read by all treasury contracts), and manages the `flashLoanModule`. It has no minting rights over the\n/// stablecoin contracts\ncontract CoreBorrow is ICoreBorrow, Initializable, AccessControlEnumerableUpgradeable {\n /// @notice Role for guardians\n bytes32 public constant GUARDIAN_ROLE = keccak256(\"GUARDIAN_ROLE\");\n /// @notice Role for governors\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n /// @notice Role for treasury contract\n bytes32 public constant FLASHLOANER_TREASURY_ROLE = keccak256(\"FLASHLOANER_TREASURY_ROLE\");\n\n // ============================= Reference =====================================\n\n /// @notice Reference to the `flashLoanModule` with minting rights over the different stablecoins of the protocol\n address public flashLoanModule;\n\n // =============================== Events ======================================\n\n event FlashLoanModuleUpdated(address indexed _flashloanModule);\n event CoreUpdated(address indexed _core);\n\n // =============================== Errors ======================================\n\n error InvalidCore();\n error IncompatibleGovernorAndGuardian();\n error NotEnoughGovernorsLeft();\n error ZeroAddress();\n\n /// @notice Initializes the `CoreBorrow` contract and the access control of the borrowing module\n /// @param governor Address of the governor of the Angle Protocol\n /// @param guardian Guardian address of the protocol\n function initialize(address governor, address guardian) public initializer {\n if (governor == address(0) || guardian == address(0)) revert ZeroAddress();\n if (governor == guardian) revert IncompatibleGovernorAndGuardian();\n _setupRole(GOVERNOR_ROLE, governor);\n _setupRole(GUARDIAN_ROLE, guardian);\n _setupRole(GUARDIAN_ROLE, governor);\n _setRoleAdmin(GUARDIAN_ROLE, GOVERNOR_ROLE);\n _setRoleAdmin(GOVERNOR_ROLE, GOVERNOR_ROLE);\n _setRoleAdmin(FLASHLOANER_TREASURY_ROLE, GOVERNOR_ROLE);\n }\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() initializer {}\n\n // =========================== View Functions ==================================\n\n /// @inheritdoc ICoreBorrow\n function isFlashLoanerTreasury(address treasury) external view returns (bool) {\n return hasRole(FLASHLOANER_TREASURY_ROLE, treasury);\n }\n\n /// @inheritdoc ICoreBorrow\n function isGovernor(address admin) external view returns (bool) {\n return hasRole(GOVERNOR_ROLE, admin);\n }\n\n /// @inheritdoc ICoreBorrow\n function isGovernorOrGuardian(address admin) external view returns (bool) {\n return hasRole(GUARDIAN_ROLE, admin);\n }\n\n // =========================== Governor Functions ==============================\n\n /// @notice Grants the `FLASHLOANER_TREASURY_ROLE` to a `treasury` contract\n /// @param treasury Contract to grant the role to\n /// @dev This function can be used to allow flash loans on a stablecoin of the protocol\n function addFlashLoanerTreasuryRole(address treasury) external {\n grantRole(FLASHLOANER_TREASURY_ROLE, treasury);\n address _flashLoanModule = flashLoanModule;\n if (_flashLoanModule != address(0)) {\n // This call will revert if `treasury` is the zero address or if it is not linked\n // to this `CoreBorrow` contract\n ITreasury(treasury).setFlashLoanModule(_flashLoanModule);\n IFlashAngle(_flashLoanModule).addStablecoinSupport(treasury);\n }\n }\n\n /// @notice Adds a governor in the protocol\n /// @param governor Address to grant the role to\n /// @dev It is necessary to call this function to grant a governor role to make sure\n /// all governors also have the guardian role\n function addGovernor(address governor) external {\n grantRole(GOVERNOR_ROLE, governor);\n grantRole(GUARDIAN_ROLE, governor);\n }\n\n /// @notice Revokes the flash loan ability for a stablecoin\n /// @param treasury Treasury address associated with the stablecoin for which flash loans\n /// should no longer be available\n function removeFlashLoanerTreasuryRole(address treasury) external {\n revokeRole(FLASHLOANER_TREASURY_ROLE, treasury);\n ITreasury(treasury).setFlashLoanModule(address(0));\n address _flashLoanModule = flashLoanModule;\n if (_flashLoanModule != address(0)) {\n IFlashAngle(flashLoanModule).removeStablecoinSupport(treasury);\n }\n }\n\n /// @notice Revokes a governor from the protocol\n /// @param governor Address to remove the role to\n /// @dev It is necessary to call this function to remove a governor role to make sure\n /// the address also loses its guardian role\n function removeGovernor(address governor) external {\n if (getRoleMemberCount(GOVERNOR_ROLE) <= 1) revert NotEnoughGovernorsLeft();\n revokeRole(GUARDIAN_ROLE, governor);\n revokeRole(GOVERNOR_ROLE, governor);\n }\n\n /// @notice Changes the `flashLoanModule` of the protocol\n /// @param _flashLoanModule Address of the new flash loan module\n function setFlashLoanModule(address _flashLoanModule) external onlyRole(GOVERNOR_ROLE) {\n if (_flashLoanModule != address(0)) {\n if (address(IFlashAngle(_flashLoanModule).core()) != address(this)) revert InvalidCore();\n }\n uint256 count = getRoleMemberCount(FLASHLOANER_TREASURY_ROLE);\n for (uint256 i; i < count; ++i) {\n ITreasury(getRoleMember(FLASHLOANER_TREASURY_ROLE, i)).setFlashLoanModule(_flashLoanModule);\n }\n flashLoanModule = _flashLoanModule;\n emit FlashLoanModuleUpdated(_flashLoanModule);\n }\n\n /// @notice Changes the core contract of the protocol\n /// @param _core New core contract\n /// @dev This function verifies that all governors of the current core contract are also governors\n /// of the new core contract. It also notifies the `flashLoanModule` of the change.\n /// @dev Governance wishing to change the core contract should also make sure to call `setCore`\n /// in the different treasury contracts\n function setCore(ICoreBorrow _core) external onlyRole(GOVERNOR_ROLE) {\n uint256 count = getRoleMemberCount(GOVERNOR_ROLE);\n bool success;\n for (uint256 i; i < count; ++i) {\n success = _core.isGovernor(getRoleMember(GOVERNOR_ROLE, i));\n if (!success) break;\n }\n if (!success) revert InvalidCore();\n address _flashLoanModule = flashLoanModule;\n if (_flashLoanModule != address(0)) IFlashAngle(_flashLoanModule).setCore(address(_core));\n emit CoreUpdated(address(_core));\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControlEnumerableUpgradeable.sol\";\nimport \"./AccessControlUpgradeable.sol\";\nimport \"../utils/structs/EnumerableSetUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessControlEnumerableUpgradeable, AccessControlUpgradeable {\n function __AccessControlEnumerable_init() internal onlyInitializing {\n }\n\n function __AccessControlEnumerable_init_unchained() internal onlyInitializing {\n }\n using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;\n\n mapping(bytes32 => EnumerableSetUpgradeable.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerableUpgradeable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override {\n super._grantRole(role, account);\n _roleMembers[role].add(account);\n }\n\n /**\n * @dev Overload {_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override {\n super._revokeRole(role, account);\n _roleMembers[role].remove(account);\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/access/IAccessControlEnumerableUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControlUpgradeable.sol\";\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerableUpgradeable is IAccessControlUpgradeable {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableSet.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSetUpgradeable {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(bytes32 => uint256) _indexes;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._indexes[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We read and store the value's index to prevent multiple reads from the same storage slot\n uint256 valueIndex = set._indexes[value];\n\n if (valueIndex != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 toDeleteIndex = valueIndex - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (lastIndex != toDeleteIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the last value to the index where the value to delete is\n set._values[toDeleteIndex] = lastValue;\n // Update the index for the moved value\n set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the index for the deleted slot\n delete set._indexes[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._indexes[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n return _values(set._inner);\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n" + }, + "contracts/mock/MockKeeperMulticall.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ncontract MockKeeperMulticall is Initializable, AccessControlUpgradeable {\n using SafeERC20 for IERC20;\n\n bytes32 public constant KEEPER_ROLE = keccak256(\"KEEPER_ROLE\");\n\n //solhint-disable-next-line\n address private constant _oneInch = 0x1111111254fb6c44bAC0beD2854e76F90643097d;\n\n struct Action {\n address target;\n bytes data;\n bool isDelegateCall;\n }\n\n event LogAction(address indexed target, bytes data);\n event SentToMiner(uint256 indexed value);\n event Recovered(address indexed tokenAddress, address indexed to, uint256 amount);\n\n error AmountOutTooLow(uint256 amount, uint256 min);\n error BalanceTooLow();\n error FlashbotsErrorPayingMiner(uint256 value);\n error IncompatibleLengths();\n error RevertBytes();\n error ZeroAddress();\n\n constructor() initializer {}\n\n function initialize(address keeper) public initializer {\n __AccessControl_init();\n\n _setupRole(KEEPER_ROLE, keeper);\n _setRoleAdmin(KEEPER_ROLE, KEEPER_ROLE);\n }\n}\n\ncontract MockKeeperMulticall2 {\n uint256 public varTest = 1;\n\n bytes32 public constant KEEPER_ROLE = keccak256(\"KEEPER_ROLE\");\n\n //solhint-disable-next-line\n address private constant _oneInch = 0x1111111254fb6c44bAC0beD2854e76F90643097d;\n\n struct Action {\n address target;\n bytes data;\n bool isDelegateCall;\n }\n\n event LogAction(address indexed target, bytes data);\n event SentToMiner(uint256 indexed value);\n event Recovered(address indexed tokenAddress, address indexed to, uint256 amount);\n\n error AmountOutTooLow(uint256 amount, uint256 min);\n error BalanceTooLow();\n error FlashbotsErrorPayingMiner(uint256 value);\n error IncompatibleLengths();\n error RevertBytes();\n error ZeroAddress();\n\n function functionTest() external pure returns (bool) {\n return true;\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n function __Ownable_init() internal onlyInitializing {\n __Ownable_init_unchained();\n }\n\n function __Ownable_init_unchained() internal onlyInitializing {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "contracts/keeperMulticall/KeeperMulticall.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"./RevertReasonParser.sol\";\n\n/// @title KeeperMulticall\n/// @notice Allows an authorized caller (keeper) to execute multiple actions in a single tx.\n/// @author Angle Labs, Inc.\n/// @dev Special features:\n/// - ability to pay the miner (for private Flashbots transactions)\n/// - swap tokens through 1inch\n/// @dev Tx need to be encoded as an array of Action. The flag `isDelegateCall` is used for calling functions within this same contract\ncontract KeeperMulticall is Initializable, AccessControlUpgradeable {\n using SafeERC20 for IERC20;\n\n bytes32 public constant KEEPER_ROLE = keccak256(\"KEEPER_ROLE\");\n\n //solhint-disable-next-line\n address private constant _oneInch = 0x1111111254fb6c44bAC0beD2854e76F90643097d;\n\n struct Action {\n address target;\n bytes data;\n bool isDelegateCall;\n }\n\n event LogAction(address indexed target, bytes data);\n event SentToMiner(uint256 indexed value);\n event Recovered(address indexed tokenAddress, address indexed to, uint256 amount);\n\n error AmountOutTooLow(uint256 amount, uint256 min);\n error BalanceTooLow();\n error FlashbotsErrorPayingMiner(uint256 value);\n error IncompatibleLengths();\n error RevertBytes();\n error WrongAmount();\n error ZeroAddress();\n\n constructor() initializer {}\n\n function initialize(address keeper) external initializer {\n __AccessControl_init();\n\n _setupRole(KEEPER_ROLE, keeper);\n _setRoleAdmin(KEEPER_ROLE, KEEPER_ROLE);\n }\n\n /// @notice Allows an authorized keeper to execute multiple actions in a single step\n /// @param actions Actions to be executed\n /// @param percentageToMiner Percentage to pay to miner expressed in bps (10000)\n /// @dev This is the main entry point for actions to be executed. The `isDelegateCall` flag is used for calling function inside this `KeeperMulticall` contract,\n /// if we call other contracts, the flag should be false\n function executeActions(Action[] memory actions, uint256 percentageToMiner)\n external\n payable\n onlyRole(KEEPER_ROLE)\n returns (bytes[] memory)\n {\n uint256 numberOfActions = actions.length;\n if (numberOfActions == 0) revert IncompatibleLengths();\n\n bytes[] memory returnValues = new bytes[](numberOfActions + 1);\n\n uint256 balanceBefore = address(this).balance;\n\n for (uint256 i; i < numberOfActions; ++i) {\n returnValues[i] = _executeAction(actions[i]);\n }\n\n if (percentageToMiner != 0) {\n if (percentageToMiner >= 10000) revert WrongAmount();\n uint256 balanceAfter = address(this).balance;\n if (balanceAfter > balanceBefore) {\n uint256 amountToMiner = ((balanceAfter - balanceBefore) * percentageToMiner) / 10000;\n returnValues[numberOfActions] = payFlashbots(amountToMiner);\n }\n }\n\n return returnValues;\n }\n\n /// @notice Gets the action address and data and executes it\n /// @param action Action to be executed\n function _executeAction(Action memory action) internal returns (bytes memory) {\n bool success;\n bytes memory response;\n\n if (action.isDelegateCall) {\n //solhint-disable-next-line\n (success, response) = action.target.delegatecall(action.data);\n } else {\n //solhint-disable-next-line\n (success, response) = action.target.call(action.data);\n }\n\n require(success, RevertReasonParser.parse(response, \"action reverted: \"));\n emit LogAction(action.target, action.data);\n return response;\n }\n\n /// @notice Ability to pay miner directly. Used for Flashbots to execute private transactions\n /// @param value Value to be sent\n function payFlashbots(uint256 value) public payable onlyRole(KEEPER_ROLE) returns (bytes memory) {\n //solhint-disable-next-line\n (bool success, bytes memory response) = block.coinbase.call{ value: value }(\"\");\n if (!success) revert FlashbotsErrorPayingMiner(value);\n emit SentToMiner(value);\n return response;\n }\n\n /// @notice Used to check the balances the token holds for each token. If we don't have enough of a token, we revert the tx\n /// @param tokens Array of tokens to check\n /// @param minBalances Array of balances for each token\n function finalBalanceCheck(IERC20[] memory tokens, uint256[] memory minBalances) external view returns (bool) {\n uint256 tokensLength = tokens.length;\n if (tokensLength == 0 || tokensLength != minBalances.length) revert IncompatibleLengths();\n\n for (uint256 i; i < tokensLength; ++i) {\n if (address(tokens[i]) == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {\n if (address(this).balance < minBalances[i]) revert BalanceTooLow();\n } else {\n if (tokens[i].balanceOf(address(this)) < minBalances[i]) revert BalanceTooLow();\n }\n }\n\n return true;\n }\n\n /// @notice Swap token to another through 1Inch\n /// @param minAmountOut Minimum amount of `out` token to receive for the swap to happen\n /// @param payload Bytes needed for 1Inch API\n function swapToken(uint256 minAmountOut, bytes memory payload) external onlyRole(KEEPER_ROLE) {\n //solhint-disable-next-line\n (bool success, bytes memory result) = _oneInch.call(payload);\n if (!success) _revertBytes(result);\n\n uint256 amountOut = abi.decode(result, (uint256));\n if (amountOut < minAmountOut) revert AmountOutTooLow(amountOut, minAmountOut);\n }\n\n /// @notice Copied from 1Inch contract, used to revert if there is an error\n function _revertBytes(bytes memory errMsg) internal pure {\n if (errMsg.length != 0) {\n //solhint-disable-next-line\n assembly {\n revert(add(32, errMsg), mload(errMsg))\n }\n }\n revert RevertBytes();\n }\n\n /// @notice Approve a `spender` for `token`\n /// @param token Address of the token to approve\n /// @param spender Address of the spender to approve\n /// @param amount Amount to approve\n function approve(\n IERC20 token,\n address spender,\n uint256 amount\n ) external onlyRole(KEEPER_ROLE) {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance < amount) {\n token.safeIncreaseAllowance(spender, amount - currentAllowance);\n } else if (currentAllowance > amount) {\n token.safeDecreaseAllowance(spender, currentAllowance - amount);\n }\n }\n\n receive() external payable {}\n\n /// @notice Withdraw stuck funds\n /// @param token Address of the token to recover\n /// @param receiver Address where to send the tokens\n /// @param amount Amount to recover\n function withdrawStuckFunds(\n address token,\n address receiver,\n uint256 amount\n ) external onlyRole(KEEPER_ROLE) {\n if (receiver == address(0)) revert ZeroAddress();\n if (token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {\n payable(receiver).transfer(amount);\n } else {\n IERC20(token).safeTransfer(receiver, amount);\n }\n\n emit Recovered(token, receiver, amount);\n }\n}\n" + }, + "contracts/keeperMulticall/RevertReasonParser.sol": { + "content": "// SPDX-License-Identifier: GNU-3\n\npragma solidity ^0.8.12;\n\n/// @title RevertReasonParser\n/// @author 1Inch team, taken from:\n/// - https://docs.1inch.io/docs/limit-order-protocol/smart-contract/libraries/RevertReasonParser/\n/// - https://etherscan.io/address/0x1111111254fb6c44bAC0beD2854e76F90643097d#code\nlibrary RevertReasonParser {\n bytes4 private constant _PANIC_SELECTOR = bytes4(keccak256(\"Panic(uint256)\"));\n bytes4 private constant _ERROR_SELECTOR = bytes4(keccak256(\"Error(string)\"));\n\n function parse(bytes memory data, string memory prefix) internal pure returns (string memory) {\n if (data.length >= 4) {\n bytes4 selector;\n //solhint-disable-next-line\n assembly {\n selector := mload(add(data, 0x20))\n }\n\n // 68 = 4-byte selector + 32 bytes offset + 32 bytes length\n if (selector == _ERROR_SELECTOR && data.length >= 68) {\n uint256 offset;\n bytes memory reason;\n // solhint-disable no-inline-assembly\n assembly {\n // 36 = 32 bytes data length + 4-byte selector\n offset := mload(add(data, 36))\n reason := add(data, add(36, offset))\n }\n /*\n revert reason is padded up to 32 bytes with ABI encoder: Error(string)\n also sometimes there is extra 32 bytes of zeros padded in the end:\n https://github.com/ethereum/solidity/issues/10170\n because of that we can't check for equality and instead check\n that offset + string length + extra 36 bytes is less than overall data length\n */\n require(data.length >= 36 + offset + reason.length, \"Invalid revert reason\");\n return string(abi.encodePacked(prefix, \"Error(\", reason, \")\"));\n }\n // 36 = 4-byte selector + 32 bytes integer\n else if (selector == _PANIC_SELECTOR && data.length == 36) {\n uint256 code;\n // solhint-disable no-inline-assembly\n assembly {\n // 36 = 32 bytes data length + 4-byte selector\n code := mload(add(data, 36))\n }\n return string(abi.encodePacked(prefix, \"Panic(\", _toHex(code), \")\"));\n }\n }\n\n return string(abi.encodePacked(prefix, \"Unknown(\", _toHex(data), \")\"));\n }\n\n function _toHex(uint256 value) private pure returns (string memory) {\n return _toHex(abi.encodePacked(value));\n }\n\n function _toHex(bytes memory data) private pure returns (string memory) {\n bytes16 alphabet = 0x30313233343536373839616263646566;\n bytes memory str = new bytes(2 + data.length * 2);\n str[0] = \"0\";\n str[1] = \"x\";\n for (uint256 i; i < data.length; ++i) {\n str[2 * i + 2] = alphabet[uint8(data[i] >> 4)];\n str[2 * i + 3] = alphabet[uint8(data[i] & 0x0f)];\n }\n return string(str);\n }\n}\n" + }, + "contracts/agToken/polygon/TokenPolygonUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.12;\n\nimport \"./utils/ERC20UpgradeableCustom.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport \"../../interfaces/IAgToken.sol\";\nimport \"../../interfaces/ITreasury.sol\";\n\ninterface IChildToken {\n function deposit(address user, bytes calldata depositData) external;\n\n function withdraw(uint256 amount) external;\n}\n\ncontract TokenPolygonUpgradeable is\n Initializable,\n ERC20UpgradeableCustom,\n AccessControlUpgradeable,\n EIP712Upgradeable,\n IChildToken\n{\n bytes32 public constant DEPOSITOR_ROLE = keccak256(\"DEPOSITOR_ROLE\");\n\n /// @dev Emitted when the child chain manager changes\n event ChildChainManagerAdded(address newAddress);\n event ChildChainManagerRevoked(address oldAddress);\n\n constructor() initializer {}\n\n function initialize(\n string memory _name,\n string memory _symbol,\n address childChainManager,\n address guardian\n ) public initializer {\n __ERC20_init(_name, _symbol);\n __AccessControl_init();\n _setupRole(DEFAULT_ADMIN_ROLE, guardian);\n _setupRole(DEPOSITOR_ROLE, childChainManager);\n __EIP712_init(_name, \"1\");\n }\n\n /**\n * @notice Called when the bridge has tokens to mint\n * @param user Address to mint the token to\n * @param depositData Encoded amount to mint\n */\n function deposit(address user, bytes calldata depositData) external override {\n require(hasRole(DEPOSITOR_ROLE, msg.sender));\n uint256 amount = abi.decode(depositData, (uint256));\n _mint(user, amount);\n }\n\n /**\n * @notice Called when user wants to withdraw tokens back to root chain\n * @dev Should burn user's tokens. This transaction will be verified when exiting on root chain\n * @param amount Amount of tokens to withdraw\n */\n function withdraw(uint256 amount) external override {\n _burn(_msgSender(), amount);\n }\n\n // =============================================================================\n // ======================= New data added for the upgrade ======================\n // =============================================================================\n\n mapping(address => bool) public isMinter;\n /// @notice Reference to the treasury contract which can grant minting rights\n address public treasury;\n /// @notice Boolean to check whether the contract has been reinitialized after its upgrade\n bool public treasuryInitialized;\n\n using SafeERC20 for IERC20;\n\n /// @notice Base used for fee computation\n uint256 public constant BASE_PARAMS = 10**9;\n\n // =============================== Bridging Data ===============================\n\n /// @notice Struct with some data about a specific bridge token\n struct BridgeDetails {\n // Limit on the balance of bridge token held by the contract: it is designed\n // to reduce the exposure of the system to hacks\n uint256 limit;\n // Limit on the hourly volume of token minted through this bridge\n // Technically the limit over a rolling hour is hourlyLimit x2 as hourly limit\n // is enforced only between x:00 and x+1:00\n uint256 hourlyLimit;\n // Fee taken for swapping in and out the token\n uint64 fee;\n // Whether the associated token is allowed or not\n bool allowed;\n // Whether swapping in and out from the associated token is paused or not\n bool paused;\n }\n\n /// @notice Maps a bridge token to data\n mapping(address => BridgeDetails) public bridges;\n /// @notice List of all bridge tokens\n address[] public bridgeTokensList;\n /// @notice Maps a bridge token to the associated hourly volume\n mapping(address => mapping(uint256 => uint256)) public usage;\n /// @notice Maps an address to whether it is exempt of fees for when it comes to swapping in and out\n mapping(address => uint256) public isFeeExempt;\n /// @notice Limit to the amount of tokens that can be sent from that chain to another chain\n uint256 public chainTotalHourlyLimit;\n /// @notice Usage per hour on that chain. Maps an hourly timestamp to the total volume swapped out on the chain\n mapping(uint256 => uint256) public chainTotalUsage;\n\n uint256[42] private __gap;\n\n // ================================== Events ===================================\n\n event BridgeTokenAdded(address indexed bridgeToken, uint256 limit, uint256 hourlyLimit, uint64 fee, bool paused);\n event BridgeTokenToggled(address indexed bridgeToken, bool toggleStatus);\n event BridgeTokenRemoved(address indexed bridgeToken);\n event BridgeTokenFeeUpdated(address indexed bridgeToken, uint64 fee);\n event BridgeTokenLimitUpdated(address indexed bridgeToken, uint256 limit);\n event BridgeTokenHourlyLimitUpdated(address indexed bridgeToken, uint256 hourlyLimit);\n event HourlyLimitUpdated(uint256 hourlyLimit);\n event FeeToggled(address indexed theAddress, uint256 toggleStatus);\n event KeeperToggled(address indexed keeper, bool toggleStatus);\n event MinterToggled(address indexed minter);\n event Recovered(address indexed token, address indexed to, uint256 amount);\n event TreasuryUpdated(address indexed _treasury);\n\n // ================================== Errors ===================================\n\n error AssetStillControlledInReserves();\n error BurnAmountExceedsAllowance();\n error HourlyLimitExceeded();\n error InvalidSender();\n error InvalidToken();\n error InvalidTreasury();\n error NotGovernor();\n error NotGovernorOrGuardian();\n error NotMinter();\n error NotTreasury();\n error TooBigAmount();\n error TooHighParameterValue();\n error TreasuryAlreadyInitialized();\n error ZeroAddress();\n\n /// @notice Checks to see if it is the `Treasury` calling this contract\n /// @dev There is no Access Control here, because it can be handled cheaply through this modifier\n modifier onlyTreasury() {\n if (msg.sender != treasury) revert NotTreasury();\n _;\n }\n\n /// @notice Checks whether the sender has the minting right\n modifier onlyMinter() {\n if (!isMinter[msg.sender]) revert NotMinter();\n _;\n }\n\n /// @notice Checks whether the `msg.sender` has the governor role or not\n modifier onlyGovernor() {\n if (!ITreasury(treasury).isGovernor(msg.sender)) revert NotGovernor();\n _;\n }\n\n /// @notice Checks whether the `msg.sender` has the governor role or the guardian role\n modifier onlyGovernorOrGuardian() {\n if (!ITreasury(treasury).isGovernorOrGuardian(msg.sender)) revert NotGovernorOrGuardian();\n _;\n }\n\n /// @notice Sets up the treasury contract on Polygon after the upgrade\n /// @param _treasury Address of the treasury contract\n function setUpTreasury(address _treasury) external {\n // Only governor on Polygon\n if (msg.sender != 0xdA2D2f638D6fcbE306236583845e5822554c02EA) revert NotGovernor();\n if (address(ITreasury(_treasury).stablecoin()) != address(this)) revert InvalidTreasury();\n if (treasuryInitialized) revert TreasuryAlreadyInitialized();\n treasury = _treasury;\n treasuryInitialized = true;\n emit TreasuryUpdated(_treasury);\n }\n\n // =========================== External Function ===============================\n\n /// @notice Allows anyone to burn agToken without redeeming collateral back\n /// @param amount Amount of stablecoins to burn\n /// @dev This function can typically be called if there is a settlement mechanism to burn stablecoins\n function burnStablecoin(uint256 amount) external {\n _burnCustom(msg.sender, amount);\n }\n\n // ======================= Minter Role Only Functions ==========================\n\n function burnSelf(uint256 amount, address burner) external onlyMinter {\n _burnCustom(burner, amount);\n }\n\n function burnFrom(\n uint256 amount,\n address burner,\n address sender\n ) external onlyMinter {\n _burnFromNoRedeem(amount, burner, sender);\n }\n\n function mint(address account, uint256 amount) external onlyMinter {\n _mint(account, amount);\n }\n\n // ======================= Treasury Only Functions =============================\n\n function addMinter(address minter) external onlyTreasury {\n isMinter[minter] = true;\n emit MinterToggled(minter);\n }\n\n function removeMinter(address minter) external {\n if (msg.sender != address(treasury) && msg.sender != minter) revert InvalidSender();\n isMinter[minter] = false;\n emit MinterToggled(minter);\n }\n\n function setTreasury(address _treasury) external onlyTreasury {\n treasury = _treasury;\n emit TreasuryUpdated(_treasury);\n }\n\n // ============================ Internal Function ==============================\n\n /// @notice Internal version of the function `burnFromNoRedeem`\n /// @param amount Amount to burn\n /// @dev It is at the level of this function that allowance checks are performed\n function _burnFromNoRedeem(\n uint256 amount,\n address burner,\n address sender\n ) internal {\n if (burner != sender) {\n uint256 currentAllowance = allowance(burner, sender);\n if (currentAllowance < amount) revert BurnAmountExceedsAllowance();\n _approve(burner, sender, currentAllowance - amount);\n }\n _burnCustom(burner, amount);\n }\n\n // ==================== External Permissionless Functions ======================\n\n /// @notice Returns the list of all supported bridge tokens\n /// @dev Helpful for UIs\n function allBridgeTokens() external view returns (address[] memory) {\n return bridgeTokensList;\n }\n\n /// @notice Returns the current volume for a bridge, for the current hour\n /// @dev Helpful for UIs\n function currentUsage(address bridge) external view returns (uint256) {\n return usage[bridge][block.timestamp / 3600];\n }\n\n /// @notice Returns the current total volume on the chain for the current hour\n /// @dev Helpful for UIs\n function currentTotalUsage() external view returns (uint256) {\n return chainTotalUsage[block.timestamp / 3600];\n }\n\n /// @notice Mints the canonical token from a supported bridge token\n /// @param bridgeToken Bridge token to use to mint\n /// @param amount Amount of bridge tokens to send\n /// @param to Address to which the stablecoin should be sent\n /// @dev Some fees may be taken by the protocol depending on the token used and on the address calling\n function swapIn(\n address bridgeToken,\n uint256 amount,\n address to\n ) external returns (uint256) {\n BridgeDetails memory bridgeDetails = bridges[bridgeToken];\n if (!bridgeDetails.allowed || bridgeDetails.paused) revert InvalidToken();\n uint256 balance = IERC20(bridgeToken).balanceOf(address(this));\n if (balance + amount > bridgeDetails.limit) {\n // In case someone maliciously sends tokens to this contract\n // Or the limit changes\n if (bridgeDetails.limit > balance) amount = bridgeDetails.limit - balance;\n else {\n amount = 0;\n }\n }\n\n // Checking requirement on the hourly volume\n uint256 hour = block.timestamp / 3600;\n uint256 hourlyUsage = usage[bridgeToken][hour] + amount;\n if (hourlyUsage > bridgeDetails.hourlyLimit) {\n // Edge case when the hourly limit changes\n if (bridgeDetails.hourlyLimit > usage[bridgeToken][hour])\n amount = bridgeDetails.hourlyLimit - usage[bridgeToken][hour];\n else {\n amount = 0;\n }\n }\n usage[bridgeToken][hour] += amount;\n\n IERC20(bridgeToken).safeTransferFrom(msg.sender, address(this), amount);\n uint256 canonicalOut = amount;\n // Computing fees\n if (isFeeExempt[msg.sender] == 0) {\n canonicalOut -= (canonicalOut * bridgeDetails.fee) / BASE_PARAMS;\n }\n _mint(to, canonicalOut);\n return canonicalOut;\n }\n\n /// @notice Burns the canonical token in exchange for a bridge token\n /// @param bridgeToken Bridge token required\n /// @param amount Amount of canonical tokens to burn\n /// @param to Address to which the bridge token should be sent\n /// @dev Some fees may be taken by the protocol depending on the token used and on the address calling\n function swapOut(\n address bridgeToken,\n uint256 amount,\n address to\n ) external returns (uint256) {\n BridgeDetails memory bridgeDetails = bridges[bridgeToken];\n if (!bridgeDetails.allowed || bridgeDetails.paused) revert InvalidToken();\n\n uint256 hour = block.timestamp / 3600;\n uint256 hourlyUsage = chainTotalUsage[hour] + amount;\n // If the amount being swapped out exceeds the limit, we revert\n // We don't want to change the amount being swapped out.\n // The user can decide to send another tx with the correct amount to reach the limit\n if (hourlyUsage > chainTotalHourlyLimit) revert HourlyLimitExceeded();\n chainTotalUsage[hour] = hourlyUsage;\n\n _burnCustom(msg.sender, amount);\n uint256 bridgeOut = amount;\n if (isFeeExempt[msg.sender] == 0) {\n bridgeOut -= (bridgeOut * bridgeDetails.fee) / BASE_PARAMS;\n }\n IERC20(bridgeToken).safeTransfer(to, bridgeOut);\n return bridgeOut;\n }\n\n // ======================= Governance Functions ================================\n\n /// @notice Adds support for a bridge token\n /// @param bridgeToken Bridge token to add: it should be a version of the stablecoin from another bridge\n /// @param limit Limit on the balance of bridge token this contract could hold\n /// @param hourlyLimit Limit on the hourly volume for this bridge\n /// @param paused Whether swapping for this token should be paused or not\n /// @param fee Fee taken upon swapping for or against this token\n function addBridgeToken(\n address bridgeToken,\n uint256 limit,\n uint256 hourlyLimit,\n uint64 fee,\n bool paused\n ) external onlyGovernor {\n if (bridges[bridgeToken].allowed || bridgeToken == address(0)) revert InvalidToken();\n if (fee > BASE_PARAMS) revert TooHighParameterValue();\n BridgeDetails memory _bridge;\n _bridge.limit = limit;\n _bridge.hourlyLimit = hourlyLimit;\n _bridge.paused = paused;\n _bridge.fee = fee;\n _bridge.allowed = true;\n bridges[bridgeToken] = _bridge;\n bridgeTokensList.push(bridgeToken);\n emit BridgeTokenAdded(bridgeToken, limit, hourlyLimit, fee, paused);\n }\n\n /// @notice Removes support for a token\n /// @param bridgeToken Address of the bridge token to remove support for\n function removeBridgeToken(address bridgeToken) external onlyGovernor {\n if (IERC20(bridgeToken).balanceOf(address(this)) != 0) revert AssetStillControlledInReserves();\n delete bridges[bridgeToken];\n // Deletion from `bridgeTokensList` loop\n uint256 bridgeTokensListLength = bridgeTokensList.length;\n for (uint256 i; i < bridgeTokensListLength - 1; ++i) {\n if (bridgeTokensList[i] == bridgeToken) {\n // Replace the `bridgeToken` to remove with the last of the list\n bridgeTokensList[i] = bridgeTokensList[bridgeTokensListLength - 1];\n break;\n }\n }\n // Remove last element in array\n bridgeTokensList.pop();\n emit BridgeTokenRemoved(bridgeToken);\n }\n\n /// @notice Recovers any ERC20 token\n /// @dev Can be used to withdraw bridge tokens for them to be de-bridged on mainnet\n function recoverERC20(\n address tokenAddress,\n address to,\n uint256 amountToRecover\n ) external onlyGovernor {\n IERC20(tokenAddress).safeTransfer(to, amountToRecover);\n emit Recovered(tokenAddress, to, amountToRecover);\n }\n\n /// @notice Updates the `limit` amount for `bridgeToken`\n function setLimit(address bridgeToken, uint256 limit) external onlyGovernorOrGuardian {\n if (!bridges[bridgeToken].allowed) revert InvalidToken();\n bridges[bridgeToken].limit = limit;\n emit BridgeTokenLimitUpdated(bridgeToken, limit);\n }\n\n /// @notice Updates the `hourlyLimit` amount for `bridgeToken`\n function setHourlyLimit(address bridgeToken, uint256 hourlyLimit) external onlyGovernorOrGuardian {\n if (!bridges[bridgeToken].allowed) revert InvalidToken();\n bridges[bridgeToken].hourlyLimit = hourlyLimit;\n emit BridgeTokenHourlyLimitUpdated(bridgeToken, hourlyLimit);\n }\n\n /// @notice Updates the `chainTotalHourlyLimit` amount\n function setChainTotalHourlyLimit(uint256 hourlyLimit) external onlyGovernorOrGuardian {\n chainTotalHourlyLimit = hourlyLimit;\n emit HourlyLimitUpdated(hourlyLimit);\n }\n\n /// @notice Updates the `fee` value for `bridgeToken`\n function setSwapFee(address bridgeToken, uint64 fee) external onlyGovernorOrGuardian {\n if (!bridges[bridgeToken].allowed) revert InvalidToken();\n if (fee > BASE_PARAMS) revert TooHighParameterValue();\n bridges[bridgeToken].fee = fee;\n emit BridgeTokenFeeUpdated(bridgeToken, fee);\n }\n\n /// @notice Pauses or unpauses swapping in and out for a token\n function toggleBridge(address bridgeToken) external onlyGovernorOrGuardian {\n if (!bridges[bridgeToken].allowed) revert InvalidToken();\n bool pausedStatus = bridges[bridgeToken].paused;\n bridges[bridgeToken].paused = !pausedStatus;\n emit BridgeTokenToggled(bridgeToken, !pausedStatus);\n }\n\n /// @notice Toggles fees for the address `theAddress`\n function toggleFeesForAddress(address theAddress) external onlyGovernorOrGuardian {\n uint256 feeExemptStatus = 1 - isFeeExempt[theAddress];\n isFeeExempt[theAddress] = feeExemptStatus;\n emit FeeToggled(theAddress, feeExemptStatus);\n }\n}\n" + }, + "contracts/treasury/TreasuryImmutable.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.17;\n\nimport \"./Treasury.sol\";\n\n/// @title Treasury\n/// @author Angle Labs, Inc.\n/// @notice Immutable Treasury of Angle Borrowing Module\ncontract TreasuryImmutable is Treasury {\n // =============================== References ==================================\n bytes32 private constant _VAULT_MANAGER_IMPL =\n hex\"fb142eb126393574530347669f9b8d8a8f6a7c6a07d17deccf3b03fe6084e96f\";\n\n // ======================= Parameters and Variables ============================\n uint8 private _isSetStablecoin;\n\n // =============================== Errors ======================================\n\n error AlreadySetStablecoin();\n error InvalidVaultManager();\n error InvalidStablecoin();\n\n /// @param _core Address of the `CoreBorrow` contract of the module\n constructor(ICoreBorrow _core) initializer {\n if (address(_core) == address(0)) revert ZeroAddress();\n core = _core;\n }\n\n /// @notice Can only be called once after by governance to link the `agToken` to the `treasury`\n /// @param _stablecoin Address of the stablecoin\n function setStablecoin(IAgToken _stablecoin) public onlyGovernor {\n if (_isSetStablecoin == type(uint8).max || IAgToken(_stablecoin).treasury() != address(this))\n revert InvalidStablecoin();\n _isSetStablecoin = type(uint8).max;\n stablecoin = _stablecoin;\n }\n\n /// @inheritdoc Treasury\n function addVaultManager(address vaultManager) external override onlyGovernor {\n if (keccak256(vaultManager.code) != _vaultManagerImpl()) revert InvalidVaultManager();\n _addVaultManager(vaultManager);\n }\n\n /// @notice Get the vault manger implementation bytecode hash\n function _vaultManagerImpl() internal view virtual returns (bytes32) {\n return _VAULT_MANAGER_IMPL;\n }\n\n /// @inheritdoc Treasury\n function initialize(ICoreBorrow _core, IAgToken _stablecoin) public override {}\n\n /// @inheritdoc Treasury\n function addMinter(address minter) external override {}\n\n /// @inheritdoc Treasury\n function removeMinter(address minter) external override {}\n\n /// @inheritdoc Treasury\n function setTreasury(address _treasury) external override {}\n}\n" + }, + "contracts/mock/MockTreasuryImmutable.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.17;\n\nimport \"../treasury/TreasuryImmutable.sol\";\n\n/// @title Treasury\n/// @author Angle Labs, Inc.\n/// @notice Mock Immutable Treasury of Angle Borrowing Module\ncontract MockTreasuryImmutable is TreasuryImmutable {\n bytes32 private _MOCK_VAULT_MANAGER_IMPLEMENTATION;\n\n /// @param _core Address of the `CoreBorrow` contract of the module\n constructor(ICoreBorrow _core) TreasuryImmutable(_core) {}\n\n /// @notice Get the vault manger implementation bytecode hash\n function _vaultManagerImpl() internal view override returns (bytes32) {\n return _MOCK_VAULT_MANAGER_IMPLEMENTATION;\n }\n\n /// @notice Get the vault manger implementation bytecode hash\n function setVaultManagerImpl(bytes32 _newImplemetation) external {\n _MOCK_VAULT_MANAGER_IMPLEMENTATION = _newImplemetation;\n }\n}\n" + }, + "contracts/agToken/BaseAgTokenSideChain.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\n/*\n * █ \n ***** ▓▓▓ \n * ▓▓▓▓▓▓▓ \n * ///. ▓▓▓▓▓▓▓▓▓▓▓▓▓ \n ***** //////// ▓▓▓▓▓▓▓ \n * ///////////// ▓▓▓ \n ▓▓ ////////////////// █ ▓▓ \n ▓▓ ▓▓ /////////////////////// ▓▓ ▓▓ \n ▓▓ ▓▓ //////////////////////////// ▓▓ ▓▓ \n ▓▓ ▓▓ /////////▓▓▓///////▓▓▓///////// ▓▓ ▓▓ \n ▓▓ ,////////////////////////////////////// ▓▓ ▓▓ \n ▓▓ ////////////////////////////////////////// ▓▓ \n ▓▓ //////////////////////▓▓▓▓///////////////////// \n ,//////////////////////////////////////////////////// \n .////////////////////////////////////////////////////////// \n .//////////////////////////██.,//////////////////////////█ \n .//////////////////////████..,./////////////////////██ \n ...////////////////███████.....,.////////////////███ \n ,.,////////////████████ ........,///////////████ \n .,.,//////█████████ ,.......///////████ \n ,..//████████ ........./████ \n ..,██████ .....,███ \n .██ ,.,█ \n \n \n \n ▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓ \n ▓▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓ ▓▓▓▓ \n ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓▓▓▓ \n ▓▓▓ ▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ \n*/\n\nimport \"../interfaces/IAgToken.sol\";\nimport \"../interfaces/ITreasury.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol\";\n\n/// @title BaseAgTokenSideChain\n/// @author Angle Labs, Inc.\n/// @notice Base contract for Angle agTokens on Ethereum and on other chains\n/// @dev By default, agTokens are ERC-20 tokens with 18 decimals\ncontract BaseAgTokenSideChain is IAgToken, ERC20PermitUpgradeable {\n // =========================== PARAMETERS / VARIABLES ==========================\n\n /// @inheritdoc IAgToken\n mapping(address => bool) public isMinter;\n /// @notice Reference to the treasury contract which can grant minting rights\n address public treasury;\n\n // =================================== EVENTS ==================================\n\n event TreasuryUpdated(address indexed _treasury);\n event MinterToggled(address indexed minter);\n\n // =================================== ERRORS ==================================\n\n error BurnAmountExceedsAllowance();\n error InvalidSender();\n error InvalidTreasury();\n error NotMinter();\n error NotTreasury();\n\n // ================================ CONSTRUCTOR ================================\n\n /// @notice Wraps `_initializeBase` for `BaseAgTokenSideChain` and makes a safety check\n /// on `_treasury`\n function _initialize(string memory name_, string memory symbol_, address _treasury) internal virtual initializer {\n if (address(ITreasury(_treasury).stablecoin()) != address(this)) revert InvalidTreasury();\n _initializeBase(name_, symbol_, _treasury);\n }\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() initializer {}\n\n /// @notice Initializes the contract\n /// @param name_ Name of the token\n /// @param symbol_ Symbol of the token\n /// @param _treasury Reference to the `Treasury` contract associated to this agToken implementation\n function _initializeBase(string memory name_, string memory symbol_, address _treasury) internal virtual {\n __ERC20Permit_init(name_);\n __ERC20_init(name_, symbol_);\n treasury = _treasury;\n emit TreasuryUpdated(address(_treasury));\n }\n\n // ================================= MODIFIERS =================================\n\n /// @notice Checks to see if it is the `Treasury` calling this contract\n /// @dev There is no Access Control here, because it can be handled cheaply through this modifier\n modifier onlyTreasury() {\n if (msg.sender != address(treasury)) revert NotTreasury();\n _;\n }\n\n /// @notice Checks whether the sender has the minting right\n modifier onlyMinter() {\n if (!isMinter[msg.sender]) revert NotMinter();\n _;\n }\n\n // ============================= EXTERNAL FUNCTION =============================\n\n /// @notice Allows anyone to burn agToken without redeeming collateral back\n /// @param amount Amount of stablecoins to burn\n /// @dev This function can typically be called if there is a settlement mechanism to burn stablecoins\n function burnStablecoin(uint256 amount) external {\n _burn(msg.sender, amount);\n }\n\n // ========================= MINTER ROLE ONLY FUNCTIONS ========================\n\n /// @inheritdoc IAgToken\n function burnSelf(uint256 amount, address burner) external onlyMinter {\n _burn(burner, amount);\n }\n\n /// @inheritdoc IAgToken\n function burnFrom(uint256 amount, address burner, address sender) external onlyMinter {\n _burnFromNoRedeem(amount, burner, sender);\n }\n\n /// @inheritdoc IAgToken\n function mint(address account, uint256 amount) external onlyMinter {\n _mint(account, amount);\n }\n\n // ========================== TREASURY ONLY FUNCTIONS ==========================\n\n /// @inheritdoc IAgToken\n function addMinter(address minter) external onlyTreasury {\n isMinter[minter] = true;\n emit MinterToggled(minter);\n }\n\n /// @inheritdoc IAgToken\n function removeMinter(address minter) external {\n if (msg.sender != address(treasury) && msg.sender != minter) revert InvalidSender();\n isMinter[minter] = false;\n emit MinterToggled(minter);\n }\n\n /// @inheritdoc IAgToken\n function setTreasury(address _treasury) external virtual onlyTreasury {\n treasury = _treasury;\n emit TreasuryUpdated(_treasury);\n }\n\n // ============================= INTERNAL FUNCTION =============================\n\n /// @notice Internal version of the function `burnFromNoRedeem`\n /// @param amount Amount to burn\n /// @dev It is at the level of this function that allowance checks are performed\n function _burnFromNoRedeem(uint256 amount, address burner, address sender) internal {\n if (burner != sender) {\n uint256 currentAllowance = allowance(burner, sender);\n if (currentAllowance < amount) revert BurnAmountExceedsAllowance();\n _approve(burner, sender, currentAllowance - amount);\n }\n _burn(burner, amount);\n }\n}\n" + }, + "contracts/mock/MockSidechainAgEUR.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"../agToken/BaseAgTokenSideChain.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/// @title AgTokenSideChainMultiBridge\n/// @author Angle Labs, Inc.\n/// @notice Contract for Angle agTokens on other chains than Ethereum mainnet\n/// @dev This contract supports bridge tokens having a minting right on the stablecoin (also referred to as the canonical\n/// or the native token)\n/// @dev References:\n/// - FRAX implementation: https://polygonscan.com/address/0x45c32fA6DF82ead1e2EF74d17b76547EDdFaFF89#code\n/// - QiDAO implementation: https://snowtrace.io/address/0x5c49b268c9841AFF1Cc3B0a418ff5c3442eE3F3b#code\ncontract MockSidechainAgEUR is BaseAgTokenSideChain {\n using SafeERC20 for IERC20;\n\n /// @notice Base used for fee computation\n uint256 public constant BASE_PARAMS = 10**9;\n\n // =============================== Bridging Data ===============================\n\n /// @notice Struct with some data about a specific bridge token\n struct BridgeDetails {\n // Limit on the balance of bridge token held by the contract: it is designed\n // to reduce the exposure of the system to hacks\n uint256 limit;\n // Limit on the hourly volume of token minted through this bridge\n // Technically the limit over a rolling hour is hourlyLimit x2 as hourly limit\n // is enforced only between x:00 and x+1:00\n uint256 hourlyLimit;\n // Fee taken for swapping in and out the token\n uint64 fee;\n // Whether the associated token is allowed or not\n bool allowed;\n // Whether swapping in and out from the associated token is paused or not\n bool paused;\n }\n\n /// @notice Maps a bridge token to data\n mapping(address => BridgeDetails) public bridges;\n /// @notice List of all bridge tokens\n address[] public bridgeTokensList;\n /// @notice Maps a bridge token to the associated hourly volume\n mapping(address => mapping(uint256 => uint256)) public usage;\n /// @notice Maps an address to whether it is exempt of fees for when it comes to swapping in and out\n mapping(address => uint256) public isFeeExempt;\n\n // ================================== Events ===================================\n\n event BridgeTokenAdded(address indexed bridgeToken, uint256 limit, uint256 hourlyLimit, uint64 fee, bool paused);\n event BridgeTokenToggled(address indexed bridgeToken, bool toggleStatus);\n event BridgeTokenRemoved(address indexed bridgeToken);\n event BridgeTokenFeeUpdated(address indexed bridgeToken, uint64 fee);\n event BridgeTokenLimitUpdated(address indexed bridgeToken, uint256 limit);\n event BridgeTokenHourlyLimitUpdated(address indexed bridgeToken, uint256 hourlyLimit);\n event HourlyLimitUpdated(uint256 hourlyLimit);\n event Recovered(address indexed token, address indexed to, uint256 amount);\n event FeeToggled(address indexed theAddress, uint256 toggleStatus);\n\n // =============================== Errors ================================\n\n error AssetStillControlledInReserves();\n error HourlyLimitExceeded();\n error InvalidToken();\n error NotGovernor();\n error NotGovernorOrGuardian();\n error TooBigAmount();\n error TooHighParameterValue();\n error ZeroAddress();\n\n // ============================= Constructor ===================================\n\n /// @notice Initializes the `AgToken` contract\n /// @param name_ Name of the token\n /// @param symbol_ Symbol of the token\n /// @param _treasury Reference to the `Treasury` contract associated to this agToken\n /// @dev By default, agTokens are ERC-20 tokens with 18 decimals\n function initialize(\n string memory name_,\n string memory symbol_,\n address _treasury\n ) external {\n _initialize(name_, symbol_, _treasury);\n }\n\n // =============================== Modifiers ===================================\n\n /// @notice Checks whether the `msg.sender` has the governor role or not\n modifier onlyGovernor() {\n if (!ITreasury(treasury).isGovernor(msg.sender)) revert NotGovernor();\n _;\n }\n\n /// @notice Checks whether the `msg.sender` has the governor role or the guardian role\n modifier onlyGovernorOrGuardian() {\n if (!ITreasury(treasury).isGovernorOrGuardian(msg.sender)) revert NotGovernorOrGuardian();\n _;\n }\n\n // ==================== External Permissionless Functions ======================\n\n /// @notice Returns the list of all supported bridge tokens\n /// @dev Helpful for UIs\n function allBridgeTokens() external view returns (address[] memory) {\n return bridgeTokensList;\n }\n\n /// @notice Returns the current volume for a bridge, for the current hour\n /// @param bridgeToken Bridge used to mint\n /// @dev Helpful for UIs\n function currentUsage(address bridgeToken) external view returns (uint256) {\n return usage[bridgeToken][block.timestamp / 3600];\n }\n\n /// @notice Mints the canonical token from a supported bridge token\n /// @param bridgeToken Bridge token to use to mint\n /// @param amount Amount of bridge tokens to send\n /// @param to Address to which the stablecoin should be sent\n /// @return Amount of the canonical stablecoin actually minted\n /// @dev Some fees may be taken by the protocol depending on the token used and on the address calling\n function swapIn(\n address bridgeToken,\n uint256 amount,\n address to\n ) external returns (uint256) {\n BridgeDetails memory bridgeDetails = bridges[bridgeToken];\n if (!bridgeDetails.allowed || bridgeDetails.paused) revert InvalidToken();\n uint256 balance = IERC20(bridgeToken).balanceOf(address(this));\n if (balance + amount > bridgeDetails.limit) {\n // In case someone maliciously sends tokens to this contract\n // Or the limit changes\n if (bridgeDetails.limit > balance) amount = bridgeDetails.limit - balance;\n else {\n amount = 0;\n }\n }\n\n // Checking requirement on the hourly volume\n uint256 hour = block.timestamp / 3600;\n uint256 hourlyUsage = usage[bridgeToken][hour] + amount;\n if (hourlyUsage > bridgeDetails.hourlyLimit) {\n // Edge case when the hourly limit changes\n if (bridgeDetails.hourlyLimit > usage[bridgeToken][hour])\n amount = bridgeDetails.hourlyLimit - usage[bridgeToken][hour];\n else {\n amount = 0;\n }\n }\n usage[bridgeToken][hour] = usage[bridgeToken][hour] + amount;\n\n IERC20(bridgeToken).safeTransferFrom(msg.sender, address(this), amount);\n uint256 canonicalOut = amount;\n // Computing fees\n if (isFeeExempt[msg.sender] == 0) {\n canonicalOut -= (canonicalOut * bridgeDetails.fee) / BASE_PARAMS;\n }\n _mint(to, canonicalOut);\n return canonicalOut;\n }\n\n /// @notice Burns the canonical token in exchange for a bridge token\n /// @param bridgeToken Bridge token required\n /// @param amount Amount of canonical tokens to burn\n /// @param to Address to which the bridge token should be sent\n /// @return Amount of bridge tokens actually sent back\n /// @dev Some fees may be taken by the protocol depending on the token used and on the address calling\n function swapOut(\n address bridgeToken,\n uint256 amount,\n address to\n ) external returns (uint256) {\n BridgeDetails memory bridgeDetails = bridges[bridgeToken];\n if (!bridgeDetails.allowed || bridgeDetails.paused) revert InvalidToken();\n\n _burn(msg.sender, amount);\n uint256 bridgeOut = amount;\n if (isFeeExempt[msg.sender] == 0) {\n bridgeOut -= (bridgeOut * bridgeDetails.fee) / BASE_PARAMS;\n }\n IERC20(bridgeToken).safeTransfer(to, bridgeOut);\n return bridgeOut;\n }\n\n // ======================= Governance Functions ================================\n\n /// @notice Adds support for a bridge token\n /// @param bridgeToken Bridge token to add: it should be a version of the stablecoin from another bridge\n /// @param limit Limit on the balance of bridge token this contract could hold\n /// @param hourlyLimit Limit on the hourly volume for this bridge\n /// @param paused Whether swapping for this token should be paused or not\n /// @param fee Fee taken upon swapping for or against this token\n function addBridgeToken(\n address bridgeToken,\n uint256 limit,\n uint256 hourlyLimit,\n uint64 fee,\n bool paused\n ) external onlyGovernor {\n if (bridges[bridgeToken].allowed || bridgeToken == address(0)) revert InvalidToken();\n if (fee > BASE_PARAMS) revert TooHighParameterValue();\n BridgeDetails memory _bridge;\n _bridge.limit = limit;\n _bridge.hourlyLimit = hourlyLimit;\n _bridge.paused = paused;\n _bridge.fee = fee;\n _bridge.allowed = true;\n bridges[bridgeToken] = _bridge;\n bridgeTokensList.push(bridgeToken);\n emit BridgeTokenAdded(bridgeToken, limit, hourlyLimit, fee, paused);\n }\n\n /// @notice Removes support for a token\n /// @param bridgeToken Address of the bridge token to remove support for\n function removeBridgeToken(address bridgeToken) external onlyGovernor {\n if (IERC20(bridgeToken).balanceOf(address(this)) != 0) revert AssetStillControlledInReserves();\n delete bridges[bridgeToken];\n // Deletion from `bridgeTokensList` loop\n uint256 bridgeTokensListLength = bridgeTokensList.length;\n for (uint256 i; i < bridgeTokensListLength - 1; ++i) {\n if (bridgeTokensList[i] == bridgeToken) {\n // Replace the `bridgeToken` to remove with the last of the list\n bridgeTokensList[i] = bridgeTokensList[bridgeTokensListLength - 1];\n break;\n }\n }\n // Remove last element in array\n bridgeTokensList.pop();\n emit BridgeTokenRemoved(bridgeToken);\n }\n\n /// @notice Recovers any ERC20 token\n /// @dev Can be used to withdraw bridge tokens for them to be de-bridged on mainnet\n function recoverERC20(\n address tokenAddress,\n address to,\n uint256 amountToRecover\n ) external onlyGovernor {\n IERC20(tokenAddress).safeTransfer(to, amountToRecover);\n emit Recovered(tokenAddress, to, amountToRecover);\n }\n\n /// @notice Updates the `limit` amount for `bridgeToken`\n function setLimit(address bridgeToken, uint256 limit) external onlyGovernorOrGuardian {\n if (!bridges[bridgeToken].allowed) revert InvalidToken();\n bridges[bridgeToken].limit = limit;\n emit BridgeTokenLimitUpdated(bridgeToken, limit);\n }\n\n /// @notice Updates the `hourlyLimit` amount for `bridgeToken`\n function setHourlyLimit(address bridgeToken, uint256 hourlyLimit) external onlyGovernorOrGuardian {\n if (!bridges[bridgeToken].allowed) revert InvalidToken();\n bridges[bridgeToken].hourlyLimit = hourlyLimit;\n emit BridgeTokenHourlyLimitUpdated(bridgeToken, hourlyLimit);\n }\n\n /// @notice Updates the `fee` value for `bridgeToken`\n function setSwapFee(address bridgeToken, uint64 fee) external onlyGovernorOrGuardian {\n if (!bridges[bridgeToken].allowed) revert InvalidToken();\n if (fee > BASE_PARAMS) revert TooHighParameterValue();\n bridges[bridgeToken].fee = fee;\n emit BridgeTokenFeeUpdated(bridgeToken, fee);\n }\n\n /// @notice Pauses or unpauses swapping in and out for a token\n function toggleBridge(address bridgeToken) external onlyGovernorOrGuardian {\n if (!bridges[bridgeToken].allowed) revert InvalidToken();\n bool pausedStatus = bridges[bridgeToken].paused;\n bridges[bridgeToken].paused = !pausedStatus;\n emit BridgeTokenToggled(bridgeToken, !pausedStatus);\n }\n\n /// @notice Toggles fees for the address `theAddress`\n function toggleFeesForAddress(address theAddress) external onlyGovernorOrGuardian {\n uint256 feeExemptStatus = 1 - isFeeExempt[theAddress];\n isFeeExempt[theAddress] = feeExemptStatus;\n emit FeeToggled(theAddress, feeExemptStatus);\n }\n}\n" + }, + "contracts/agToken/AgTokenSideChainMultiBridge.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"./BaseAgTokenSideChain.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/// @title AgTokenSideChainMultiBridge\n/// @author Angle Labs, Inc.\n/// @notice Contract for Angle agTokens on other chains than Ethereum mainnet\n/// @dev This contract supports bridge tokens having a minting right on the stablecoin (also referred to as the canonical\n/// or the native token)\n/// @dev References:\n/// - FRAX implementation: https://polygonscan.com/address/0x45c32fA6DF82ead1e2EF74d17b76547EDdFaFF89#code\n/// - QiDAO implementation: https://snowtrace.io/address/0x5c49b268c9841AFF1Cc3B0a418ff5c3442eE3F3b#code\ncontract AgTokenSideChainMultiBridge is BaseAgTokenSideChain {\n using SafeERC20 for IERC20;\n\n /// @notice Base used for fee computation\n uint256 public constant BASE_PARAMS = 10**9;\n\n // =============================== Bridging Data ===============================\n\n /// @notice Struct with some data about a specific bridge token\n struct BridgeDetails {\n // Limit on the balance of bridge token held by the contract: it is designed\n // to reduce the exposure of the system to hacks\n uint256 limit;\n // Limit on the hourly volume of token minted through this bridge\n // Technically the limit over a rolling hour is hourlyLimit x2 as hourly limit\n // is enforced only between x:00 and x+1:00\n uint256 hourlyLimit;\n // Fee taken for swapping in and out the token\n uint64 fee;\n // Whether the associated token is allowed or not\n bool allowed;\n // Whether swapping in and out from the associated token is paused or not\n bool paused;\n }\n\n /// @notice Maps a bridge token to data\n mapping(address => BridgeDetails) public bridges;\n /// @notice List of all bridge tokens\n address[] public bridgeTokensList;\n /// @notice Maps a bridge token to the associated hourly volume\n mapping(address => mapping(uint256 => uint256)) public usage;\n /// @notice Maps an address to whether it is exempt of fees for when it comes to swapping in and out\n mapping(address => uint256) public isFeeExempt;\n /// @notice Limit to the amount of tokens that can be sent from that chain to another chain\n uint256 public chainTotalHourlyLimit;\n /// @notice Usage per hour on that chain. Maps an hourly timestamp to the total volume swapped out on the chain\n mapping(uint256 => uint256) public chainTotalUsage;\n\n // ================================== Events ===================================\n\n event BridgeTokenAdded(address indexed bridgeToken, uint256 limit, uint256 hourlyLimit, uint64 fee, bool paused);\n event BridgeTokenToggled(address indexed bridgeToken, bool toggleStatus);\n event BridgeTokenRemoved(address indexed bridgeToken);\n event BridgeTokenFeeUpdated(address indexed bridgeToken, uint64 fee);\n event BridgeTokenLimitUpdated(address indexed bridgeToken, uint256 limit);\n event BridgeTokenHourlyLimitUpdated(address indexed bridgeToken, uint256 hourlyLimit);\n event HourlyLimitUpdated(uint256 hourlyLimit);\n event Recovered(address indexed token, address indexed to, uint256 amount);\n event FeeToggled(address indexed theAddress, uint256 toggleStatus);\n\n // =============================== Errors ================================\n\n error AssetStillControlledInReserves();\n error HourlyLimitExceeded();\n error InvalidToken();\n error NotGovernor();\n error NotGovernorOrGuardian();\n error TooBigAmount();\n error TooHighParameterValue();\n error ZeroAddress();\n\n // ============================= Constructor ===================================\n\n /// @notice Initializes the `AgToken` contract\n /// @param name_ Name of the token\n /// @param symbol_ Symbol of the token\n /// @param _treasury Reference to the `Treasury` contract associated to this agToken\n /// @dev By default, agTokens are ERC-20 tokens with 18 decimals\n function initialize(\n string memory name_,\n string memory symbol_,\n address _treasury\n ) external {\n _initialize(name_, symbol_, _treasury);\n }\n\n // =============================== Modifiers ===================================\n\n /// @notice Checks whether the `msg.sender` has the governor role or not\n modifier onlyGovernor() {\n if (!ITreasury(treasury).isGovernor(msg.sender)) revert NotGovernor();\n _;\n }\n\n /// @notice Checks whether the `msg.sender` has the governor role or the guardian role\n modifier onlyGovernorOrGuardian() {\n if (!ITreasury(treasury).isGovernorOrGuardian(msg.sender)) revert NotGovernorOrGuardian();\n _;\n }\n\n // ==================== External Permissionless Functions ======================\n\n /// @notice Returns the list of all supported bridge tokens\n /// @dev Helpful for UIs\n function allBridgeTokens() external view returns (address[] memory) {\n return bridgeTokensList;\n }\n\n /// @notice Returns the current volume for a bridge, for the current hour\n /// @param bridgeToken Bridge used to mint\n /// @dev Helpful for UIs\n function currentUsage(address bridgeToken) external view returns (uint256) {\n return usage[bridgeToken][block.timestamp / 3600];\n }\n\n /// @notice Returns the current total volume on the chain for the current hour\n /// @dev Helpful for UIs\n function currentTotalUsage() external view returns (uint256) {\n return chainTotalUsage[block.timestamp / 3600];\n }\n\n /// @notice Mints the canonical token from a supported bridge token\n /// @param bridgeToken Bridge token to use to mint\n /// @param amount Amount of bridge tokens to send\n /// @param to Address to which the stablecoin should be sent\n /// @return Amount of the canonical stablecoin actually minted\n /// @dev Some fees may be taken by the protocol depending on the token used and on the address calling\n function swapIn(\n address bridgeToken,\n uint256 amount,\n address to\n ) external returns (uint256) {\n BridgeDetails memory bridgeDetails = bridges[bridgeToken];\n if (!bridgeDetails.allowed || bridgeDetails.paused) revert InvalidToken();\n uint256 balance = IERC20(bridgeToken).balanceOf(address(this));\n if (balance + amount > bridgeDetails.limit) {\n // In case someone maliciously sends tokens to this contract\n // Or the limit changes\n if (bridgeDetails.limit > balance) amount = bridgeDetails.limit - balance;\n else {\n amount = 0;\n }\n }\n\n // Checking requirement on the hourly volume\n uint256 hour = block.timestamp / 3600;\n uint256 hourlyUsage = usage[bridgeToken][hour];\n if (hourlyUsage + amount > bridgeDetails.hourlyLimit) {\n // Edge case when the hourly limit changes\n amount = bridgeDetails.hourlyLimit > hourlyUsage ? bridgeDetails.hourlyLimit - hourlyUsage : 0;\n }\n usage[bridgeToken][hour] = hourlyUsage + amount;\n\n IERC20(bridgeToken).safeTransferFrom(msg.sender, address(this), amount);\n uint256 canonicalOut = amount;\n // Computing fees\n if (isFeeExempt[msg.sender] == 0) {\n canonicalOut -= (canonicalOut * bridgeDetails.fee) / BASE_PARAMS;\n }\n _mint(to, canonicalOut);\n return canonicalOut;\n }\n\n /// @notice Burns the canonical token in exchange for a bridge token\n /// @param bridgeToken Bridge token required\n /// @param amount Amount of canonical tokens to burn\n /// @param to Address to which the bridge token should be sent\n /// @return Amount of bridge tokens actually sent back\n /// @dev Some fees may be taken by the protocol depending on the token used and on the address calling\n function swapOut(\n address bridgeToken,\n uint256 amount,\n address to\n ) external returns (uint256) {\n BridgeDetails memory bridgeDetails = bridges[bridgeToken];\n if (!bridgeDetails.allowed || bridgeDetails.paused) revert InvalidToken();\n\n uint256 hour = block.timestamp / 3600;\n uint256 hourlyUsage = chainTotalUsage[hour] + amount;\n // If the amount being swapped out exceeds the limit, we revert\n // We don't want to change the amount being swapped out.\n // The user can decide to send another tx with the correct amount to reach the limit\n if (hourlyUsage > chainTotalHourlyLimit) revert HourlyLimitExceeded();\n chainTotalUsage[hour] = hourlyUsage;\n\n _burn(msg.sender, amount);\n uint256 bridgeOut = amount;\n if (isFeeExempt[msg.sender] == 0) {\n bridgeOut -= (bridgeOut * bridgeDetails.fee) / BASE_PARAMS;\n }\n IERC20(bridgeToken).safeTransfer(to, bridgeOut);\n return bridgeOut;\n }\n\n // ======================= Governance Functions ================================\n\n /// @notice Adds support for a bridge token\n /// @param bridgeToken Bridge token to add: it should be a version of the stablecoin from another bridge\n /// @param limit Limit on the balance of bridge token this contract could hold\n /// @param hourlyLimit Limit on the hourly volume for this bridge\n /// @param paused Whether swapping for this token should be paused or not\n /// @param fee Fee taken upon swapping for or against this token\n function addBridgeToken(\n address bridgeToken,\n uint256 limit,\n uint256 hourlyLimit,\n uint64 fee,\n bool paused\n ) external onlyGovernor {\n if (bridges[bridgeToken].allowed || bridgeToken == address(0)) revert InvalidToken();\n if (fee > BASE_PARAMS) revert TooHighParameterValue();\n BridgeDetails memory _bridge;\n _bridge.limit = limit;\n _bridge.hourlyLimit = hourlyLimit;\n _bridge.paused = paused;\n _bridge.fee = fee;\n _bridge.allowed = true;\n bridges[bridgeToken] = _bridge;\n bridgeTokensList.push(bridgeToken);\n emit BridgeTokenAdded(bridgeToken, limit, hourlyLimit, fee, paused);\n }\n\n /// @notice Removes support for a token\n /// @param bridgeToken Address of the bridge token to remove support for\n function removeBridgeToken(address bridgeToken) external onlyGovernor {\n if (IERC20(bridgeToken).balanceOf(address(this)) != 0) revert AssetStillControlledInReserves();\n delete bridges[bridgeToken];\n // Deletion from `bridgeTokensList` loop\n uint256 bridgeTokensListLength = bridgeTokensList.length;\n for (uint256 i; i < bridgeTokensListLength - 1; ++i) {\n if (bridgeTokensList[i] == bridgeToken) {\n // Replace the `bridgeToken` to remove with the last of the list\n bridgeTokensList[i] = bridgeTokensList[bridgeTokensListLength - 1];\n break;\n }\n }\n // Remove last element in array\n bridgeTokensList.pop();\n emit BridgeTokenRemoved(bridgeToken);\n }\n\n /// @notice Recovers any ERC20 token\n /// @dev Can be used to withdraw bridge tokens for them to be de-bridged on mainnet\n function recoverERC20(\n address tokenAddress,\n address to,\n uint256 amountToRecover\n ) external onlyGovernor {\n IERC20(tokenAddress).safeTransfer(to, amountToRecover);\n emit Recovered(tokenAddress, to, amountToRecover);\n }\n\n /// @notice Updates the `limit` amount for `bridgeToken`\n function setLimit(address bridgeToken, uint256 limit) external onlyGovernorOrGuardian {\n if (!bridges[bridgeToken].allowed) revert InvalidToken();\n bridges[bridgeToken].limit = limit;\n emit BridgeTokenLimitUpdated(bridgeToken, limit);\n }\n\n /// @notice Updates the `hourlyLimit` amount for `bridgeToken`\n function setHourlyLimit(address bridgeToken, uint256 hourlyLimit) external onlyGovernorOrGuardian {\n if (!bridges[bridgeToken].allowed) revert InvalidToken();\n bridges[bridgeToken].hourlyLimit = hourlyLimit;\n emit BridgeTokenHourlyLimitUpdated(bridgeToken, hourlyLimit);\n }\n\n /// @notice Updates the `chainTotalHourlyLimit` amount\n function setChainTotalHourlyLimit(uint256 hourlyLimit) external onlyGovernorOrGuardian {\n chainTotalHourlyLimit = hourlyLimit;\n emit HourlyLimitUpdated(hourlyLimit);\n }\n\n /// @notice Updates the `fee` value for `bridgeToken`\n function setSwapFee(address bridgeToken, uint64 fee) external onlyGovernorOrGuardian {\n if (!bridges[bridgeToken].allowed) revert InvalidToken();\n if (fee > BASE_PARAMS) revert TooHighParameterValue();\n bridges[bridgeToken].fee = fee;\n emit BridgeTokenFeeUpdated(bridgeToken, fee);\n }\n\n /// @notice Pauses or unpauses swapping in and out for a token\n function toggleBridge(address bridgeToken) external onlyGovernorOrGuardian {\n if (!bridges[bridgeToken].allowed) revert InvalidToken();\n bool pausedStatus = bridges[bridgeToken].paused;\n bridges[bridgeToken].paused = !pausedStatus;\n emit BridgeTokenToggled(bridgeToken, !pausedStatus);\n }\n\n /// @notice Toggles fees for the address `theAddress`\n function toggleFeesForAddress(address theAddress) external onlyGovernorOrGuardian {\n uint256 feeExemptStatus = 1 - isFeeExempt[theAddress];\n isFeeExempt[theAddress] = feeExemptStatus;\n emit FeeToggled(theAddress, feeExemptStatus);\n }\n}\n" + }, + "contracts/agToken/AgTokenSideChain.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"./BaseAgTokenSideChain.sol\";\n\n/// @title AgTokenSideChain\n/// @author Angle Labs, Inc.\n/// @notice Implementation for Angle agTokens to be deployed on chains where there is no need to support\n/// bridging and swapping in and out from other bridge tokens\ncontract AgTokenSideChain is BaseAgTokenSideChain {\n function initialize(\n string memory name_,\n string memory symbol_,\n address _treasury\n ) external {\n _initialize(name_, symbol_, _treasury);\n }\n}\n" + }, + "contracts/agToken/AgTokenSideChainImmutable.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.17;\n\nimport \"./AgTokenSideChain.sol\";\n\n/// @title AgTokenImmutable\n/// @author Angle Labs, Inc.\n/// @notice Contract for immutable Angle's stablecoins\ncontract AgTokenSideChainImmutable is AgTokenSideChain {\n constructor(string memory name_, string memory symbol_, address _treasury) AgTokenSideChain() initializer {\n _initializeBase(name_, symbol_, _treasury);\n }\n\n /// @inheritdoc BaseAgTokenSideChain\n function _initialize(string memory name_, string memory symbol_, address _treasury) internal override {}\n}\n" + }, + "contracts/agToken/AgToken.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"../interfaces/IAgToken.sol\";\nimport \"../interfaces/coreModule/IStableMaster.sol\";\nimport \"../interfaces/ITreasury.sol\";\n// OpenZeppelin may update its version of the ERC20PermitUpgradeable token\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol\";\n\n/// @title AgToken\n/// @author Angle Labs, Inc.\n/// @notice Base contract for agEUR, Angle's Euro stablecoin\n/// @dev This contract is an upgraded version of the first agEUR implementation deployed on Ethereum mainnet\n/// @dev This implementation can be generalized to other Angle stablecoins which support the protocol's Core Module\ncontract AgToken is IAgToken, ERC20PermitUpgradeable {\n // ========================= References to other contracts =====================\n\n /// @notice Reference to the `StableMaster` contract associated to this `AgToken`\n address public stableMaster;\n\n // ============================= Constructor ===================================\n\n /// @notice Initializes the `AgToken` contract\n /// @param name_ Name of the token\n /// @param symbol_ Symbol of the token\n /// @param stableMaster_ Reference to the `StableMaster` contract associated to this agToken\n /// @dev By default, agTokens are ERC-20 tokens with 18 decimals\n function initialize(\n string memory name_,\n string memory symbol_,\n address stableMaster_\n ) external initializer {\n __ERC20Permit_init(name_);\n __ERC20_init(name_, symbol_);\n require(stableMaster_ != address(0), \"0\");\n stableMaster = stableMaster_;\n }\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() initializer {}\n\n // ======= Added Parameters and Variables from the first implementation ========\n\n /// @inheritdoc IAgToken\n mapping(address => bool) public isMinter;\n /// @notice Reference to the treasury contract which can grant minting rights\n address public treasury;\n /// @notice Boolean to check whether the contract has been reinitialized after its upgrade\n bool public treasuryInitialized;\n\n // =============================== Added Events ================================\n\n event TreasuryUpdated(address indexed _treasury);\n event MinterToggled(address indexed minter);\n\n // =============================== Added Errors ================================\n\n error BurnAmountExceedsAllowance();\n error InvalidSender();\n error InvalidTreasury();\n error NotGovernor();\n error NotMinter();\n error NotTreasury();\n error TreasuryAlreadyInitialized();\n\n // =============================== Setup Function ==============================\n\n /// @notice Sets up the treasury contract in this AgToken contract\n /// @param _treasury Treasury contract to add\n /// @dev The address calling this function has to be hard-coded in the contract\n /// @dev Can be called only once\n function setUpTreasury(address _treasury) external {\n // Only governor\n if (msg.sender != 0xdC4e6DFe07EFCa50a197DF15D9200883eF4Eb1c8) revert NotGovernor();\n if (address(ITreasury(_treasury).stablecoin()) != address(this)) revert InvalidTreasury();\n if (treasuryInitialized) revert TreasuryAlreadyInitialized();\n treasury = _treasury;\n treasuryInitialized = true;\n isMinter[stableMaster] = true;\n emit TreasuryUpdated(_treasury);\n }\n\n // =============================== Modifiers ===================================\n\n /// @notice Checks to see if it is the `Treasury` calling this contract\n /// @dev There is no Access Control here, because it can be handled cheaply through this modifier\n modifier onlyTreasury() {\n if (msg.sender != treasury) revert NotTreasury();\n _;\n }\n\n /// @notice Checks whether the sender has the minting right\n modifier onlyMinter() {\n if (!isMinter[msg.sender]) revert NotMinter();\n _;\n }\n\n // ========================= External Functions ================================\n // The following functions allow anyone to burn stablecoins without redeeming collateral\n // in exchange for that\n\n /// @notice Destroys `amount` token from the caller without giving collateral back\n /// @param amount Amount to burn\n /// @param poolManager Reference to the `PoolManager` contract for which the `stocksUsers` will\n /// need to be updated\n /// @dev When calling this function, people should specify the `poolManager` for which they want to decrease\n /// the `stocksUsers`: this is a way for the protocol to maintain healthy accounting variables\n function burnNoRedeem(uint256 amount, address poolManager) external {\n _burn(msg.sender, amount);\n IStableMaster(stableMaster).updateStocksUsers(amount, poolManager);\n }\n\n /// @notice Burns `amount` of agToken on behalf of another account without redeeming collateral back\n /// @param account Account to burn on behalf of\n /// @param amount Amount to burn\n /// @param poolManager Reference to the `PoolManager` contract for which the `stocksUsers` will need to be updated\n function burnFromNoRedeem(\n address account,\n uint256 amount,\n address poolManager\n ) external {\n _burnFromNoRedeem(amount, account, msg.sender);\n IStableMaster(stableMaster).updateStocksUsers(amount, poolManager);\n }\n\n /// @notice Allows anyone to burn agToken without redeeming collateral back\n /// @param amount Amount of stablecoins to burn\n /// @dev This function can typically be called if there is a settlement mechanism to burn stablecoins\n function burnStablecoin(uint256 amount) external {\n _burn(msg.sender, amount);\n }\n\n // ======================= Minter Role Only Functions ==========================\n\n /// @inheritdoc IAgToken\n function burnSelf(uint256 amount, address burner) external onlyMinter {\n _burn(burner, amount);\n }\n\n /// @inheritdoc IAgToken\n function burnFrom(\n uint256 amount,\n address burner,\n address sender\n ) external onlyMinter {\n _burnFromNoRedeem(amount, burner, sender);\n }\n\n /// @inheritdoc IAgToken\n function mint(address account, uint256 amount) external onlyMinter {\n _mint(account, amount);\n }\n\n // ======================= Treasury Only Functions =============================\n\n /// @inheritdoc IAgToken\n function addMinter(address minter) external onlyTreasury {\n isMinter[minter] = true;\n emit MinterToggled(minter);\n }\n\n /// @inheritdoc IAgToken\n function removeMinter(address minter) external {\n // The `treasury` contract cannot remove the `stableMaster`\n if (msg.sender != minter && (msg.sender != address(treasury) || minter == stableMaster)) revert InvalidSender();\n isMinter[minter] = false;\n emit MinterToggled(minter);\n }\n\n /// @inheritdoc IAgToken\n function setTreasury(address _treasury) external onlyTreasury {\n treasury = _treasury;\n emit TreasuryUpdated(_treasury);\n }\n\n // ============================ Internal Function ==============================\n\n /// @notice Internal version of the function `burnFromNoRedeem`\n /// @param amount Amount to burn\n /// @dev It is at the level of this function that allowance checks are performed\n function _burnFromNoRedeem(\n uint256 amount,\n address burner,\n address sender\n ) internal {\n if (burner != sender) {\n uint256 currentAllowance = allowance(burner, sender);\n if (currentAllowance < amount) revert BurnAmountExceedsAllowance();\n _approve(burner, sender, currentAllowance - amount);\n }\n _burn(burner, amount);\n }\n}\n" + }, + "contracts/mock/MockTokenPermit.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.7;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ncontract MockTokenPermit is ERC20Permit {\n using SafeERC20 for IERC20;\n event Minting(address indexed _to, address indexed _minter, uint256 _amount);\n\n event Burning(address indexed _from, address indexed _burner, uint256 _amount);\n\n uint8 internal _decimal;\n mapping(address => bool) public minters;\n address public treasury;\n uint256 public fees;\n\n bool public reverts;\n\n constructor(\n string memory name_,\n string memory symbol_,\n uint8 decimal_\n ) ERC20Permit(name_) ERC20(name_, symbol_) {\n _decimal = decimal_;\n }\n\n function decimals() public view override returns (uint8) {\n return _decimal;\n }\n\n function mint(address account, uint256 amount) external {\n _mint(account, amount);\n emit Minting(account, msg.sender, amount);\n }\n\n function burn(address account, uint256 amount) public {\n _burn(account, amount);\n emit Burning(account, msg.sender, amount);\n }\n\n function setAllowance(address from, address to) public {\n _approve(from, to, type(uint256).max);\n }\n\n function burnSelf(uint256 amount, address account) public {\n _burn(account, amount);\n emit Burning(account, msg.sender, amount);\n }\n\n function addMinter(address minter) public {\n minters[minter] = true;\n }\n\n function removeMinter(address minter) public {\n minters[minter] = false;\n }\n\n function setTreasury(address _treasury) public {\n treasury = _treasury;\n }\n\n function setFees(uint256 _fees) public {\n fees = _fees;\n }\n\n function recoverERC20(\n IERC20 token,\n address to,\n uint256 amount\n ) external {\n token.safeTransfer(to, amount);\n }\n\n function swapIn(\n address bridgeToken,\n uint256 amount,\n address to\n ) external returns (uint256) {\n require(!reverts);\n\n IERC20(bridgeToken).safeTransferFrom(msg.sender, address(this), amount);\n uint256 canonicalOut = amount;\n canonicalOut -= (canonicalOut * fees) / 10**9;\n _mint(to, canonicalOut);\n return canonicalOut;\n }\n\n function swapOut(\n address bridgeToken,\n uint256 amount,\n address to\n ) external returns (uint256) {\n require(!reverts);\n _burn(msg.sender, amount);\n uint256 bridgeOut = amount;\n bridgeOut -= (bridgeOut * fees) / 10**9;\n IERC20(bridgeToken).safeTransfer(to, bridgeOut);\n return bridgeOut;\n }\n}\n" + }, + "contracts/mock/MockLiquidityGauge.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.12;\n\nimport { ILiquidityGauge } from \"../interfaces/coreModule/ILiquidityGauge.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockLiquidityGauge is ILiquidityGauge, ERC20 {\n using SafeERC20 for IERC20;\n\n IERC20 internal _ANGLE = IERC20(0x31429d1856aD1377A8A0079410B297e1a9e214c2);\n IERC20 internal _token;\n mapping(address => uint256) public rewards;\n\n constructor(\n string memory name_,\n string memory symbol_,\n address token_\n ) ERC20(name_, symbol_) {\n _token = IERC20(token_);\n }\n\n function deposit(\n uint256 _value,\n address _addr,\n // solhint-disable-next-line\n bool\n ) external {\n _token.safeTransferFrom(msg.sender, address(this), _value);\n _mint(_addr, _value);\n }\n\n function withdraw(\n uint256 _value,\n // solhint-disable-next-line\n bool\n ) external {\n _burn(msg.sender, _value);\n _token.safeTransfer(msg.sender, _value);\n }\n\n // solhint-disable-next-line\n function claim_rewards(address _addr, address _receiver) external {\n if (_receiver == address(0)) _receiver = _addr;\n _ANGLE.safeTransfer(_receiver, rewards[_addr]);\n rewards[_addr] = 0;\n }\n\n // solhint-disable-next-line\n function claimable_reward(address _addr, address) external view returns (uint256 amount) {\n return rewards[_addr];\n }\n\n function setReward(address receiver_, uint256 amount) external {\n rewards[receiver_] = amount;\n }\n}\n" + }, + "@openzeppelin/contracts/access/Ownable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" + }, + "contracts/external/ProxyAdmin.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"./TransparentUpgradeableProxy.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n/**\n * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an\n * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.\n * This contract was fully forked from OpenZeppelin `ProxyAdmin`\n */\ncontract ProxyAdmin is Ownable {\n /**\n * @dev Returns the current implementation of `proxy`.\n *\n * Requirements:\n *\n * - This contract must be the admin of `proxy`.\n */\n function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) {\n // We need to manually run the static call since the getter cannot be flagged as view\n // bytes4(keccak256(\"implementation()\")) == 0x5c60da1b\n (bool success, bytes memory returndata) = address(proxy).staticcall(hex\"5c60da1b\");\n require(success);\n return abi.decode(returndata, (address));\n }\n\n /**\n * @dev Returns the current admin of `proxy`.\n *\n * Requirements:\n *\n * - This contract must be the admin of `proxy`.\n */\n function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) {\n // We need to manually run the static call since the getter cannot be flagged as view\n // bytes4(keccak256(\"admin()\")) == 0xf851a440\n (bool success, bytes memory returndata) = address(proxy).staticcall(hex\"f851a440\");\n require(success);\n return abi.decode(returndata, (address));\n }\n\n /**\n * @dev Changes the admin of `proxy` to `newAdmin`.\n *\n * Requirements:\n *\n * - This contract must be the current admin of `proxy`.\n */\n function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {\n proxy.changeAdmin(newAdmin);\n }\n\n /**\n * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.\n *\n * Requirements:\n *\n * - This contract must be the admin of `proxy`.\n */\n function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {\n proxy.upgradeTo(implementation);\n }\n\n /**\n * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See\n * {TransparentUpgradeableProxy-upgradeToAndCall}.\n *\n * Requirements:\n *\n * - This contract must be the admin of `proxy`.\n */\n function upgradeAndCall(\n TransparentUpgradeableProxy proxy,\n address implementation,\n bytes memory data\n ) public payable virtual onlyOwner {\n proxy.upgradeToAndCall{ value: msg.value }(implementation, data);\n }\n}\n" + }, + "contracts/external/TransparentUpgradeableProxy.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol\";\n\n/**\n * @dev This contract implements a proxy that is upgradeable by an admin. It is fully forked from OpenZeppelin\n * `TransparentUpgradeableProxy`\n *\n * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector\n * clashing], which can potentially be used in an attack, this contract uses the\n * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two\n * things that go hand in hand:\n *\n * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if\n * that call matches one of the admin functions exposed by the proxy itself.\n * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the\n * implementation. If the admin tries to call a function on the implementation it will fail with an error that says\n * \"admin cannot fallback to proxy target\".\n *\n * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing\n * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due\n * to sudden errors when trying to call a function from the proxy implementation.\n *\n * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,\n * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.\n */\ncontract TransparentUpgradeableProxy is ERC1967Proxy {\n /**\n * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and\n * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.\n */\n constructor(\n address _logic,\n address admin_,\n bytes memory _data\n ) payable ERC1967Proxy(_logic, _data) {\n assert(_ADMIN_SLOT == bytes32(uint256(keccak256(\"eip1967.proxy.admin\")) - 1));\n _changeAdmin(admin_);\n }\n\n /**\n * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.\n */\n modifier ifAdmin() {\n if (msg.sender == _getAdmin()) {\n _;\n } else {\n _fallback();\n }\n }\n\n /**\n * @dev Returns the current admin.\n *\n * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.\n *\n * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the\n * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.\n * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`\n */\n function admin() external ifAdmin returns (address admin_) {\n admin_ = _getAdmin();\n }\n\n /**\n * @dev Returns the current implementation.\n *\n * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.\n *\n * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the\n * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.\n * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`\n */\n function implementation() external ifAdmin returns (address implementation_) {\n implementation_ = _implementation();\n }\n\n /**\n * @dev Changes the admin of the proxy.\n *\n * Emits an {AdminChanged} event.\n *\n * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.\n */\n function changeAdmin(address newAdmin) external virtual ifAdmin {\n _changeAdmin(newAdmin);\n }\n\n /**\n * @dev Upgrade the implementation of the proxy.\n *\n * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.\n */\n function upgradeTo(address newImplementation) external ifAdmin {\n _upgradeToAndCall(newImplementation, bytes(\"\"), false);\n }\n\n /**\n * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified\n * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the\n * proxied contract.\n *\n * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.\n */\n function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {\n _upgradeToAndCall(newImplementation, data, true);\n }\n\n /**\n * @dev Returns the current admin.\n */\n function _admin() internal view virtual returns (address) {\n return _getAdmin();\n }\n\n /**\n * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.\n */\n function _beforeFallback() internal virtual override {\n require(msg.sender != _getAdmin(), \"TransparentUpgradeableProxy: admin cannot fallback to proxy target\");\n super._beforeFallback();\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Proxy.sol\";\nimport \"./ERC1967Upgrade.sol\";\n\n/**\n * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an\n * implementation address that can be changed. This address is stored in storage in the location specified by\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the\n * implementation behind the proxy.\n */\ncontract ERC1967Proxy is Proxy, ERC1967Upgrade {\n /**\n * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.\n *\n * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded\n * function call, and allows initializing the storage of the proxy like a Solidity constructor.\n */\n constructor(address _logic, bytes memory _data) payable {\n _upgradeToAndCall(_logic, _data, false);\n }\n\n /**\n * @dev Returns the current implementation address.\n */\n function _implementation() internal view virtual override returns (address impl) {\n return ERC1967Upgrade._getImplementation();\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/Proxy.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM\n * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to\n * be specified by overriding the virtual {_implementation} function.\n *\n * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a\n * different contract through the {_delegate} function.\n *\n * The success and return data of the delegated call will be returned back to the caller of the proxy.\n */\nabstract contract Proxy {\n /**\n * @dev Delegates the current call to `implementation`.\n *\n * This function does not return to its internal call site, it will return directly to the external caller.\n */\n function _delegate(address implementation) internal virtual {\n assembly {\n // Copy msg.data. We take full control of memory in this inline assembly\n // block because it will not return to Solidity code. We overwrite the\n // Solidity scratch pad at memory position 0.\n calldatacopy(0, 0, calldatasize())\n\n // Call the implementation.\n // out and outsize are 0 because we don't know the size yet.\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\n\n // Copy the returned data.\n returndatacopy(0, 0, returndatasize())\n\n switch result\n // delegatecall returns 0 on error.\n case 0 {\n revert(0, returndatasize())\n }\n default {\n return(0, returndatasize())\n }\n }\n }\n\n /**\n * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function\n * and {_fallback} should delegate.\n */\n function _implementation() internal view virtual returns (address);\n\n /**\n * @dev Delegates the current call to the address returned by `_implementation()`.\n *\n * This function does not return to its internal call site, it will return directly to the external caller.\n */\n function _fallback() internal virtual {\n _beforeFallback();\n _delegate(_implementation());\n }\n\n /**\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\n * function in the contract matches the call data.\n */\n fallback() external payable virtual {\n _fallback();\n }\n\n /**\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data\n * is empty.\n */\n receive() external payable virtual {\n _fallback();\n }\n\n /**\n * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`\n * call, or as part of the Solidity `fallback` or `receive` functions.\n *\n * If overridden should call `super._beforeFallback()`.\n */\n function _beforeFallback() internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../beacon/IBeacon.sol\";\nimport \"../../interfaces/draft-IERC1822.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/StorageSlot.sol\";\n\n/**\n * @dev This abstract contract provides getters and event emitting update functions for\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\n *\n * _Available since v4.1._\n *\n * @custom:oz-upgrades-unsafe-allow delegatecall\n */\nabstract contract ERC1967Upgrade {\n // This is the keccak-256 hash of \"eip1967.proxy.rollback\" subtracted by 1\n bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\n\n /**\n * @dev Storage slot with the address of the current implementation.\n * This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n /**\n * @dev Emitted when the implementation is upgraded.\n */\n event Upgraded(address indexed implementation);\n\n /**\n * @dev Returns the current implementation address.\n */\n function _getImplementation() internal view returns (address) {\n return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n }\n\n /**\n * @dev Stores a new address in the EIP1967 implementation slot.\n */\n function _setImplementation(address newImplementation) private {\n require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n }\n\n /**\n * @dev Perform implementation upgrade\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeTo(address newImplementation) internal {\n _setImplementation(newImplementation);\n emit Upgraded(newImplementation);\n }\n\n /**\n * @dev Perform implementation upgrade with additional setup call.\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeToAndCall(\n address newImplementation,\n bytes memory data,\n bool forceCall\n ) internal {\n _upgradeTo(newImplementation);\n if (data.length > 0 || forceCall) {\n Address.functionDelegateCall(newImplementation, data);\n }\n }\n\n /**\n * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeToAndCallUUPS(\n address newImplementation,\n bytes memory data,\n bool forceCall\n ) internal {\n // Upgrades from old implementations will perform a rollback test. This test requires the new\n // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\n // this special case will break upgrade paths from old UUPS implementation to new ones.\n if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {\n _setImplementation(newImplementation);\n } else {\n try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\n require(slot == _IMPLEMENTATION_SLOT, \"ERC1967Upgrade: unsupported proxiableUUID\");\n } catch {\n revert(\"ERC1967Upgrade: new implementation is not UUPS\");\n }\n _upgradeToAndCall(newImplementation, data, forceCall);\n }\n }\n\n /**\n * @dev Storage slot with the admin of the contract.\n * This is the keccak-256 hash of \"eip1967.proxy.admin\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\n\n /**\n * @dev Emitted when the admin account has changed.\n */\n event AdminChanged(address previousAdmin, address newAdmin);\n\n /**\n * @dev Returns the current admin.\n */\n function _getAdmin() internal view returns (address) {\n return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;\n }\n\n /**\n * @dev Stores a new address in the EIP1967 admin slot.\n */\n function _setAdmin(address newAdmin) private {\n require(newAdmin != address(0), \"ERC1967: new admin is the zero address\");\n StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;\n }\n\n /**\n * @dev Changes the admin of the proxy.\n *\n * Emits an {AdminChanged} event.\n */\n function _changeAdmin(address newAdmin) internal {\n emit AdminChanged(_getAdmin(), newAdmin);\n _setAdmin(newAdmin);\n }\n\n /**\n * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\n * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.\n */\n bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\n\n /**\n * @dev Emitted when the beacon is upgraded.\n */\n event BeaconUpgraded(address indexed beacon);\n\n /**\n * @dev Returns the current beacon.\n */\n function _getBeacon() internal view returns (address) {\n return StorageSlot.getAddressSlot(_BEACON_SLOT).value;\n }\n\n /**\n * @dev Stores a new beacon in the EIP1967 beacon slot.\n */\n function _setBeacon(address newBeacon) private {\n require(Address.isContract(newBeacon), \"ERC1967: new beacon is not a contract\");\n require(\n Address.isContract(IBeacon(newBeacon).implementation()),\n \"ERC1967: beacon implementation is not a contract\"\n );\n StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;\n }\n\n /**\n * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does\n * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).\n *\n * Emits a {BeaconUpgraded} event.\n */\n function _upgradeBeaconToAndCall(\n address newBeacon,\n bytes memory data,\n bool forceCall\n ) internal {\n _setBeacon(newBeacon);\n emit BeaconUpgraded(newBeacon);\n if (data.length > 0 || forceCall) {\n Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/beacon/IBeacon.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\n */\ninterface IBeacon {\n /**\n * @dev Must return an address that can be used as a delegate call target.\n *\n * {BeaconProxy} will check that this address is a contract.\n */\n function implementation() external view returns (address);\n}\n" + }, + "@openzeppelin/contracts/interfaces/draft-IERC1822.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\n * proxy whose upgrades are fully controlled by the current implementation.\n */\ninterface IERC1822Proxiable {\n /**\n * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\n * address.\n *\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\n * function revert if invoked through a proxy.\n */\n function proxiableUUID() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts/utils/StorageSlot.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC1967 implementation slot:\n * ```\n * contract ERC1967 {\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n * function _getImplementation() internal view returns (address) {\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n * }\n *\n * function _setImplementation(address newImplementation) internal {\n * require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n * }\n * }\n * ```\n *\n * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._\n */\nlibrary StorageSlot {\n struct AddressSlot {\n address value;\n }\n\n struct BooleanSlot {\n bool value;\n }\n\n struct Bytes32Slot {\n bytes32 value;\n }\n\n struct Uint256Slot {\n uint256 value;\n }\n\n /**\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n */\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\n */\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\n */\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\n */\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n}\n" + }, + "contracts/interfaces/external/IERC4626.sol": { + "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\n/// @notice Minimal IERC4646 tokenized Vault interface.\n/// @author Forked from Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/mixins/ERC4626.sol)\n/// @dev Do not use in production! ERC-4626 is still in the review stage and is subject to change.\ninterface IERC4626 {\n event Deposit(address indexed from, address indexed to, uint256 amount, uint256 shares);\n event Withdraw(address indexed from, address indexed to, uint256 amount, uint256 shares);\n\n /// @notice Transfers a given amount of asset to the reactor and mint shares accordingly\n /// @param amount Given amount of asset\n /// @param to Address to mint shares to\n /// @return shares Amount of shares minted to `to`\n function deposit(uint256 amount, address to) external returns (uint256 shares);\n\n /// @notice Mints a given amount of shares to the reactor and transfer assets accordingly\n /// @param shares Given amount of shares\n /// @param to Address to mint shares to\n /// @return amount Amount of `asset` taken to the `msg.sender` to mint `shares`\n function mint(uint256 shares, address to) external returns (uint256 amount);\n\n /// @notice Transfers a given amount of asset from the reactor and burn shares accordingly\n /// @param amount Given amount of asset\n /// @param to Address to transfer assets to\n /// @param from Address to burn shares from\n /// @return shares Amount of shares burnt in the operation\n function withdraw(\n uint256 amount,\n address to,\n address from\n ) external returns (uint256 shares);\n\n /// @notice Burns a given amount of shares to the reactor and transfer assets accordingly\n /// @param shares Given amount of shares\n /// @param to Address to transfer assets to\n /// @param from Address to burn shares from\n /// @return amount Amount of assets redeemed in the operation\n function redeem(\n uint256 shares,\n address to,\n address from\n ) external returns (uint256 amount);\n\n /// @notice Returns the total assets managed by this reactor\n function totalAssets() external view returns (uint256);\n\n /// @notice Converts an amount of assets to the corresponding amount of reactor shares\n /// @param assets Amount of asset to convert\n /// @return Shares corresponding to the amount of assets obtained\n function convertToShares(uint256 assets) external view returns (uint256);\n\n /// @notice Converts an amount of shares to its current value in asset\n /// @param shares Amount of shares to convert\n /// @return Amount of assets corresponding to the amount of assets given\n function convertToAssets(uint256 shares) external view returns (uint256);\n\n /// @notice Computes how many shares one would get by depositing `assets`\n /// @param assets Amount of asset to convert\n function previewDeposit(uint256 assets) external view returns (uint256);\n\n /// @notice Computes how many assets one would need to mint `shares`\n /// @param shares Amount of shares required\n function previewMint(uint256 shares) external view returns (uint256);\n\n /// @notice Computes how many shares one would need to withdraw assets\n /// @param assets Amount of asset to withdraw\n function previewWithdraw(uint256 assets) external view returns (uint256);\n\n /// @notice Computes how many assets one would get by burning shares\n /// @param shares Amount of shares to burn\n function previewRedeem(uint256 shares) external view returns (uint256);\n\n /// @notice Max deposit allowed for a user\n /// @param user Address of the user to check\n function maxDeposit(address user) external returns (uint256);\n\n /// @notice Max mint allowed for a user\n /// @param user Address of the user to check\n function maxMint(address user) external returns (uint256);\n\n /// @notice Max withdraw allowed for a user\n /// @param user Address of the user to check\n function maxWithdraw(address user) external returns (uint256);\n\n /// @notice Max redeem allowed for a user\n /// @param user Address of the user to check\n function maxRedeem(address user) external returns (uint256);\n}\n" + }, + "contracts/mock/MockSwapperSidechain.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"../swapper/Swapper.sol\";\n\n/// @title MockSwapperSidechain\n/// @author Angle Labs, Inc.\ncontract MockSwapperSidechain is Swapper {\n error NotImplemented();\n\n /// @notice Constructor of the contract\n /// @param _core Core address\n /// @param _uniV3Router UniswapV3 Router address\n /// @param _oneInch 1Inch Router address\n /// @param _angleRouter AngleRouter contract address\n constructor(\n ICoreBorrow _core,\n IUniswapV3Router _uniV3Router,\n address _oneInch,\n IAngleRouterSidechain _angleRouter\n ) Swapper(_core, _uniV3Router, _oneInch, _angleRouter) {}\n\n function _swapLeverage(bytes memory) internal pure override returns (uint256) {\n revert NotImplemented();\n }\n}\n" + }, + "contracts/mock/MockSwapper.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport \"../interfaces/ISwapper.sol\";\n\ncontract MockSwapper is ISwapper {\n bytes32 public constant CALLBACK_SUCCESS = keccak256(\"ERC3156FlashBorrower.onFlashLoan\");\n\n uint256 public counter;\n\n constructor() {}\n\n function swap(\n IERC20,\n IERC20,\n address,\n uint256,\n uint256,\n bytes calldata data\n ) external {\n counter += 1;\n data;\n }\n}\n\ncontract MockSwapperWithSwap is ISwapper {\n using SafeERC20 for IERC20;\n bytes32 public constant CALLBACK_SUCCESS = keccak256(\"ERC3156FlashBorrower.onFlashLoan\");\n\n uint256 public counter;\n\n constructor() {}\n\n function swap(\n IERC20,\n IERC20 outToken,\n address outTokenRecipient,\n uint256 outTokenOwed,\n uint256,\n bytes calldata data\n ) external {\n counter += 1;\n outToken.safeTransfer(outTokenRecipient, outTokenOwed);\n\n data;\n }\n}\n" + }, + "contracts/mock/MockEulerPool.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ncontract MockEulerPool {\n IERC20 public collateral;\n uint256 public poolSize;\n //solhint-disable-next-line\n uint256 public MAX_SANE_AMOUNT;\n\n mapping(address => uint256) public users;\n uint256 public interestRateAccumulator;\n\n constructor(IERC20 collateral_, uint256 poolSize_) {\n collateral = collateral_;\n poolSize = poolSize_;\n interestRateAccumulator = 10**18;\n MAX_SANE_AMOUNT = type(uint112).max;\n }\n\n function setPoolSize(uint256 poolSize_) external {\n uint256 balance = collateral.balanceOf(address(this));\n poolSize = poolSize_;\n if (balance > poolSize_) collateral.transfer(msg.sender, balance - poolSize_);\n if (balance < poolSize_) collateral.transferFrom(msg.sender, address(this), poolSize_ - balance);\n }\n\n function setInterestRateAccumulator(uint256 interestRateAccumulator_) external {\n interestRateAccumulator = interestRateAccumulator_;\n }\n\n //solhint-disable-next-line\n function setMAXSANEAMOUNT(uint256 MAX_SANE_AMOUNT_) external {\n MAX_SANE_AMOUNT = MAX_SANE_AMOUNT_;\n }\n\n function balanceOfUnderlying(address account) external view returns (uint256) {\n return (users[account] * interestRateAccumulator) / 10**18;\n }\n\n function deposit(uint256, uint256 amount) external {\n users[msg.sender] += (amount * 10**18) / interestRateAccumulator;\n poolSize += amount;\n collateral.transferFrom(msg.sender, address(this), amount);\n }\n\n function withdraw(uint256, uint256 amount) external {\n if (amount == type(uint256).max) amount = (users[msg.sender] * interestRateAccumulator) / 10**18;\n\n require(amount <= poolSize, \"4\");\n users[msg.sender] -= (amount * 10**18) / interestRateAccumulator;\n collateral.transfer(msg.sender, amount);\n }\n}\n" + }, + "contracts/mock/Mock1Inch.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\ncontract Mock1Inch {\n using SafeERC20 for IERC20;\n\n function swap(\n address tokenIn,\n uint256 amountIn,\n address to,\n address tokenOut,\n uint256 amountOut\n ) external {\n IERC20(tokenIn).safeTransferFrom(msg.sender, to, amountIn);\n if (tokenOut == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {\n //solhint-disable-next-line\n (bool sent, bytes memory data) = msg.sender.call{ value: amountOut }(\"\");\n data;\n require(sent, \"Failed to send Ether\");\n } else {\n IERC20(tokenOut).safeTransferFrom(to, msg.sender, amountOut);\n }\n }\n\n receive() external payable {}\n}\n" + }, + "contracts/interfaces/external/IWETH9.sol": { + "content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/// @title Interface for WETH9\ninterface IWETH9 is IERC20 {\n /// @notice Deposit ether to get wrapped ether\n function deposit() external payable;\n\n /// @notice Withdraw wrapped ether to get ether\n function withdraw(uint256) external;\n}\n" + }, + "contracts/deprecated/vaultManager/OldVaultManagerERC721.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"./OldVaultManagerStorage.sol\";\n\n/// @title VaultManagerERC721\n/// @author Angle Labs, Inc.\n/// @dev Base ERC721 Implementation of VaultManager\nabstract contract OldVaultManagerERC721 is IERC721MetadataUpgradeable, OldVaultManagerStorage {\n using SafeERC20 for IERC20;\n using Address for address;\n\n /// @inheritdoc IERC721MetadataUpgradeable\n string public name;\n /// @inheritdoc IERC721MetadataUpgradeable\n string public symbol;\n\n // ================================= MODIFIERS =================================\n\n /// @notice Checks if the person interacting with the vault with `vaultID` is approved\n /// @param caller Address of the person seeking to interact with the vault\n /// @param vaultID ID of the concerned vault\n modifier onlyApprovedOrOwner(address caller, uint256 vaultID) {\n if (!_isApprovedOrOwner(caller, vaultID)) revert NotApproved();\n _;\n }\n\n // ================================ ERC721 LOGIC ===============================\n\n /// @notice Checks whether a given address is approved for a vault or owns this vault\n /// @param spender Address for which vault ownership should be checked\n /// @param vaultID ID of the vault to check\n /// @return Whether the `spender` address owns or is approved for `vaultID`\n function isApprovedOrOwner(address spender, uint256 vaultID) external view returns (bool) {\n return _isApprovedOrOwner(spender, vaultID);\n }\n\n /// @inheritdoc IERC721MetadataUpgradeable\n function tokenURI(uint256 vaultID) external view returns (string memory) {\n if (!_exists(vaultID)) revert NonexistentVault();\n // There is no vault with `vaultID` equal to 0, so the following variable is\n // always greater than zero\n uint256 temp = vaultID;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (vaultID != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(vaultID % 10)));\n vaultID /= 10;\n }\n return bytes(_baseURI).length > 0 ? string(abi.encodePacked(_baseURI, string(buffer))) : \"\";\n }\n\n /// @inheritdoc IERC721Upgradeable\n function balanceOf(address owner) external view returns (uint256) {\n if (owner == address(0)) revert ZeroAddress();\n return _balances[owner];\n }\n\n /// @inheritdoc IERC721Upgradeable\n function ownerOf(uint256 vaultID) external view returns (address) {\n return _ownerOf(vaultID);\n }\n\n /// @inheritdoc IERC721Upgradeable\n function approve(address to, uint256 vaultID) external {\n address owner = _ownerOf(vaultID);\n if (to == owner) revert ApprovalToOwner();\n if (msg.sender != owner && !isApprovedForAll(owner, msg.sender)) revert NotApproved();\n\n _approve(to, vaultID);\n }\n\n /// @inheritdoc IERC721Upgradeable\n function getApproved(uint256 vaultID) external view returns (address) {\n if (!_exists(vaultID)) revert NonexistentVault();\n return _getApproved(vaultID);\n }\n\n /// @inheritdoc IERC721Upgradeable\n function setApprovalForAll(address operator, bool approved) external {\n _setApprovalForAll(msg.sender, operator, approved);\n }\n\n /// @inheritdoc IERC721Upgradeable\n function isApprovedForAll(address owner, address operator) public view returns (bool) {\n return _operatorApprovals[owner][operator] == 1;\n }\n\n /// @inheritdoc IERC721Upgradeable\n function transferFrom(\n address from,\n address to,\n uint256 vaultID\n ) external onlyApprovedOrOwner(msg.sender, vaultID) {\n _transfer(from, to, vaultID);\n }\n\n /// @inheritdoc IERC721Upgradeable\n function safeTransferFrom(\n address from,\n address to,\n uint256 vaultID\n ) external {\n safeTransferFrom(from, to, vaultID, \"\");\n }\n\n /// @inheritdoc IERC721Upgradeable\n function safeTransferFrom(\n address from,\n address to,\n uint256 vaultID,\n bytes memory _data\n ) public onlyApprovedOrOwner(msg.sender, vaultID) {\n _safeTransfer(from, to, vaultID, _data);\n }\n\n // ================================ ERC165 LOGIC ===============================\n\n /// @inheritdoc IERC165Upgradeable\n function supportsInterface(bytes4 interfaceId) external pure returns (bool) {\n return\n interfaceId == type(IERC721MetadataUpgradeable).interfaceId ||\n interfaceId == type(IERC721Upgradeable).interfaceId ||\n interfaceId == type(IVaultManager).interfaceId ||\n interfaceId == type(IERC165Upgradeable).interfaceId;\n }\n\n // ================== INTERNAL FUNCTIONS FOR THE ERC721 LOGIC ==================\n\n /// @notice Internal version of the `ownerOf` function\n function _ownerOf(uint256 vaultID) internal view returns (address owner) {\n owner = _owners[vaultID];\n if (owner == address(0)) revert NonexistentVault();\n }\n\n /// @notice Internal version of the `getApproved` function\n function _getApproved(uint256 vaultID) internal view returns (address) {\n return _vaultApprovals[vaultID];\n }\n\n /// @notice Internal version of the `safeTransferFrom` function (with the data parameter)\n function _safeTransfer(\n address from,\n address to,\n uint256 vaultID,\n bytes memory _data\n ) internal {\n _transfer(from, to, vaultID);\n if (!_checkOnERC721Received(from, to, vaultID, _data)) revert NonERC721Receiver();\n }\n\n /// @notice Checks whether a vault exists\n /// @param vaultID ID of the vault to check\n /// @return Whether `vaultID` has been created\n function _exists(uint256 vaultID) internal view returns (bool) {\n return _owners[vaultID] != address(0);\n }\n\n /// @notice Internal version of the `isApprovedOrOwner` function\n function _isApprovedOrOwner(address spender, uint256 vaultID) internal view returns (bool) {\n // The following checks if the vault exists\n address owner = _ownerOf(vaultID);\n return (spender == owner || _getApproved(vaultID) == spender || _operatorApprovals[owner][spender] == 1);\n }\n\n /// @notice Internal version of the `createVault` function\n /// Mints `vaultID` and transfers it to `to`\n /// @dev This method is equivalent to the `_safeMint` method used in OpenZeppelin ERC721 contract\n /// @dev Emits a {Transfer} event\n function _mint(address to) internal returns (uint256 vaultID) {\n if (whitelistingActivated && (isWhitelisted[to] != 1 || isWhitelisted[msg.sender] != 1))\n revert NotWhitelisted();\n if (to == address(0)) revert ZeroAddress();\n\n unchecked {\n vaultIDCount += 1;\n }\n\n vaultID = vaultIDCount;\n _beforeTokenTransfer(address(0), to, vaultID);\n\n unchecked {\n _balances[to] += 1;\n }\n\n _owners[vaultID] = to;\n emit Transfer(address(0), to, vaultID);\n if (!_checkOnERC721Received(address(0), to, vaultID, \"\")) revert NonERC721Receiver();\n }\n\n /// @notice Destroys `vaultID`\n /// @dev `vaultID` must exist\n /// @dev Emits a {Transfer} event\n function _burn(uint256 vaultID) internal {\n address owner = _ownerOf(vaultID);\n\n _beforeTokenTransfer(owner, address(0), vaultID);\n // Clear approvals\n _approve(address(0), vaultID);\n // The following line cannot underflow as the owner's balance is necessarily\n // greater than 1\n unchecked {\n _balances[owner] -= 1;\n }\n delete _owners[vaultID];\n delete vaultData[vaultID];\n\n emit Transfer(owner, address(0), vaultID);\n }\n\n /// @notice Transfers `vaultID` from `from` to `to` as opposed to {transferFrom},\n /// this imposes no restrictions on msg.sender\n /// @dev `to` cannot be the zero address and `perpetualID` must be owned by `from`\n /// @dev Emits a {Transfer} event\n /// @dev A whitelist check is performed if necessary on the `to` address\n function _transfer(\n address from,\n address to,\n uint256 vaultID\n ) internal {\n if (_ownerOf(vaultID) != from) revert NotApproved();\n if (to == address(0)) revert ZeroAddress();\n if (whitelistingActivated && isWhitelisted[to] != 1) revert NotWhitelisted();\n\n _beforeTokenTransfer(from, to, vaultID);\n\n // Clear approvals from the previous owner\n _approve(address(0), vaultID);\n unchecked {\n _balances[from] -= 1;\n _balances[to] += 1;\n }\n _owners[vaultID] = to;\n\n emit Transfer(from, to, vaultID);\n }\n\n /// @notice Approves `to` to operate on `vaultID`\n function _approve(address to, uint256 vaultID) internal {\n _vaultApprovals[vaultID] = to;\n emit Approval(_ownerOf(vaultID), to, vaultID);\n }\n\n /// @notice Internal version of the `setApprovalForAll` function\n /// @dev It contains an `approver` field to be used in case someone signs a permit for a particular\n /// address, and this signature is given to the contract by another address (like a router)\n function _setApprovalForAll(\n address approver,\n address operator,\n bool approved\n ) internal {\n if (operator == approver) revert ApprovalToCaller();\n uint256 approval = approved ? 1 : 0;\n _operatorApprovals[approver][operator] = approval;\n emit ApprovalForAll(approver, operator, approved);\n }\n\n /// @notice Internal function to invoke {IERC721Receiver-onERC721Received} on a target address\n /// The call is not executed if the target address is not a contract\n /// @param from Address representing the previous owner of the given token ID\n /// @param to Target address that will receive the tokens\n /// @param vaultID ID of the token to be transferred\n /// @param _data Bytes optional data to send along with the call\n /// @return Bool whether the call correctly returned the expected value\n function _checkOnERC721Received(\n address from,\n address to,\n uint256 vaultID,\n bytes memory _data\n ) private returns (bool) {\n if (to.isContract()) {\n try IERC721ReceiverUpgradeable(to).onERC721Received(msg.sender, from, vaultID, _data) returns (\n bytes4 retval\n ) {\n return retval == IERC721ReceiverUpgradeable.onERC721Received.selector;\n } catch (bytes memory reason) {\n if (reason.length == 0) {\n revert NonERC721Receiver();\n } else {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n revert(add(32, reason), mload(reason))\n }\n }\n }\n } else {\n return true;\n }\n }\n\n /// @notice Hook that is called before any token transfer. This includes minting and burning.\n /// Calling conditions:\n ///\n /// - When `from` and `to` are both non-zero, `from`'s `vaultID` will be\n /// transferred to `to`.\n /// - When `from` is zero, `vaultID` will be minted for `to`.\n /// - When `to` is zero, `from`'s `vaultID` will be burned.\n /// - `from` and `to` are never both zero.\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 vaultID\n ) internal virtual {}\n}\n" + }, + "contracts/deprecated/vaultManager/OldVaultManagerPermit.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"./OldVaultManagerERC721.sol\";\nimport \"../../interfaces/external/IERC1271.sol\";\n\n/// @title VaultManagerPermit\n/// @author Angle Labs, Inc.\n/// @dev Base Implementation of permit functions for the `VaultManager` contract\nabstract contract OldVaultManagerPermit is Initializable, OldVaultManagerERC721 {\n using Address for address;\n\n mapping(address => uint256) private _nonces;\n /* solhint-disable var-name-mixedcase */\n bytes32 private _HASHED_NAME;\n bytes32 private _HASHED_VERSION;\n bytes32 private _PERMIT_TYPEHASH;\n /* solhint-enable var-name-mixedcase */\n\n error ExpiredDeadline();\n error InvalidSignature();\n\n //solhint-disable-next-line\n function __ERC721Permit_init(string memory _name) internal onlyInitializing {\n _PERMIT_TYPEHASH = keccak256(\n \"Permit(address owner,address spender,bool approved,uint256 nonce,uint256 deadline)\"\n );\n _HASHED_NAME = keccak256(bytes(_name));\n _HASHED_VERSION = keccak256(bytes(\"1\"));\n }\n\n /// @notice Allows an address to give or revoke approval for all its vaults to another address\n /// @param owner Address signing the permit and giving (or revoking) its approval for all the controlled vaults\n /// @param spender Address to give approval to\n /// @param approved Whether to give or revoke the approval\n /// @param deadline Deadline parameter for the signature to be valid\n /// @dev The `v`, `r`, and `s` parameters are used as signature data\n function permit(\n address owner,\n address spender,\n bool approved,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external {\n if (block.timestamp > deadline) revert ExpiredDeadline();\n // Additional signature checks performed in the `ECDSAUpgradeable.recover` function\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 || (v != 27 && v != 28))\n revert InvalidSignature();\n\n bytes32 digest = keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n _domainSeparatorV4(),\n keccak256(\n abi.encode(\n _PERMIT_TYPEHASH,\n // 0x3f43a9c6bafb5c7aab4e0cfe239dc5d4c15caf0381c6104188191f78a6640bd8,\n owner,\n spender,\n approved,\n _useNonce(owner),\n deadline\n )\n )\n )\n );\n if (owner.isContract()) {\n if (IERC1271(owner).isValidSignature(digest, abi.encodePacked(r, s, v)) != 0x1626ba7e)\n revert InvalidSignature();\n } else {\n address signer = ecrecover(digest, v, r, s);\n if (signer != owner || signer == address(0)) revert InvalidSignature();\n }\n\n _setApprovalForAll(owner, spender, approved);\n }\n\n /// @notice Returns the current nonce for an `owner` address\n function nonces(address owner) public view returns (uint256) {\n return _nonces[owner];\n }\n\n /// @notice Returns the domain separator for the current chain.\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /// @notice Internal version of the `DOMAIN_SEPARATOR` function\n function _domainSeparatorV4() internal view returns (bytes32) {\n return\n keccak256(\n abi.encode(\n // keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)')\n 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f,\n _HASHED_NAME,\n _HASHED_VERSION,\n block.chainid,\n address(this)\n )\n );\n }\n\n /// @notice Consumes a nonce for an address: returns the current value and increments it\n function _useNonce(address owner) internal returns (uint256 current) {\n current = _nonces[owner];\n _nonces[owner] = current + 1;\n }\n\n uint256[49] private __gap;\n}\n" + }, + "contracts/interfaces/external/IERC1271.sol": { + "content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity ^0.8.12;\n\n/// @title Interface for verifying contract-based account signatures\n/// @notice Interface that verifies provided signature for the data\n/// @dev Interface defined by EIP-1271\ninterface IERC1271 {\n /// @notice Returns whether the provided signature is valid for the provided data\n /// @dev MUST return the bytes4 magic value 0x1626ba7e when function passes.\n /// MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5).\n /// MUST allow external calls.\n /// @param hash Hash of the data to be signed\n /// @param signature Signature byte array associated with _data\n /// @return magicValue The bytes4 magic value 0x1626ba7e\n function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);\n}\n" + }, + "contracts/vaultManager/VaultManagerPermit.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"./VaultManagerERC721.sol\";\nimport \"../interfaces/external/IERC1271.sol\";\n\n/// @title VaultManagerPermit\n/// @author Angle Labs, Inc.\n/// @dev Base Implementation of permit functions for the `VaultManager` contract\nabstract contract VaultManagerPermit is Initializable, VaultManagerERC721 {\n using Address for address;\n\n mapping(address => uint256) private _nonces;\n /* solhint-disable var-name-mixedcase */\n bytes32 private _HASHED_NAME;\n bytes32 private _HASHED_VERSION;\n bytes32 private _PERMIT_TYPEHASH;\n /* solhint-enable var-name-mixedcase */\n\n error ExpiredDeadline();\n error InvalidSignature();\n\n //solhint-disable-next-line\n function __ERC721Permit_init(string memory _name) internal onlyInitializing {\n _PERMIT_TYPEHASH = keccak256(\n \"Permit(address owner,address spender,bool approved,uint256 nonce,uint256 deadline)\"\n );\n _HASHED_NAME = keccak256(bytes(_name));\n _HASHED_VERSION = keccak256(bytes(\"1\"));\n }\n\n /// @notice Allows an address to give or revoke approval for all its vaults to another address\n /// @param owner Address signing the permit and giving (or revoking) its approval for all the controlled vaults\n /// @param spender Address to give approval to\n /// @param approved Whether to give or revoke the approval\n /// @param deadline Deadline parameter for the signature to be valid\n /// @dev The `v`, `r`, and `s` parameters are used as signature data\n function permit(\n address owner,\n address spender,\n bool approved,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external {\n if (block.timestamp > deadline) revert ExpiredDeadline();\n // Additional signature checks performed in the `ECDSAUpgradeable.recover` function\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 || (v != 27 && v != 28))\n revert InvalidSignature();\n\n bytes32 digest = keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n _domainSeparatorV4(),\n keccak256(\n abi.encode(\n _PERMIT_TYPEHASH,\n // 0x3f43a9c6bafb5c7aab4e0cfe239dc5d4c15caf0381c6104188191f78a6640bd8,\n owner,\n spender,\n approved,\n _useNonce(owner),\n deadline\n )\n )\n )\n );\n if (owner.isContract()) {\n if (IERC1271(owner).isValidSignature(digest, abi.encodePacked(r, s, v)) != 0x1626ba7e)\n revert InvalidSignature();\n } else {\n address signer = ecrecover(digest, v, r, s);\n if (signer != owner || signer == address(0)) revert InvalidSignature();\n }\n\n _setApprovalForAll(owner, spender, approved);\n }\n\n /// @notice Returns the current nonce for an `owner` address\n function nonces(address owner) public view returns (uint256) {\n return _nonces[owner];\n }\n\n /// @notice Returns the domain separator for the current chain.\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /// @notice Internal version of the `DOMAIN_SEPARATOR` function\n function _domainSeparatorV4() internal view returns (bytes32) {\n return\n keccak256(\n abi.encode(\n // keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)')\n 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f,\n _HASHED_NAME,\n _HASHED_VERSION,\n block.chainid,\n address(this)\n )\n );\n }\n\n /// @notice Consumes a nonce for an address: returns the current value and increments it\n function _useNonce(address owner) internal returns (uint256 current) {\n current = _nonces[owner];\n _nonces[owner] = current + 1;\n }\n\n uint256[49] private __gap;\n}\n" + }, + "contracts/vaultManager/VaultManagerERC721.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"./VaultManagerStorage.sol\";\n\n/// @title VaultManagerERC721\n/// @author Angle Labs, Inc.\n/// @dev Base ERC721 Implementation of VaultManager\nabstract contract VaultManagerERC721 is IERC721MetadataUpgradeable, VaultManagerStorage {\n using SafeERC20 for IERC20;\n using Address for address;\n\n /// @inheritdoc IERC721MetadataUpgradeable\n string public name;\n /// @inheritdoc IERC721MetadataUpgradeable\n string public symbol;\n\n // ================================= MODIFIERS =================================\n\n /// @notice Checks if the person interacting with the vault with `vaultID` is approved\n /// @param caller Address of the person seeking to interact with the vault\n /// @param vaultID ID of the concerned vault\n modifier onlyApprovedOrOwner(address caller, uint256 vaultID) {\n if (!_isApprovedOrOwner(caller, vaultID)) revert NotApproved();\n _;\n }\n\n // ================================ ERC721 LOGIC ===============================\n\n /// @notice Checks whether a given address is approved for a vault or owns this vault\n /// @param spender Address for which vault ownership should be checked\n /// @param vaultID ID of the vault to check\n /// @return Whether the `spender` address owns or is approved for `vaultID`\n function isApprovedOrOwner(address spender, uint256 vaultID) external view returns (bool) {\n return _isApprovedOrOwner(spender, vaultID);\n }\n\n /// @inheritdoc IERC721MetadataUpgradeable\n function tokenURI(uint256 vaultID) external view returns (string memory) {\n if (!_exists(vaultID)) revert NonexistentVault();\n // There is no vault with `vaultID` equal to 0, so the following variable is\n // always greater than zero\n uint256 temp = vaultID;\n uint256 digits;\n while (temp != 0) {\n ++digits;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (vaultID != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(vaultID % 10)));\n vaultID /= 10;\n }\n return bytes(_baseURI).length != 0 ? string(abi.encodePacked(_baseURI, string(buffer))) : \"\";\n }\n\n /// @inheritdoc IERC721Upgradeable\n function balanceOf(address owner) external view returns (uint256) {\n if (owner == address(0)) revert ZeroAddress();\n return _balances[owner];\n }\n\n /// @inheritdoc IERC721Upgradeable\n function ownerOf(uint256 vaultID) external view returns (address) {\n return _ownerOf(vaultID);\n }\n\n /// @inheritdoc IERC721Upgradeable\n function approve(address to, uint256 vaultID) external {\n address owner = _ownerOf(vaultID);\n if (to == owner) revert ApprovalToOwner();\n if (msg.sender != owner && !isApprovedForAll(owner, msg.sender)) revert NotApproved();\n\n _approve(to, vaultID);\n }\n\n /// @inheritdoc IERC721Upgradeable\n function getApproved(uint256 vaultID) external view returns (address) {\n if (!_exists(vaultID)) revert NonexistentVault();\n return _getApproved(vaultID);\n }\n\n /// @inheritdoc IERC721Upgradeable\n function setApprovalForAll(address operator, bool approved) external {\n _setApprovalForAll(msg.sender, operator, approved);\n }\n\n /// @inheritdoc IERC721Upgradeable\n function isApprovedForAll(address owner, address operator) public view returns (bool) {\n return _operatorApprovals[owner][operator] == 1;\n }\n\n /// @inheritdoc IERC721Upgradeable\n function transferFrom(address from, address to, uint256 vaultID) external onlyApprovedOrOwner(msg.sender, vaultID) {\n _transfer(from, to, vaultID);\n }\n\n /// @inheritdoc IERC721Upgradeable\n function safeTransferFrom(address from, address to, uint256 vaultID) external {\n safeTransferFrom(from, to, vaultID, \"\");\n }\n\n /// @inheritdoc IERC721Upgradeable\n function safeTransferFrom(\n address from,\n address to,\n uint256 vaultID,\n bytes memory _data\n ) public onlyApprovedOrOwner(msg.sender, vaultID) {\n _safeTransfer(from, to, vaultID, _data);\n }\n\n // ================================ ERC165 LOGIC ===============================\n\n /// @inheritdoc IERC165Upgradeable\n function supportsInterface(bytes4 interfaceId) external pure returns (bool) {\n return\n interfaceId == type(IERC721MetadataUpgradeable).interfaceId ||\n interfaceId == type(IERC721Upgradeable).interfaceId ||\n interfaceId == type(IVaultManager).interfaceId ||\n interfaceId == type(IERC165Upgradeable).interfaceId;\n }\n\n // ================== INTERNAL FUNCTIONS FOR THE ERC721 LOGIC ==================\n\n /// @notice Internal version of the `ownerOf` function\n function _ownerOf(uint256 vaultID) internal view returns (address owner) {\n owner = _owners[vaultID];\n if (owner == address(0)) revert NonexistentVault();\n }\n\n /// @notice Internal version of the `getApproved` function\n function _getApproved(uint256 vaultID) internal view returns (address) {\n return _vaultApprovals[vaultID];\n }\n\n /// @notice Internal version of the `safeTransferFrom` function (with the data parameter)\n function _safeTransfer(address from, address to, uint256 vaultID, bytes memory _data) internal {\n _transfer(from, to, vaultID);\n if (!_checkOnERC721Received(from, to, vaultID, _data)) revert NonERC721Receiver();\n }\n\n /// @notice Checks whether a vault exists\n /// @param vaultID ID of the vault to check\n /// @return Whether `vaultID` has been created\n function _exists(uint256 vaultID) internal view returns (bool) {\n return _owners[vaultID] != address(0);\n }\n\n /// @notice Internal version of the `isApprovedOrOwner` function\n function _isApprovedOrOwner(address spender, uint256 vaultID) internal view returns (bool) {\n // The following checks if the vault exists\n address owner = _ownerOf(vaultID);\n return (spender == owner || _getApproved(vaultID) == spender || _operatorApprovals[owner][spender] == 1);\n }\n\n /// @notice Internal version of the `createVault` function\n /// Mints `vaultID` and transfers it to `to`\n /// @dev This method is equivalent to the `_safeMint` method used in OpenZeppelin ERC721 contract\n /// @dev Emits a {Transfer} event\n function _mint(address to) internal returns (uint256 vaultID) {\n if (to == address(0)) revert ZeroAddress();\n\n unchecked {\n vaultIDCount += 1;\n }\n\n vaultID = vaultIDCount;\n _beforeTokenTransfer(address(0), to, vaultID);\n\n unchecked {\n _balances[to] += 1;\n }\n\n _owners[vaultID] = to;\n emit Transfer(address(0), to, vaultID);\n if (!_checkOnERC721Received(address(0), to, vaultID, \"\")) revert NonERC721Receiver();\n }\n\n /// @notice Destroys `vaultID`\n /// @dev `vaultID` must exist\n /// @dev Emits a {Transfer} event\n function _burn(uint256 vaultID) internal {\n address owner = _ownerOf(vaultID);\n\n _beforeTokenTransfer(owner, address(0), vaultID);\n // Clear approvals\n _approve(address(0), vaultID);\n // The following line cannot underflow as the owner's balance is necessarily\n // greater than 1\n unchecked {\n _balances[owner] -= 1;\n }\n delete _owners[vaultID];\n delete vaultData[vaultID];\n\n emit Transfer(owner, address(0), vaultID);\n }\n\n /// @notice Transfers `vaultID` from `from` to `to` as opposed to {transferFrom},\n /// this imposes no restrictions on msg.sender\n /// @dev `to` cannot be the zero address and `perpetualID` must be owned by `from`\n /// @dev Emits a {Transfer} event\n function _transfer(address from, address to, uint256 vaultID) internal {\n if (_ownerOf(vaultID) != from) revert NotApproved();\n if (to == address(0)) revert ZeroAddress();\n\n _beforeTokenTransfer(from, to, vaultID);\n\n // Clear approvals from the previous owner\n _approve(address(0), vaultID);\n unchecked {\n _balances[from] -= 1;\n _balances[to] += 1;\n }\n _owners[vaultID] = to;\n\n emit Transfer(from, to, vaultID);\n }\n\n /// @notice Approves `to` to operate on `vaultID`\n function _approve(address to, uint256 vaultID) internal {\n _vaultApprovals[vaultID] = to;\n emit Approval(_ownerOf(vaultID), to, vaultID);\n }\n\n /// @notice Internal version of the `setApprovalForAll` function\n /// @dev It contains an `approver` field to be used in case someone signs a permit for a particular\n /// address, and this signature is given to the contract by another address (like a router)\n function _setApprovalForAll(address approver, address operator, bool approved) internal {\n if (operator == approver) revert ApprovalToCaller();\n uint256 approval = approved ? 1 : 0;\n _operatorApprovals[approver][operator] = approval;\n emit ApprovalForAll(approver, operator, approved);\n }\n\n /// @notice Internal function to invoke {IERC721Receiver-onERC721Received} on a target address\n /// The call is not executed if the target address is not a contract\n /// @param from Address representing the previous owner of the given token ID\n /// @param to Target address that will receive the tokens\n /// @param vaultID ID of the token to be transferred\n /// @param _data Bytes optional data to send along with the call\n /// @return Bool whether the call correctly returned the expected value\n function _checkOnERC721Received(\n address from,\n address to,\n uint256 vaultID,\n bytes memory _data\n ) private returns (bool) {\n if (to.isContract()) {\n try IERC721ReceiverUpgradeable(to).onERC721Received(msg.sender, from, vaultID, _data) returns (\n bytes4 retval\n ) {\n return retval == IERC721ReceiverUpgradeable.onERC721Received.selector;\n } catch (bytes memory reason) {\n if (reason.length == 0) {\n revert NonERC721Receiver();\n } else {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n revert(add(32, reason), mload(reason))\n }\n }\n }\n } else {\n return true;\n }\n }\n\n /// @notice Hook that is called before any token transfer. This includes minting and burning.\n /// Calling conditions:\n ///\n /// - When `from` and `to` are both non-zero, `from`'s `vaultID` will be\n /// transferred to `to`.\n /// - When `from` is zero, `vaultID` will be minted for `to`.\n /// - When `to` is zero, `from`'s `vaultID` will be burned.\n /// - `from` and `to` are never both zero.\n function _beforeTokenTransfer(address from, address to, uint256 vaultID) internal virtual {}\n\n /// @notice Get `whitelistingActivated` in storage only if needed\n function _whitelistingActivated() internal view virtual returns (bool) {\n return whitelistingActivated;\n }\n}\n" + }, + "contracts/mock/MockERC1271.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.12;\n\nimport \"../interfaces/external/IERC1271.sol\";\n\ncontract MockERC1271 is IERC1271 {\n uint256 public mode = 0;\n\n function setMode(uint256 _mode) public {\n mode = _mode;\n }\n\n /// @notice Returns whether the provided signature is valid for the provided data\n /// @dev MUST return the bytes4 magic value 0x1626ba7e when function passes.\n /// MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5).\n /// MUST allow external calls.\n /// @return magicValue The bytes4 magic value 0x1626ba7e\n function isValidSignature(bytes32, bytes memory) external view returns (bytes4 magicValue) {\n if (mode == 1) magicValue = 0x1626ba7e;\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates", + "devdoc", + "userdoc" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/deployments/mainnet/solcInputs/dd5bbe02f1e84bb60ce90a2cdb3bdbaa.json b/deployments/mainnet/solcInputs/dd5bbe02f1e84bb60ce90a2cdb3bdbaa.json new file mode 100644 index 00000000..6a6139d7 --- /dev/null +++ b/deployments/mainnet/solcInputs/dd5bbe02f1e84bb60ce90a2cdb3bdbaa.json @@ -0,0 +1,127 @@ +{ + "language": "Solidity", + "sources": { + "contracts/vaultManager/VaultManagerLiquidationBoost.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"./VaultManager.sol\";\n\n/// @title VaultManagerLiquidationBoost\n/// @author Angle Labs, Inc.\n/// @notice Liquidation discount depending also on the liquidator veANGLE balance\ncontract VaultManagerLiquidationBoost is VaultManager {\n using SafeERC20 for IERC20;\n using Address for address;\n\n // =================================== SETTER ==================================\n\n /// @inheritdoc VaultManager\n /// @param _veBoostProxy Address which queries veANGLE balances and adjusted balances from delegation\n /// @param xBoost Threshold values of veANGLE adjusted balances\n /// @param yBoost Values of the liquidation boost at the threshold values of x\n /// @dev There are 2 modes:\n /// When boost is enabled, `xBoost` and `yBoost` should have a length of 2, but if they have a\n /// higher length contract will still work as expected. Contract will also work as expected if their\n /// length differ\n /// When boost is disabled, `_veBoostProxy` needs to be zero address and `yBoost[0]` is the base boost\n function setLiquidationBoostParameters(\n address _veBoostProxy,\n uint256[] memory xBoost,\n uint256[] memory yBoost\n ) external override onlyGovernorOrGuardian {\n if (\n (xBoost.length != yBoost.length) ||\n (yBoost[0] == 0) ||\n ((_veBoostProxy != address(0)) && (xBoost[1] <= xBoost[0] || yBoost[1] < yBoost[0]))\n ) revert InvalidSetOfParameters();\n veBoostProxy = IVeBoostProxy(_veBoostProxy);\n xLiquidationBoost = xBoost;\n yLiquidationBoost = yBoost;\n emit LiquidationBoostParametersUpdated(_veBoostProxy, xBoost, yBoost);\n }\n\n // ======================== OVERRIDEN VIRTUAL FUNCTIONS ========================\n\n /// @inheritdoc VaultManager\n function _computeLiquidationBoost(address liquidator) internal view override returns (uint256) {\n if (address(veBoostProxy) == address(0)) {\n return yLiquidationBoost[0];\n } else {\n uint256 adjustedBalance = veBoostProxy.adjusted_balance_of(liquidator);\n if (adjustedBalance >= xLiquidationBoost[1]) return yLiquidationBoost[1];\n else if (adjustedBalance <= xLiquidationBoost[0]) return yLiquidationBoost[0];\n else\n return\n yLiquidationBoost[0] +\n ((yLiquidationBoost[1] - yLiquidationBoost[0]) * (adjustedBalance - xLiquidationBoost[0])) /\n (xLiquidationBoost[1] - xLiquidationBoost[0]);\n }\n }\n}\n" + }, + "contracts/vaultManager/VaultManager.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\n/*\n * █ \n ***** ▓▓▓ \n * ▓▓▓▓▓▓▓ \n * ///. ▓▓▓▓▓▓▓▓▓▓▓▓▓ \n ***** //////// ▓▓▓▓▓▓▓ \n * ///////////// ▓▓▓ \n ▓▓ ////////////////// █ ▓▓ \n ▓▓ ▓▓ /////////////////////// ▓▓ ▓▓ \n ▓▓ ▓▓ //////////////////////////// ▓▓ ▓▓ \n ▓▓ ▓▓ /////////▓▓▓///////▓▓▓///////// ▓▓ ▓▓ \n ▓▓ ,////////////////////////////////////// ▓▓ ▓▓ \n ▓▓ ////////////////////////////////////////// ▓▓ \n ▓▓ //////////////////////▓▓▓▓///////////////////// \n ,//////////////////////////////////////////////////// \n .////////////////////////////////////////////////////////// \n .//////////////////////////██.,//////////////////////////█ \n .//////////////////////████..,./////////////////////██ \n ...////////////////███████.....,.////////////////███ \n ,.,////////////████████ ........,///////////████ \n .,.,//////█████████ ,.......///////████ \n ,..//████████ ........./████ \n ..,██████ .....,███ \n .██ ,.,█ \n \n \n \n ▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓ \n ▓▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓ ▓▓▓▓ \n ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓ ▓▓▓▓▓ \n ▓▓▓ ▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ \n*/\n\npragma solidity ^0.8.12;\n\nimport \"./VaultManagerPermit.sol\";\n\n/// @title VaultManager\n/// @author Angle Labs, Inc.\n/// @notice This contract allows people to deposit collateral and open up loans of a given AgToken. It handles all the loan\n/// logic (fees and interest rate) as well as the liquidation logic\n/// @dev This implementation only supports non-rebasing ERC20 tokens as collateral\n/// @dev This contract is encoded as a NFT contract\ncontract VaultManager is VaultManagerPermit, IVaultManagerFunctions {\n using SafeERC20 for IERC20;\n using Address for address;\n\n /// @inheritdoc IVaultManagerFunctions\n uint256 public dust;\n\n /// @notice Minimum amount of collateral (in stablecoin value, e.g in `BASE_TOKENS = 10**18`) that can be left\n /// in a vault during a liquidation where the health factor function is decreasing\n uint256 internal _dustCollateral;\n\n /// @notice If the amount of debt of a vault that gets liquidated is below this amount, then the liquidator\n /// can liquidate all the debt of the vault (and not just what's needed to get to the target health factor)\n uint256 public dustLiquidation;\n\n uint256[47] private __gapVaultManager;\n\n /// @inheritdoc IVaultManagerFunctions\n function initialize(\n ITreasury _treasury,\n IERC20 _collateral,\n IOracle _oracle,\n VaultParameters calldata params,\n string memory _symbol\n ) external virtual initializer {\n _initialize(_treasury, _collateral, _oracle, params, _symbol);\n whitelistingActivated = params.whitelistingActivated;\n paused = true;\n }\n\n /// @notice Internal logic to `initialize`\n function _initialize(\n ITreasury _treasury,\n IERC20 _collateral,\n IOracle _oracle,\n VaultParameters memory params,\n string memory _symbol\n ) internal virtual {\n if (_oracle.treasury() != _treasury) revert InvalidTreasury();\n treasury = _treasury;\n collateral = _collateral;\n _collatBase = 10 ** (IERC20Metadata(address(collateral)).decimals());\n stablecoin = IAgToken(_treasury.stablecoin());\n oracle = _oracle;\n string memory _name = string.concat(\"Angle Protocol \", _symbol, \" Vault\");\n name = _name;\n __ERC721Permit_init(_name);\n symbol = string.concat(_symbol, \"-vault\");\n\n interestAccumulator = BASE_INTEREST;\n lastInterestAccumulatorUpdated = block.timestamp;\n\n // Checking if the parameters have been correctly initialized\n if (\n params.collateralFactor > params.liquidationSurcharge ||\n params.liquidationSurcharge > BASE_PARAMS ||\n BASE_PARAMS > params.targetHealthFactor ||\n params.maxLiquidationDiscount >= BASE_PARAMS ||\n params.baseBoost == 0\n ) revert InvalidSetOfParameters();\n\n debtCeiling = params.debtCeiling;\n collateralFactor = params.collateralFactor;\n targetHealthFactor = params.targetHealthFactor;\n interestRate = params.interestRate;\n liquidationSurcharge = params.liquidationSurcharge;\n maxLiquidationDiscount = params.maxLiquidationDiscount;\n yLiquidationBoost = [params.baseBoost];\n }\n\n // ================================= MODIFIERS =================================\n\n /// @notice Checks whether the `msg.sender` has the governor role or not\n modifier onlyGovernor() {\n if (!treasury.isGovernor(msg.sender)) revert NotGovernor();\n _;\n }\n\n /// @notice Checks whether the `msg.sender` has the governor role or the guardian role\n modifier onlyGovernorOrGuardian() {\n if (!treasury.isGovernorOrGuardian(msg.sender)) revert NotGovernorOrGuardian();\n _;\n }\n\n /// @notice Checks whether the `msg.sender` is the treasury contract\n modifier onlyTreasury() {\n if (msg.sender != address(treasury)) revert NotTreasury();\n _;\n }\n\n /// @notice Checks whether the contract is paused\n modifier whenNotPaused() {\n if (_paused()) revert Paused();\n _;\n }\n\n // ============================== VAULT FUNCTIONS ==============================\n\n /// @inheritdoc IVaultManagerFunctions\n function createVault(address toVault) external whenNotPaused returns (uint256) {\n return _mint(toVault);\n }\n\n /// @inheritdoc IVaultManagerFunctions\n function angle(\n ActionType[] memory actions,\n bytes[] memory datas,\n address from,\n address to\n ) external returns (PaymentData memory) {\n return angle(actions, datas, from, to, address(0), new bytes(0));\n }\n\n /// @inheritdoc IVaultManagerFunctions\n function angle(\n ActionType[] memory actions,\n bytes[] memory datas,\n address from,\n address to,\n address who,\n bytes memory repayData\n ) public whenNotPaused nonReentrant returns (PaymentData memory paymentData) {\n if (actions.length != datas.length || actions.length == 0) revert IncompatibleLengths();\n // `newInterestAccumulator` and `oracleValue` are expensive to compute. Therefore, they are computed\n // only once inside the first action where they are necessary, then they are passed forward to further actions\n uint256 newInterestAccumulator;\n uint256 oracleValue;\n uint256 collateralAmount;\n uint256 stablecoinAmount;\n uint256 vaultID;\n for (uint256 i; i < actions.length; ++i) {\n ActionType action = actions[i];\n // Processing actions which do not need the value of the oracle or of the `interestAccumulator`\n if (action == ActionType.createVault) {\n _mint(abi.decode(datas[i], (address)));\n } else if (action == ActionType.addCollateral) {\n (vaultID, collateralAmount) = abi.decode(datas[i], (uint256, uint256));\n if (vaultID == 0) vaultID = vaultIDCount;\n _addCollateral(vaultID, collateralAmount);\n paymentData.collateralAmountToReceive += collateralAmount;\n } else if (action == ActionType.permit) {\n address owner;\n bytes32 r;\n bytes32 s;\n // Watch out naming conventions for permit are not respected to save some space and reduce the stack size\n // `vaultID` is used in place of the `deadline` parameter\n // Same for `collateralAmount` used in place of `value`\n // `stablecoinAmount` is used in place of the `v`\n (owner, collateralAmount, vaultID, stablecoinAmount, r, s) = abi.decode(\n datas[i],\n (address, uint256, uint256, uint256, bytes32, bytes32)\n );\n IERC20PermitUpgradeable(address(collateral)).permit(\n owner,\n address(this),\n collateralAmount,\n vaultID,\n uint8(stablecoinAmount),\n r,\n s\n );\n } else {\n // Processing actions which rely on the `interestAccumulator`: first accruing it to make\n // sure surplus is correctly taken into account between debt changes\n if (newInterestAccumulator == 0) newInterestAccumulator = _accrue();\n if (action == ActionType.repayDebt) {\n (vaultID, stablecoinAmount) = abi.decode(datas[i], (uint256, uint256));\n if (vaultID == 0) vaultID = vaultIDCount;\n stablecoinAmount = _repayDebt(vaultID, stablecoinAmount, newInterestAccumulator);\n uint256 stablecoinAmountPlusRepayFee = (stablecoinAmount * BASE_PARAMS) /\n (BASE_PARAMS - _repayFee());\n surplus += stablecoinAmountPlusRepayFee - stablecoinAmount;\n paymentData.stablecoinAmountToReceive += stablecoinAmountPlusRepayFee;\n } else {\n // Processing actions which need the oracle value\n if (oracleValue == 0) oracleValue = oracle.read();\n if (action == ActionType.closeVault) {\n vaultID = abi.decode(datas[i], (uint256));\n if (vaultID == 0) vaultID = vaultIDCount;\n (stablecoinAmount, collateralAmount) = _closeVault(\n vaultID,\n oracleValue,\n newInterestAccumulator\n );\n paymentData.collateralAmountToGive += collateralAmount;\n paymentData.stablecoinAmountToReceive += stablecoinAmount;\n } else if (action == ActionType.removeCollateral) {\n (vaultID, collateralAmount) = abi.decode(datas[i], (uint256, uint256));\n if (vaultID == 0) vaultID = vaultIDCount;\n _removeCollateral(vaultID, collateralAmount, oracleValue, newInterestAccumulator);\n paymentData.collateralAmountToGive += collateralAmount;\n } else if (action == ActionType.borrow) {\n (vaultID, stablecoinAmount) = abi.decode(datas[i], (uint256, uint256));\n if (vaultID == 0) vaultID = vaultIDCount;\n stablecoinAmount = _borrow(vaultID, stablecoinAmount, oracleValue, newInterestAccumulator);\n paymentData.stablecoinAmountToGive += stablecoinAmount;\n } else if (action == ActionType.getDebtIn) {\n address vaultManager;\n uint256 dstVaultID;\n (vaultID, vaultManager, dstVaultID, stablecoinAmount) = abi.decode(\n datas[i],\n (uint256, address, uint256, uint256)\n );\n if (vaultID == 0) vaultID = vaultIDCount;\n _getDebtIn(\n vaultID,\n IVaultManager(vaultManager),\n dstVaultID,\n stablecoinAmount,\n oracleValue,\n newInterestAccumulator\n );\n }\n }\n }\n }\n\n // Processing the different cases for the repayment, there are 4 of them:\n // - (1) Stablecoins to receive + collateral to send\n // - (2) Stablecoins to receive + collateral to receive\n // - (3) Stablecoins to send + collateral to send\n // - (4) Stablecoins to send + collateral to receive\n if (paymentData.stablecoinAmountToReceive >= paymentData.stablecoinAmountToGive) {\n uint256 stablecoinPayment = paymentData.stablecoinAmountToReceive - paymentData.stablecoinAmountToGive;\n if (paymentData.collateralAmountToGive >= paymentData.collateralAmountToReceive) {\n // In the case where all amounts are null, the function will enter here and nothing will be done\n // for the repayment\n _handleRepay(\n // Collateral payment is the difference between what to give and what to receive\n paymentData.collateralAmountToGive - paymentData.collateralAmountToReceive,\n stablecoinPayment,\n from,\n to,\n who,\n repayData\n );\n } else {\n if (stablecoinPayment != 0) stablecoin.burnFrom(stablecoinPayment, from, msg.sender);\n // In this case the collateral amount is necessarily non null\n collateral.safeTransferFrom(\n msg.sender,\n address(this),\n paymentData.collateralAmountToReceive - paymentData.collateralAmountToGive\n );\n }\n } else {\n uint256 stablecoinPayment = paymentData.stablecoinAmountToGive - paymentData.stablecoinAmountToReceive;\n // `stablecoinPayment` is strictly positive in this case\n stablecoin.mint(to, stablecoinPayment);\n if (paymentData.collateralAmountToGive > paymentData.collateralAmountToReceive) {\n collateral.safeTransfer(to, paymentData.collateralAmountToGive - paymentData.collateralAmountToReceive);\n } else {\n uint256 collateralPayment = paymentData.collateralAmountToReceive - paymentData.collateralAmountToGive;\n if (collateralPayment != 0) {\n if (repayData.length != 0) {\n ISwapper(who).swap(\n IERC20(address(stablecoin)),\n collateral,\n msg.sender,\n // As per the `ISwapper` interface, we must first give the amount of token owed by the address before\n // the amount of token it (or another related address) obtained\n collateralPayment,\n stablecoinPayment,\n repayData\n );\n }\n collateral.safeTransferFrom(msg.sender, address(this), collateralPayment);\n }\n }\n }\n }\n\n /// @inheritdoc IVaultManagerFunctions\n function getDebtOut(\n uint256 vaultID,\n uint256 stablecoinAmount,\n uint256 senderBorrowFee,\n uint256 senderRepayFee\n ) external whenNotPaused {\n if (!treasury.isVaultManager(msg.sender)) revert NotVaultManager();\n // Getting debt out of a vault is equivalent to repaying a portion of your debt, and this could leave exploits:\n // someone could borrow from a vault and transfer its debt to a `VaultManager` contract where debt repayment will\n // be cheaper: in which case we're making people pay the delta\n uint256 repayFee_;\n {\n uint256 _repayFeeReceiver = _repayFee();\n if (_repayFeeReceiver > senderRepayFee) {\n repayFee_ = _repayFeeReceiver - senderRepayFee;\n }\n }\n // Checking the delta of borrow fees to eliminate the risk of exploits here: a similar thing could happen: people\n // could mint from where it is cheap to mint and then transfer their debt to places where it is more expensive\n // to mint\n uint256 _borrowFee;\n if (senderBorrowFee > borrowFee) {\n _borrowFee = senderBorrowFee - borrowFee;\n }\n\n uint256 stablecoinAmountLessFeePaid = (stablecoinAmount *\n (BASE_PARAMS - repayFee_) *\n (BASE_PARAMS - _borrowFee)) / (BASE_PARAMS ** 2);\n surplus += stablecoinAmount - stablecoinAmountLessFeePaid;\n _repayDebt(vaultID, stablecoinAmountLessFeePaid, 0);\n }\n\n // =============================== VIEW FUNCTIONS ==============================\n\n /// @inheritdoc IVaultManagerFunctions\n function getVaultDebt(uint256 vaultID) external view returns (uint256) {\n return (vaultData[vaultID].normalizedDebt * _calculateCurrentInterestAccumulator()) / BASE_INTEREST;\n }\n\n /// @inheritdoc IVaultManagerFunctions\n function getTotalDebt() external view returns (uint256) {\n return (totalNormalizedDebt * _calculateCurrentInterestAccumulator()) / BASE_INTEREST;\n }\n\n /// @notice Checks whether a given vault is liquidable and if yes gives information regarding its liquidation\n /// @param vaultID ID of the vault to check\n /// @param liquidator Address of the liquidator which will be performing the liquidation\n /// @return liqOpp Description of the opportunity of liquidation\n /// @dev This function will revert if it's called on a vault that does not exist\n function checkLiquidation(\n uint256 vaultID,\n address liquidator\n ) external view returns (LiquidationOpportunity memory liqOpp) {\n liqOpp = _checkLiquidation(\n vaultData[vaultID],\n liquidator,\n oracle.read(),\n _calculateCurrentInterestAccumulator()\n );\n }\n\n // ====================== INTERNAL UTILITY VIEW FUNCTIONS ======================\n\n /// @notice Computes the health factor of a given vault. This can later be used to check whether a given vault is solvent\n /// (i.e. should be liquidated or not)\n /// @param vault Data of the vault to check\n /// @param oracleValue Oracle value at the time of the call (it is in the base of the stablecoin, that is for agTokens 10**18)\n /// @param newInterestAccumulator Value of the `interestAccumulator` at the time of the call\n /// @return healthFactor Health factor of the vault: if it's inferior to 1 (`BASE_PARAMS` in fact) this means that the vault can be liquidated\n /// @return currentDebt Current value of the debt of the vault (taking into account interest)\n /// @return collateralAmountInStable Collateral in the vault expressed in stablecoin value\n function _isSolvent(\n Vault memory vault,\n uint256 oracleValue,\n uint256 newInterestAccumulator\n ) internal view returns (uint256 healthFactor, uint256 currentDebt, uint256 collateralAmountInStable) {\n currentDebt = (vault.normalizedDebt * newInterestAccumulator) / BASE_INTEREST;\n collateralAmountInStable = (vault.collateralAmount * oracleValue) / _collatBase;\n if (currentDebt == 0) healthFactor = type(uint256).max;\n else healthFactor = (collateralAmountInStable * collateralFactor) / currentDebt;\n }\n\n /// @notice Calculates the current value of the `interestAccumulator` without updating the value\n /// in storage\n /// @dev This function avoids expensive exponentiation and the calculation is performed using a binomial approximation\n /// (1+x)^n = 1+n*x+[n/2*(n-1)]*x^2+[n/6*(n-1)*(n-2)*x^3...\n /// @dev The approximation slightly undercharges borrowers with the advantage of a great gas cost reduction\n /// @dev This function was mostly inspired from Aave implementation\n function _calculateCurrentInterestAccumulator() internal view returns (uint256) {\n uint256 exp = block.timestamp - lastInterestAccumulatorUpdated;\n uint256 ratePerSecond = interestRate;\n if (exp == 0 || ratePerSecond == 0) return interestAccumulator;\n uint256 expMinusOne = exp - 1;\n uint256 expMinusTwo = exp > 2 ? exp - 2 : 0;\n uint256 basePowerTwo = (ratePerSecond * ratePerSecond + HALF_BASE_INTEREST) / BASE_INTEREST;\n uint256 basePowerThree = (basePowerTwo * ratePerSecond + HALF_BASE_INTEREST) / BASE_INTEREST;\n uint256 secondTerm = (exp * expMinusOne * basePowerTwo) / 2;\n uint256 thirdTerm = (exp * expMinusOne * expMinusTwo * basePowerThree) / 6;\n return (interestAccumulator * (BASE_INTEREST + ratePerSecond * exp + secondTerm + thirdTerm)) / BASE_INTEREST;\n }\n\n // ================= INTERNAL UTILITY STATE-MODIFYING FUNCTIONS ================\n\n /// @notice Closes a vault without handling the repayment of the concerned address\n /// @param vaultID ID of the vault to close\n /// @param oracleValue Oracle value at the start of the call\n /// @param newInterestAccumulator Interest rate accumulator value at the start of the call\n /// @return Current debt of the vault to be repaid\n /// @return Value of the collateral in the vault to reimburse\n /// @dev The returned values are here to facilitate composability between calls\n function _closeVault(\n uint256 vaultID,\n uint256 oracleValue,\n uint256 newInterestAccumulator\n ) internal onlyApprovedOrOwner(msg.sender, vaultID) returns (uint256, uint256) {\n Vault memory vault = vaultData[vaultID];\n (uint256 healthFactor, uint256 currentDebt, ) = _isSolvent(vault, oracleValue, newInterestAccumulator);\n if (healthFactor <= BASE_PARAMS) revert InsolventVault();\n totalNormalizedDebt -= vault.normalizedDebt;\n _burn(vaultID);\n uint256 currentDebtPlusRepayFee = (currentDebt * BASE_PARAMS) / (BASE_PARAMS - _repayFee());\n surplus += currentDebtPlusRepayFee - currentDebt;\n return (currentDebtPlusRepayFee, vault.collateralAmount);\n }\n\n /// @notice Increases the collateral balance of a vault\n /// @param vaultID ID of the vault to increase the collateral balance of\n /// @param collateralAmount Amount by which increasing the collateral balance of\n function _addCollateral(uint256 vaultID, uint256 collateralAmount) internal {\n if (!_exists(vaultID)) revert NonexistentVault();\n _checkpointCollateral(vaultID, collateralAmount, true);\n vaultData[vaultID].collateralAmount += collateralAmount;\n emit CollateralAmountUpdated(vaultID, collateralAmount, 1);\n }\n\n /// @notice Decreases the collateral balance from a vault (without proceeding to collateral transfers)\n /// @param vaultID ID of the vault to decrease the collateral balance of\n /// @param collateralAmount Amount of collateral to reduce the balance of\n /// @param oracleValue Oracle value at the start of the call (given here to avoid double computations)\n /// @param interestAccumulator_ Value of the interest rate accumulator (potentially zero if it has not been\n /// computed yet)\n function _removeCollateral(\n uint256 vaultID,\n uint256 collateralAmount,\n uint256 oracleValue,\n uint256 interestAccumulator_\n ) internal onlyApprovedOrOwner(msg.sender, vaultID) {\n _checkpointCollateral(vaultID, collateralAmount, false);\n vaultData[vaultID].collateralAmount -= collateralAmount;\n (uint256 healthFactor, , ) = _isSolvent(vaultData[vaultID], oracleValue, interestAccumulator_);\n if (healthFactor <= BASE_PARAMS) revert InsolventVault();\n emit CollateralAmountUpdated(vaultID, collateralAmount, 0);\n }\n\n /// @notice Increases the debt balance of a vault and takes into account borrowing fees\n /// @param vaultID ID of the vault to increase borrow balance of\n /// @param stablecoinAmount Amount of stablecoins to borrow\n /// @param oracleValue Oracle value at the start of the call\n /// @param newInterestAccumulator Value of the interest rate accumulator\n /// @return toMint Amount of stablecoins to mint\n function _borrow(\n uint256 vaultID,\n uint256 stablecoinAmount,\n uint256 oracleValue,\n uint256 newInterestAccumulator\n ) internal onlyApprovedOrOwner(msg.sender, vaultID) returns (uint256 toMint) {\n stablecoinAmount = _increaseDebt(vaultID, stablecoinAmount, oracleValue, newInterestAccumulator);\n uint256 borrowFeePaid = (borrowFee * stablecoinAmount) / BASE_PARAMS;\n surplus += borrowFeePaid;\n toMint = stablecoinAmount - borrowFeePaid;\n }\n\n /// @notice Gets debt in a vault from another vault potentially in another `VaultManager` contract\n /// @param srcVaultID ID of the vault from this contract for which growing debt\n /// @param vaultManager Address of the `VaultManager` where the targeted vault is\n /// @param dstVaultID ID of the vault in the target contract\n /// @param stablecoinAmount Amount of stablecoins to grow the debt of. This amount will be converted\n /// to a normalized value in both `VaultManager` contracts\n /// @param oracleValue Oracle value at the start of the call (potentially zero if it has not been computed yet)\n /// @param newInterestAccumulator Value of the interest rate accumulator (potentially zero if it has not been\n /// computed yet)\n /// @dev A solvency check is performed after the debt increase in the source `vaultID`\n /// @dev Only approved addresses by the source vault owner can perform this action, however any vault\n /// from any vaultManager contract can see its debt reduced by this means\n function _getDebtIn(\n uint256 srcVaultID,\n IVaultManager vaultManager,\n uint256 dstVaultID,\n uint256 stablecoinAmount,\n uint256 oracleValue,\n uint256 newInterestAccumulator\n ) internal onlyApprovedOrOwner(msg.sender, srcVaultID) {\n emit DebtTransferred(srcVaultID, dstVaultID, address(vaultManager), stablecoinAmount);\n // The `stablecoinAmount` needs to be rounded down in the `_increaseDebt` function to reduce the room for exploits\n stablecoinAmount = _increaseDebt(srcVaultID, stablecoinAmount, oracleValue, newInterestAccumulator);\n if (address(vaultManager) == address(this)) {\n // No repayFees taken in this case, otherwise the same stablecoin may end up paying fees twice\n _repayDebt(dstVaultID, stablecoinAmount, newInterestAccumulator);\n } else {\n // No need to check the integrity of `VaultManager` here because `_getDebtIn` can be entered only through the\n // `angle` function which is non reentrant. Also, `getDebtOut` failing would be at the attacker loss, as they\n // would get their debt increasing in the current vault without decreasing it in the remote vault.\n vaultManager.getDebtOut(dstVaultID, stablecoinAmount, borrowFee, _repayFee());\n }\n }\n\n /// @notice Increases the debt of a given vault and verifies that this vault is still solvent\n /// @param vaultID ID of the vault to increase the debt of\n /// @param stablecoinAmount Amount of stablecoin to increase the debt of: this amount is converted in\n /// normalized debt using the pre-computed (or not) `newInterestAccumulator` value\n /// @param oracleValue Oracle value at the start of the call (given here to avoid double computations)\n /// @param newInterestAccumulator Value of the interest rate accumulator (potentially zero if it has not been\n /// computed yet)\n /// @return Amount of stablecoins to issue from this debt increase\n /// @dev The `stablecoinAmount` outputted need to be rounded down with respect to the change amount so that\n /// amount of stablecoins minted is smaller than the debt increase\n function _increaseDebt(\n uint256 vaultID,\n uint256 stablecoinAmount,\n uint256 oracleValue,\n uint256 newInterestAccumulator\n ) internal returns (uint256) {\n // We normalize the amount by dividing it by `newInterestAccumulator`. This makes accounting easier, since\n // it allows us to process all (past and future) debts like debts created at the inception of the contract.\n uint256 changeAmount = (stablecoinAmount * BASE_INTEREST) / newInterestAccumulator;\n // if there was no previous debt, we have to check that the debt creation will be higher than `dust`\n if (vaultData[vaultID].normalizedDebt == 0)\n if (stablecoinAmount <= dust) revert DustyLeftoverAmount();\n vaultData[vaultID].normalizedDebt += changeAmount;\n totalNormalizedDebt += changeAmount;\n if (totalNormalizedDebt * newInterestAccumulator > debtCeiling * BASE_INTEREST) revert DebtCeilingExceeded();\n (uint256 healthFactor, , ) = _isSolvent(vaultData[vaultID], oracleValue, newInterestAccumulator);\n if (healthFactor <= BASE_PARAMS) revert InsolventVault();\n emit InternalDebtUpdated(vaultID, changeAmount, 1);\n return (changeAmount * newInterestAccumulator) / BASE_INTEREST;\n }\n\n /// @notice Decreases the debt of a given vault and verifies that this vault still has an amount of debt superior\n /// to a dusty amount or no debt at all\n /// @param vaultID ID of the vault to decrease the debt of\n /// @param stablecoinAmount Amount of stablecoin to decrease the debt of: this amount is converted in\n /// normalized debt using the pre-computed (or not) `newInterestAccumulator` value\n /// To repay the whole debt, one can pass `type(uint256).max`\n /// @param newInterestAccumulator Value of the interest rate accumulator (potentially zero if it has not been\n /// computed yet, like in `getDebtOut`)\n /// @return Amount of stablecoins to be burnt to correctly repay the debt\n /// @dev If `stablecoinAmount` is `type(uint256).max`, this function will repay all the debt of the vault\n function _repayDebt(\n uint256 vaultID,\n uint256 stablecoinAmount,\n uint256 newInterestAccumulator\n ) internal returns (uint256) {\n if (newInterestAccumulator == 0) newInterestAccumulator = _accrue();\n uint256 newVaultNormalizedDebt = vaultData[vaultID].normalizedDebt;\n // To save one variable declaration, `changeAmount` is first expressed in stablecoin amount before being converted\n // to a normalized amount. Here we first store the maximum amount that can be repaid given the current debt\n uint256 changeAmount = (newVaultNormalizedDebt * newInterestAccumulator) / BASE_INTEREST;\n // In some situations (e.g. liquidations), the `stablecoinAmount` is rounded above and we want to make\n // sure to avoid underflows in all situations\n if (stablecoinAmount >= changeAmount) {\n stablecoinAmount = changeAmount;\n changeAmount = newVaultNormalizedDebt;\n } else {\n changeAmount = (stablecoinAmount * BASE_INTEREST) / newInterestAccumulator;\n }\n newVaultNormalizedDebt -= changeAmount;\n totalNormalizedDebt -= changeAmount;\n if (newVaultNormalizedDebt != 0 && newVaultNormalizedDebt * newInterestAccumulator <= dust * BASE_INTEREST)\n revert DustyLeftoverAmount();\n vaultData[vaultID].normalizedDebt = newVaultNormalizedDebt;\n emit InternalDebtUpdated(vaultID, changeAmount, 0);\n return stablecoinAmount;\n }\n\n /// @notice Handles the simultaneous repayment of stablecoins with a transfer of collateral\n /// @param collateralAmountToGive Amount of collateral the contract should give\n /// @param stableAmountToRepay Amount of stablecoins the contract should burn from the call\n /// @param from Address from which stablecoins should be burnt: it should be the `msg.sender` or at least\n /// approved by it\n /// @param to Address to which collateral should be sent\n /// @param who Address which should be notified if needed of the transfer\n /// @param data Data to pass to the `who` contract for it to successfully give the correct amount of stablecoins\n /// to the `from` address\n /// @dev This function allows for capital-efficient liquidations and repayments of loans\n function _handleRepay(\n uint256 collateralAmountToGive,\n uint256 stableAmountToRepay,\n address from,\n address to,\n address who,\n bytes memory data\n ) internal {\n if (collateralAmountToGive != 0) collateral.safeTransfer(to, collateralAmountToGive);\n if (stableAmountToRepay != 0) {\n if (data.length != 0) {\n ISwapper(who).swap(\n collateral,\n IERC20(address(stablecoin)),\n from,\n stableAmountToRepay,\n collateralAmountToGive,\n data\n );\n }\n stablecoin.burnFrom(stableAmountToRepay, from, msg.sender);\n }\n }\n\n // ====================== TREASURY RELATIONSHIP FUNCTIONS ======================\n\n /// @inheritdoc IVaultManagerFunctions\n function accrueInterestToTreasury() external onlyTreasury returns (uint256 surplusValue, uint256 badDebtValue) {\n _accrue();\n surplusValue = surplus;\n badDebtValue = badDebt;\n surplus = 0;\n badDebt = 0;\n if (surplusValue >= badDebtValue) {\n surplusValue -= badDebtValue;\n badDebtValue = 0;\n stablecoin.mint(address(treasury), surplusValue);\n } else {\n badDebtValue -= surplusValue;\n surplusValue = 0;\n }\n emit AccruedToTreasury(surplusValue, badDebtValue);\n }\n\n /// @notice Accrues interest accumulated across all vaults to the surplus and updates the `interestAccumulator`\n /// @return newInterestAccumulator Computed value of the interest accumulator\n /// @dev It should also be called when updating the value of the per second interest rate or when the `totalNormalizedDebt`\n /// value is about to change\n function _accrue() internal returns (uint256 newInterestAccumulator) {\n newInterestAccumulator = _calculateCurrentInterestAccumulator();\n uint256 interestAccrued = (totalNormalizedDebt * (newInterestAccumulator - interestAccumulator)) /\n BASE_INTEREST;\n surplus += interestAccrued;\n interestAccumulator = newInterestAccumulator;\n lastInterestAccumulatorUpdated = block.timestamp;\n emit InterestAccumulatorUpdated(newInterestAccumulator, block.timestamp);\n return newInterestAccumulator;\n }\n\n // ================================ LIQUIDATIONS ===============================\n\n /// @notice Liquidates an ensemble of vaults specified by their IDs\n /// @dev This function is a simplified wrapper of the function below. It is built to remove for liquidators the need to specify\n /// a `who` and a `data` parameter\n function liquidate(\n uint256[] memory vaultIDs,\n uint256[] memory amounts,\n address from,\n address to\n ) external returns (LiquidatorData memory) {\n return liquidate(vaultIDs, amounts, from, to, address(0), new bytes(0));\n }\n\n /// @notice Liquidates an ensemble of vaults specified by their IDs\n /// @param vaultIDs List of the vaults to liquidate\n /// @param amounts Amount of stablecoin to bring for the liquidation of each vault\n /// @param from Address from which the stablecoins for the liquidation should be taken: this address should be the `msg.sender`\n /// or have received an approval\n /// @param to Address to which discounted collateral should be sent\n /// @param who Address of the contract to handle repayment of stablecoins from received collateral\n /// @param data Data to pass to the repayment contract in case of. If empty, liquidators simply have to bring the exact amount of\n /// stablecoins to get the discounted collateral. If not, it is used by the repayment contract to swap a portion or all\n /// of the collateral received to stablecoins to be sent to the `from` address. More details in the `_handleRepay` function\n /// @return liqData Data about the liquidation process for the liquidator to track everything that has been going on (like how much\n /// stablecoins have been repaid, how much collateral has been received)\n /// @dev This function will revert if it's called on a vault that cannot be liquidated or that does not exist\n /// @dev A whitelist check may be performed on the address liquidating the vault or on the address receiving\n /// the funds from the liquidiation\n function liquidate(\n uint256[] memory vaultIDs,\n uint256[] memory amounts,\n address from,\n address to,\n address who,\n bytes memory data\n ) public whenNotPaused nonReentrant returns (LiquidatorData memory liqData) {\n if (_whitelistingActivated() && isWhitelisted[msg.sender] != 1 && isWhitelisted[to] != 1)\n revert NotWhitelisted();\n uint256 vaultIDsLength = vaultIDs.length;\n if (vaultIDsLength != amounts.length || vaultIDsLength == 0) revert IncompatibleLengths();\n // Stores all the data about an ongoing liquidation of multiple vaults\n liqData.oracleValue = oracle.read();\n liqData.newInterestAccumulator = _accrue();\n emit LiquidatedVaults(vaultIDs);\n for (uint256 i; i < vaultIDsLength; ++i) {\n Vault memory vault = vaultData[vaultIDs[i]];\n // Computing if liquidation can take place for a vault\n LiquidationOpportunity memory liqOpp = _checkLiquidation(\n vault,\n msg.sender,\n liqData.oracleValue,\n liqData.newInterestAccumulator\n );\n\n // Makes sure not to leave a dusty amount in the vault by either not liquidating too much\n // or everything\n if (\n (liqOpp.thresholdRepayAmount != 0 && amounts[i] >= liqOpp.thresholdRepayAmount) ||\n amounts[i] > liqOpp.maxStablecoinAmountToRepay\n ) amounts[i] = liqOpp.maxStablecoinAmountToRepay;\n\n // liqOpp.discount stores in fact `1-discount`\n uint256 collateralReleased = (amounts[i] * BASE_PARAMS * _collatBase) /\n (liqOpp.discount * liqData.oracleValue);\n\n _checkpointCollateral(\n vaultIDs[i],\n vault.collateralAmount <= collateralReleased ? vault.collateralAmount : collateralReleased,\n false\n );\n // Because we're rounding up in some divisions, `collateralReleased` can be greater than the `collateralAmount` of the vault\n // In this case, `stablecoinAmountToReceive` is still rounded up\n if (vault.collateralAmount <= collateralReleased) {\n // Liquidators should never get more collateral than what's in the vault\n collateralReleased = vault.collateralAmount;\n // Remove all the vault's debt (debt repayed + bad debt) from VaultManager totalDebt\n totalNormalizedDebt -= vault.normalizedDebt;\n // Reinitializing the `vaultID`: we're not burning the vault in this case for integration purposes\n delete vaultData[vaultIDs[i]];\n {\n uint256 debtReimbursed = (amounts[i] * liquidationSurcharge) / BASE_PARAMS;\n liqData.badDebtFromLiquidation += debtReimbursed < liqOpp.currentDebt\n ? liqOpp.currentDebt - debtReimbursed\n : 0;\n }\n // There may be an edge case in which: `amounts[i] = (currentDebt * BASE_PARAMS) / surcharge + 1`\n // In this case, as long as `surcharge < BASE_PARAMS`, there cannot be any underflow in the operation\n // above\n emit InternalDebtUpdated(vaultIDs[i], vault.normalizedDebt, 0);\n } else {\n vaultData[vaultIDs[i]].collateralAmount -= collateralReleased;\n _repayDebt(\n vaultIDs[i],\n (amounts[i] * liquidationSurcharge) / BASE_PARAMS,\n liqData.newInterestAccumulator\n );\n }\n liqData.collateralAmountToGive += collateralReleased;\n liqData.stablecoinAmountToReceive += amounts[i];\n }\n // Normalization of good and bad debt is already handled in the `accrueInterestToTreasury` function\n surplus += (liqData.stablecoinAmountToReceive * (BASE_PARAMS - liquidationSurcharge)) / BASE_PARAMS;\n badDebt += liqData.badDebtFromLiquidation;\n _handleRepay(liqData.collateralAmountToGive, liqData.stablecoinAmountToReceive, from, to, who, data);\n }\n\n /// @notice Internal version of the `checkLiquidation` function\n /// @dev This function takes two additional parameters as when entering this function `oracleValue`\n /// and `newInterestAccumulator` should have always been computed\n function _checkLiquidation(\n Vault memory vault,\n address liquidator,\n uint256 oracleValue,\n uint256 newInterestAccumulator\n ) internal view returns (LiquidationOpportunity memory liqOpp) {\n // Checking if the vault can be liquidated\n (uint256 healthFactor, uint256 currentDebt, uint256 collateralAmountInStable) = _isSolvent(\n vault,\n oracleValue,\n newInterestAccumulator\n );\n // Health factor of a vault that does not exist is `type(uint256).max`\n if (healthFactor >= BASE_PARAMS) revert HealthyVault();\n\n uint256 liquidationDiscount = (_computeLiquidationBoost(liquidator) * (BASE_PARAMS - healthFactor)) /\n BASE_PARAMS;\n // In fact `liquidationDiscount` is stored here as 1 minus discount to save some computation costs\n // This value is necessarily != 0 as `maxLiquidationDiscount < BASE_PARAMS`\n liquidationDiscount = liquidationDiscount >= maxLiquidationDiscount\n ? BASE_PARAMS - maxLiquidationDiscount\n : BASE_PARAMS - liquidationDiscount;\n // Same for the surcharge here: it's in fact 1 - the fee taken by the protocol\n uint256 surcharge = liquidationSurcharge;\n uint256 maxAmountToRepay;\n uint256 thresholdRepayAmount;\n // Checking if we're in a situation where the health factor is an increasing or a decreasing function of the\n // amount repaid. In the first case, the health factor is an increasing function which means that the liquidator\n // can bring the vault to the target health ratio\n if (healthFactor * liquidationDiscount * surcharge >= collateralFactor * BASE_PARAMS ** 2) {\n // This is the max amount to repay that will bring the person to the target health factor\n // Denom is always positive when a vault gets liquidated in this case and when the health factor\n // is an increasing function of the amount of stablecoins repaid\n // And given that most parameters are in base 9, the numerator can very hardly overflow here\n maxAmountToRepay =\n ((targetHealthFactor * currentDebt - collateralAmountInStable * collateralFactor) *\n BASE_PARAMS *\n liquidationDiscount) /\n (surcharge * targetHealthFactor * liquidationDiscount - (BASE_PARAMS ** 2) * collateralFactor);\n // Need to check for the dust as liquidating should not leave a dusty amount in the vault\n uint256 dustParameter = dustLiquidation;\n if (currentDebt * BASE_PARAMS <= maxAmountToRepay * surcharge + dustParameter * BASE_PARAMS) {\n // If liquidating to the target threshold would leave a dusty amount: the liquidator can repay all.\n // We're avoiding here propagation of rounding errors and rounding up the max amount to repay to make\n // sure all the debt ends up being paid\n maxAmountToRepay =\n (vault.normalizedDebt * newInterestAccumulator * BASE_PARAMS) /\n (surcharge * BASE_INTEREST) +\n 1;\n // In this case the threshold amount is such that it leaves just enough dust: amount is rounded\n // down such that if a liquidator repays this amount then there is more than `dustLiquidation` left in\n // the liquidated vault\n if (currentDebt > dustParameter)\n thresholdRepayAmount = ((currentDebt - dustParameter) * BASE_PARAMS) / surcharge;\n // If there is from the beginning a dusty debt, then liquidator should repay everything that's left\n else thresholdRepayAmount = 1;\n }\n } else {\n // In this case, the liquidator can repay stablecoins such that they'll end up getting exactly the collateral\n // in the liquidated vault\n maxAmountToRepay =\n (vault.collateralAmount * liquidationDiscount * oracleValue) /\n (BASE_PARAMS * _collatBase) +\n 1;\n // It should however make sure not to leave a dusty amount of collateral (in stablecoin value) in the vault\n if (collateralAmountInStable > _dustCollateral)\n // There's no issue with this amount being rounded down\n thresholdRepayAmount =\n ((collateralAmountInStable - _dustCollateral) * liquidationDiscount) /\n BASE_PARAMS;\n // If there is from the beginning a dusty amount of collateral, liquidator should repay everything that's left\n else thresholdRepayAmount = 1;\n }\n liqOpp.maxStablecoinAmountToRepay = maxAmountToRepay;\n liqOpp.maxCollateralAmountGiven =\n (maxAmountToRepay * BASE_PARAMS * _collatBase) /\n (oracleValue * liquidationDiscount);\n liqOpp.thresholdRepayAmount = thresholdRepayAmount;\n liqOpp.discount = liquidationDiscount;\n liqOpp.currentDebt = currentDebt;\n }\n\n // ================================== SETTERS ==================================\n\n /// @notice Sets parameters encoded as uint64\n /// @param param Value for the parameter\n /// @param what Parameter to change\n /// @dev This function performs the required checks when updating a parameter\n /// @dev When setting parameters governance or the guardian should make sure that when `HF < CF/((1-surcharge)(1-discount))`\n /// and hence when liquidating a vault is going to decrease its health factor, `discount = max discount`.\n /// Otherwise, it may be profitable for the liquidator to liquidate in multiple times: as it will decrease\n /// the HF and therefore increase the discount between each time\n function setUint64(uint64 param, bytes32 what) external virtual onlyGovernorOrGuardian {\n if (what == \"CF\") {\n if (param > liquidationSurcharge) revert TooHighParameterValue();\n collateralFactor = param;\n } else if (what == \"THF\") {\n if (param < BASE_PARAMS) revert TooSmallParameterValue();\n targetHealthFactor = param;\n } else if (what == \"BF\") {\n if (param > BASE_PARAMS) revert TooHighParameterValue();\n borrowFee = param;\n } else if (what == \"RF\") {\n // As liquidation surcharge is stored as `1-fee` and as we need `repayFee` to be smaller\n // than the liquidation surcharge, we need to have:\n // `liquidationSurcharge <= BASE_PARAMS - repayFee` and as such `liquidationSurcharge + repayFee <= BASE_PARAMS`\n if (param + liquidationSurcharge > BASE_PARAMS) revert TooHighParameterValue();\n repayFee = param;\n } else if (what == \"IR\") {\n _accrue();\n interestRate = param;\n } else if (what == \"LS\") {\n if (collateralFactor > param || param + repayFee > BASE_PARAMS) revert InvalidParameterValue();\n liquidationSurcharge = param;\n } else if (what == \"MLD\") {\n if (param > BASE_PARAMS) revert TooHighParameterValue();\n maxLiquidationDiscount = param;\n } else {\n revert InvalidParameterType();\n }\n emit FiledUint64(param, what);\n }\n\n /// @notice Sets `debtCeiling`\n /// @param _debtCeiling New value for `debtCeiling`\n /// @dev `debtCeiling` should not be bigger than `type(uint256).max / 10**27` otherwise there could be overflows\n function setDebtCeiling(uint256 _debtCeiling) external onlyGovernorOrGuardian {\n debtCeiling = _debtCeiling;\n emit DebtCeilingUpdated(_debtCeiling);\n }\n\n /// @notice Sets the parameters for the liquidation booster which encodes the slope of the discount\n function setLiquidationBoostParameters(\n address _veBoostProxy,\n uint256[] memory xBoost,\n uint256[] memory yBoost\n ) external virtual onlyGovernorOrGuardian {\n if (yBoost[0] == 0) revert InvalidSetOfParameters();\n yLiquidationBoost = yBoost;\n emit LiquidationBoostParametersUpdated(_veBoostProxy, xBoost, yBoost);\n }\n\n /// @notice Pauses external permissionless functions of the contract\n function togglePause() external virtual onlyGovernorOrGuardian {\n paused = !paused;\n }\n\n /// @notice Changes the ERC721 metadata URI\n function setBaseURI(string memory baseURI_) external onlyGovernorOrGuardian {\n _baseURI = baseURI_;\n }\n\n /// @notice Changes the whitelisting of an address\n /// @param target Address to toggle\n /// @dev If the `target` address is the zero address then this function toggles whitelisting\n /// for all addresses\n function toggleWhitelist(address target) external virtual onlyGovernor {\n if (target != address(0)) {\n isWhitelisted[target] = 1 - isWhitelisted[target];\n } else {\n whitelistingActivated = !whitelistingActivated;\n }\n }\n\n /// @notice Changes the reference to the oracle contract used to get the price of the oracle\n /// @param _oracle Reference to the oracle contract\n function setOracle(address _oracle) external virtual onlyGovernor {\n if (IOracle(_oracle).treasury() != treasury) revert InvalidTreasury();\n oracle = IOracle(_oracle);\n }\n\n /// @notice Sets the dust variables\n /// @param _dust New minimum debt allowed\n /// @param _dustLiquidation New `dustLiquidation` value\n /// @param dustCollateral_ New minimum collateral allowed in a vault after a liquidation\n /// @dev dustCollateral_ is in stable value\n function setDusts(uint256 _dust, uint256 _dustLiquidation, uint256 dustCollateral_) external onlyGovernor {\n if (_dust > _dustLiquidation) revert InvalidParameterValue();\n dust = _dust;\n dustLiquidation = _dustLiquidation;\n _dustCollateral = dustCollateral_;\n }\n\n /// @inheritdoc IVaultManagerFunctions\n function setTreasury(address _treasury) external virtual onlyTreasury {\n treasury = ITreasury(_treasury);\n // This function makes sure to propagate the change to the associated contract\n // even though a single oracle contract could be used in different places\n oracle.setTreasury(_treasury);\n }\n\n // ============================= VIRTUAL FUNCTIONS =============================\n\n /// @notice Returns the liquidation boost of a given address, that is the slope of the discount function\n /// @return The slope of the discount function\n function _computeLiquidationBoost(address) internal view virtual returns (uint256) {\n return yLiquidationBoost[0];\n }\n\n /// @notice Hook called before any collateral internal changes\n /// @param vaultID Vault which sees its collateral amount changed\n /// @param amount Collateral amount balance of the owner of vaultID increase/decrease\n /// @param add Whether the balance should be increased/decreased\n /// @param vaultID Vault which sees its collateral amount changed\n function _checkpointCollateral(uint256 vaultID, uint256 amount, bool add) internal virtual {}\n\n /// @notice Get `paused` in storage only if needed\n function _paused() internal view virtual returns (bool) {\n return paused;\n }\n\n /// @notice Get `repayFee` in storage only if needed\n function _repayFee() internal view virtual returns (uint64) {\n return repayFee;\n }\n}\n" + }, + "contracts/vaultManager/VaultManagerPermit.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"./VaultManagerERC721.sol\";\nimport \"../interfaces/external/IERC1271.sol\";\n\n/// @title VaultManagerPermit\n/// @author Angle Labs, Inc.\n/// @dev Base Implementation of permit functions for the `VaultManager` contract\nabstract contract VaultManagerPermit is Initializable, VaultManagerERC721 {\n using Address for address;\n\n mapping(address => uint256) private _nonces;\n /* solhint-disable var-name-mixedcase */\n bytes32 private _HASHED_NAME;\n bytes32 private _HASHED_VERSION;\n bytes32 private _PERMIT_TYPEHASH;\n /* solhint-enable var-name-mixedcase */\n\n error ExpiredDeadline();\n error InvalidSignature();\n\n //solhint-disable-next-line\n function __ERC721Permit_init(string memory _name) internal onlyInitializing {\n _PERMIT_TYPEHASH = keccak256(\n \"Permit(address owner,address spender,bool approved,uint256 nonce,uint256 deadline)\"\n );\n _HASHED_NAME = keccak256(bytes(_name));\n _HASHED_VERSION = keccak256(bytes(\"1\"));\n }\n\n /// @notice Allows an address to give or revoke approval for all its vaults to another address\n /// @param owner Address signing the permit and giving (or revoking) its approval for all the controlled vaults\n /// @param spender Address to give approval to\n /// @param approved Whether to give or revoke the approval\n /// @param deadline Deadline parameter for the signature to be valid\n /// @dev The `v`, `r`, and `s` parameters are used as signature data\n function permit(\n address owner,\n address spender,\n bool approved,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external {\n if (block.timestamp > deadline) revert ExpiredDeadline();\n // Additional signature checks performed in the `ECDSAUpgradeable.recover` function\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 || (v != 27 && v != 28))\n revert InvalidSignature();\n\n bytes32 digest = keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n _domainSeparatorV4(),\n keccak256(\n abi.encode(\n _PERMIT_TYPEHASH,\n // 0x3f43a9c6bafb5c7aab4e0cfe239dc5d4c15caf0381c6104188191f78a6640bd8,\n owner,\n spender,\n approved,\n _useNonce(owner),\n deadline\n )\n )\n )\n );\n if (owner.isContract()) {\n if (IERC1271(owner).isValidSignature(digest, abi.encodePacked(r, s, v)) != 0x1626ba7e)\n revert InvalidSignature();\n } else {\n address signer = ecrecover(digest, v, r, s);\n if (signer != owner || signer == address(0)) revert InvalidSignature();\n }\n\n _setApprovalForAll(owner, spender, approved);\n }\n\n /// @notice Returns the current nonce for an `owner` address\n function nonces(address owner) public view returns (uint256) {\n return _nonces[owner];\n }\n\n /// @notice Returns the domain separator for the current chain.\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /// @notice Internal version of the `DOMAIN_SEPARATOR` function\n function _domainSeparatorV4() internal view returns (bytes32) {\n return\n keccak256(\n abi.encode(\n // keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)')\n 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f,\n _HASHED_NAME,\n _HASHED_VERSION,\n block.chainid,\n address(this)\n )\n );\n }\n\n /// @notice Consumes a nonce for an address: returns the current value and increments it\n function _useNonce(address owner) internal returns (uint256 current) {\n current = _nonces[owner];\n _nonces[owner] = current + 1;\n }\n\n uint256[49] private __gap;\n}\n" + }, + "contracts/vaultManager/VaultManagerERC721.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"./VaultManagerStorage.sol\";\n\n/// @title VaultManagerERC721\n/// @author Angle Labs, Inc.\n/// @dev Base ERC721 Implementation of VaultManager\nabstract contract VaultManagerERC721 is IERC721MetadataUpgradeable, VaultManagerStorage {\n using SafeERC20 for IERC20;\n using Address for address;\n\n /// @inheritdoc IERC721MetadataUpgradeable\n string public name;\n /// @inheritdoc IERC721MetadataUpgradeable\n string public symbol;\n\n // ================================= MODIFIERS =================================\n\n /// @notice Checks if the person interacting with the vault with `vaultID` is approved\n /// @param caller Address of the person seeking to interact with the vault\n /// @param vaultID ID of the concerned vault\n modifier onlyApprovedOrOwner(address caller, uint256 vaultID) {\n if (!_isApprovedOrOwner(caller, vaultID)) revert NotApproved();\n _;\n }\n\n // ================================ ERC721 LOGIC ===============================\n\n /// @notice Checks whether a given address is approved for a vault or owns this vault\n /// @param spender Address for which vault ownership should be checked\n /// @param vaultID ID of the vault to check\n /// @return Whether the `spender` address owns or is approved for `vaultID`\n function isApprovedOrOwner(address spender, uint256 vaultID) external view returns (bool) {\n return _isApprovedOrOwner(spender, vaultID);\n }\n\n /// @inheritdoc IERC721MetadataUpgradeable\n function tokenURI(uint256 vaultID) external view returns (string memory) {\n if (!_exists(vaultID)) revert NonexistentVault();\n // There is no vault with `vaultID` equal to 0, so the following variable is\n // always greater than zero\n uint256 temp = vaultID;\n uint256 digits;\n while (temp != 0) {\n ++digits;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (vaultID != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(vaultID % 10)));\n vaultID /= 10;\n }\n return bytes(_baseURI).length != 0 ? string(abi.encodePacked(_baseURI, string(buffer))) : \"\";\n }\n\n /// @inheritdoc IERC721Upgradeable\n function balanceOf(address owner) external view returns (uint256) {\n if (owner == address(0)) revert ZeroAddress();\n return _balances[owner];\n }\n\n /// @inheritdoc IERC721Upgradeable\n function ownerOf(uint256 vaultID) external view returns (address) {\n return _ownerOf(vaultID);\n }\n\n /// @inheritdoc IERC721Upgradeable\n function approve(address to, uint256 vaultID) external {\n address owner = _ownerOf(vaultID);\n if (to == owner) revert ApprovalToOwner();\n if (msg.sender != owner && !isApprovedForAll(owner, msg.sender)) revert NotApproved();\n\n _approve(to, vaultID);\n }\n\n /// @inheritdoc IERC721Upgradeable\n function getApproved(uint256 vaultID) external view returns (address) {\n if (!_exists(vaultID)) revert NonexistentVault();\n return _getApproved(vaultID);\n }\n\n /// @inheritdoc IERC721Upgradeable\n function setApprovalForAll(address operator, bool approved) external {\n _setApprovalForAll(msg.sender, operator, approved);\n }\n\n /// @inheritdoc IERC721Upgradeable\n function isApprovedForAll(address owner, address operator) public view returns (bool) {\n return _operatorApprovals[owner][operator] == 1;\n }\n\n /// @inheritdoc IERC721Upgradeable\n function transferFrom(address from, address to, uint256 vaultID) external onlyApprovedOrOwner(msg.sender, vaultID) {\n _transfer(from, to, vaultID);\n }\n\n /// @inheritdoc IERC721Upgradeable\n function safeTransferFrom(address from, address to, uint256 vaultID) external {\n safeTransferFrom(from, to, vaultID, \"\");\n }\n\n /// @inheritdoc IERC721Upgradeable\n function safeTransferFrom(\n address from,\n address to,\n uint256 vaultID,\n bytes memory _data\n ) public onlyApprovedOrOwner(msg.sender, vaultID) {\n _safeTransfer(from, to, vaultID, _data);\n }\n\n // ================================ ERC165 LOGIC ===============================\n\n /// @inheritdoc IERC165Upgradeable\n function supportsInterface(bytes4 interfaceId) external pure returns (bool) {\n return\n interfaceId == type(IERC721MetadataUpgradeable).interfaceId ||\n interfaceId == type(IERC721Upgradeable).interfaceId ||\n interfaceId == type(IVaultManager).interfaceId ||\n interfaceId == type(IERC165Upgradeable).interfaceId;\n }\n\n // ================== INTERNAL FUNCTIONS FOR THE ERC721 LOGIC ==================\n\n /// @notice Internal version of the `ownerOf` function\n function _ownerOf(uint256 vaultID) internal view returns (address owner) {\n owner = _owners[vaultID];\n if (owner == address(0)) revert NonexistentVault();\n }\n\n /// @notice Internal version of the `getApproved` function\n function _getApproved(uint256 vaultID) internal view returns (address) {\n return _vaultApprovals[vaultID];\n }\n\n /// @notice Internal version of the `safeTransferFrom` function (with the data parameter)\n function _safeTransfer(address from, address to, uint256 vaultID, bytes memory _data) internal {\n _transfer(from, to, vaultID);\n if (!_checkOnERC721Received(from, to, vaultID, _data)) revert NonERC721Receiver();\n }\n\n /// @notice Checks whether a vault exists\n /// @param vaultID ID of the vault to check\n /// @return Whether `vaultID` has been created\n function _exists(uint256 vaultID) internal view returns (bool) {\n return _owners[vaultID] != address(0);\n }\n\n /// @notice Internal version of the `isApprovedOrOwner` function\n function _isApprovedOrOwner(address spender, uint256 vaultID) internal view returns (bool) {\n // The following checks if the vault exists\n address owner = _ownerOf(vaultID);\n return (spender == owner || _getApproved(vaultID) == spender || _operatorApprovals[owner][spender] == 1);\n }\n\n /// @notice Internal version of the `createVault` function\n /// Mints `vaultID` and transfers it to `to`\n /// @dev This method is equivalent to the `_safeMint` method used in OpenZeppelin ERC721 contract\n /// @dev Emits a {Transfer} event\n function _mint(address to) internal returns (uint256 vaultID) {\n if (to == address(0)) revert ZeroAddress();\n\n unchecked {\n vaultIDCount += 1;\n }\n\n vaultID = vaultIDCount;\n _beforeTokenTransfer(address(0), to, vaultID);\n\n unchecked {\n _balances[to] += 1;\n }\n\n _owners[vaultID] = to;\n emit Transfer(address(0), to, vaultID);\n if (!_checkOnERC721Received(address(0), to, vaultID, \"\")) revert NonERC721Receiver();\n }\n\n /// @notice Destroys `vaultID`\n /// @dev `vaultID` must exist\n /// @dev Emits a {Transfer} event\n function _burn(uint256 vaultID) internal {\n address owner = _ownerOf(vaultID);\n\n _beforeTokenTransfer(owner, address(0), vaultID);\n // Clear approvals\n _approve(address(0), vaultID);\n // The following line cannot underflow as the owner's balance is necessarily\n // greater than 1\n unchecked {\n _balances[owner] -= 1;\n }\n delete _owners[vaultID];\n delete vaultData[vaultID];\n\n emit Transfer(owner, address(0), vaultID);\n }\n\n /// @notice Transfers `vaultID` from `from` to `to` as opposed to {transferFrom},\n /// this imposes no restrictions on msg.sender\n /// @dev `to` cannot be the zero address and `perpetualID` must be owned by `from`\n /// @dev Emits a {Transfer} event\n function _transfer(address from, address to, uint256 vaultID) internal {\n if (_ownerOf(vaultID) != from) revert NotApproved();\n if (to == address(0)) revert ZeroAddress();\n\n _beforeTokenTransfer(from, to, vaultID);\n\n // Clear approvals from the previous owner\n _approve(address(0), vaultID);\n unchecked {\n _balances[from] -= 1;\n _balances[to] += 1;\n }\n _owners[vaultID] = to;\n\n emit Transfer(from, to, vaultID);\n }\n\n /// @notice Approves `to` to operate on `vaultID`\n function _approve(address to, uint256 vaultID) internal {\n _vaultApprovals[vaultID] = to;\n emit Approval(_ownerOf(vaultID), to, vaultID);\n }\n\n /// @notice Internal version of the `setApprovalForAll` function\n /// @dev It contains an `approver` field to be used in case someone signs a permit for a particular\n /// address, and this signature is given to the contract by another address (like a router)\n function _setApprovalForAll(address approver, address operator, bool approved) internal {\n if (operator == approver) revert ApprovalToCaller();\n uint256 approval = approved ? 1 : 0;\n _operatorApprovals[approver][operator] = approval;\n emit ApprovalForAll(approver, operator, approved);\n }\n\n /// @notice Internal function to invoke {IERC721Receiver-onERC721Received} on a target address\n /// The call is not executed if the target address is not a contract\n /// @param from Address representing the previous owner of the given token ID\n /// @param to Target address that will receive the tokens\n /// @param vaultID ID of the token to be transferred\n /// @param _data Bytes optional data to send along with the call\n /// @return Bool whether the call correctly returned the expected value\n function _checkOnERC721Received(\n address from,\n address to,\n uint256 vaultID,\n bytes memory _data\n ) private returns (bool) {\n if (to.isContract()) {\n try IERC721ReceiverUpgradeable(to).onERC721Received(msg.sender, from, vaultID, _data) returns (\n bytes4 retval\n ) {\n return retval == IERC721ReceiverUpgradeable.onERC721Received.selector;\n } catch (bytes memory reason) {\n if (reason.length == 0) {\n revert NonERC721Receiver();\n } else {\n // solhint-disable-next-line no-inline-assembly\n assembly {\n revert(add(32, reason), mload(reason))\n }\n }\n }\n } else {\n return true;\n }\n }\n\n /// @notice Hook that is called before any token transfer. This includes minting and burning.\n /// Calling conditions:\n ///\n /// - When `from` and `to` are both non-zero, `from`'s `vaultID` will be\n /// transferred to `to`.\n /// - When `from` is zero, `vaultID` will be minted for `to`.\n /// - When `to` is zero, `from`'s `vaultID` will be burned.\n /// - `from` and `to` are never both zero.\n function _beforeTokenTransfer(address from, address to, uint256 vaultID) internal virtual {}\n\n /// @notice Get `whitelistingActivated` in storage only if needed\n function _whitelistingActivated() internal view virtual returns (bool) {\n return whitelistingActivated;\n }\n}\n" + }, + "contracts/interfaces/external/IERC1271.sol": { + "content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity ^0.8.12;\n\n/// @title Interface for verifying contract-based account signatures\n/// @notice Interface that verifies provided signature for the data\n/// @dev Interface defined by EIP-1271\ninterface IERC1271 {\n /// @notice Returns whether the provided signature is valid for the provided data\n /// @dev MUST return the bytes4 magic value 0x1626ba7e when function passes.\n /// MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5).\n /// MUST allow external calls.\n /// @param hash Hash of the data to be signed\n /// @param signature Signature byte array associated with _data\n /// @return magicValue The bytes4 magic value 0x1626ba7e\n function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);\n}\n" + }, + "contracts/vaultManager/VaultManagerStorage.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/interfaces/IERC721MetadataUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport \"../interfaces/IAgToken.sol\";\nimport \"../interfaces/IOracle.sol\";\nimport \"../interfaces/ISwapper.sol\";\nimport \"../interfaces/ITreasury.sol\";\nimport \"../interfaces/IVaultManager.sol\";\nimport \"../interfaces/governance/IVeBoostProxy.sol\";\n\n/// @title VaultManagerStorage\n/// @author Angle Labs, Inc.\n/// @dev Variables, references, parameters and events needed in the `VaultManager` contract\n// solhint-disable-next-line max-states-count\ncontract VaultManagerStorage is IVaultManagerStorage, Initializable, ReentrancyGuardUpgradeable {\n /// @notice Base used for parameter computation: almost all the parameters of this contract are set in `BASE_PARAMS`\n uint256 public constant BASE_PARAMS = 10**9;\n /// @notice Base used for interest rate computation\n uint256 public constant BASE_INTEREST = 10**27;\n /// @notice Used for interest rate computation\n uint256 public constant HALF_BASE_INTEREST = 10**27 / 2;\n\n // ================================= REFERENCES ================================\n\n /// @inheritdoc IVaultManagerStorage\n ITreasury public treasury;\n /// @inheritdoc IVaultManagerStorage\n IERC20 public collateral;\n /// @inheritdoc IVaultManagerStorage\n IAgToken public stablecoin;\n /// @inheritdoc IVaultManagerStorage\n IOracle public oracle;\n /// @notice Reference to the contract which computes adjusted veANGLE balances for liquidators boosts\n IVeBoostProxy public veBoostProxy;\n /// @notice Base of the collateral\n uint256 internal _collatBase;\n\n // ================================= PARAMETERS ================================\n // Unless specified otherwise, parameters of this contract are expressed in `BASE_PARAMS`\n\n /// @notice Maximum amount of stablecoins that can be issued with this contract (in `BASE_TOKENS`). This parameter should\n /// not be bigger than `type(uint256).max / BASE_INTEREST` otherwise there may be some overflows in the `increaseDebt` function\n uint256 public debtCeiling;\n /// @notice Threshold veANGLE balance values for the computation of the boost for liquidators: the length of this array\n /// should normally be 2. The base of the x-values in this array should be `BASE_TOKENS`\n uint256[] public xLiquidationBoost;\n /// @notice Values of the liquidation boost at the threshold values of x\n uint256[] public yLiquidationBoost;\n /// @inheritdoc IVaultManagerStorage\n uint64 public collateralFactor;\n /// @notice Maximum Health factor at which a vault can end up after a liquidation (unless it's fully liquidated)\n uint64 public targetHealthFactor;\n /// @notice Upfront fee taken when borrowing stablecoins: this fee is optional and should in practice not be used\n uint64 public borrowFee;\n /// @notice Upfront fee taken when repaying stablecoins: this fee is optional as well. It should be smaller\n /// than the liquidation surcharge (cf below) to avoid exploits where people voluntarily get liquidated at a 0\n /// discount to pay smaller repaying fees\n uint64 public repayFee;\n /// @notice Per second interest taken to borrowers taking agToken loans. Contrarily to other parameters, it is set in `BASE_INTEREST`\n /// that is to say in base 10**27\n uint64 public interestRate;\n /// @notice Fee taken by the protocol during a liquidation. Technically, this value is not the fee per se, it's 1 - fee.\n /// For instance for a 2% fee, `liquidationSurcharge` should be 98%\n uint64 public liquidationSurcharge;\n /// @notice Maximum discount given to liquidators\n uint64 public maxLiquidationDiscount;\n /// @notice Whether whitelisting is required to own a vault or not\n bool public whitelistingActivated;\n /// @notice Whether the contract is paused or not\n bool public paused;\n\n // ================================= VARIABLES =================================\n\n /// @notice Timestamp at which the `interestAccumulator` was updated\n uint256 public lastInterestAccumulatorUpdated;\n /// @inheritdoc IVaultManagerStorage\n uint256 public interestAccumulator;\n /// @inheritdoc IVaultManagerStorage\n uint256 public totalNormalizedDebt;\n /// @notice Surplus accumulated by the contract: surplus is always in stablecoins, and is then reset\n /// when the value is communicated to the treasury contract\n uint256 public surplus;\n /// @notice Bad debt made from liquidated vaults which ended up having no collateral and a positive amount\n /// of stablecoins\n uint256 public badDebt;\n\n // ================================== MAPPINGS =================================\n\n /// @inheritdoc IVaultManagerStorage\n mapping(uint256 => Vault) public vaultData;\n /// @notice Maps an address to 1 if it's whitelisted and can open or own a vault\n mapping(address => uint256) public isWhitelisted;\n\n // ================================ ERC721 DATA ================================\n\n /// @inheritdoc IVaultManagerStorage\n uint256 public vaultIDCount;\n\n /// @notice URI\n string internal _baseURI;\n\n // Mapping from `vaultID` to owner address\n mapping(uint256 => address) internal _owners;\n\n // Mapping from owner address to vault owned count\n mapping(address => uint256) internal _balances;\n\n // Mapping from `vaultID` to approved address\n mapping(uint256 => address) internal _vaultApprovals;\n\n // Mapping from owner to operator approvals\n mapping(address => mapping(address => uint256)) internal _operatorApprovals;\n\n uint256[50] private __gap;\n\n // =================================== EVENTS ==================================\n\n event AccruedToTreasury(uint256 surplusEndValue, uint256 badDebtEndValue);\n event CollateralAmountUpdated(uint256 vaultID, uint256 collateralAmount, uint8 isIncrease);\n event InterestAccumulatorUpdated(uint256 value, uint256 timestamp);\n event InternalDebtUpdated(uint256 vaultID, uint256 internalAmount, uint8 isIncrease);\n event FiledUint64(uint64 param, bytes32 what);\n event DebtCeilingUpdated(uint256 debtCeiling);\n event LiquidationBoostParametersUpdated(address indexed _veBoostProxy, uint256[] xBoost, uint256[] yBoost);\n event LiquidatedVaults(uint256[] vaultIDs);\n event DebtTransferred(uint256 srcVaultID, uint256 dstVaultID, address dstVaultManager, uint256 amount);\n\n // =================================== ERRORS ==================================\n\n error ApprovalToOwner();\n error ApprovalToCaller();\n error DustyLeftoverAmount();\n error DebtCeilingExceeded();\n error HealthyVault();\n error IncompatibleLengths();\n error InsolventVault();\n error InvalidParameterValue();\n error InvalidParameterType();\n error InvalidSetOfParameters();\n error InvalidTreasury();\n error NonERC721Receiver();\n error NonexistentVault();\n error NotApproved();\n error NotGovernor();\n error NotGovernorOrGuardian();\n error NotTreasury();\n error NotWhitelisted();\n error NotVaultManager();\n error Paused();\n error TooHighParameterValue();\n error TooSmallParameterValue();\n error ZeroAddress();\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() initializer {}\n}\n" + }, + "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n * @custom:oz-retyped-from bool\n */\n uint8 private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint8 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.\n */\n modifier initializer() {\n bool isTopLevelCall = !_initializing;\n require(\n (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n \"Initializable: contract is already initialized\"\n );\n _initialized = 1;\n if (isTopLevelCall) {\n _initializing = true;\n }\n _;\n if (isTopLevelCall) {\n _initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n * initialization step. This is essential to configure modules that are added through upgrades and that require\n * initialization.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n */\n modifier reinitializer(uint8 version) {\n require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n _initialized = version;\n _initializing = true;\n _;\n _initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n require(_initializing, \"Initializable: contract is not initializing\");\n _;\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n */\n function _disableInitializers() internal virtual {\n require(!_initializing, \"Initializable: contract is initializing\");\n if (_initialized < type(uint8).max) {\n _initialized = type(uint8).max;\n emit Initialized(type(uint8).max);\n }\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20PermitUpgradeable {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721ReceiverUpgradeable {\n /**\n * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n * by `operator` from `from`, this function is called.\n *\n * It must return its Solidity selector to confirm the token transfer.\n * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.\n *\n * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.\n */\n function onERC721Received(\n address operator,\n address from,\n uint256 tokenId,\n bytes calldata data\n ) external returns (bytes4);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/interfaces/IERC721MetadataUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../token/ERC721/extensions/IERC721MetadataUpgradeable.sol\";\n" + }, + "@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165Upgradeable {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n function __ReentrancyGuard_init() internal onlyInitializing {\n __ReentrancyGuard_init_unchained();\n }\n\n function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n // On the first call to nonReentrant, _notEntered will be true\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n\n _;\n\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n function safePermit(\n IERC20Permit token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "contracts/interfaces/IAgToken.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\n\n/// @title IAgToken\n/// @author Angle Labs, Inc.\n/// @notice Interface for the stablecoins `AgToken` contracts\n/// @dev This interface only contains functions of the `AgToken` contract which are called by other contracts\n/// of this module or of the first module of the Angle Protocol\ninterface IAgToken is IERC20Upgradeable {\n // ======================= Minter Role Only Functions ===========================\n\n /// @notice Lets the `StableMaster` contract or another whitelisted contract mint agTokens\n /// @param account Address to mint to\n /// @param amount Amount to mint\n /// @dev The contracts allowed to issue agTokens are the `StableMaster` contract, `VaultManager` contracts\n /// associated to this stablecoin as well as the flash loan module (if activated) and potentially contracts\n /// whitelisted by governance\n function mint(address account, uint256 amount) external;\n\n /// @notice Burns `amount` tokens from a `burner` address after being asked to by `sender`\n /// @param amount Amount of tokens to burn\n /// @param burner Address to burn from\n /// @param sender Address which requested the burn from `burner`\n /// @dev This method is to be called by a contract with the minter right after being requested\n /// to do so by a `sender` address willing to burn tokens from another `burner` address\n /// @dev The method checks the allowance between the `sender` and the `burner`\n function burnFrom(\n uint256 amount,\n address burner,\n address sender\n ) external;\n\n /// @notice Burns `amount` tokens from a `burner` address\n /// @param amount Amount of tokens to burn\n /// @param burner Address to burn from\n /// @dev This method is to be called by a contract with a minter right on the AgToken after being\n /// requested to do so by an address willing to burn tokens from its address\n function burnSelf(uint256 amount, address burner) external;\n\n // ========================= Treasury Only Functions ===========================\n\n /// @notice Adds a minter in the contract\n /// @param minter Minter address to add\n /// @dev Zero address checks are performed directly in the `Treasury` contract\n function addMinter(address minter) external;\n\n /// @notice Removes a minter from the contract\n /// @param minter Minter address to remove\n /// @dev This function can also be called by a minter wishing to revoke itself\n function removeMinter(address minter) external;\n\n /// @notice Sets a new treasury contract\n /// @param _treasury New treasury address\n function setTreasury(address _treasury) external;\n\n // ========================= External functions ================================\n\n /// @notice Checks whether an address has the right to mint agTokens\n /// @param minter Address for which the minting right should be checked\n /// @return Whether the address has the right to mint agTokens or not\n function isMinter(address minter) external view returns (bool);\n\n /// @notice Get the associated treasury\n function treasury() external view returns (address);\n}\n" + }, + "contracts/interfaces/IOracle.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"./ITreasury.sol\";\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\n/// @title IOracle\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `Oracle` contract\n/// @dev This interface only contains functions of the contract which are called by other contracts\n/// of this module\ninterface IOracle {\n /// @notice Reads the rate from the Chainlink circuit and other data provided\n /// @return quoteAmount The current rate between the in-currency and out-currency in the base\n /// of the out currency\n /// @dev For instance if the out currency is EUR (and hence agEUR), then the base of the returned\n /// value is 10**18\n function read() external view returns (uint256);\n\n /// @notice Changes the treasury contract\n /// @param _treasury Address of the new treasury contract\n /// @dev This function can be called by an approved `VaultManager` contract which can call\n /// this function after being requested to do so by a `treasury` contract\n /// @dev In some situations (like reactor contracts), the `VaultManager` may not directly be linked\n /// to the `oracle` contract and as such we may need governors to be able to call this function as well\n function setTreasury(address _treasury) external;\n\n /// @notice Reference to the `treasury` contract handling this `VaultManager`\n function treasury() external view returns (ITreasury treasury);\n\n /// @notice Array with the list of Chainlink feeds in the order in which they are read\n function circuitChainlink() external view returns (AggregatorV3Interface[] memory);\n}\n" + }, + "contracts/interfaces/ISwapper.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/// @title ISwapper\n/// @author Angle Labs, Inc.\n/// @notice Interface for Swapper contracts\n/// @dev This interface defines the key functions `Swapper` contracts should have when interacting with\n/// Angle\ninterface ISwapper {\n /// @notice Notifies a contract that an address should be given `outToken` from `inToken`\n /// @param inToken Address of the token received\n /// @param outToken Address of the token to obtain\n /// @param outTokenRecipient Address to which the outToken should be sent\n /// @param outTokenOwed Minimum amount of outToken the `outTokenRecipient` address should have at the end of the call\n /// @param inTokenObtained Amount of collateral obtained by a related address prior\n /// to the call to this function\n /// @param data Extra data needed (to encode Uniswap swaps for instance)\n function swap(\n IERC20 inToken,\n IERC20 outToken,\n address outTokenRecipient,\n uint256 outTokenOwed,\n uint256 inTokenObtained,\n bytes calldata data\n ) external;\n}\n" + }, + "contracts/interfaces/ITreasury.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"./IAgToken.sol\";\nimport \"./ICoreBorrow.sol\";\nimport \"./IFlashAngle.sol\";\n\n/// @title ITreasury\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `Treasury` contract\n/// @dev This interface only contains functions of the `Treasury` which are called by other contracts\n/// of this module\ninterface ITreasury {\n /// @notice Stablecoin handled by this `treasury` contract\n function stablecoin() external view returns (IAgToken);\n\n /// @notice Checks whether a given address has the governor role\n /// @param admin Address to check\n /// @return Whether the address has the governor role\n /// @dev Access control is only kept in the `CoreBorrow` contract\n function isGovernor(address admin) external view returns (bool);\n\n /// @notice Checks whether a given address has the guardian or the governor role\n /// @param admin Address to check\n /// @return Whether the address has the guardian or the governor role\n /// @dev Access control is only kept in the `CoreBorrow` contract which means that this function\n /// queries the `CoreBorrow` contract\n function isGovernorOrGuardian(address admin) external view returns (bool);\n\n /// @notice Checks whether a given address has well been initialized in this contract\n /// as a `VaultManager`\n /// @param _vaultManager Address to check\n /// @return Whether the address has been initialized or not\n function isVaultManager(address _vaultManager) external view returns (bool);\n\n /// @notice Sets a new flash loan module for this stablecoin\n /// @param _flashLoanModule Reference to the new flash loan module\n /// @dev This function removes the minting right to the old flash loan module and grants\n /// it to the new module\n function setFlashLoanModule(address _flashLoanModule) external;\n}\n" + }, + "contracts/interfaces/IVaultManager.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"@openzeppelin/contracts/interfaces/IERC721Metadata.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./ITreasury.sol\";\nimport \"./IOracle.sol\";\n\n// ========================= Key Structs and Enums =============================\n\n/// @notice Parameters associated to a given `VaultManager` contract: these all correspond\n/// to parameters which signification is detailed in the `VaultManagerStorage` file\nstruct VaultParameters {\n uint256 debtCeiling;\n uint64 collateralFactor;\n uint64 targetHealthFactor;\n uint64 interestRate;\n uint64 liquidationSurcharge;\n uint64 maxLiquidationDiscount;\n bool whitelistingActivated;\n uint256 baseBoost;\n}\n\n/// @notice Data stored to track someone's loan (or equivalently called position)\nstruct Vault {\n // Amount of collateral deposited in the vault, in collateral decimals. For example, if the collateral\n // is USDC with 6 decimals, then `collateralAmount` will be in base 10**6\n uint256 collateralAmount;\n // Normalized value of the debt (that is to say of the stablecoins borrowed). It is expressed\n // in the base of Angle stablecoins (i.e. `BASE_TOKENS = 10**18`)\n uint256 normalizedDebt;\n}\n\n/// @notice For a given `vaultID`, this encodes a liquidation opportunity that is to say details about the maximum\n/// amount that could be repaid by liquidating the position\n/// @dev All the values are null in the case of a vault which cannot be liquidated under these conditions\nstruct LiquidationOpportunity {\n // Maximum stablecoin amount that can be repaid upon liquidating the vault\n uint256 maxStablecoinAmountToRepay;\n // Collateral amount given to the person in the case where the maximum amount to repay is given\n uint256 maxCollateralAmountGiven;\n // Threshold value of stablecoin amount to repay: it is ok for a liquidator to repay below threshold,\n // but if this threshold is non null and the liquidator wants to repay more than threshold, it should repay\n // the max stablecoin amount given in this vault\n uint256 thresholdRepayAmount;\n // Discount proposed to the liquidator on the collateral\n uint256 discount;\n // Amount of debt in the vault\n uint256 currentDebt;\n}\n\n/// @notice Data stored during a liquidation process to keep in memory what's due to a liquidator and some\n/// essential data for vaults being liquidated\nstruct LiquidatorData {\n // Current amount of stablecoins the liquidator should give to the contract\n uint256 stablecoinAmountToReceive;\n // Current amount of collateral the contract should give to the liquidator\n uint256 collateralAmountToGive;\n // Bad debt accrued across the liquidation process\n uint256 badDebtFromLiquidation;\n // Oracle value (in stablecoin base) at the time of the liquidation\n uint256 oracleValue;\n // Value of the `interestAccumulator` at the time of the call\n uint256 newInterestAccumulator;\n}\n\n/// @notice Data to track during a series of action the amount to give or receive in stablecoins and collateral\n/// to the caller or associated addresses\nstruct PaymentData {\n // Stablecoin amount the contract should give\n uint256 stablecoinAmountToGive;\n // Stablecoin amount owed to the contract\n uint256 stablecoinAmountToReceive;\n // Collateral amount the contract should give\n uint256 collateralAmountToGive;\n // Collateral amount owed to the contract\n uint256 collateralAmountToReceive;\n}\n\n/// @notice Actions possible when composing calls to the different entry functions proposed\nenum ActionType {\n createVault,\n closeVault,\n addCollateral,\n removeCollateral,\n repayDebt,\n borrow,\n getDebtIn,\n permit\n}\n\n// ========================= Interfaces =============================\n\n/// @title IVaultManagerFunctions\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `VaultManager` contract\n/// @dev This interface only contains functions of the contract which are called by other contracts\n/// of this module (without getters)\ninterface IVaultManagerFunctions {\n /// @notice Accrues interest accumulated across all vaults to the surplus and sends the surplus to the treasury\n /// @return surplusValue Value of the surplus communicated to the `Treasury`\n /// @return badDebtValue Value of the bad debt communicated to the `Treasury`\n /// @dev `surplus` and `badDebt` should be reset to 0 once their current value have been given to the `treasury` contract\n function accrueInterestToTreasury() external returns (uint256 surplusValue, uint256 badDebtValue);\n\n /// @notice Removes debt from a vault after being requested to do so by another `VaultManager` contract\n /// @param vaultID ID of the vault to remove debt from\n /// @param amountStablecoins Amount of stablecoins to remove from the debt: this amount is to be converted to an\n /// internal debt amount\n /// @param senderBorrowFee Borrowing fees from the contract which requested this: this is to make sure that people are not\n /// arbitraging difference in minting fees\n /// @param senderRepayFee Repay fees from the contract which requested this: this is to make sure that people are not arbitraging\n /// differences in repay fees\n /// @dev This function can only be called from a vaultManager registered in the same Treasury\n function getDebtOut(\n uint256 vaultID,\n uint256 amountStablecoins,\n uint256 senderBorrowFee,\n uint256 senderRepayFee\n ) external;\n\n /// @notice Gets the current debt of a vault\n /// @param vaultID ID of the vault to check\n /// @return Debt of the vault\n function getVaultDebt(uint256 vaultID) external view returns (uint256);\n\n /// @notice Gets the total debt across all vaults\n /// @return Total debt across all vaults, taking into account the interest accumulated\n /// over time\n function getTotalDebt() external view returns (uint256);\n\n /// @notice Sets the treasury contract\n /// @param _treasury New treasury contract\n /// @dev All required checks when setting up a treasury contract are performed in the contract\n /// calling this function\n function setTreasury(address _treasury) external;\n\n /// @notice Creates a vault\n /// @param toVault Address for which the va\n /// @return vaultID ID of the vault created\n /// @dev This function just creates the vault without doing any collateral or\n function createVault(address toVault) external returns (uint256);\n\n /// @notice Allows composability between calls to the different entry points of this module. Any user calling\n /// this function can perform any of the allowed actions in the order of their choice\n /// @param actions Set of actions to perform\n /// @param datas Data to be decoded for each action: it can include like the `vaultID` or the `stablecoinAmount` to borrow\n /// @param from Address from which stablecoins will be taken if one action includes burning stablecoins. This address\n /// should either be the `msg.sender` or be approved by the latter\n /// @param to Address to which stablecoins and/or collateral will be sent in case of\n /// @param who Address of the contract to handle in case of repayment of stablecoins from received collateral\n /// @param repayData Data to pass to the repayment contract in case of\n /// @return paymentData Struct containing the accounting changes from the protocol's perspective (like how much of collateral\n /// or how much has been received). Note that the values in the struct are not aggregated and you could have in the output\n /// a positive amount of stablecoins to receive as well as a positive amount of stablecoins to give\n /// @dev This function is optimized to reduce gas cost due to payment from or to the user and that expensive calls\n /// or computations (like `oracleValue`) are done only once\n /// @dev When specifying `vaultID` in `data`, it is important to know that if you specify `vaultID = 0`, it will simply\n /// use the latest `vaultID`. This is the default behavior, and unless you're engaging into some complex protocol actions\n /// it is encouraged to use `vaultID = 0` only when the first action of the batch is `createVault`\n function angle(\n ActionType[] memory actions,\n bytes[] memory datas,\n address from,\n address to,\n address who,\n bytes memory repayData\n ) external returns (PaymentData memory paymentData);\n\n /// @notice This function is a wrapper built on top of the function above. It enables users to interact with the contract\n /// without having to provide `who` and `repayData` parameters\n function angle(\n ActionType[] memory actions,\n bytes[] memory datas,\n address from,\n address to\n ) external returns (PaymentData memory paymentData);\n\n /// @notice Initializes the `VaultManager` contract\n /// @param _treasury Treasury address handling the contract\n /// @param _collateral Collateral supported by this contract\n /// @param _oracle Oracle contract used\n /// @param _symbol Symbol used to define the `VaultManager` name and symbol\n /// @dev The parameters and the oracle are the only elements which could be modified once the\n /// contract has been initialized\n /// @dev For the contract to be fully initialized, governance needs to set the parameters for the liquidation\n /// boost\n function initialize(\n ITreasury _treasury,\n IERC20 _collateral,\n IOracle _oracle,\n VaultParameters calldata params,\n string memory _symbol\n ) external;\n\n /// @notice Minimum amount of debt a vault can have, expressed in `BASE_TOKENS` that is to say the base of the agTokens\n function dust() external view returns (uint256);\n}\n\n/// @title IVaultManagerStorage\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `VaultManager` contract\n/// @dev This interface contains getters of the contract's public variables used by other contracts\n/// of this module\ninterface IVaultManagerStorage {\n /// @notice Encodes the maximum ratio stablecoin/collateral a vault can have before being liquidated. It's what\n /// determines the minimum collateral ratio of a position\n function collateralFactor() external view returns (uint64);\n\n /// @notice Stablecoin handled by this contract. Another `VaultManager` contract could have\n /// the same rights as this `VaultManager` on the stablecoin contract\n function stablecoin() external view returns (IAgToken);\n\n /// @notice Reference to the `treasury` contract handling this `VaultManager`\n function treasury() external view returns (ITreasury);\n\n /// @notice Oracle contract to get access to the price of the collateral with respect to the stablecoin\n function oracle() external view returns (IOracle);\n\n /// @notice The `interestAccumulator` variable keeps track of the interest that should accrue to the protocol.\n /// The stored value is not necessarily the true value: this one is recomputed every time an action takes place\n /// within the protocol. It is in base `BASE_INTEREST`\n function interestAccumulator() external view returns (uint256);\n\n /// @notice Reference to the collateral handled by this `VaultManager`\n function collateral() external view returns (IERC20);\n\n /// @notice Total normalized amount of stablecoins borrowed, not taking into account the potential bad debt accumulated\n /// This value is expressed in the base of Angle stablecoins (`BASE_TOKENS = 10**18`)\n function totalNormalizedDebt() external view returns (uint256);\n\n /// @notice Maximum amount of stablecoins that can be issued with this contract. It is expressed in `BASE_TOKENS`\n function debtCeiling() external view returns (uint256);\n\n /// @notice Maps a `vaultID` to its data (namely collateral amount and normalized debt)\n function vaultData(uint256 vaultID) external view returns (uint256 collateralAmount, uint256 normalizedDebt);\n\n /// @notice ID of the last vault created. The `vaultIDCount` variables serves as a counter to generate a unique\n /// `vaultID` for each vault: it is like `tokenID` in basic ERC721 contracts\n function vaultIDCount() external view returns (uint256);\n}\n\n/// @title IVaultManager\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `VaultManager` contract\ninterface IVaultManager is IVaultManagerFunctions, IVaultManagerStorage, IERC721Metadata {\n function isApprovedOrOwner(address spender, uint256 vaultID) external view returns (bool);\n}\n\n/// @title IVaultManagerListing\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `VaultManagerListing` contract\ninterface IVaultManagerListing is IVaultManager {\n /// @notice Get the collateral owned by `user` in the contract\n /// @dev This function effectively sums the collateral amounts of all the vaults owned by `user`\n function getUserCollateral(address user) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/governance/IVeBoostProxy.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\n/// @title IVeBoostProxy\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `VeBoostProxy` contract\n/// @dev This interface only contains functions of the contract which are called by other contracts\n/// of this module\n/// @dev The `veBoostProxy` contract used by Angle is a full fork of Curve Finance implementation\ninterface IVeBoostProxy {\n /// @notice Reads the adjusted veANGLE balance of an address (adjusted by delegation)\n //solhint-disable-next-line\n function adjusted_balance_of(address) external view returns (uint256);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/IERC721MetadataUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721Upgradeable.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721MetadataUpgradeable is IERC721Upgradeable {\n /**\n * @dev Returns the token collection name.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the token collection symbol.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n */\n function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165Upgradeable.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721Upgradeable is IERC165Upgradeable {\n /**\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n */\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n */\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n */\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /**\n * @dev Returns the number of tokens in ``owner``'s account.\n */\n function balanceOf(address owner) external view returns (uint256 balance);\n\n /**\n * @dev Returns the owner of the `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes calldata data\n ) external;\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Transfers `tokenId` token from `from` to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n * The approval is cleared when the token is transferred.\n *\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n *\n * Requirements:\n *\n * - The caller must own the token or be an approved operator.\n * - `tokenId` must exist.\n *\n * Emits an {Approval} event.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev Approve or remove `operator` as an operator for the caller.\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n *\n * Requirements:\n *\n * - The `operator` cannot be the caller.\n *\n * Emits an {ApprovalForAll} event.\n */\n function setApprovalForAll(address operator, bool _approved) external;\n\n /**\n * @dev Returns the account approved for `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function getApproved(uint256 tokenId) external view returns (address operator);\n\n /**\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n *\n * See {setApprovalForAll}\n */\n function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20Upgradeable {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool);\n}\n" + }, + "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n\n function decimals()\n external\n view\n returns (\n uint8\n );\n\n function description()\n external\n view\n returns (\n string memory\n );\n\n function version()\n external\n view\n returns (\n uint256\n );\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(\n uint80 _roundId\n )\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n}\n" + }, + "contracts/interfaces/ICoreBorrow.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\n/// @title ICoreBorrow\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `CoreBorrow` contract\n/// @dev This interface only contains functions of the `CoreBorrow` contract which are called by other contracts\n/// of this module\ninterface ICoreBorrow {\n /// @notice Checks if an address corresponds to a treasury of a stablecoin with a flash loan\n /// module initialized on it\n /// @param treasury Address to check\n /// @return Whether the address has the `FLASHLOANER_TREASURY_ROLE` or not\n function isFlashLoanerTreasury(address treasury) external view returns (bool);\n\n /// @notice Checks whether an address is governor of the Angle Protocol or not\n /// @param admin Address to check\n /// @return Whether the address has the `GOVERNOR_ROLE` or not\n function isGovernor(address admin) external view returns (bool);\n\n /// @notice Checks whether an address is governor or a guardian of the Angle Protocol or not\n /// @param admin Address to check\n /// @return Whether the address has the `GUARDIAN_ROLE` or not\n /// @dev Governance should make sure when adding a governor to also give this governor the guardian\n /// role by calling the `addGovernor` function\n function isGovernorOrGuardian(address admin) external view returns (bool);\n}\n" + }, + "contracts/interfaces/IFlashAngle.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity ^0.8.12;\n\nimport \"./IAgToken.sol\";\nimport \"./ICoreBorrow.sol\";\n\n/// @title IFlashAngle\n/// @author Angle Labs, Inc.\n/// @notice Interface for the `FlashAngle` contract\n/// @dev This interface only contains functions of the contract which are called by other contracts\n/// of this module\ninterface IFlashAngle {\n /// @notice Reference to the `CoreBorrow` contract managing the FlashLoan module\n function core() external view returns (ICoreBorrow);\n\n /// @notice Sends the fees taken from flash loans to the treasury contract associated to the stablecoin\n /// @param stablecoin Stablecoin from which profits should be sent\n /// @return balance Amount of profits sent\n /// @dev This function can only be called by the treasury contract\n function accrueInterestToTreasury(IAgToken stablecoin) external returns (uint256 balance);\n\n /// @notice Adds support for a stablecoin\n /// @param _treasury Treasury associated to the stablecoin to add support for\n /// @dev This function can only be called by the `CoreBorrow` contract\n function addStablecoinSupport(address _treasury) external;\n\n /// @notice Removes support for a stablecoin\n /// @param _treasury Treasury associated to the stablecoin to remove support for\n /// @dev This function can only be called by the `CoreBorrow` contract\n function removeStablecoinSupport(address _treasury) external;\n\n /// @notice Sets a new core contract\n /// @param _core Core contract address to set\n /// @dev This function can only be called by the `CoreBorrow` contract\n function setCore(address _core) external;\n}\n" + }, + "@openzeppelin/contracts/interfaces/IERC721Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../token/ERC721/extensions/IERC721Metadata.sol\";\n" + }, + "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721Metadata is IERC721 {\n /**\n * @dev Returns the token collection name.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the token collection symbol.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n */\n function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/IERC721.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n /**\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n */\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n */\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n */\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /**\n * @dev Returns the number of tokens in ``owner``'s account.\n */\n function balanceOf(address owner) external view returns (uint256 balance);\n\n /**\n * @dev Returns the owner of the `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes calldata data\n ) external;\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Transfers `tokenId` token from `from` to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n * The approval is cleared when the token is transferred.\n *\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n *\n * Requirements:\n *\n * - The caller must own the token or be an approved operator.\n * - `tokenId` must exist.\n *\n * Emits an {Approval} event.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev Approve or remove `operator` as an operator for the caller.\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n *\n * Requirements:\n *\n * - The `operator` cannot be the caller.\n *\n * Emits an {ApprovalForAll} event.\n */\n function setApprovalForAll(address operator, bool _approved) external;\n\n /**\n * @dev Returns the account approved for `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function getApproved(uint256 tokenId) external view returns (address operator);\n\n /**\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n *\n * See {setApprovalForAll}\n */\n function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ], + "": [ + "ast" + ] + } + } + } +} \ No newline at end of file diff --git a/e2e/mainnet/oraclesChainlink.test.ts b/e2e/mainnet/oraclesChainlink.test.ts index bc4106da..3bbc5a01 100644 --- a/e2e/mainnet/oraclesChainlink.test.ts +++ b/e2e/mainnet/oraclesChainlink.test.ts @@ -15,10 +15,14 @@ import { OracleETHEURChainlink__factory, OracleETHXAUChainlink, OracleETHXAUChainlink__factory, + OracleIB01EURChainlink, + OracleIB01EURChainlink__factory, OracleLUSDEURChainlink, OracleLUSDEURChainlink__factory, OracleLUSDXAUChainlink, OracleLUSDXAUChainlink__factory, + OracleUSDCEURChainlink, + OracleUSDCEURChainlink__factory, OracleUSDCXAUChainlink, OracleUSDCXAUChainlink__factory, OracleWSTETHEURChainlink, @@ -41,6 +45,8 @@ contract('Oracles Chainlink', () => { let oracleETHXAU: OracleETHXAUChainlink; let oracleUSDCXAU: OracleUSDCXAUChainlink; let oracleWSTETHXAU: OracleWSTETHXAUChainlink; + let oracleIB01: OracleIB01EURChainlink; + let oracleUSDC: OracleUSDCEURChainlink; let stalePeriod: BigNumber; let treasury: MockTreasury; @@ -53,7 +59,7 @@ contract('Oracles Chainlink', () => { { forking: { jsonRpcUrl: process.env.ETH_NODE_URI_FORK, - blockNumber: 16526566, + blockNumber: 17122178, }, }, ], @@ -76,6 +82,8 @@ contract('Oracles Chainlink', () => { oracleETHXAU = await new OracleETHXAUChainlink__factory(deployer).deploy(stalePeriod, treasury.address); oracleWSTETHXAU = await new OracleWSTETHXAUChainlink__factory(deployer).deploy(stalePeriod, treasury.address); oracleUSDCXAU = await new OracleUSDCXAUChainlink__factory(deployer).deploy(stalePeriod, treasury.address); + oracleIB01 = await new OracleIB01EURChainlink__factory(deployer).deploy(stalePeriod, treasury.address); + oracleUSDC = await new OracleUSDCEURChainlink__factory(deployer).deploy(stalePeriod, treasury.address); }); describe('Oracle wStETHEUR', () => { @@ -188,4 +196,28 @@ contract('Oracles Chainlink', () => { expect(await oracleUSDCXAU.treasury()).to.be.equal(treasury.address); }); }); + describe('Oracle IB01', () => { + it('read', async () => { + const receipt = await oracleIB01.read(); + const gas = await oracleIB01.estimateGas.read(); + console.log(gas.toString()); + console.log(receipt.toString()); + }); + it('initialization', async () => { + expect(await oracleIB01.stalePeriod()).to.be.equal(stalePeriod); + expect(await oracleIB01.treasury()).to.be.equal(treasury.address); + }); + }); + describe('Oracle USDC', () => { + it('read', async () => { + const receipt = await oracleUSDC.read(); + const gas = await oracleUSDC.estimateGas.read(); + console.log(gas.toString()); + console.log(receipt.toString()); + }); + it('initialization', async () => { + expect(await oracleUSDC.stalePeriod()).to.be.equal(stalePeriod); + expect(await oracleUSDC.treasury()).to.be.equal(treasury.address); + }); + }); }); diff --git a/hardhat.config.ts b/hardhat.config.ts index 1255d891..45e5c19d 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -109,15 +109,6 @@ const config: HardhatUserConfig = { }, }, }, - 'contracts/reactor/EulerReactor.sol': { - version: '0.8.12', - settings: { - optimizer: { - enabled: true, - runs: 1000, - }, - }, - }, 'contracts/router/AngleRouter01.sol': { version: '0.8.12', settings: { @@ -150,8 +141,8 @@ const config: HardhatUserConfig = { forking: { enabled: argv.fork || false, // Mainnet - url: nodeUrl('fork'), - blockNumber: 16526566, + url: nodeUrl('mainnet'), + blockNumber: 17122178, // Polygon /* diff --git a/package.json b/package.json index d41bf284..395f3b7c 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ }, "homepage": "https://github.com/AngleProtocol/angle-borrow#readme", "devDependencies": { - "@angleprotocol/sdk": "3.0.1", + "@angleprotocol/sdk": "3.0.40", "@chainlink/contracts": "0.2.1", "@nomiclabs/hardhat-ethers": "npm:hardhat-deploy-ethers", "@nomiclabs/hardhat-etherscan": "3.1.0", diff --git a/scripts/getDebtCeiling.ts b/scripts/getDebtCeiling.ts new file mode 100644 index 00000000..b76c53d7 --- /dev/null +++ b/scripts/getDebtCeiling.ts @@ -0,0 +1,36 @@ +import { ChainId, formatAmount, registry } from '@angleprotocol/sdk'; +import { ethers, network } from 'hardhat'; + +import { Treasury, Treasury__factory, VaultManager, VaultManager__factory } from '../typechain'; + +async function main() { + const { deployer } = await ethers.getNamedSigners(); + const treasuryAddress = registry(network.config.chainId as ChainId)?.agEUR?.Treasury!; + + const treasury = new ethers.Contract(treasuryAddress, Treasury__factory.createInterface(), deployer) as Treasury; + let result = true; + let i = 0; + while (result) { + try { + const address = await treasury.vaultManagerList(i); + console.log(`Address ${i}: ${address}`); + const vaultManager = new ethers.Contract( + address, + VaultManager__factory.createInterface(), + deployer, + ) as VaultManager; + const debt = await vaultManager.getTotalDebt(); + const ceiling = await vaultManager.debtCeiling(); + console.log(await vaultManager.name(), formatAmount.ether(debt), formatAmount.ether(ceiling)); + console.log(formatAmount.ether(ceiling.sub(debt))); + } catch { + result = false; + } + i++; + } +} + +main().catch(error => { + console.error(error); + process.exit(1); +}); diff --git a/test/hardhat/reactor/reactor.test.ts b/test/hardhat/reactor/reactor.test.ts deleted file mode 100644 index 98e3bef0..00000000 --- a/test/hardhat/reactor/reactor.test.ts +++ /dev/null @@ -1,1259 +0,0 @@ -import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; -import { BigNumber, Signer, utils } from 'ethers'; -import { formatBytes32String, parseEther, parseUnits } from 'ethers/lib/utils'; -import hre, { contract, ethers } from 'hardhat'; - -import { - AgToken, - AgToken__factory, - MockOracle, - MockOracle__factory, - MockReactor, - MockReactor__factory, - MockStableMaster, - MockStableMaster__factory, - MockToken, - MockToken__factory, - MockTreasury, - MockTreasury__factory, - Reactor, - Reactor__factory, - VaultManagerLiquidationBoost, - VaultManagerLiquidationBoost__factory, -} from '../../../typechain'; -import { expect } from '../utils/chai-setup'; -import { inIndirectReceipt, inReceipt } from '../utils/expectEvent'; -import { - angle, - deployUpgradeable, - displayReactorState, - displayVaultState, - expectApprox, - latestTime, - MAX_UINT256, - repayDebt, - ZERO_ADDRESS, -} from '../utils/helpers'; - -contract('Reactor', () => { - const log = true; - - let deployer: SignerWithAddress; - let governor: SignerWithAddress; - let guardian: SignerWithAddress; - let alice: SignerWithAddress; - let bob: SignerWithAddress; - - let reactor: Reactor; - let reactorClaimable: MockReactor; - let treasury: MockTreasury; - let ANGLE: MockToken; - let oracle: MockOracle; - let stableMaster: MockStableMaster; - let agEUR: AgToken; - let vaultManager: VaultManagerLiquidationBoost; - let lastTime: number; - - const impersonatedSigners: { [key: string]: Signer } = {}; - - const collatBase = 9; - const yearlyRate = 1.05; - const ratePerSecond = yearlyRate ** (1 / (365 * 24 * 3600)) - 1; - const lowerCF = 0.2e9; - const targetCF = 0.4e9; - const upperCF = 0.6e9; - - const params = { - debtCeiling: parseEther('100'), - collateralFactor: 0.9e9, - targetHealthFactor: 1.1e9, - borrowFee: 0.1e9, - interestRate: parseUnits(ratePerSecond.toFixed(27), 27), - liquidationSurcharge: 0.9e9, - maxLiquidationDiscount: 0.1e9, - liquidationBooster: 0.1e9, - whitelistingActivated: false, - baseBoost: 1e9, - }; - - before(async () => { - ({ deployer, alice, bob, governor, guardian } = await ethers.getNamedSigners()); - // add any addresses you want to impersonate here - const impersonatedAddresses = [{ address: '0xdC4e6DFe07EFCa50a197DF15D9200883eF4Eb1c8', name: 'governor' }]; - - for (const ob of impersonatedAddresses) { - await hre.network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [ob.address], - }); - - await hre.network.provider.send('hardhat_setBalance', [ob.address, '0x10000000000000000000000000000']); - - impersonatedSigners[ob.name] = await ethers.getSigner(ob.address); - } - }); - - beforeEach(async () => { - stableMaster = await new MockStableMaster__factory(deployer).deploy(); - - agEUR = (await deployUpgradeable(new AgToken__factory(deployer))) as AgToken; - await agEUR.connect(deployer).initialize('agEUR', 'agEUR', stableMaster.address); - - ANGLE = await new MockToken__factory(deployer).deploy('ANGLE', 'ANGLE', collatBase); - - vaultManager = (await deployUpgradeable( - new VaultManagerLiquidationBoost__factory(deployer), - )) as VaultManagerLiquidationBoost; - - treasury = await new MockTreasury__factory(deployer).deploy( - agEUR.address, - governor.address, - guardian.address, - vaultManager.address, - ZERO_ADDRESS, - ZERO_ADDRESS, - ); - await agEUR.connect(impersonatedSigners.governor).setUpTreasury(treasury.address); - await treasury.addMinter(agEUR.address, vaultManager.address); - await treasury.addMinter(agEUR.address, bob.address); - - oracle = await new MockOracle__factory(deployer).deploy(parseUnits('2', 18), treasury.address); - - stableMaster = await new MockStableMaster__factory(deployer).deploy(); - - await vaultManager.initialize(treasury.address, ANGLE.address, oracle.address, params, 'USDC/agEUR'); - await vaultManager.connect(governor).setDusts(0.1e15, 0.1e15, 0.1e15); - await vaultManager.connect(guardian).togglePause(); - - reactor = (await deployUpgradeable(new Reactor__factory(deployer))) as Reactor; - await reactor.initialize( - 'ANGLE/agEUR Reactor', - 'ANGLE/agEUR Reactor', - vaultManager.address, - lowerCF, - targetCF, - upperCF, - 0, - ); - - reactorClaimable = (await deployUpgradeable(new MockReactor__factory(deployer))) as MockReactor; - await reactorClaimable.initialize( - 'ANGLE/agEUR Reactor Claimable', - 'ANGLE/agEUR Reactor Claimable', - vaultManager.address, - lowerCF, - targetCF, - upperCF, - 0, - ); - await vaultManager.connect(governor).setUint64(params.borrowFee, formatBytes32String('BF')); - }); - describe('initialization', () => { - it('success - correct state and references', async () => { - expect(await reactor.lowerCF()).to.be.equal(lowerCF); - expect(await reactor.targetCF()).to.be.equal(targetCF); - expect(await reactor.upperCF()).to.be.equal(upperCF); - expect(await reactor.vaultManager()).to.be.equal(vaultManager.address); - expect(await reactor.treasury()).to.be.equal(treasury.address); - expect(await reactor.oracle()).to.be.equal(oracle.address); - expect(await reactor.asset()).to.be.equal(ANGLE.address); - expect(await reactor.stablecoin()).to.be.equal(agEUR.address); - expect(await ANGLE.allowance(reactor.address, vaultManager.address)).to.be.equal(MAX_UINT256); - expect(await vaultManager.ownerOf(1)).to.be.equal(reactor.address); - expect(await ANGLE.decimals()).to.be.equal(collatBase); - expect(await agEUR.isMinter(vaultManager.address)).to.be.equal(true); - expect(await reactor.surplusManager()).to.be.equal(ZERO_ADDRESS); - expect(await reactor.protocolInterestShare()).to.be.equal(0); - }); - it('reverts - invalid collateral factor values', async () => { - reactor = (await deployUpgradeable(new Reactor__factory(deployer))) as Reactor; - await expect( - reactor.initialize('ANGLE/agEUR Reactor', 'ANGLE/agEUR Reactor', vaultManager.address, 0, targetCF, upperCF, 0), - ).to.be.revertedWith('InvalidSetOfParameters'); - await expect( - reactor.initialize( - 'ANGLE/agEUR Reactor', - 'ANGLE/agEUR Reactor', - vaultManager.address, - upperCF, - targetCF, - upperCF, - 0, - ), - ).to.be.revertedWith('InvalidSetOfParameters'); - await expect( - reactor.initialize( - 'ANGLE/agEUR Reactor', - 'ANGLE/agEUR Reactor', - vaultManager.address, - lowerCF, - targetCF, - lowerCF, - 0, - ), - ).to.be.revertedWith('InvalidSetOfParameters'); - await expect( - reactor.initialize( - 'ANGLE/agEUR Reactor', - 'ANGLE/agEUR Reactor', - vaultManager.address, - lowerCF, - params.collateralFactor, - upperCF, - 0, - ), - ).to.be.revertedWith('InvalidSetOfParameters'); - await expect( - reactor.initialize( - 'ANGLE/agEUR Reactor', - 'ANGLE/agEUR Reactor', - vaultManager.address, - lowerCF, - targetCF, - 1e9, - 0, - ), - ).to.be.revertedWith('InvalidSetOfParameters'); - await expect( - reactor.initialize( - 'ANGLE/agEUR Reactor', - 'ANGLE/agEUR Reactor', - vaultManager.address, - lowerCF, - targetCF, - upperCF, - 2e9, - ), - ).to.be.revertedWith('InvalidSetOfParameters'); - }); - }); - describe('maxMint', () => { - it('success - correct value when zero balance', async () => { - expect(await reactor.maxMint(alice.address)).to.be.equal(MAX_UINT256); - expect(await reactor.maxMint(ZERO_ADDRESS)).to.be.equal(MAX_UINT256); - }); - it('success - correct value when non-null balance', async () => { - const sharesAmount = parseUnits('1', collatBase); - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - expect(await reactor.maxMint(alice.address)).to.be.equal(MAX_UINT256); - }); - }); - describe('maxDeposit', () => { - it('success - correct value when zero balance', async () => { - expect(await reactor.maxDeposit(alice.address)).to.be.equal(MAX_UINT256); - expect(await reactor.maxDeposit(ZERO_ADDRESS)).to.be.equal(MAX_UINT256); - }); - it('success - correct value when non-null balance', async () => { - const sharesAmount = parseUnits('1', collatBase); - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - expect(await reactor.maxDeposit(alice.address)).to.be.equal(MAX_UINT256); - }); - }); - - describe('maxWithdraw', () => { - const sharesAmount = parseUnits('1', collatBase); - it('success - when no asset', async () => { - expect(await reactor.maxWithdraw(alice.address)).to.be.equal(0); - }); - it('success - when some has been minted', async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - expect(await reactor.maxWithdraw(alice.address)).to.be.equal(sharesAmount); - }); - it('success - when some has been minted and a gain has been made', async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - const gains = parseUnits('1', collatBase); - await ANGLE.mint(reactor.address, gains); - expect(await reactor.maxWithdraw(alice.address)).to.be.equal(sharesAmount.mul(2)); - }); - }); - describe('maxRedeem', () => { - const sharesAmount = parseUnits('1', collatBase); - it('success - when no asset', async () => { - expect(await reactor.maxRedeem(alice.address)).to.be.equal(0); - }); - it('success - when some has been minted', async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - expect(await reactor.maxRedeem(alice.address)).to.be.equal(sharesAmount); - }); - it('success - when some has been minted and a gain has been made', async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - const gains = parseUnits('1', collatBase); - await ANGLE.mint(reactor.address, gains); - // It's still the balance of the user - expect(await reactor.maxRedeem(alice.address)).to.be.equal(sharesAmount); - }); - }); - - describe('previewDeposit', () => { - const sharesAmount = parseUnits('1', collatBase); - it('success - when no asset', async () => { - expect(await reactor.previewDeposit(sharesAmount)).to.be.equal(sharesAmount); - }); - it('success - when some has been minted', async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - expect(await reactor.previewDeposit(sharesAmount)).to.be.equal(sharesAmount); - }); - it('success - when some has been minted and a gain has been made', async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - const gains = parseUnits('1', collatBase); - await ANGLE.mint(reactor.address, gains); - expect(await reactor.previewDeposit(sharesAmount)).to.be.equal(sharesAmount.div(2)); - }); - }); - describe('previewWithdraw', () => { - const sharesAmount = parseUnits('1', collatBase); - it('success - when no asset', async () => { - expect(await reactor.previewWithdraw(sharesAmount)).to.be.equal(sharesAmount); - }); - it('success - when some has been minted', async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - expect(await reactor.previewWithdraw(sharesAmount)).to.be.equal(sharesAmount); - }); - it('success - when some has been minted and a gain has been made', async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - const gains = parseUnits('1', collatBase); - await ANGLE.mint(reactor.address, gains); - expect(await reactor.previewWithdraw(sharesAmount)).to.be.equal(sharesAmount.div(2)); - }); - it('success - rounded up shares', async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - const gains = parseUnits('1', collatBase).sub(1); - await ANGLE.mint(reactor.address, gains); - expect(await reactor.previewWithdraw(sharesAmount)).to.be.equal(sharesAmount.div(2).add(1)); - }); - }); - describe('previewMint', () => { - const sharesAmount = parseUnits('1', collatBase); - it('success - when no asset', async () => { - expect(await reactor.previewMint(sharesAmount)).to.be.equal(sharesAmount); - }); - it('success - when some has been minted', async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - expect(await reactor.previewMint(sharesAmount)).to.be.equal(sharesAmount); - }); - it('success - when some has been minted and a gain has been made', async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - const gains = parseUnits('1', collatBase); - await ANGLE.mint(reactor.address, gains); - expect(await reactor.previewMint(sharesAmount)).to.be.equal(sharesAmount.mul(2)); - }); - it('success - rounded up assets', async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - const gains = parseUnits('1', collatBase).sub(1); - await ANGLE.mint(reactor.address, gains); - expect(await reactor.previewMint(sharesAmount.div(2).sub(1))).to.be.equal(sharesAmount.sub(2)); - }); - }); - describe('previewRedeem', () => { - const sharesAmount = parseUnits('1', collatBase); - it('success - when no asset', async () => { - expect(await reactor.previewRedeem(sharesAmount)).to.be.equal(sharesAmount); - }); - it('success - when some has been minted', async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - expect(await reactor.previewRedeem(sharesAmount)).to.be.equal(sharesAmount); - }); - it('success - when some has been minted and a gain has been made', async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - const gains = parseUnits('1', collatBase); - await ANGLE.mint(reactor.address, gains); - expect(await reactor.previewRedeem(sharesAmount)).to.be.equal(sharesAmount.mul(2)); - }); - }); - describe('onERC721Received', () => { - it('reverts - sender is not vaultManager', async () => { - await expect(reactor.onERC721Received(alice.address, alice.address, 0, '0x')).to.be.revertedWith( - 'NotVaultManager', - ); - }); - }); - describe('setOracle', () => { - it('success - when value has not changed', async () => { - await reactor.setOracle(); - expect(await reactor.oracle()).to.be.equal(oracle.address); - }); - it('success - when value has changed', async () => { - const newOracle = await new MockOracle__factory(deployer).deploy(parseUnits('2', 18), treasury.address); - await vaultManager.connect(governor).setOracle(newOracle.address); - expect(await vaultManager.oracle()).to.be.equal(newOracle.address); - await reactor.setOracle(); - expect(await reactor.oracle()).to.be.equal(newOracle.address); - }); - }); - describe('setTreasury', () => { - it('success - when value has not changed', async () => { - await reactor.setTreasury(); - expect(await reactor.treasury()).to.be.equal(treasury.address); - }); - it('success - when value has changed', async () => { - await treasury.connect(governor).setTreasury(vaultManager.address, agEUR.address); - expect(await vaultManager.treasury()).to.be.equal(agEUR.address); - await reactor.setTreasury(); - expect(await reactor.treasury()).to.be.equal(agEUR.address); - }); - }); - - describe('setDust', () => { - it('success - when value has not changed', async () => { - await reactor.setDust(); - expect(await reactor.vaultManagerDust()).to.be.equal(0.1e15); - }); - }); - - describe('setSurplusManager', () => { - it('reverts - access control', async () => { - await expect(reactor.connect(alice).setSurplusManager(alice.address)).to.be.revertedWith('NotGovernorOrGuardian'); - }); - it('reverts - zero address', async () => { - await expect(reactor.connect(guardian).setSurplusManager(ZERO_ADDRESS)).to.be.revertedWith('ZeroAddress'); - }); - it('success - variable updated', async () => { - await reactor.connect(guardian).setSurplusManager(alice.address); - expect(await reactor.surplusManager()).to.be.equal(alice.address); - }); - }); - - describe('setUint64', () => { - it('reverts - access control', async () => { - await expect(reactor.connect(alice).setUint64(lowerCF, formatBytes32String('lowerCF'))).to.be.revertedWith( - 'NotGovernorOrGuardian', - ); - }); - it('success - guardian and lowerCF', async () => { - const receipt = await (await reactor.connect(guardian).setUint64(0.1e9, formatBytes32String('lowerCF'))).wait(); - inReceipt(receipt, 'FiledUint64', { - param: 0.1e9, - what: formatBytes32String('lowerCF'), - }); - expect(await reactor.lowerCF()).to.be.equal(0.1e9); - }); - it('success - governor and lowerCF', async () => { - await reactor.connect(governor).setUint64(0.1e9, formatBytes32String('lowerCF')); - expect(await reactor.lowerCF()).to.be.equal(0.1e9); - }); - it('success - targetCF', async () => { - const receipt = await (await reactor.connect(governor).setUint64(0.5e9, formatBytes32String('targetCF'))).wait(); - expect(await reactor.targetCF()).to.be.equal(0.5e9); - inReceipt(receipt, 'FiledUint64', { - param: 0.5e9, - what: formatBytes32String('targetCF'), - }); - }); - it('success - upperCF', async () => { - const receipt = await (await reactor.connect(governor).setUint64(0.7e9, formatBytes32String('upperCF'))).wait(); - expect(await reactor.upperCF()).to.be.equal(0.7e9); - inReceipt(receipt, 'FiledUint64', { - param: 0.7e9, - what: formatBytes32String('upperCF'), - }); - }); - it('success - protocolInterestShare', async () => { - const receipt = await ( - await reactor.connect(governor).setUint64(0.7e9, formatBytes32String('protocolInterestShare')) - ).wait(); - expect(await reactor.protocolInterestShare()).to.be.equal(0.7e9); - inReceipt(receipt, 'FiledUint64', { - param: 0.7e9, - what: formatBytes32String('protocolInterestShare'), - }); - }); - it('reverts - invalid lowerCF', async () => { - await expect(reactor.connect(governor).setUint64(0.6e9, formatBytes32String('lowerCF'))).to.be.revertedWith( - 'InvalidParameterValue', - ); - await expect(reactor.connect(governor).setUint64(0, formatBytes32String('lowerCF'))).to.be.revertedWith( - 'InvalidParameterValue', - ); - }); - it('reverts - invalid targetCF', async () => { - await expect(reactor.connect(governor).setUint64(1e9, formatBytes32String('targetCF'))).to.be.revertedWith( - 'InvalidParameterValue', - ); - await expect(reactor.connect(governor).setUint64(0, formatBytes32String('targetCF'))).to.be.revertedWith( - 'InvalidParameterValue', - ); - }); - it('reverts - invalid upperCF', async () => { - await expect(reactor.connect(governor).setUint64(1e9, formatBytes32String('upperCF'))).to.be.revertedWith( - 'InvalidParameterValue', - ); - await expect(reactor.connect(governor).setUint64(0, formatBytes32String('upperCF'))).to.be.revertedWith( - 'InvalidParameterValue', - ); - }); - it('reverts - invalid protocolInterestShare', async () => { - await expect( - reactor.connect(governor).setUint64(2e9, formatBytes32String('protocolInterestShare')), - ).to.be.revertedWith('TooHighParameterValue'); - }); - it('reverts - invalid parameter', async () => { - await expect(reactor.connect(governor).setUint64(1e9, formatBytes32String('wrong message'))).to.be.revertedWith( - 'InvalidParameterType', - ); - }); - }); - describe('recoverERC20', () => { - it('reverts - nonGovernor', async () => { - await expect(reactor.recoverERC20(agEUR.address, bob.address, 1)).to.be.revertedWith('NotGovernor'); - }); - it('success - when token is collateral', async () => { - const gains = parseUnits('1', collatBase); - await ANGLE.mint(reactor.address, gains); - const receipt = await (await reactor.connect(governor).recoverERC20(ANGLE.address, bob.address, gains)).wait(); - inReceipt(receipt, 'Recovered', { - token: ANGLE.address, - to: bob.address, - amount: gains, - }); - expect(await ANGLE.balanceOf(bob.address)).to.be.equal(gains); - expect(await ANGLE.balanceOf(reactor.address)).to.be.equal(0); - }); - it('reverts - when token is stablecoin', async () => { - await treasury.addMinter(agEUR.address, alice.address); - await agEUR.connect(alice).mint(reactor.address, parseEther('1')); - await expect(reactor.connect(governor).recoverERC20(agEUR.address, bob.address, 1)).to.be.revertedWith( - 'InvalidToken', - ); - }); - }); - - describe('pushProtocolFees', () => { - it('reverts - zero address', async () => { - await expect(reactor.pushProtocolFees(ZERO_ADDRESS)).to.be.revertedWith('ZeroAddress'); - }); - it('reverts - not guardian', async () => { - await expect(reactor.connect(alice).pushProtocolFees(alice.address)).to.be.revertedWith('NotGovernorOrGuardian'); - }); - it('success - when zero available', async () => { - await reactor.connect(guardian).pushProtocolFees(alice.address); - }); - it('success - when some available and guardian', async () => { - await reactorClaimable.increaseAccumulator(parseEther('1')); - expect(await reactorClaimable.protocolInterestAccumulated()).to.be.equal(parseEther('1')); - await treasury.addMinter(agEUR.address, alice.address); - await agEUR.connect(alice).mint(reactorClaimable.address, parseEther('1')); - await reactorClaimable.connect(guardian).pushProtocolFees(alice.address); - expect(await reactorClaimable.protocolInterestAccumulated()).to.be.equal(0); - expect(await agEUR.balanceOf(alice.address)).to.be.equal(parseEther('1')); - }); - it('success - when some available and surplusManager', async () => { - await reactorClaimable.connect(guardian).setSurplusManager(bob.address); - await reactorClaimable.increaseAccumulator(parseEther('1')); - expect(await reactorClaimable.protocolInterestAccumulated()).to.be.equal(parseEther('1')); - await treasury.addMinter(agEUR.address, alice.address); - await agEUR.connect(alice).mint(reactorClaimable.address, parseEther('1')); - await reactorClaimable.connect(alice).pushProtocolFees(bob.address); - expect(await reactorClaimable.protocolInterestAccumulated()).to.be.equal(0); - expect(await agEUR.balanceOf(bob.address)).to.be.equal(parseEther('1')); - }); - it('success - when some available and surplusManager and guardian', async () => { - await reactorClaimable.connect(guardian).setSurplusManager(bob.address); - await reactorClaimable.increaseAccumulator(parseEther('1')); - expect(await reactorClaimable.protocolInterestAccumulated()).to.be.equal(parseEther('1')); - await treasury.addMinter(agEUR.address, alice.address); - await agEUR.connect(alice).mint(reactorClaimable.address, parseEther('1')); - await reactorClaimable.connect(guardian).pushProtocolFees(bob.address); - expect(await reactorClaimable.protocolInterestAccumulated()).to.be.equal(0); - expect(await agEUR.balanceOf(bob.address)).to.be.equal(parseEther('1')); - }); - it('reverts - when not enough funds', async () => { - await reactorClaimable.connect(guardian).setSurplusManager(bob.address); - await reactorClaimable.increaseAccumulator(parseEther('1')); - expect(await reactorClaimable.protocolInterestAccumulated()).to.be.equal(parseEther('1')); - await treasury.addMinter(agEUR.address, alice.address); - await agEUR.connect(alice).mint(reactorClaimable.address, parseEther('0.5')); - await expect(reactorClaimable.connect(guardian).pushProtocolFees(bob.address)).to.be.reverted; - }); - it('success - when less is pulled than interest accumulated', async () => { - await reactorClaimable.connect(guardian).setSurplusManager(bob.address); - await reactorClaimable.setMultiplier(0.3e9); - await reactorClaimable.increaseAccumulator(parseEther('1')); - expect(await reactorClaimable.protocolInterestAccumulated()).to.be.equal(parseEther('1')); - await treasury.addMinter(agEUR.address, alice.address); - await agEUR.connect(alice).mint(reactorClaimable.address, parseEther('1')); - await reactorClaimable.connect(guardian).pushProtocolFees(bob.address); - expect(await reactorClaimable.protocolInterestAccumulated()).to.be.equal(parseEther('0.7')); - expect(await agEUR.balanceOf(bob.address)).to.be.equal(parseEther('0.3')); - }); - }); - describe('mint', () => { - const sharesAmount = parseUnits('1', collatBase); - beforeEach(async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - lastTime = await latestTime(); - }); - it('success - added collateral to vault', async () => { - await displayReactorState(reactor, log); - expect(await ANGLE.balanceOf(reactor.address)).to.be.equal(0); - expect(await ANGLE.balanceOf(vaultManager.address)).to.be.equal(sharesAmount); - expect(await reactor.balanceOf(alice.address)).to.be.equal(sharesAmount); - expect(await reactor.lastTime()).to.be.equal(lastTime); - expect(await reactor.lastTimeOf(alice.address)).to.be.equal(lastTime); - expect(await reactor.rewardsAccumulatorOf(alice.address)).to.be.equal(0); - expect(await reactor.rewardsAccumulator()).to.be.equal(0); - // It works here as collatBase is 9 (= base params) and base of the stablecoin is 18 - expectApprox(await vaultManager.getVaultDebt(1), sharesAmount.mul(2).mul(targetCF), 0.00001); - }); - it('success - mint when there is a gain in stablecoins', async () => { - const sharesAmount = parseUnits('1', collatBase); - await ANGLE.connect(alice).mint(alice.address, sharesAmount.mul(100)); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount.mul(100)); - // Shares amount is consumed -> debt is now 0.8 - expectApprox(await vaultManager.getVaultDebt(1), sharesAmount.mul(2).mul(targetCF), 0.00001); - await treasury.addMinter(agEUR.address, bob.address); - await agEUR.connect(bob).mint(bob.address, parseEther('1')); - // To make a gain we need to repay debt on behalf of the vault - await angle(vaultManager, bob, [repayDebt(1, parseEther('1'))]); - expect(await vaultManager.getVaultDebt(1)).to.be.equal(0); - await reactor.connect(alice).mint(sharesAmount, alice.address); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(sharesAmount.mul(99)); - expect(await reactor.lastDebt()).to.be.equal(parseEther('1.44')); - expect(await reactor.currentLoss()).to.be.equal(parseEther('0')); - const claimable = await reactor.claimableRewards(); - expectApprox(claimable, parseEther('0.72'), 0.00001); - }); - it('success - mint with rounding', async () => { - const sharesAmount = parseUnits('1', collatBase); - await ANGLE.connect(alice).mint(alice.address, sharesAmount.mul(100)); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount.mul(100)); - // Shares amount is consumed - expectApprox(await vaultManager.getVaultDebt(1), sharesAmount.mul(2).mul(targetCF), 0.00001); - await treasury.addMinter(agEUR.address, bob.address); - await agEUR.connect(bob).mint(bob.address, parseEther('1')); - // To make a gain we need to repay debt on behalf of the vault - await angle(vaultManager, bob, [repayDebt(1, parseEther('1'))]); - await reactor.connect(alice).mint(sharesAmount.div(2).add(1), alice.address); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(sharesAmount.mul(199).div(2).sub(1)); - }); - /* - it('success - second mint with borrow', async () => { - const secondSharesAmount = sharesAmount; - await ANGLE.connect(alice).mint(alice.address, secondSharesAmount); - await ANGLE.connect(alice).approve(reactor.address, secondSharesAmount); - const receipt = await (await reactor.connect(alice).mint(secondSharesAmount, alice.address)).wait(); - inReceipt(receipt, 'Deposit', { - from: alice.address, - to: alice.address, - amount: secondSharesAmount, - shares: secondSharesAmount, - }); - inReceipt(receipt, 'Transfer', { - from: ZERO_ADDRESS, - to: alice.address, - value: secondSharesAmount, - }); - await displayReactorState(reactor, log); - expect(await ANGLE.balanceOf(reactor.address)).to.be.equal(0); - expect(await ANGLE.balanceOf(vaultManager.address)).to.be.equal(sharesAmount.add(secondSharesAmount)); - expect(await reactor.balanceOf(alice.address)).to.be.equal(sharesAmount.add(secondSharesAmount)); - expect(await reactor.lastTime()).to.be.equal(await latestTime()); - expect(await reactor.lastTimeOf(alice.address)).to.be.equal(await latestTime()); - expect(await reactor.rewardsAccumulatorOf(alice.address)).to.be.equal( - BigNumber.from((await latestTime()) - lastTime).mul(sharesAmount), - ); - expect(await reactor.rewardsAccumulator()).to.be.equal( - BigNumber.from((await latestTime()) - lastTime).mul(sharesAmount), - ); - const sum = sharesAmount.add(secondSharesAmount); - expectApprox(await vaultManager.getVaultDebt(1), sum.mul(2).mul(targetCF), 0.00001); - }); - */ - - it('success - second mint to a different address', async () => { - const secondSharesAmount = sharesAmount; - await ANGLE.connect(alice).mint(alice.address, secondSharesAmount); - await ANGLE.connect(alice).approve(reactor.address, secondSharesAmount); - const receipt = await (await reactor.connect(alice).mint(secondSharesAmount, bob.address)).wait(); - inReceipt(receipt, 'Deposit', { - from: alice.address, - to: bob.address, - amount: secondSharesAmount, - shares: secondSharesAmount, - }); - inReceipt(receipt, 'Transfer', { - from: ZERO_ADDRESS, - to: bob.address, - value: secondSharesAmount, - }); - expect(await ANGLE.balanceOf(reactor.address)).to.be.equal(0); - expect(await ANGLE.balanceOf(vaultManager.address)).to.be.equal(sharesAmount.add(secondSharesAmount)); - expect(await reactor.balanceOf(alice.address)).to.be.equal(sharesAmount); - expect(await reactor.balanceOf(bob.address)).to.be.equal(secondSharesAmount); - expect(await reactor.lastTime()).to.be.equal(await latestTime()); - expect(await reactor.lastTimeOf(alice.address)).to.be.equal(lastTime); - expect(await reactor.lastTimeOf(bob.address)).to.be.equal(await latestTime()); - expect(await reactor.rewardsAccumulatorOf(alice.address)).to.be.equal(0); - expect(await reactor.rewardsAccumulatorOf(bob.address)).to.be.equal(0); - expect(await reactor.rewardsAccumulator()).to.be.equal( - BigNumber.from((await latestTime()) - lastTime).mul(sharesAmount), - ); - }); - - it('success - second mint without borrow', async () => { - const secondSharesAmount = parseUnits('0.4', collatBase); - await ANGLE.connect(alice).mint(alice.address, secondSharesAmount); - await ANGLE.connect(alice).approve(reactor.address, secondSharesAmount); - const receipt = await (await reactor.connect(alice).mint(secondSharesAmount, alice.address)).wait(); - inReceipt(receipt, 'Deposit', { - from: alice.address, - to: alice.address, - amount: secondSharesAmount, - shares: secondSharesAmount, - }); - inReceipt(receipt, 'Transfer', { - from: ZERO_ADDRESS, - to: alice.address, - value: secondSharesAmount, - }); - - await displayReactorState(reactor, log); - - expect(await ANGLE.balanceOf(reactor.address)).to.be.equal(0); - expect(await ANGLE.balanceOf(vaultManager.address)).to.be.equal(sharesAmount.add(secondSharesAmount)); - // Does not change below or above the collateral ratio so it does not change anything - expectApprox(await vaultManager.getVaultDebt(1), sharesAmount.mul(2).mul(targetCF), 0.00001); - }); - - it('success - second mint after gain', async () => { - const gains = parseUnits('1', collatBase); - await ANGLE.mint(reactor.address, gains); - - const secondSharesAmount = parseUnits('0.2', collatBase); - const secondAssetAmount = parseUnits('0.4', collatBase); - await ANGLE.connect(alice).mint(alice.address, secondAssetAmount); - await ANGLE.connect(alice).approve(reactor.address, secondAssetAmount); - await reactor.connect(alice).mint(secondSharesAmount, alice.address); - - await displayReactorState(reactor, log); - - expect(await ANGLE.balanceOf(reactor.address)).to.be.equal(0); - expect(await ANGLE.balanceOf(vaultManager.address)).to.be.equal(sharesAmount.add(secondAssetAmount).add(gains)); - expectApprox( - await vaultManager.getVaultDebt(1), - sharesAmount.add(secondAssetAmount).add(gains).mul(2).mul(targetCF), - 0.00001, - ); - }); - }); - describe('rebalance', () => { - const sharesAmount = parseUnits('1', collatBase); - beforeEach(async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - lastTime = await latestTime(); - }); - it('success - correctly rebalances after a gain in collateral', async () => { - await ANGLE.connect(alice).mint(reactor.address, sharesAmount); - await reactor.rebalance(); - await displayReactorState(reactor, log); - expect(await ANGLE.balanceOf(reactor.address)).to.be.equal(0); - expect(await ANGLE.balanceOf(vaultManager.address)).to.be.equal(sharesAmount.mul(2)); - expect(await reactor.balanceOf(alice.address)).to.be.equal(sharesAmount); - // Last time should remain unchanged - expect(await reactor.lastTime()).to.be.equal(lastTime); - expect(await reactor.lastTimeOf(alice.address)).to.be.equal(lastTime); - expectApprox(await vaultManager.getVaultDebt(1), sharesAmount.mul(4).mul(targetCF), 0.00001); - }); - it('success - correctly rebalances after a gain in stablecoin', async () => { - await treasury.addMinter(agEUR.address, bob.address); - await agEUR.connect(bob).mint(bob.address, parseEther('1')); - // To make a gain we need to repay debt on behalf of the vault - await angle(vaultManager, bob, [repayDebt(1, parseEther('1'))]); - await reactor.rebalance(); - expect(await reactor.claimableRewards()).to.be.equal(parseEther('0.72')); - // State of the reactor should not change otherwise - expectApprox(await vaultManager.getVaultDebt(1), sharesAmount.mul(2).mul(targetCF), 0.00001); - expect(await ANGLE.balanceOf(reactor.address)).to.be.equal(0); - expect(await ANGLE.balanceOf(vaultManager.address)).to.be.equal(sharesAmount.mul(1)); - expect(await reactor.balanceOf(alice.address)).to.be.equal(sharesAmount); - // Last time should remain unchanged - expect(await reactor.lastTime()).to.be.equal(lastTime); - expect(await reactor.lastTimeOf(alice.address)).to.be.equal(lastTime); - }); - }); - - describe('deposit', () => { - const assetsAmount = parseUnits('1', collatBase); - beforeEach(async () => { - await ANGLE.connect(alice).mint(alice.address, assetsAmount); - await ANGLE.connect(alice).approve(reactor.address, assetsAmount); - await reactor.connect(alice).deposit(assetsAmount, alice.address); - }); - - it('success - added collateral to vault', async () => { - await displayReactorState(reactor, log); - expect(await ANGLE.balanceOf(reactor.address)).to.be.equal(0); - expect(await ANGLE.balanceOf(vaultManager.address)).to.be.equal(assetsAmount); - expectApprox(await vaultManager.getVaultDebt(1), assetsAmount.mul(2).mul(targetCF), 0.00001); - }); - it('reverts - zero shares', async () => { - await expect(reactor.connect(alice).deposit(0, alice.address)).to.be.revertedWith('ZeroShares'); - }); - }); - - describe('redeem', () => { - const sharesAmount = parseUnits('0.8', collatBase); - const assetsAmount = parseUnits('1.6', collatBase); - const totalAsset = parseUnits('2', collatBase); - - beforeEach(async () => { - await ANGLE.connect(alice).mint(alice.address, parseUnits('1', collatBase)); - await ANGLE.connect(alice).approve(reactor.address, parseUnits('1', collatBase)); - await reactor.connect(alice).mint(parseUnits('1', collatBase), alice.address); - await ANGLE.mint(reactor.address, parseUnits('1', collatBase)); - }); - - it('success - from/to are the same address', async () => { - await displayReactorState(reactor, log); - expect(await reactor.balanceOf(alice.address)).to.be.equal(parseUnits('1', collatBase)); - await reactor.connect(alice).redeem(sharesAmount, alice.address, alice.address); - expect(await reactor.balanceOf(alice.address)).to.be.equal(parseUnits('0.2', collatBase)); - await displayReactorState(reactor, log); - expect(await ANGLE.balanceOf(reactor.address)).to.be.equal(0); - expect(await ANGLE.balanceOf(vaultManager.address)).to.be.equal(totalAsset.sub(assetsAmount)); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(assetsAmount); - expectApprox(await vaultManager.getVaultDebt(1), totalAsset.sub(assetsAmount).mul(2).mul(targetCF), 0.00001); - }); - it('reverts - from not approved by msg.sender', async () => { - await expect(reactor.connect(bob).redeem(sharesAmount, alice.address, alice.address)).to.be.revertedWith( - 'TransferAmountExceedsAllowance', - ); - }); - it('reverts - redeems more shares', async () => { - await expect(reactor.connect(alice).withdraw(assetsAmount.mul(1000), alice.address, alice.address)).to.be - .reverted; - }); - it('reverts - zero assets', async () => { - await expect(reactor.connect(bob).redeem(0, alice.address, alice.address)).to.be.revertedWith('ZeroAssets'); - }); - it('success - from approved by msg.sender and reduced allowance', async () => { - await reactor.connect(alice).approve(bob.address, sharesAmount); - const receipt = await (await reactor.connect(bob).redeem(sharesAmount, alice.address, alice.address)).wait(); - inReceipt(receipt, 'Withdraw', { - from: alice.address, - to: alice.address, - amount: assetsAmount, - shares: sharesAmount, - }); - inIndirectReceipt( - receipt, - new utils.Interface(['event Transfer(address indexed from, address indexed to, uint256 value)']), - 'Transfer', - { - from: reactor.address, - to: alice.address, - value: assetsAmount, - }, - ); - expect(await reactor.balanceOf(alice.address)).to.be.equal(parseUnits('0.2', collatBase)); - expect(await ANGLE.balanceOf(reactor.address)).to.be.equal(0); - expect(await ANGLE.balanceOf(vaultManager.address)).to.be.equal(totalAsset.sub(assetsAmount)); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(assetsAmount); - expect(await reactor.allowance(alice.address, bob.address)).to.be.equal(0); - expectApprox(await vaultManager.getVaultDebt(1), totalAsset.sub(assetsAmount).mul(2).mul(targetCF), 0.00001); - }); - it('success - from approved by msg.sender and different to address', async () => { - await reactor.connect(alice).approve(bob.address, sharesAmount); - const receipt = await (await reactor.connect(bob).redeem(sharesAmount, bob.address, alice.address)).wait(); - inReceipt(receipt, 'Withdraw', { - from: alice.address, - to: bob.address, - amount: assetsAmount, - shares: sharesAmount, - }); - inIndirectReceipt( - receipt, - new utils.Interface(['event Transfer(address indexed from, address indexed to, uint256 value)']), - 'Transfer', - { - from: reactor.address, - to: bob.address, - value: assetsAmount, - }, - ); - expect(await reactor.balanceOf(alice.address)).to.be.equal(parseUnits('0.2', collatBase)); - expect(await ANGLE.balanceOf(reactor.address)).to.be.equal(0); - expect(await ANGLE.balanceOf(vaultManager.address)).to.be.equal(totalAsset.sub(assetsAmount)); - expect(await ANGLE.balanceOf(bob.address)).to.be.equal(assetsAmount); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(0); - expect(await reactor.allowance(alice.address, bob.address)).to.be.equal(0); - expectApprox(await vaultManager.getVaultDebt(1), totalAsset.sub(assetsAmount).mul(2).mul(targetCF), 0.00001); - }); - it('success - from approved by msg.sender and different to address with a max approval', async () => { - await reactor.connect(alice).approve(bob.address, MAX_UINT256); - await reactor.connect(bob).redeem(sharesAmount, bob.address, alice.address); - expect(await reactor.balanceOf(alice.address)).to.be.equal(parseUnits('0.2', collatBase)); - expect(await ANGLE.balanceOf(reactor.address)).to.be.equal(0); - expect(await ANGLE.balanceOf(vaultManager.address)).to.be.equal(totalAsset.sub(assetsAmount)); - expect(await ANGLE.balanceOf(bob.address)).to.be.equal(assetsAmount); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(0); - expect(await reactor.allowance(alice.address, bob.address)).to.be.equal(MAX_UINT256); - expectApprox(await vaultManager.getVaultDebt(1), totalAsset.sub(assetsAmount).mul(2).mul(targetCF), 0.00001); - }); - }); - describe('withdraw', () => { - const sharesAmount = parseUnits('0.8', collatBase); - const assetsAmount = parseUnits('1.6', collatBase); - const totalAsset = parseUnits('2', collatBase); - - beforeEach(async () => { - await ANGLE.connect(alice).mint(alice.address, parseUnits('1', collatBase)); - await ANGLE.connect(alice).approve(reactor.address, parseUnits('1', collatBase)); - await reactor.connect(alice).mint(parseUnits('1', collatBase), alice.address); - await ANGLE.mint(reactor.address, parseUnits('1', collatBase)); - }); - - it('success - from/to are the same address', async () => { - await displayReactorState(reactor, log); - expect(await reactor.balanceOf(alice.address)).to.be.equal(parseUnits('1', collatBase)); - await reactor.connect(alice).withdraw(assetsAmount, alice.address, alice.address); - expect(await reactor.balanceOf(alice.address)).to.be.equal(parseUnits('0.2', collatBase)); - expect(await ANGLE.balanceOf(reactor.address)).to.be.equal(0); - expect(await ANGLE.balanceOf(vaultManager.address)).to.be.equal(totalAsset.sub(assetsAmount)); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(assetsAmount); - expectApprox(await vaultManager.getVaultDebt(1), totalAsset.sub(assetsAmount).mul(2).mul(targetCF), 0.00001); - }); - it('reverts - from not approved by msg.sender', async () => { - await expect(reactor.connect(bob).withdraw(assetsAmount, alice.address, alice.address)).to.be.revertedWith( - 'TransferAmountExceedsAllowance', - ); - }); - it('reverts - withdraw more than what is in the reactor', async () => { - await expect(reactor.connect(alice).withdraw(assetsAmount.mul(1000), alice.address, alice.address)).to.be - .reverted; - }); - it('success - from approved by msg.sender and reduced allowance', async () => { - await reactor.connect(alice).approve(bob.address, sharesAmount); - const receipt = await (await reactor.connect(bob).withdraw(assetsAmount, alice.address, alice.address)).wait(); - inReceipt(receipt, 'Withdraw', { - from: alice.address, - to: alice.address, - amount: assetsAmount, - shares: sharesAmount, - }); - inIndirectReceipt( - receipt, - new utils.Interface(['event Transfer(address indexed from, address indexed to, uint256 value)']), - 'Transfer', - { - from: reactor.address, - to: alice.address, - value: assetsAmount, - }, - ); - expect(await reactor.balanceOf(alice.address)).to.be.equal(parseUnits('0.2', collatBase)); - expect(await ANGLE.balanceOf(reactor.address)).to.be.equal(0); - expect(await ANGLE.balanceOf(vaultManager.address)).to.be.equal(totalAsset.sub(assetsAmount)); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(assetsAmount); - expect(await reactor.allowance(alice.address, bob.address)).to.be.equal(0); - expectApprox(await vaultManager.getVaultDebt(1), totalAsset.sub(assetsAmount).mul(2).mul(targetCF), 0.00001); - }); - it('success - withdraw with rounding', async () => { - const sharesAmount = parseUnits('1', collatBase); - await ANGLE.connect(alice).mint(alice.address, sharesAmount.mul(100)); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount.mul(100)); - // Shares amount is consumed - expectApprox(await vaultManager.getVaultDebt(1), sharesAmount.mul(2).mul(targetCF), 0.00001); - await treasury.addMinter(agEUR.address, bob.address); - await agEUR.connect(bob).mint(bob.address, parseEther('1')); - // To make a gain we need to repay debt on behalf of the vault - await angle(vaultManager, bob, [repayDebt(1, parseEther('1'))]); - await reactor.connect(alice).withdraw(sharesAmount.sub(1), alice.address, alice.address); - expect(await reactor.balanceOf(alice.address)).to.be.equal(sharesAmount.div(2)); - }); - it('success - from approved by msg.sender and different to address', async () => { - await reactor.connect(alice).approve(bob.address, sharesAmount); - const receipt = await (await reactor.connect(bob).withdraw(assetsAmount, bob.address, alice.address)).wait(); - inReceipt(receipt, 'Withdraw', { - from: alice.address, - to: bob.address, - amount: assetsAmount, - shares: sharesAmount, - }); - inIndirectReceipt( - receipt, - new utils.Interface(['event Transfer(address indexed from, address indexed to, uint256 value)']), - 'Transfer', - { - from: reactor.address, - to: bob.address, - value: assetsAmount, - }, - ); - expect(await reactor.balanceOf(alice.address)).to.be.equal(parseUnits('0.2', collatBase)); - expect(await ANGLE.balanceOf(reactor.address)).to.be.equal(0); - expect(await ANGLE.balanceOf(vaultManager.address)).to.be.equal(totalAsset.sub(assetsAmount)); - expect(await ANGLE.balanceOf(bob.address)).to.be.equal(assetsAmount); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(0); - expect(await reactor.allowance(alice.address, bob.address)).to.be.equal(0); - expectApprox(await vaultManager.getVaultDebt(1), totalAsset.sub(assetsAmount).mul(2).mul(targetCF), 0.00001); - }); - it('success - from approved by msg.sender and different to address with a max approval', async () => { - await reactor.connect(alice).approve(bob.address, MAX_UINT256); - await reactor.connect(bob).withdraw(assetsAmount, bob.address, alice.address); - expect(await reactor.balanceOf(alice.address)).to.be.equal(parseUnits('0.2', collatBase)); - expect(await ANGLE.balanceOf(reactor.address)).to.be.equal(0); - expect(await ANGLE.balanceOf(vaultManager.address)).to.be.equal(totalAsset.sub(assetsAmount)); - expect(await ANGLE.balanceOf(bob.address)).to.be.equal(assetsAmount); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(0); - expect(await reactor.allowance(alice.address, bob.address)).to.be.equal(MAX_UINT256); - expectApprox(await vaultManager.getVaultDebt(1), totalAsset.sub(assetsAmount).mul(2).mul(targetCF), 0.00001); - }); - }); - describe('claim', () => { - it('reverts - when nothing in the reactor because division by zero', async () => { - await expect(reactor.connect(alice).claim(alice.address)).to.be.reverted; - }); - it('reverts - when 0 claimable rewards', async () => { - await expect(reactor.connect(alice).claim(alice.address)).to.be.reverted; - }); - it('success - when there are claimable rewards', async () => { - const sharesAmount = parseUnits('1', collatBase); - await ANGLE.connect(alice).mint(alice.address, sharesAmount.mul(100)); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount.mul(100)); - // Shares amount is consumed - await reactor.connect(alice).mint(sharesAmount, alice.address); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(sharesAmount.mul(99)); - expectApprox(await vaultManager.getVaultDebt(1), sharesAmount.mul(2).mul(targetCF), 0.00001); - await treasury.addMinter(agEUR.address, bob.address); - await agEUR.connect(bob).mint(bob.address, parseEther('1')); - // To make a gain we need to repay debt on behalf of the vault - await angle(vaultManager, bob, [repayDebt(1, parseEther('1'))]); - await reactor.connect(alice).mint(sharesAmount, alice.address); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(sharesAmount.mul(98)); - expect(await reactor.lastDebt()).to.be.equal(parseEther('1.44')); - expect(await reactor.currentLoss()).to.be.equal(parseEther('0')); - const claimable = await reactor.claimableRewards(); - expectApprox(claimable, parseEther('0.72'), 0.00001); - await reactor.claim(alice.address); - // In this implementation, `pull` just returns 0 and so claimable rewards are not modified at all - expect(await agEUR.balanceOf(alice.address)).to.be.equal(0); - expect(await reactor.claimableRewards()).to.be.equal(claimable); - expect(await reactor.claimedRewardsAccumulator()).to.be.equal(0); - }); - it('success - when there are claimable rewards but that a small loss decreased it', async () => { - const sharesAmount = parseUnits('1', collatBase); - await ANGLE.connect(alice).mint(alice.address, sharesAmount.mul(100)); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount.mul(100)); - // Shares amount is consumed - await reactor.connect(alice).mint(sharesAmount, alice.address); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(sharesAmount.mul(99)); - expectApprox(await vaultManager.getVaultDebt(1), sharesAmount.mul(2).mul(targetCF), 0.00001); - await treasury.addMinter(agEUR.address, bob.address); - await agEUR.connect(bob).mint(bob.address, parseEther('1')); - // To make a gain we need to repay debt on behalf of the vault - await angle(vaultManager, bob, [repayDebt(1, parseEther('1'))]); - // Here we record a gain - await reactor.connect(alice).mint(sharesAmount, alice.address); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(sharesAmount.mul(98)); - // But here we record a loss since interest have been taken in the meantime - await reactor.connect(alice).mint(sharesAmount, alice.address); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(sharesAmount.mul(97)); - expectApprox(await reactor.lastDebt(), parseEther('1.6'), 0.0001); - expect(await reactor.currentLoss()).to.be.equal(parseEther('0')); - // There are still claimable rewards - const claimable = await reactor.claimableRewards(); - expectApprox(claimable, parseEther('0.56'), 0.00001); - await reactor.claim(alice.address); - // In this implementation, `pull` just returns and rewards should not be modified - expect(await agEUR.balanceOf(alice.address)).to.be.equal(0); - expect(await reactor.claimableRewards()).to.be.equal(claimable); - expect(await reactor.claimedRewardsAccumulator()).to.be.equal(0); - }); - it('success - when there are claimable rewards with an adapted reactor', async () => { - const sharesAmount = parseUnits('1', collatBase); - await ANGLE.connect(alice).mint(alice.address, sharesAmount.mul(100)); - await ANGLE.connect(alice).approve(reactorClaimable.address, sharesAmount.mul(100)); - // Shares amount is consumed - await reactorClaimable.connect(alice).mint(sharesAmount, alice.address); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(sharesAmount.mul(99)); - // This is the second vault - expectApprox(await vaultManager.getVaultDebt(2), sharesAmount.mul(2).mul(targetCF), 0.00001); - await treasury.addMinter(agEUR.address, bob.address); - await agEUR.connect(bob).mint(bob.address, parseEther('1')); - // To make a gain we need to repay debt on behalf of the vault - await angle(vaultManager, bob, [repayDebt(2, parseEther('1'))]); - await reactorClaimable.connect(alice).mint(sharesAmount, alice.address); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(sharesAmount.mul(98)); - expect(await reactorClaimable.lastDebt()).to.be.equal(parseEther('1.44')); - expect(await reactorClaimable.currentLoss()).to.be.equal(parseEther('0')); - const claimable = await reactorClaimable.claimableRewards(); - expectApprox(claimable, parseEther('0.72'), 0.00001); - await reactorClaimable.claim(alice.address); - // In this implementation, `pull` returns exactly the amount - expect(await agEUR.balanceOf(alice.address)).to.be.gt(0); - expect(await reactorClaimable.claimableRewards()).to.be.equal(0); - expect(await reactorClaimable.rewardsAccumulatorOf(alice.address)).to.be.equal(0); - expect(await reactorClaimable.lastTimeOf(alice.address)).to.be.equal(await latestTime()); - expect(await reactorClaimable.claimedRewardsAccumulator()).to.be.equal( - await reactorClaimable.rewardsAccumulator(), - ); - }); - it('success - when there are claimable rewards but that a small loss decreased it with an adapted reactor', async () => { - const sharesAmount = parseUnits('1', collatBase); - await ANGLE.connect(alice).mint(alice.address, sharesAmount.mul(100)); - await ANGLE.connect(alice).approve(reactorClaimable.address, sharesAmount.mul(100)); - // Shares amount is consumed - await reactorClaimable.connect(alice).mint(sharesAmount, alice.address); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(sharesAmount.mul(99)); - expectApprox(await vaultManager.getVaultDebt(2), sharesAmount.mul(2).mul(targetCF), 0.00001); - await treasury.addMinter(agEUR.address, bob.address); - await agEUR.connect(bob).mint(bob.address, parseEther('1')); - // To make a gain we need to repay debt on behalf of the vault - await angle(vaultManager, bob, [repayDebt(2, parseEther('1'))]); - // Here we record a gain - await reactorClaimable.connect(alice).mint(sharesAmount, alice.address); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(sharesAmount.mul(98)); - // But here we record a loss since interest have been taken in the meantime - await reactorClaimable.connect(alice).mint(sharesAmount, alice.address); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(sharesAmount.mul(97)); - expectApprox(await reactorClaimable.lastDebt(), parseEther('1.6'), 0.0001); - expect(await reactorClaimable.currentLoss()).to.be.equal(parseEther('0')); - // There are still claimable rewards - const claimable = await reactorClaimable.claimableRewards(); - expectApprox(claimable, parseEther('0.56'), 0.00001); - await reactorClaimable.claim(alice.address); - // In this implementation, `pull` returns exactly the amount - expect(await agEUR.balanceOf(alice.address)).to.be.gt(0); - expect(await reactorClaimable.claimableRewards()).to.be.equal(0); - expect(await reactorClaimable.rewardsAccumulatorOf(alice.address)).to.be.equal(0); - expect(await reactorClaimable.lastTimeOf(alice.address)).to.be.equal(await latestTime()); - expect(await reactorClaimable.claimedRewardsAccumulator()).to.be.equal( - await reactorClaimable.rewardsAccumulator(), - ); - }); - }); - describe('scenari', () => { - it('success - nothing borrowed because dusty amount', async () => { - const sharesAmount = parseUnits('1', collatBase); - await ANGLE.connect(alice).mint(alice.address, sharesAmount.mul(100)); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount.mul(100)); - await agEUR.connect(bob).mint(bob.address, parseEther('1000')); - // Shares amount is consumed - await reactor.connect(alice).mint(100, alice.address); - expect(await vaultManager.getVaultDebt(1)).to.be.equal(0); - expect(await ANGLE.balanceOf(reactor.address)).to.be.equal(0); - expect((await vaultManager.vaultData(1)).collateralAmount).to.be.equal(100); - }); - it('reverts - everything repaid because dusty amount but not enough stablecoins in balance', async () => { - const sharesAmount = parseUnits('1', collatBase); - await ANGLE.connect(alice).mint(alice.address, sharesAmount.mul(100)); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount.mul(100)); - await agEUR.connect(bob).mint(bob.address, parseEther('1000')); - await reactor.connect(alice).mint(sharesAmount, alice.address); - expectApprox(await vaultManager.getVaultDebt(1), parseEther('0.8'), 0.00001); - expect(await ANGLE.balanceOf(reactor.address)).to.be.equal(0); - expect((await vaultManager.vaultData(1)).collateralAmount).to.be.equal(sharesAmount); - // Here the strategy cannot reimburse it all - await expect(reactor.connect(alice).withdraw(parseUnits('0.999999', collatBase), alice.address, alice.address)).to - .be.reverted; - }); - it('reverts - everything repaid because dusty amount but not enough stablecoins in balance', async () => { - const sharesAmount = parseUnits('1', collatBase); - await ANGLE.connect(alice).mint(alice.address, sharesAmount.mul(100)); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount.mul(100)); - await agEUR.connect(bob).mint(bob.address, parseEther('1000')); - await reactor.connect(alice).mint(sharesAmount, alice.address); - expectApprox(await vaultManager.getVaultDebt(1), parseEther('0.8'), 0.00001); - expect(await ANGLE.balanceOf(reactor.address)).to.be.equal(0); - expect((await vaultManager.vaultData(1)).collateralAmount).to.be.equal(sharesAmount); - // Here the strategy cannot reimburse it all - await agEUR.connect(bob).mint(reactor.address, parseEther('0.1')); - await reactor.connect(alice).withdraw(parseUnits('0.999999', collatBase), alice.address, alice.address); - expect(await vaultManager.getVaultDebt(1)).to.be.equal(parseEther('0')); - expect((await vaultManager.vaultData(1)).collateralAmount).to.be.gt(0); - }); - - it('reverts - liquidation and no asset left in the reactor', async () => { - const sharesAmount = parseUnits('1', collatBase); - await ANGLE.connect(alice).mint(alice.address, sharesAmount.mul(100)); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount.mul(100)); - await agEUR.connect(bob).mint(bob.address, parseEther('1000')); - await reactor.connect(alice).mint(sharesAmount, alice.address); - const rate = 0.5; - await oracle.update(parseEther(rate.toString())); - // In this case, vault cannot be brought in a healthy pos - // Limit is `healthFactor * liquidationDiscount * surcharge >= collateralFactor` - await displayVaultState(vaultManager, 1, log, collatBase); - const discount = Math.max((2 * rate * 0.5) / 1, 0.9); - const maxStablecoinAmountToRepay = rate * 2 * discount; - - await vaultManager - .connect(bob) - ['liquidate(uint256[],uint256[],address,address)']( - [1], - [parseEther(maxStablecoinAmountToRepay.toString())], - bob.address, - bob.address, - ); - await displayVaultState(vaultManager, 1, log, collatBase); - await expect(vaultManager.checkLiquidation(1, bob.address)).to.be.reverted; - expect(await vaultManager.badDebt()).to.be.gt(0); - await expect(reactor.connect(alice).withdraw(sharesAmount, alice.address, alice.address)).to.be.reverted; - }); - - it('success - liquidation and withdraw all asset left in the reactor', async () => { - const sharesAmount = parseUnits('1', collatBase); - await ANGLE.connect(alice).mint(alice.address, sharesAmount.mul(100)); - await ANGLE.connect(alice).approve(reactorClaimable.address, sharesAmount.mul(100)); - await agEUR.connect(bob).mint(bob.address, parseEther('1000')); - // Shares amount is consumed - await reactorClaimable.connect(alice).mint(sharesAmount, alice.address); - const rate = 0.5; - await oracle.update(parseEther(rate.toString())); - const discount = Math.max((2 * rate * 0.5) / 1, 0.9); - const maxStablecoinAmountToRepay = rate * 2 * discount; - - await vaultManager - .connect(bob) - ['liquidate(uint256[],uint256[],address,address)']( - [2], - [parseEther(maxStablecoinAmountToRepay.toString())], - bob.address, - bob.address, - ); - - expect(await vaultManager.badDebt()).to.be.gt(0); - const gains = parseUnits('0.05', collatBase); - await ANGLE.mint(reactorClaimable.address, gains); - const balancePre = await ANGLE.balanceOf(alice.address); - await reactorClaimable.connect(alice).redeem(sharesAmount, alice.address, alice.address); - expect(await reactorClaimable.claimableRewards()).to.be.equal(0); - // Null balance because pull function is not yet implemented - expect(await agEUR.balanceOf(alice.address)).to.be.gt(parseEther('0')); - expect(await reactorClaimable.lastDebt()).to.be.equal(0); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(gains.add(balancePre)); - }); - }); -}); diff --git a/test/hardhat/reactor/reactorEuler.test.ts b/test/hardhat/reactor/reactorEuler.test.ts deleted file mode 100644 index bdae12c1..00000000 --- a/test/hardhat/reactor/reactorEuler.test.ts +++ /dev/null @@ -1,512 +0,0 @@ -import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; -import { Signer } from 'ethers'; -import { formatBytes32String, parseEther, parseUnits } from 'ethers/lib/utils'; -import hre, { contract, ethers } from 'hardhat'; - -import { - AgToken, - AgToken__factory, - EulerReactor, - EulerReactor__factory, - MockEulerPool, - MockEulerPool__factory, - MockOracle, - MockOracle__factory, - MockStableMaster, - MockStableMaster__factory, - MockToken, - MockToken__factory, - MockTreasury, - MockTreasury__factory, - VaultManagerLiquidationBoost, - VaultManagerLiquidationBoost__factory, -} from '../../../typechain'; -import { expect } from '../utils/chai-setup'; -import { deployUpgradeable, expectApprox, expectApproxDelta, ZERO_ADDRESS } from '../utils/helpers'; - -const PRECISION = 5; - -contract('ReactorEuler', () => { - let deployer: SignerWithAddress; - let governor: SignerWithAddress; - let guardian: SignerWithAddress; - let alice: SignerWithAddress; - let bob: SignerWithAddress; - - let reactor: EulerReactor; - let eulerMarketA: MockEulerPool; - let treasury: MockTreasury; - let ANGLE: MockToken; - let oracle: MockOracle; - let stableMaster: MockStableMaster; - let agEUR: AgToken; - let vaultManager: VaultManagerLiquidationBoost; - - const impersonatedSigners: { [key: string]: Signer } = {}; - - const collatBase = 6; - const yearlyRate = 1.05; - const ratePerSecond = yearlyRate ** (1 / (365 * 24 * 3600)) - 1; - const lowerCF = 0.2e9; - const targetCF = 0.4e9; - const upperCF = 0.6e9; - - const params = { - debtCeiling: parseEther('100'), - collateralFactor: 0.9e9, - targetHealthFactor: 1.1e9, - borrowFee: 0e9, - interestRate: parseUnits(ratePerSecond.toFixed(27), 27), - liquidationSurcharge: 0.9e9, - maxLiquidationDiscount: 0.1e9, - liquidationBooster: 0.1e9, - whitelistingActivated: false, - baseBoost: 1e9, - }; - - before(async () => { - ({ deployer, alice, bob, governor, guardian } = await ethers.getNamedSigners()); - // add any addresses you want to impersonate here - const impersonatedAddresses = [{ address: '0xdC4e6DFe07EFCa50a197DF15D9200883eF4Eb1c8', name: 'governor' }]; - - for (const ob of impersonatedAddresses) { - await hre.network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [ob.address], - }); - - await hre.network.provider.send('hardhat_setBalance', [ob.address, '0x10000000000000000000000000000']); - - impersonatedSigners[ob.name] = await ethers.getSigner(ob.address); - } - }); - - beforeEach(async () => { - stableMaster = await new MockStableMaster__factory(deployer).deploy(); - - agEUR = (await deployUpgradeable(new AgToken__factory(deployer))) as AgToken; - await agEUR.connect(deployer).initialize('agEUR', 'agEUR', stableMaster.address); - - ANGLE = await new MockToken__factory(deployer).deploy('ANGLE', 'ANGLE', collatBase); - - vaultManager = (await deployUpgradeable( - new VaultManagerLiquidationBoost__factory(deployer), - )) as VaultManagerLiquidationBoost; - - treasury = await new MockTreasury__factory(deployer).deploy( - agEUR.address, - governor.address, - guardian.address, - vaultManager.address, - ZERO_ADDRESS, - ZERO_ADDRESS, - ); - await agEUR.connect(impersonatedSigners.governor).setUpTreasury(treasury.address); - await treasury.addMinter(agEUR.address, vaultManager.address); - await treasury.addMinter(agEUR.address, bob.address); - await agEUR.connect(bob).mint(bob.address, parseUnits('10000000', 18)); - - oracle = await new MockOracle__factory(deployer).deploy(parseUnits('2', 18), treasury.address); - - stableMaster = await new MockStableMaster__factory(deployer).deploy(); - - await vaultManager.initialize(treasury.address, ANGLE.address, oracle.address, params, 'USDC/agEUR'); - await vaultManager.connect(guardian).togglePause(); - - eulerMarketA = await new MockEulerPool__factory(deployer).deploy(agEUR.address, parseUnits('0', 18)); - reactor = (await deployUpgradeable(new EulerReactor__factory(deployer))) as EulerReactor; - await reactor.initialize( - eulerMarketA.address, - ethers.constants.Zero, - 'ANGLE/agEUR Reactor', - 'ANGLE/agEUR Reactor', - vaultManager.address, - lowerCF, - targetCF, - upperCF, - 0, - ); - // await reactor.connect(guardian).changeAllowance(ethers.constants.MaxUint256); - await agEUR.connect(bob).approve(eulerMarketA.address, ethers.constants.MaxUint256); - }); - describe('setMinInvest', () => { - it('initialize', async () => { - expect(await reactor.minInvest()).to.be.equal(0); - }); - it('reverts - only guardian or governor', async () => { - const newMinInvest = parseUnits('1', collatBase); - await expect(reactor.connect(alice).setMinInvest(newMinInvest)).to.be.revertedWith('NotGovernorOrGuardian'); - }); - it('success - invest only at 1 unit', async () => { - const newMinInvest = parseUnits('1', collatBase); - await reactor.connect(guardian).setMinInvest(newMinInvest); - expect(await reactor.minInvest()).to.be.equal(newMinInvest); - }); - it('success - invest at all thres', async () => { - const newMinInvest = parseUnits('0', collatBase); - await reactor.connect(governor).setMinInvest(newMinInvest); - expect(await reactor.minInvest()).to.be.equal(newMinInvest); - }); - }); - describe('changeAllowance', () => { - it('reverts - only guardian or governor', async () => { - await expect(reactor.connect(alice).changeAllowance(ethers.constants.Zero)).to.be.revertedWith( - 'NotGovernorOrGuardian', - ); - }); - it('success - decrease allowance', async () => { - await reactor.connect(guardian).changeAllowance(ethers.constants.Zero); - expect(await agEUR.allowance(reactor.address, eulerMarketA.address)).to.be.equal(parseEther('0')); - }); - it('success - allowance modified', async () => { - await reactor.connect(guardian).changeAllowance(ethers.constants.MaxUint256); - expect(await agEUR.allowance(reactor.address, eulerMarketA.address)).to.be.equal(ethers.constants.MaxUint256); - }); - it('success - increase allowance', async () => { - await reactor.connect(guardian).changeAllowance(ethers.constants.Zero); - expect(await agEUR.allowance(reactor.address, eulerMarketA.address)).to.be.equal(parseEther('0')); - await reactor.connect(guardian).changeAllowance(ethers.constants.MaxUint256); - expect(await agEUR.allowance(reactor.address, eulerMarketA.address)).to.be.equal(ethers.constants.MaxUint256); - }); - }); - describe('maxDeposit', () => { - beforeEach(async () => { - await vaultManager.connect(governor).setDebtCeiling(ethers.constants.MaxUint256.div(parseUnits('1', 27))); - }); - it('success - debtCeiling and max sane amount on Euler are infinite', async () => { - expect(await reactor.maxDeposit(alice.address)).to.be.equal(ethers.constants.MaxUint256); - }); - it('success - debtCeiling is infinite but max sane amount on Euler is not infinite', async () => { - await eulerMarketA.setMAXSANEAMOUNT(parseUnits('100', 18)); - expect(await reactor.maxDeposit(alice.address)).to.be.equal(parseUnits('125', collatBase)); - }); - it('success - debtCeiling is not infinite but max sane amount on Euler is infinite', async () => { - await vaultManager.connect(governor).setDebtCeiling(parseUnits('100', 18)); - expect(await reactor.maxDeposit(alice.address)).to.be.equal(parseUnits('125', collatBase)); - }); - it('success - debtCeiling < max sane amount - not infinite', async () => { - await eulerMarketA.setMAXSANEAMOUNT(parseUnits('100', 18)); - await vaultManager.connect(governor).setDebtCeiling(parseUnits('50', 18)); - expect(await reactor.maxDeposit(alice.address)).to.be.equal(parseUnits('62.5', collatBase)); - }); - it('success - debtCeiling > max sane amount - not infinite', async () => { - await eulerMarketA.setMAXSANEAMOUNT(parseUnits('50', 18)); - await vaultManager.connect(governor).setDebtCeiling(parseUnits('100', 18)); - expect(await reactor.maxDeposit(alice.address)).to.be.equal(parseUnits('62.5', collatBase)); - }); - it('success - super low max sane amount - but no borrow triggered ', async () => { - const sharesAmount = parseUnits('100', collatBase); - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - await eulerMarketA.setMAXSANEAMOUNT(parseUnits('0.0001', 18)); - expect(await reactor.maxDeposit(alice.address)).to.be.equal(parseUnits('100', collatBase)); - }); - }); - describe('maxMint', () => { - it('success', async () => { - await eulerMarketA.setMAXSANEAMOUNT(parseUnits('50', 18)); - await vaultManager.connect(governor).setDebtCeiling(parseUnits('100', 18)); - expect(await reactor.maxMint(alice.address)).to.be.equal(parseUnits('62.5', collatBase)); - }); - }); - describe('maxWithdraw', () => { - const sharesAmount = parseUnits('1', collatBase); - it('success - when no asset', async () => { - expect(await reactor.maxWithdraw(alice.address)).to.be.equal(0); - }); - it('success - when some has been minted', async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - // await eulerMarketA.connect(bob).setPoolSize(sharesAmount); - expect(await reactor.maxWithdraw(alice.address)).to.be.equal(sharesAmount.sub(1)); - // attention here you can't withdraw all if the interest rate from borrow is > 0 and we didn't do any profit on Euler - // because you can't repay the debt - }); - it('success - when no liquidity on Euler', async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - await eulerMarketA.connect(bob).setPoolSize(ethers.constants.Zero); - expect(await reactor.maxWithdraw(alice.address)).to.be.equal(ethers.constants.Zero); - }); - it('success - when some has been minted and no need to withdraw from Euler', async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - const gains = parseUnits('1', collatBase); - await ANGLE.connect(bob).mint(reactor.address, gains); - expect(await reactor.maxWithdraw(alice.address)).to.be.equal(sharesAmount.mul(2)); - }); - it('success - when some has been minted and no need to withdraw from Euler', async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await ANGLE.connect(bob).mint(bob.address, sharesAmount); - await ANGLE.connect(bob).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - await reactor.connect(bob).mint(sharesAmount, bob.address); - // this will have only a marginal impact on the maxWithdraw function - // it only allows to correct rounding errors which is why it is equal to sharesAmount - const gains = parseUnits('1', 18); - await agEUR.connect(bob).mint(reactor.address, gains); - expect(await reactor.maxWithdraw(alice.address)).to.be.equal(sharesAmount); - }); - }); - describe('maxRedeem', () => { - const sharesAmount = parseUnits('1', collatBase); - it('success - when no asset', async () => { - expect(await reactor.maxRedeem(alice.address)).to.be.equal(0); - }); - it('success - when some has been minted', async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - expect(await reactor.maxRedeem(alice.address)).to.be.equal(sharesAmount.sub(1)); - }); - }); - describe('withdraw', () => { - const sharesAmount = parseUnits('1', collatBase); - it('success - set interest rate to 0', async () => { - const balanceAgEUR = await agEUR.balanceOf(alice.address); - await vaultManager.connect(governor).setUint64(ethers.constants.AddressZero, formatBytes32String('IR')); - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - const amountInvestedInEuler = await eulerMarketA.balanceOfUnderlying(reactor.address); - expect(amountInvestedInEuler).to.be.equal(parseUnits('0.8', 18).sub(1)); - expect(await reactor.maxWithdraw(alice.address)).to.be.equal(sharesAmount.sub(1)); - await reactor.connect(alice).withdraw(await reactor.maxWithdraw(alice.address), alice.address, alice.address); - expect(await agEUR.balanceOf(alice.address)).to.be.equal(balanceAgEUR); - }); - it('success - under minInvest', async () => { - const newMinInvest = parseUnits('1', 18); - await reactor.connect(guardian).setMinInvest(newMinInvest); - - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - - const amountInvestedInEuler = await eulerMarketA.balanceOfUnderlying(reactor.address); - const lastBalance = await reactor.lastBalance(); - const vaultDebt = await vaultManager.getVaultDebt(1); - expect(amountInvestedInEuler).to.be.equal(ethers.constants.Zero); - expect(lastBalance).to.be.equal(parseUnits('0.8', 18).sub(1)); - expectApproxDelta(vaultDebt, parseUnits('0.8', 18), parseUnits('1', PRECISION)); - }); - it('success - no need to withdraw from Euler', async () => { - const sharesAmountBob = parseUnits('10', collatBase); - await vaultManager.connect(governor).setUint64(ethers.constants.AddressZero, formatBytes32String('IR')); - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - await ANGLE.connect(bob).mint(bob.address, sharesAmountBob); - await ANGLE.connect(bob).approve(reactor.address, sharesAmountBob); - await reactor.connect(bob).deposit(sharesAmountBob, bob.address); - let lastBalance = await reactor.lastBalance(); - expect(lastBalance).to.be.equal(parseUnits('8.8', 18).sub(1)); - const gains = parseUnits('1', 18); - await agEUR.connect(bob).mint(reactor.address, gains); - // to trigger lastBalance - await reactor.connect(alice).claim(alice.address); - await reactor.connect(alice).withdraw(await reactor.maxWithdraw(alice.address), alice.address, alice.address); - const amountInvestedInEuler = await eulerMarketA.balanceOfUnderlying(reactor.address); - lastBalance = await reactor.lastBalance(); - expectApprox(amountInvestedInEuler, parseUnits('8.8', 18).sub(1), 0.1); - }); - it('success - over the upperCF but poolSize too small', async () => { - const balanceAgEUR = await agEUR.balanceOf(alice.address); - await vaultManager.connect(governor).setUint64(ethers.constants.AddressZero, formatBytes32String('IR')); - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - await eulerMarketA.connect(bob).setPoolSize(parseUnits('0.4', 18)); - expect(await reactor.maxWithdraw(alice.address)).to.be.equal(sharesAmount.div(2)); - await reactor.connect(alice).withdraw(await reactor.maxWithdraw(alice.address), alice.address, alice.address); - expect(await agEUR.balanceOf(alice.address)).to.be.equal(balanceAgEUR); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(sharesAmount.div(2)); - expect(await reactor.balanceOf(alice.address)).to.be.equal(sharesAmount.div(2)); - }); - it('success - withdraw under the upperCF', async () => { - const sharesAmountBob = parseUnits('10', collatBase); - const balanceAgEUR = await agEUR.balanceOf(alice.address); - await vaultManager.connect(governor).setUint64(ethers.constants.AddressZero, formatBytes32String('IR')); - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - await ANGLE.connect(bob).mint(bob.address, sharesAmountBob); - await ANGLE.connect(bob).approve(reactor.address, sharesAmountBob); - await reactor.connect(bob).deposit(sharesAmountBob, bob.address); - expect(await reactor.maxWithdraw(alice.address)).to.be.equal(sharesAmount); - await reactor.connect(alice).withdraw(await reactor.maxWithdraw(alice.address), alice.address, alice.address); - expect(await agEUR.balanceOf(alice.address)).to.be.equal(balanceAgEUR); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(sharesAmount); - }); - it('success - over the upperCF but not reaching the dust', async () => { - const sharesAmountBob = parseUnits('0.2', collatBase); - const balanceAgEUR = await agEUR.balanceOf(alice.address); - await vaultManager.connect(governor).setUint64(ethers.constants.AddressZero, formatBytes32String('IR')); - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - await ANGLE.connect(bob).mint(bob.address, sharesAmountBob); - await ANGLE.connect(bob).approve(reactor.address, sharesAmountBob); - await reactor.connect(bob).deposit(sharesAmountBob, bob.address); - expect(await reactor.maxWithdraw(alice.address)).to.be.equal(sharesAmount); - await reactor.connect(alice).withdraw(await reactor.maxWithdraw(alice.address), alice.address, alice.address); - expect(await agEUR.balanceOf(alice.address)).to.be.equal(balanceAgEUR); - expect(await ANGLE.balanceOf(alice.address)).to.be.equal(sharesAmount); - }); - it('success - overall profit', async () => { - const balanceAgEUR = await agEUR.balanceOf(alice.address); - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - // fake a profit on Euler markets - await eulerMarketA.connect(bob).setInterestRateAccumulator(parseUnits('2', 18)); - await eulerMarketA.connect(bob).setPoolSize(parseUnits('1.6', 18)); - expect(await reactor.maxWithdraw(alice.address)).to.be.equal(sharesAmount); - const vaultDebt = await vaultManager.getVaultDebt(1); - await reactor.connect(alice).withdraw(await reactor.maxWithdraw(alice.address), alice.address, alice.address); - // sub(2) because we have the interest rate x2 but the actual deposit was 0.79999... - const approxProfit = parseUnits('1.6', 18).sub(2).sub(vaultDebt); - expectApproxDelta( - await agEUR.balanceOf(alice.address), - balanceAgEUR.add(approxProfit), - parseUnits('1', PRECISION), - ); - }); - it('success - loss also on Euler', async () => { - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - // fake a loss on Euler markets - await eulerMarketA.connect(bob).setInterestRateAccumulator(parseUnits('0.5', 18)); - await eulerMarketA.connect(bob).setPoolSize(parseUnits('0.4', 18)); - expect(await reactor.maxWithdraw(alice.address)).to.be.equal(sharesAmount.div(2).sub(1)); - const vaultDebt = await vaultManager.getVaultDebt(1); - await reactor.connect(alice).withdraw(await reactor.maxWithdraw(alice.address), alice.address, alice.address); - const loss = parseUnits('0.4', 18).add(vaultDebt.sub(parseUnits('0.8', 18))); - expectApproxDelta(await reactor.connect(alice).currentLoss(), loss, parseUnits('1', PRECISION)); - }); - it('success - profit with a non null protocol interest share', async () => { - await vaultManager.connect(governor).setUint64(ethers.constants.AddressZero, formatBytes32String('IR')); - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - // fake a gain on Euler markets - await eulerMarketA.connect(bob).setInterestRateAccumulator(parseUnits('2', 18)); - await agEUR.connect(bob).mint(eulerMarketA.address, parseUnits('100', 18)); - const vaultDebt = await vaultManager.getVaultDebt(1); - await reactor.connect(governor).setUint64(0.5e9, formatBytes32String('protocolInterestShare')); - await reactor.connect(alice).redeem(sharesAmount, alice.address, alice.address); - expect(await agEUR.balanceOf(alice.address)).to.be.equal(vaultDebt.div(2).add(1)); - expect(await reactor.protocolInterestAccumulated()).to.be.equal(vaultDebt.div(2)); - }); - it('success - loss with a non null protocol interest share', async () => { - await vaultManager.connect(governor).setUint64(ethers.constants.AddressZero, formatBytes32String('IR')); - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - // fake a loss on Euler markets - await eulerMarketA.connect(bob).setInterestRateAccumulator(parseUnits('0.5', 18)); - await agEUR.connect(bob).mint(eulerMarketA.address, parseUnits('100', 18)); - const vaultDebt = await vaultManager.getVaultDebt(1); - await reactor.connect(governor).setUint64(0.5e9, formatBytes32String('protocolInterestShare')); - await reactor.connect(alice).withdraw(await reactor.maxWithdraw(alice.address), alice.address, alice.address); - // You can only withdraw half of what you had in this case - expect(await agEUR.balanceOf(alice.address)).to.be.equal(0); - expect(await reactor.protocolDebt()).to.be.equal(vaultDebt.div(4).add(1)); - expect(await reactor.currentLoss()).to.be.equal(vaultDebt.div(4).add(1)); - }); - - it('success - profit with a non null protocol interest share and a small loss already accumulated', async () => { - await vaultManager.connect(governor).setUint64(ethers.constants.AddressZero, formatBytes32String('IR')); - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - // fake a loss on Euler markets - await eulerMarketA.connect(bob).setInterestRateAccumulator(parseUnits('0.5', 18)); - await agEUR.connect(bob).mint(eulerMarketA.address, parseUnits('100', 18)); - const vaultDebt = await vaultManager.getVaultDebt(1); - await reactor.connect(governor).setUint64(0.5e9, formatBytes32String('protocolInterestShare')); - - await reactor.connect(alice).withdraw(await reactor.maxWithdraw(alice.address), alice.address, alice.address); - // You can only withdraw half of what you had in this case - expect(await agEUR.balanceOf(alice.address)).to.be.equal(0); - expect(await reactor.protocolDebt()).to.be.equal(vaultDebt.div(4).add(1)); - expect(await reactor.currentLoss()).to.be.equal(vaultDebt.div(4).add(1)); - expect(await reactor.protocolInterestAccumulated()).to.be.equal(0); - // Only dust is left in the protocol - // Alice has 0.5 shares now -> minting so that she has 1.5 - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - // fake a gain on Euler markets - await eulerMarketA.connect(bob).setInterestRateAccumulator(parseUnits('2', 18)); - await reactor.connect(alice).redeem(sharesAmount, alice.address, alice.address); - expect(await reactor.currentLoss()).to.be.equal(0); - // Previous loss was 0.2 -> and there are still 0.8 stablecoins out there, so 3.2 after gain is realized -> new gain - // is hence 2.4 which divided by 2 makes a protocol gain of 1.2 to offset the loss of 0.2 -> so it's 1 eventually - expectApprox(await reactor.protocolInterestAccumulated(), parseEther('1'), 0.1); - expectApprox(await agEUR.balanceOf(alice.address), parseEther('1'), 0.1); - }); - - it('success - profit with a non null protocol interest share and a big loss already accumulated', async () => { - await vaultManager.connect(governor).setUint64(ethers.constants.AddressZero, formatBytes32String('IR')); - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - // fake a loss on Euler markets - await eulerMarketA.connect(bob).setInterestRateAccumulator(parseUnits('0.5', 18)); - await agEUR.connect(bob).mint(eulerMarketA.address, parseUnits('100', 18)); - const vaultDebt = await vaultManager.getVaultDebt(1); - await reactor.connect(governor).setUint64(0.5e9, formatBytes32String('protocolInterestShare')); - - await reactor.connect(alice).withdraw(await reactor.maxWithdraw(alice.address), alice.address, alice.address); - // You can only withdraw half of what you had in this case - expect(await agEUR.balanceOf(alice.address)).to.be.equal(0); - expect(await reactor.protocolDebt()).to.be.equal(vaultDebt.div(4).add(1)); - expect(await reactor.currentLoss()).to.be.equal(vaultDebt.div(4).add(1)); - expect(await reactor.protocolInterestAccumulated()).to.be.equal(0); - // Only dust is left in the protocol - // Alice has 0.5 shares now -> minting so that she has 1.5 - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - // fake a gain on Euler markets - await eulerMarketA.connect(bob).setInterestRateAccumulator(parseUnits('0.6', 18)); - await reactor.connect(alice).redeem(sharesAmount, alice.address, alice.address); - // Previous loss was 0.2 -> and there are still 0.8 stablecoins out there, so 0.96 after gain is realized -> new gain - // is hence 0.18 which divided by 2 makes a protocol gain of 0.09 to offset the loss of 0.2 - expect(await reactor.protocolInterestAccumulated()).to.be.equal(0); - expect(await agEUR.balanceOf(alice.address)).to.be.equal(0); - expectApprox(await reactor.protocolDebt(), parseEther('0.12'), 0.01); - expectApprox(await reactor.currentLoss(), parseEther('0.12'), 0.01); - }); - - it('success - small loss after a big profit with a non null protocol interest share', async () => { - await vaultManager.connect(governor).setUint64(ethers.constants.AddressZero, formatBytes32String('IR')); - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - // fake a gain on Euler markets - await eulerMarketA.connect(bob).setInterestRateAccumulator(parseUnits('2', 18)); - await agEUR.connect(bob).mint(eulerMarketA.address, parseUnits('100', 18)); - const vaultDebt = await vaultManager.getVaultDebt(1); - await reactor.connect(governor).setUint64(0.5e9, formatBytes32String('protocolInterestShare')); - await reactor.connect(alice).redeem(sharesAmount, alice.address, alice.address); - expect(await agEUR.balanceOf(alice.address)).to.be.equal(vaultDebt.div(2).add(1)); - // Gain is 0.4 - expect(await reactor.protocolInterestAccumulated()).to.be.equal(vaultDebt.div(2)); - await ANGLE.connect(alice).mint(alice.address, sharesAmount); - await ANGLE.connect(alice).approve(reactor.address, sharesAmount); - await reactor.connect(alice).mint(sharesAmount, alice.address); - await eulerMarketA.connect(bob).setInterestRateAccumulator(parseUnits('1.5', 18)); - // Here there are 1.2 stablecoins and a loss of 0.3 on it -> so 0.15 less - await reactor.connect(alice).redeem(sharesAmount.div(2), alice.address, alice.address); - expect(await reactor.protocolInterestAccumulated()).to.be.equal(vaultDebt.div(2).sub(parseEther('0.15'))); - expectApprox(await reactor.currentLoss(), parseEther('0.15'), 0.001); - }); - }); -}); diff --git a/test/hardhat/utils/helpers.ts b/test/hardhat/utils/helpers.ts index ba47e2c3..d54427bc 100644 --- a/test/hardhat/utils/helpers.ts +++ b/test/hardhat/utils/helpers.ts @@ -6,7 +6,6 @@ import hre, { ethers } from 'hardhat'; import { IERC20Metadata, IOracle, - Reactor, TransparentUpgradeableProxy__factory, VaultManager, VaultManagerLiquidationBoost, @@ -221,14 +220,6 @@ function permit(permitData: TypePermit): Call { }; } -async function displayReactorState(reactor: Reactor, log: boolean): Promise { - if (log) { - const vaultManager = (await ethers.getContractAt('VaultManager', await reactor.vaultManager())) as VaultManager; - const asset = (await ethers.getContractAt('IERC20Metadata', await reactor.asset())) as IERC20Metadata; - return await displayVaultState(vaultManager, await reactor.vaultID(), log, await asset.decimals()); - } -} - async function displayVaultState( vaultManager: VaultManager | VaultManagerLiquidationBoost, vaultID: BigNumberish, @@ -331,7 +322,6 @@ export { closeVault, createVault, deployUpgradeable, - displayReactorState, displayVaultState, expectApprox, expectApproxDelta, diff --git a/test/hardhat/vaultManager/vaultManager.test.ts b/test/hardhat/vaultManager/vaultManager.test.ts index fa27b038..850cc567 100644 --- a/test/hardhat/vaultManager/vaultManager.test.ts +++ b/test/hardhat/vaultManager/vaultManager.test.ts @@ -171,10 +171,6 @@ contract('VaultManagerLiquidationBoost', () => { expect(await vaultManager.ownerOf(2)).to.be.equal(alice.address); }); - it('reverts - not whitelisted', async () => { - await vaultManager.connect(governor).toggleWhitelist(ZERO_ADDRESS); - await expect(angle(vaultManager, alice, [createVault(alice.address)])).to.be.revertedWith('NotWhitelisted'); - }); it('reverts - unknown action', async () => { await expect( vaultManager @@ -192,15 +188,6 @@ contract('VaultManagerLiquidationBoost', () => { vaultManager.connect(governor)['angle(uint8[],bytes[],address,address)']([1], [], ZERO_ADDRESS, ZERO_ADDRESS), ).to.be.revertedWith('IncompatibleLengths'); }); - - it('success - whitelisted', async () => { - await vaultManager.connect(governor).toggleWhitelist(ZERO_ADDRESS); - await vaultManager.connect(governor).toggleWhitelist(alice.address); - await angle(vaultManager, alice, [createVault(alice.address), createVault(alice.address)]); - expect(await vaultManager.balanceOf(alice.address)).to.be.equal(2); - expect(await vaultManager.ownerOf(1)).to.be.equal(alice.address); - expect(await vaultManager.ownerOf(2)).to.be.equal(alice.address); - }); }); describe('closeVault', () => { @@ -1827,7 +1814,28 @@ contract('VaultManagerLiquidationBoost', () => { ), ).to.be.revertedWith('Paused'); }); - it('success - no liquidation boost', async () => { + it('reverts - not whitelisted', async () => { + await vaultManager.connect(governor).toggleWhitelist(ZERO_ADDRESS); + await expect( + vaultManager.connect(bob)['liquidate(uint256[],uint256[],address,address)']([1], [1], bob.address, bob.address), + ).to.be.revertedWith('NotWhitelisted'); + await expect( + vaultManager + .connect(bob) + ['liquidate(uint256[],uint256[],address,address,address,bytes)']( + [1], + [1], + bob.address, + bob.address, + ZERO_ADDRESS, + '0x', + ), + ).to.be.revertedWith('NotWhitelisted'); + }); + it('success - no liquidation boost and whitelist', async () => { + await vaultManager.connect(governor).toggleWhitelist(ZERO_ADDRESS); + await vaultManager.connect(governor).toggleWhitelist(bob.address); + expect(await vaultManager.isWhitelisted(bob.address)).to.be.equal(1); const rate = 0.99; await oracle.update(parseEther(rate.toString())); @@ -1849,6 +1857,28 @@ contract('VaultManagerLiquidationBoost', () => { 0.0001, ); + await expect( + vaultManager + .connect(alice) + ['liquidate(uint256[],uint256[],address,address)']( + [2], + [parseEther(maxStablecoinAmountToRepay.toString())], + alice.address, + alice.address, + ), + ).to.be.revertedWith('NotWhitelisted'); + + await expect( + vaultManager + .connect(governor) + ['liquidate(uint256[],uint256[],address,address)']( + [2], + [parseEther(maxStablecoinAmountToRepay.toString())], + governor.address, + governor.address, + ), + ).to.be.revertedWith('NotWhitelisted'); + const receipt = await ( await vaultManager .connect(bob) @@ -1873,7 +1903,57 @@ contract('VaultManagerLiquidationBoost', () => { 0.001, ); }); + it('success - no liquidation boost', async () => { + await vaultManager.connect(governor).toggleWhitelist(ZERO_ADDRESS); + await vaultManager.connect(governor).toggleWhitelist(bob.address); + const rate = 0.99; + await oracle.update(parseEther(rate.toString())); + + // Target health factor is 1.1 + // discount: `collateralAmountInStable * collateralFactor) / currentDebt` + const discount = (2 * rate * 0.5) / 1; + const maxStablecoinAmountToRepay = (1.1 - rate * 2 * 0.5) / (0.9 * 1.1 - 0.5 / discount); + + await displayVaultState(vaultManager, 2, log, collatBase); + + expectApprox( + (await vaultManager.checkLiquidation(2, bob.address)).maxStablecoinAmountToRepay, + parseEther(maxStablecoinAmountToRepay.toString()), + 0.0001, + ); + expectApprox( + (await vaultManager.checkLiquidation(2, bob.address)).maxCollateralAmountGiven, + parseUnits((maxStablecoinAmountToRepay / rate / discount).toFixed(10), collatBase), + 0.0001, + ); + + const receipt = await ( + await vaultManager + .connect(bob) + ['liquidate(uint256[],uint256[],address,address)']( + [2], + [parseEther(maxStablecoinAmountToRepay.toString())], + bob.address, + alice.address, + ) + ).wait(); + + inReceipt(receipt, 'LiquidatedVaults', { + vaultIDs: [BigNumber.from(2)], + }); + + await displayVaultState(vaultManager, 2, log, collatBase); + + await expect(vaultManager.checkLiquidation(2, bob.address)).to.be.reverted; + expectApprox( + await vaultManager.totalNormalizedDebt(), + borrowAmount.sub(parseEther(maxStablecoinAmountToRepay.toString()).mul(params.liquidationSurcharge).div(1e9)), + 0.001, + ); + }); it('success - no liquidation boost and base swapper contract', async () => { + await vaultManager.connect(governor).toggleWhitelist(ZERO_ADDRESS); + await vaultManager.connect(governor).toggleWhitelist(bob.address); const rate = 0.99; await oracle.update(parseEther(rate.toString())); @@ -1897,11 +1977,11 @@ contract('VaultManagerLiquidationBoost', () => { const receipt = await ( await vaultManager - .connect(bob) + .connect(alice) ['liquidate(uint256[],uint256[],address,address,address,bytes)']( [2], [parseEther(maxStablecoinAmountToRepay.toString())], - bob.address, + alice.address, bob.address, mockSwapper.address, web3.utils.keccak256('test'), diff --git a/test/hardhat/vaultManager/vaultManagerERC721.test.ts b/test/hardhat/vaultManager/vaultManagerERC721.test.ts index 08e69a83..365c9891 100644 --- a/test/hardhat/vaultManager/vaultManagerERC721.test.ts +++ b/test/hardhat/vaultManager/vaultManagerERC721.test.ts @@ -412,13 +412,6 @@ contract('VaultManagerLiquidationBoost - ERC721', () => { ); }); - it('reverts - not whitelisted', async () => { - await vaultManager.connect(governor).toggleWhitelist(ZERO_ADDRESS); - await expect(vaultManager.connect(alice).transferFrom(alice.address, bob.address, 2)).to.be.revertedWith( - 'NotWhitelisted', - ); - }); - it('success', async () => { await vaultManager.connect(alice).transferFrom(alice.address, bob.address, 2); expect(await vaultManager.ownerOf(2)).to.be.equal(bob.address); @@ -512,11 +505,6 @@ contract('VaultManagerLiquidationBoost - ERC721', () => { 'NonERC721Receiver', ); }); - - it('reverts - not whitelisted', async () => { - await vaultManager.connect(governor).toggleWhitelist(ZERO_ADDRESS); - await expect(angle(vaultManager, alice, [createVault(alice.address)])).to.be.revertedWith('NotWhitelisted'); - }); }); }); }); diff --git a/yarn.lock b/yarn.lock index 800d32a9..0d05f488 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,16 +2,17 @@ # yarn lockfile v1 -"@angleprotocol/sdk@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@angleprotocol/sdk/-/sdk-3.0.1.tgz#0efb35dd2eef51fa2702240a7600dc4849ffec5e" - integrity sha512-CKSxuy+1Zv4xsv3k4owLxQuDR/4j12NwJmh+pWdUtpyDsf199WThvSTiZGYbUKbmX1E8Zoold0ZFilpjB4YX9Q== +"@angleprotocol/sdk@3.0.40": + version "3.0.40" + resolved "https://registry.yarnpkg.com/@angleprotocol/sdk/-/sdk-3.0.40.tgz#2c04c5c985c19729b407e1e48cfb2e5ed28a9e70" + integrity sha512-kFK1DdSsHUd8HB3aV01uIRn0JegFTom+67NaWFgn0T+Fr6NU5uUrcLUvzRMxMI4CyM+dWh4jzOXPioiF7G2dmA== dependencies: "@typechain/ethers-v5" "^10.0.0" "@types/lodash" "^4.14.180" ethers "^5.6.4" graphql "^15.7.1" graphql-request "^3.6.1" + jsbi "^4.3.0" keccak256 "^1.0.6" lodash "^4.17.21" merkletreejs "^0.3.9" @@ -8335,6 +8336,11 @@ jsbi@^3.1.4: resolved "https://registry.yarnpkg.com/jsbi/-/jsbi-3.2.5.tgz#b37bb90e0e5c2814c1c2a1bcd8c729888a2e37d6" integrity sha512-aBE4n43IPvjaddScbvWRA2YlTzKEynHzu7MqOyTipdHucf/VxS63ViCjxYRg86M8Rxwbt/GfzHl1kKERkt45fQ== +jsbi@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/jsbi/-/jsbi-4.3.0.tgz#b54ee074fb6fcbc00619559305c8f7e912b04741" + integrity sha512-SnZNcinB4RIcnEyZqFPdGPVgrg2AcnykiBy0sHVJQKHYeaLUvi3Exj+iaPpLnFVkDPZIV4U0yvgC9/R4uEAZ9g== + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"