feat: Added imports in a different file as too long, implemented getLimits and getTokens

This commit is contained in:
domenicodev
2024-01-23 16:54:38 +01:00
parent 94644ac735
commit ba289d5bd1
2 changed files with 235 additions and 42 deletions

View File

@@ -2,7 +2,8 @@
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
pragma solidity ^0.8.13; pragma solidity ^0.8.13;
import {IERC20, ISwapAdapter} from "src/interfaces/ISwapAdapter.sol"; /// @dev Wrapped imports (incl. ISwapAdapter and IERC20) are included in utils
import "./AngleUtils.sol";
/// @title AngleAdapter /// @title AngleAdapter
contract AngleAdapter is ISwapAdapter { contract AngleAdapter is ISwapAdapter {
@@ -13,6 +14,7 @@ contract AngleAdapter is ISwapAdapter {
transmuter = _transmuter; transmuter = _transmuter;
} }
/// @inheritdoc ISwapAdapter
function price( function price(
bytes32, bytes32,
IERC20 _sellToken, IERC20 _sellToken,
@@ -38,11 +40,42 @@ contract AngleAdapter is ISwapAdapter {
revert NotImplemented("TemplateSwapAdapter.swap"); revert NotImplemented("TemplateSwapAdapter.swap");
} }
/// @inheritdoc ISwapAdapter
/// @dev mint may have no limits, but we underestimate them to make sure, with the same amount of sellToken.
/// We use the quoteIn (incl. fee), because calculating fee requires a part of the implementation of
/// the Angle Diamond Storage, and therefore redundant functions and excessive contract size, with an high complexity.
function getLimits(bytes32, IERC20 sellToken, IERC20 buyToken) function getLimits(bytes32, IERC20 sellToken, IERC20 buyToken)
external external
view
override
returns (uint256[] memory limits) returns (uint256[] memory limits)
{ {
revert NotImplemented("TemplateSwapAdapter.getLimits"); limits = new uint256[](2);
address sellTokenAddress = address(sellToken);
address buyTokenAddress = address(buyToken);
if(buyTokenAddress == transmuter.agToken()) { // mint(buy agToken)
Collateral memory collatInfo = transmuter.getCollateralInfo(sellTokenAddress);
if(collatInfo.isManaged > 0) {
limits[0] = LibManager.maxAvailable(collatInfo.managerData.config);
}
else {
limits[0] = sellToken.balanceOf(address(transmuter));
}
limits[1] = transmuter.quoteIn(limits[0], sellTokenAddress, buyTokenAddress);
}
else { // burn(sell agToken)
Collateral memory collatInfo = transmuter.getCollateralInfo(buyTokenAddress);
uint256 collatLimit;
if(collatInfo.isManaged > 0) {
collatLimit = LibManager.maxAvailable(collatInfo.managerData.config);
}
else {
collatLimit = buyToken.balanceOf(address(transmuter));
}
limits[0] = transmuter.quoteIn(collatLimit, buyTokenAddress, sellTokenAddress);
limits[1] = collatLimit;
}
} }
function getCapabilities(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) function getCapabilities(bytes32 poolId, IERC20 sellToken, IERC20 buyToken)
@@ -52,11 +85,21 @@ contract AngleAdapter is ISwapAdapter {
revert NotImplemented("TemplateSwapAdapter.getCapabilities"); revert NotImplemented("TemplateSwapAdapter.getCapabilities");
} }
function getTokens(bytes32 poolId) /// @inheritdoc ISwapAdapter
/// @dev Since Angle has no pool IDs but supports 3 tokens(agToken and the collaterals),
/// we return all the available collaterals and the agToken(agEUR)
function getTokens(bytes32)
external external
view
override
returns (IERC20[] memory tokens) returns (IERC20[] memory tokens)
{ {
revert NotImplemented("TemplateSwapAdapter.getTokens"); address[] memory collateralsAddresses = transmuter.getCollateralList();
tokens = new IERC20[](collateralsAddresses.length + 1);
for(uint256 i = 0; i < collateralsAddresses.length; i++) {
tokens[i] = IERC20(collateralsAddresses[i]);
}
tokens[collateralsAddresses.length] = IERC20(transmuter.agToken());
} }
function getPoolIds(uint256 offset, uint256 limit) function getPoolIds(uint256 offset, uint256 limit)
@@ -85,39 +128,6 @@ contract AngleAdapter is ISwapAdapter {
} }
abstract contract ITransmuter { abstract contract ITransmuter {
struct Tuple6871229 {
address facetAddress;
uint8 action;
bytes4[] functionSelectors;
}
struct Tuple1236461 {
address facetAddress;
bytes4[] functionSelectors;
}
struct Tuple3550792 {
uint8 isManaged;
uint8 isMintLive;
uint8 isBurnLive;
uint8 decimals;
uint8 onlyWhitelisted;
uint216 normalizedStables;
uint64[] xFeeMint;
int64[] yFeeMint;
uint64[] xFeeBurn;
int64[] yFeeBurn;
bytes oracleConfig;
bytes whitelistData;
Tuple5479340 managerData;
}
struct Tuple5479340 {
address[] subCollaterals;
bytes config;
}
function diamondCut(Tuple6871229[] memory _diamondCut, address _init, bytes memory _calldata) external {}
function implementation() external view returns (address) {} function implementation() external view returns (address) {}
@@ -129,8 +139,6 @@ abstract contract ITransmuter {
function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory _facetFunctionSelectors) {} function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory _facetFunctionSelectors) {}
function facets() external view returns (Tuple1236461[] memory facets_) {}
function accessControlManager() external view returns (address) {} function accessControlManager() external view returns (address) {}
function agToken() external view returns (address) {} function agToken() external view returns (address) {}
@@ -141,7 +149,7 @@ abstract contract ITransmuter {
function getCollateralDecimals(address collateral) external view returns (uint8) {} function getCollateralDecimals(address collateral) external view returns (uint8) {}
function getCollateralInfo(address collateral) external view returns (Tuple3550792 memory) {} function getCollateralInfo(address collateral) external view returns (Collateral memory) {}
function getCollateralList() external view returns (address[] memory) {} function getCollateralList() external view returns (address[] memory) {}
@@ -203,8 +211,6 @@ abstract contract ITransmuter {
function setAccessControlManager(address _newAccessControlManager) external {} function setAccessControlManager(address _newAccessControlManager) external {}
function setCollateralManager(address collateral, Tuple5479340 memory managerData) external {}
function setOracle(address collateral, bytes memory oracleConfig) external {} function setOracle(address collateral, bytes memory oracleConfig) external {}
function setWhitelistStatus(address collateral, uint8 whitelistStatus, bytes memory whitelistData) external {} function setWhitelistStatus(address collateral, uint8 whitelistStatus, bytes memory whitelistData) external {}

View File

@@ -0,0 +1,187 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
/**
* @dev Collection of wrapped interfaces, items and libraries for Angle
* we use them here to maintain integrity and readability of contracts
* as there are many different imports and items
*/
import {IERC20, ISwapAdapter} from "src/interfaces/ISwapAdapter.sol";
interface IAgToken is IERC20 {
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
MINTER ROLE ONLY FUNCTIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
/// @notice Lets a whitelisted contract mint agTokens
/// @param account Address to mint to
/// @param amount Amount to mint
function mint(address account, uint256 amount) external;
/// @notice Burns `amount` tokens from a `burner` address after being asked to by `sender`
/// @param amount Amount of tokens to burn
/// @param burner Address to burn from
/// @param sender Address which requested the burn from `burner`
/// @dev This method is to be called by a contract with the minter right after being requested
/// to do so by a `sender` address willing to burn tokens from another `burner` address
/// @dev The method checks the allowance between the `sender` and the `burner`
function burnFrom(uint256 amount, address burner, address sender) external;
/// @notice Burns `amount` tokens from a `burner` address
/// @param amount Amount of tokens to burn
/// @param burner Address to burn from
/// @dev This method is to be called by a contract with a minter right on the AgToken after being
/// requested to do so by an address willing to burn tokens from its address
function burnSelf(uint256 amount, address burner) external;
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TREASURY ONLY FUNCTIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
/// @notice Adds a minter in the contract
/// @param minter Minter address to add
/// @dev Zero address checks are performed directly in the `Treasury` contract
function addMinter(address minter) external;
/// @notice Removes a minter from the contract
/// @param minter Minter address to remove
/// @dev This function can also be called by a minter wishing to revoke itself
function removeMinter(address minter) external;
/// @notice Sets a new treasury contract
/// @param _treasury New treasury address
function setTreasury(address _treasury) external;
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
EXTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
/// @notice Checks whether an address has the right to mint agTokens
/// @param minter Address for which the minting right should be checked
/// @return Whether the address has the right to mint agTokens or not
function isMinter(address minter) external view returns (bool);
/// @notice Amount of decimals of the stablecoin
function decimals() external view returns (uint8);
}
enum ManagerType {
EXTERNAL
}
enum WhitelistType {
BACKED
}
struct ManagerStorage {
IERC20[] subCollaterals; // Subtokens handled by the manager or strategies
bytes config; // Additional configuration data
}
struct Collateral {
uint8 isManaged; // If the collateral is managed through external strategies
uint8 isMintLive; // If minting from this asset is unpaused
uint8 isBurnLive; // If burning to this asset is unpaused
uint8 decimals; // IERC20Metadata(collateral).decimals()
uint8 onlyWhitelisted; // If only whitelisted addresses can burn or redeem for this token
uint216 normalizedStables; // Normalized amount of stablecoins issued from this collateral
uint64[] xFeeMint; // Increasing exposures in [0,BASE_9[
int64[] yFeeMint; // Mint fees at the exposures specified in `xFeeMint`
uint64[] xFeeBurn; // Decreasing exposures in ]0,BASE_9]
int64[] yFeeBurn; // Burn fees at the exposures specified in `xFeeBurn`
bytes oracleConfig; // Data about the oracle used for the collateral
bytes whitelistData; // For whitelisted collateral, data used to verify whitelists
ManagerStorage managerData; // For managed collateral, data used to handle the strategies
}
struct TransmuterStorage {
IAgToken agToken; // agToken handled by the system
uint8 isRedemptionLive; // If redemption is unpaused
uint8 statusReentrant; // If call is reentrant or not
uint128 normalizedStables; // Normalized amount of stablecoins issued by the system
uint128 normalizer; // To reconcile `normalizedStables` values with the actual amount
address[] collateralList; // List of collateral assets supported by the system
uint64[] xRedemptionCurve; // Increasing collateral ratios > 0
int64[] yRedemptionCurve; // Value of the redemption fees at `xRedemptionCurve`
mapping(address => Collateral) collaterals; // Maps a collateral asset to its parameters
mapping(address => uint256) isTrusted; // If an address is trusted to update the normalizer value
mapping(address => uint256) isSellerTrusted; // If an address is trusted to sell accruing reward tokens
mapping(WhitelistType => mapping(address => uint256)) isWhitelistedForType;
}
interface IManager {
/// @notice Returns the amount of collateral managed by the Manager
/// @return balances Balances of all the subCollaterals handled by the manager
/// @dev MUST NOT revert
function totalAssets() external view returns (uint256[] memory balances, uint256 totalValue);
/// @notice Hook to invest `amount` of `collateral`
/// @dev MUST revert if the manager cannot accept these funds
/// @dev MUST have received the funds beforehand
function invest(uint256 amount) external;
/// @notice Sends `amount` of `collateral` to the `to` address
/// @dev Called when `agToken` are burnt and during redemptions
// @dev MUST revert if there are not funds enough available
/// @dev MUST be callable only by the transmuter
function release(address asset, address to, uint256 amount) external;
/// @notice Gives the maximum amount of collateral immediately available for a transfer
/// @dev Useful for integrators using `quoteIn` and `quoteOut`
function maxAvailable() external view returns (uint256);
}
/// @title LibManager
/// @author Angle Labs, Inc.
/// @dev Managed collateral assets may be handled through external smart contracts or directly through this library
/// @dev There is no implementation at this point for a managed collateral handled through this library, and
/// a new specific `ManagerType` would need to be added in this case
library LibManager {
/// @notice Checks to which address managed funds must be transferred
function transferRecipient(bytes memory config) internal view returns (address recipient) {
(ManagerType managerType, bytes memory data) = parseManagerConfig(config);
recipient = address(this);
if (managerType == ManagerType.EXTERNAL) return abi.decode(data, (address));
}
/// @notice Performs a transfer of `token` for a collateral that is managed to a `to` address
/// @dev `token` may not be the actual collateral itself, as some collaterals have subcollaterals associated
/// with it
/// @dev Eventually pulls funds from strategies
function release(address token, address to, uint256 amount, bytes memory config) internal {
(ManagerType managerType, bytes memory data) = parseManagerConfig(config);
if (managerType == ManagerType.EXTERNAL) abi.decode(data, (IManager)).release(token, to, amount);
}
/// @notice Gets the balances of all the tokens controlled through `managerData`
/// @return balances An array of size `subCollaterals` with current balances of all subCollaterals
/// including the one corresponding to the `managerData` given
/// @return totalValue The value of all the `subCollaterals` in `collateral`
/// @dev `subCollaterals` must always have as first token (index 0) the collateral itself
function totalAssets(bytes memory config) internal view returns (uint256[] memory balances, uint256 totalValue) {
(ManagerType managerType, bytes memory data) = parseManagerConfig(config);
if (managerType == ManagerType.EXTERNAL) return abi.decode(data, (IManager)).totalAssets();
}
/// @notice Calls a hook if needed after new funds have been transfered to a manager
function invest(uint256 amount, bytes memory config) internal {
(ManagerType managerType, bytes memory data) = parseManagerConfig(config);
if (managerType == ManagerType.EXTERNAL) abi.decode(data, (IManager)).invest(amount);
}
/// @notice Returns available underlying tokens, for instance if liquidity is fully used and
/// not withdrawable the function will return 0
function maxAvailable(bytes memory config) internal view returns (uint256 available) {
(ManagerType managerType, bytes memory data) = parseManagerConfig(config);
if (managerType == ManagerType.EXTERNAL) return abi.decode(data, (IManager)).maxAvailable();
}
/// @notice Decodes the `managerData` associated to a collateral
function parseManagerConfig(
bytes memory config
) internal pure returns (ManagerType managerType, bytes memory data) {
(managerType, data) = abi.decode(config, (ManagerType, bytes));
}
}