OracleSwapFreezer

Description:

Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "src/contracts/facilitators/gsm/swapFreezer/OracleSwapFreezer.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import {IPoolAddressesProvider} from 'aave-v3-origin/contracts/interfaces/IPoolAddressesProvider.sol';
import {IPriceOracle} from 'aave-v3-origin/contracts/interfaces/IPriceOracle.sol';
import {AutomationCompatibleInterface} from 'src/contracts/dependencies/chainlink/AutomationCompatibleInterface.sol';
import {IGsm} from 'src/contracts/facilitators/gsm/interfaces/IGsm.sol';

/**
 * @title OracleSwapFreezer
 * @author Aave
 * @notice Swap freezer that enacts the freeze action based on underlying oracle price, GSM's state and predefined price boundaries
 * @dev Chainlink Automation-compatible contract using Aave V3 Price Oracle, where prices are USD denominated with 8-decimal precision
 * @dev Freeze action is executable if GSM is not seized, not frozen and price is outside of the freeze bounds
 * @dev Unfreeze action is executable if GSM is not seized, frozen, unfreezing is allowed and price is inside the unfreeze bounds
 */
contract OracleSwapFreezer is AutomationCompatibleInterface {
  enum Action {
    NONE,
    FREEZE,
    UNFREEZE
  }

  IGsm public immutable GSM;
  address public immutable UNDERLYING_ASSET;
  IPoolAddressesProvider public immutable ADDRESS_PROVIDER;
  uint128 internal immutable _freezeLowerBound;
  uint128 internal immutable _freezeUpperBound;
  uint128 internal immutable _unfreezeLowerBound;
  uint128 internal immutable _unfreezeUpperBound;
  bool internal immutable _allowUnfreeze;

  /**
   * @dev Constructor
   * @dev Freeze/unfreeze bounds are specified in USD with 8-decimal precision, like Aave v3 Price Oracles
   * @dev Unfreeze boundaries are "contained" in freeze boundaries, where freezeLowerBound < unfreezeLowerBound and unfreezeUpperBound < freezeUpperBound
   * @dev All bound ranges are inclusive
   * @param gsm The GSM that this contract will trigger freezes/unfreezes on
   * @param underlyingAsset The address of the collateral asset
   * @param addressProvider The Aave Addresses Provider for looking up the Price Oracle
   * @param freezeLowerBound The lower price bound for freeze operations
   * @param freezeUpperBound The upper price bound for freeze operations
   * @param unfreezeLowerBound The lower price bound for unfreeze operations, must be 0 if unfreezing not allowed
   * @param unfreezeUpperBound The upper price bound for unfreeze operations, must be 0 if unfreezing not allowed
   * @param allowUnfreeze True if bounds verification should factor in the unfreeze boundary, false otherwise
   */
  constructor(
    IGsm gsm,
    address underlyingAsset,
    IPoolAddressesProvider addressProvider,
    uint128 freezeLowerBound,
    uint128 freezeUpperBound,
    uint128 unfreezeLowerBound,
    uint128 unfreezeUpperBound,
    bool allowUnfreeze
  ) {
    require(underlyingAsset != address(0), 'ZERO_ADDRESS_NOT_VALID');
    require(
      _validateBounds(
        freezeLowerBound,
        freezeUpperBound,
        unfreezeLowerBound,
        unfreezeUpperBound,
        allowUnfreeze
      ),
      'BOUNDS_NOT_VALID'
    );
    GSM = gsm;
    UNDERLYING_ASSET = underlyingAsset;
    ADDRESS_PROVIDER = addressProvider;
    _freezeLowerBound = freezeLowerBound;
    _freezeUpperBound = freezeUpperBound;
    _unfreezeLowerBound = unfreezeLowerBound;
    _unfreezeUpperBound = unfreezeUpperBound;
    _allowUnfreeze = allowUnfreeze;
  }

  /// @inheritdoc AutomationCompatibleInterface
  function performUpkeep(bytes calldata) external {
    Action action = _getAction();
    if (action == Action.FREEZE) {
      GSM.setSwapFreeze(true);
    } else if (action == Action.UNFREEZE) {
      GSM.setSwapFreeze(false);
    }
  }

  /// @inheritdoc AutomationCompatibleInterface
  function checkUpkeep(bytes calldata) external view returns (bool, bytes memory) {
    return (_getAction() == Action.NONE ? false : true, '');
  }

  /**
   * @notice Returns whether or not the swap freezer can unfreeze a GSM
   * @return True if the freezer can unfreeze, false otherwise
   */
  function getCanUnfreeze() external view returns (bool) {
    return _allowUnfreeze;
  }

  /**
   * @notice Returns the bound used for freeze operations
   * @return The freeze lower bound (inclusive)
   * @return The freeze upper bound (inclusive)
   */
  function getFreezeBound() external view returns (uint128, uint128) {
    return (_freezeLowerBound, _freezeUpperBound);
  }

  /**
   * @notice Returns the bound used for unfreeze operations, or (0, 0) if unfreezing not allowed
   * @return The unfreeze lower bound (inclusive), or 0 if unfreezing not allowed
   * @return The unfreeze upper bound (inclusive), or 0 if unfreezing not allowed
   */
  function getUnfreezeBound() external view returns (uint128, uint128) {
    return (_unfreezeLowerBound, _unfreezeUpperBound);
  }

  /**
   * @notice Fetches price oracle data and checks whether a swap freeze or unfreeze action is required
   * @return The action to take (none, freeze, or unfreeze)
   */
  function _getAction() internal view returns (Action) {
    if (GSM.hasRole(GSM.SWAP_FREEZER_ROLE(), address(this))) {
      if (GSM.getIsSeized()) {
        return Action.NONE;
      } else if (!GSM.getIsFrozen()) {
        if (_isActionAllowed(Action.FREEZE)) {
          return Action.FREEZE;
        }
      } else if (_allowUnfreeze) {
        if (_isActionAllowed(Action.UNFREEZE)) {
          return Action.UNFREEZE;
        }
      }
    }
    return Action.NONE;
  }

  /**
   * @notice Checks whether the action is allowed, based on the action, oracle price and freeze/unfreeze bounds
   * @dev Freeze action is allowed if price is outside of the freeze bounds
   * @dev Unfreeze action is allowed if price is inside the unfreeze bounds
   * @param actionToExecute The requested action type to validate
   * @return True if conditions to execute the action passed are met, false otherwise
   */
  function _isActionAllowed(Action actionToExecute) internal view returns (bool) {
    uint256 oraclePrice = IPriceOracle(ADDRESS_PROVIDER.getPriceOracle()).getAssetPrice(
      UNDERLYING_ASSET
    );
    // Assume a 0 oracle price is invalid and no action should be taken based on that data
    if (oraclePrice == 0) {
      return false;
    } else if (actionToExecute == Action.FREEZE) {
      if (oraclePrice <= _freezeLowerBound || oraclePrice >= _freezeUpperBound) {
        return true;
      }
    } else if (actionToExecute == Action.UNFREEZE) {
      if (oraclePrice >= _unfreezeLowerBound && oraclePrice <= _unfreezeUpperBound) {
        return true;
      }
    }
    return false;
  }

  /**
   * @notice Verifies that the unfreeze bound and freeze bounds do not conflict, causing unexpected behaviour
   * @param freezeLowerBound The lower bound for freeze operations
   * @param freezeUpperBound The upper bound for freeze operations
   * @param unfreezeLowerBound The lower bound for unfreeze operations, must be 0 if unfreezing not allowed
   * @param unfreezeUpperBound The upper bound for unfreeze operations, must be 0 if unfreezing not allowed
   * @param allowUnfreeze True if bounds verification should factor in the unfreeze boundary, false otherwise
   * @return True if the bounds are valid and conflict-free, false otherwise
   */
  function _validateBounds(
    uint128 freezeLowerBound,
    uint128 freezeUpperBound,
    uint128 unfreezeLowerBound,
    uint128 unfreezeUpperBound,
    bool allowUnfreeze
  ) internal pure returns (bool) {
    if (freezeLowerBound >= freezeUpperBound) {
      return false;
    } else if (allowUnfreeze) {
      if (
        unfreezeLowerBound >= unfreezeUpperBound ||
        freezeLowerBound >= unfreezeLowerBound ||
        freezeUpperBound <= unfreezeUpperBound
      ) {
        return false;
      }
    } else {
      if (unfreezeLowerBound != 0 || unfreezeUpperBound != 0) {
        return false;
      }
    }
    return true;
  }
}
"
    },
    "lib/aave-v3-origin/src/contracts/interfaces/IPoolAddressesProvider.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title IPoolAddressesProvider
 * @author Aave
 * @notice Defines the basic interface for a Pool Addresses Provider.
 */
interface IPoolAddressesProvider {
  /**
   * @dev Emitted when the market identifier is updated.
   * @param oldMarketId The old id of the market
   * @param newMarketId The new id of the market
   */
  event MarketIdSet(string indexed oldMarketId, string indexed newMarketId);

  /**
   * @dev Emitted when the pool is updated.
   * @param oldAddress The old address of the Pool
   * @param newAddress The new address of the Pool
   */
  event PoolUpdated(address indexed oldAddress, address indexed newAddress);

  /**
   * @dev Emitted when the pool configurator is updated.
   * @param oldAddress The old address of the PoolConfigurator
   * @param newAddress The new address of the PoolConfigurator
   */
  event PoolConfiguratorUpdated(address indexed oldAddress, address indexed newAddress);

  /**
   * @dev Emitted when the price oracle is updated.
   * @param oldAddress The old address of the PriceOracle
   * @param newAddress The new address of the PriceOracle
   */
  event PriceOracleUpdated(address indexed oldAddress, address indexed newAddress);

  /**
   * @dev Emitted when the ACL manager is updated.
   * @param oldAddress The old address of the ACLManager
   * @param newAddress The new address of the ACLManager
   */
  event ACLManagerUpdated(address indexed oldAddress, address indexed newAddress);

  /**
   * @dev Emitted when the ACL admin is updated.
   * @param oldAddress The old address of the ACLAdmin
   * @param newAddress The new address of the ACLAdmin
   */
  event ACLAdminUpdated(address indexed oldAddress, address indexed newAddress);

  /**
   * @dev Emitted when the price oracle sentinel is updated.
   * @param oldAddress The old address of the PriceOracleSentinel
   * @param newAddress The new address of the PriceOracleSentinel
   */
  event PriceOracleSentinelUpdated(address indexed oldAddress, address indexed newAddress);

  /**
   * @dev Emitted when the pool data provider is updated.
   * @param oldAddress The old address of the PoolDataProvider
   * @param newAddress The new address of the PoolDataProvider
   */
  event PoolDataProviderUpdated(address indexed oldAddress, address indexed newAddress);

  /**
   * @dev Emitted when a new proxy is created.
   * @param id The identifier of the proxy
   * @param proxyAddress The address of the created proxy contract
   * @param implementationAddress The address of the implementation contract
   */
  event ProxyCreated(
    bytes32 indexed id,
    address indexed proxyAddress,
    address indexed implementationAddress
  );

  /**
   * @dev Emitted when a new non-proxied contract address is registered.
   * @param id The identifier of the contract
   * @param oldAddress The address of the old contract
   * @param newAddress The address of the new contract
   */
  event AddressSet(bytes32 indexed id, address indexed oldAddress, address indexed newAddress);

  /**
   * @dev Emitted when the implementation of the proxy registered with id is updated
   * @param id The identifier of the contract
   * @param proxyAddress The address of the proxy contract
   * @param oldImplementationAddress The address of the old implementation contract
   * @param newImplementationAddress The address of the new implementation contract
   */
  event AddressSetAsProxy(
    bytes32 indexed id,
    address indexed proxyAddress,
    address oldImplementationAddress,
    address indexed newImplementationAddress
  );

  /**
   * @notice Returns the id of the Aave market to which this contract points to.
   * @return The market id
   */
  function getMarketId() external view returns (string memory);

  /**
   * @notice Associates an id with a specific PoolAddressesProvider.
   * @dev This can be used to create an onchain registry of PoolAddressesProviders to
   * identify and validate multiple Aave markets.
   * @param newMarketId The market id
   */
  function setMarketId(string calldata newMarketId) external;

  /**
   * @notice Returns an address by its identifier.
   * @dev The returned address might be an EOA or a contract, potentially proxied
   * @dev It returns ZERO if there is no registered address with the given id
   * @param id The id
   * @return The address of the registered for the specified id
   */
  function getAddress(bytes32 id) external view returns (address);

  /**
   * @notice General function to update the implementation of a proxy registered with
   * certain `id`. If there is no proxy registered, it will instantiate one and
   * set as implementation the `newImplementationAddress`.
   * @dev IMPORTANT Use this function carefully, only for ids that don't have an explicit
   * setter function, in order to avoid unexpected consequences
   * @param id The id
   * @param newImplementationAddress The address of the new implementation
   */
  function setAddressAsProxy(bytes32 id, address newImplementationAddress) external;

  /**
   * @notice Sets an address for an id replacing the address saved in the addresses map.
   * @dev IMPORTANT Use this function carefully, as it will do a hard replacement
   * @param id The id
   * @param newAddress The address to set
   */
  function setAddress(bytes32 id, address newAddress) external;

  /**
   * @notice Returns the address of the Pool proxy.
   * @return The Pool proxy address
   */
  function getPool() external view returns (address);

  /**
   * @notice Updates the implementation of the Pool, or creates a proxy
   * setting the new `pool` implementation when the function is called for the first time.
   * @param newPoolImpl The new Pool implementation
   */
  function setPoolImpl(address newPoolImpl) external;

  /**
   * @notice Returns the address of the PoolConfigurator proxy.
   * @return The PoolConfigurator proxy address
   */
  function getPoolConfigurator() external view returns (address);

  /**
   * @notice Updates the implementation of the PoolConfigurator, or creates a proxy
   * setting the new `PoolConfigurator` implementation when the function is called for the first time.
   * @param newPoolConfiguratorImpl The new PoolConfigurator implementation
   */
  function setPoolConfiguratorImpl(address newPoolConfiguratorImpl) external;

  /**
   * @notice Returns the address of the price oracle.
   * @return The address of the PriceOracle
   */
  function getPriceOracle() external view returns (address);

  /**
   * @notice Updates the address of the price oracle.
   * @param newPriceOracle The address of the new PriceOracle
   */
  function setPriceOracle(address newPriceOracle) external;

  /**
   * @notice Returns the address of the ACL manager.
   * @return The address of the ACLManager
   */
  function getACLManager() external view returns (address);

  /**
   * @notice Updates the address of the ACL manager.
   * @param newAclManager The address of the new ACLManager
   */
  function setACLManager(address newAclManager) external;

  /**
   * @notice Returns the address of the ACL admin.
   * @return The address of the ACL admin
   */
  function getACLAdmin() external view returns (address);

  /**
   * @notice Updates the address of the ACL admin.
   * @param newAclAdmin The address of the new ACL admin
   */
  function setACLAdmin(address newAclAdmin) external;

  /**
   * @notice Returns the address of the price oracle sentinel.
   * @return The address of the PriceOracleSentinel
   */
  function getPriceOracleSentinel() external view returns (address);

  /**
   * @notice Updates the address of the price oracle sentinel.
   * @param newPriceOracleSentinel The address of the new PriceOracleSentinel
   */
  function setPriceOracleSentinel(address newPriceOracleSentinel) external;

  /**
   * @notice Returns the address of the data provider.
   * @return The address of the DataProvider
   */
  function getPoolDataProvider() external view returns (address);

  /**
   * @notice Updates the address of the data provider.
   * @param newDataProvider The address of the new DataProvider
   */
  function setPoolDataProvider(address newDataProvider) external;
}
"
    },
    "lib/aave-v3-origin/src/contracts/interfaces/IPriceOracle.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title IPriceOracle
 * @author Aave
 * @notice Defines the basic interface for a Price oracle.
 */
interface IPriceOracle {
  /**
   * @notice Returns the asset price in the base currency
   * @param asset The address of the asset
   * @return The price of the asset
   */
  function getAssetPrice(address asset) external view returns (uint256);

  /**
   * @notice Set the price of the asset
   * @param asset The address of the asset
   * @param price The price of the asset
   */
  function setAssetPrice(address asset, uint256 price) external;
}
"
    },
    "src/contracts/dependencies/chainlink/AutomationCompatibleInterface.sol": {
      "content": "// SPDX-License-Identifier: MIT
// Chainlink Contracts v0.8
pragma solidity ^0.8.0;

interface AutomationCompatibleInterface {
  /**
   * @notice method that is simulated by the keepers to see if any work actually
   * needs to be performed. This method does does not actually need to be
   * executable, and since it is only ever simulated it can consume lots of gas.
   * @dev To ensure that it is never called, you may want to add the
   * cannotExecute modifier from KeeperBase to your implementation of this
   * method.
   * @param checkData specified in the upkeep registration so it is always the
   * same for a registered upkeep. This can easily be broken down into specific
   * arguments using `abi.decode`, so multiple upkeeps can be registered on the
   * same contract and easily differentiated by the contract.
   * @return upkeepNeeded boolean to indicate whether the keeper should call
   * performUpkeep or not.
   * @return performData bytes that the keeper should call performUpkeep with, if
   * upkeep is needed. If you would like to encode data to decode later, try
   * `abi.encode`.
   */
  function checkUpkeep(
    bytes calldata checkData
  ) external returns (bool upkeepNeeded, bytes memory performData);

  /**
   * @notice method that is actually executed by the keepers, via the registry.
   * The data returned by the checkUpkeep simulation will be passed into
   * this method to actually be executed.
   * @dev The input to this method should not be trusted, and the caller of the
   * method should not even be restricted to any single registry. Anyone should
   * be able call it, and the input should be validated, there is no guarantee
   * that the data passed in is the performData returned from checkUpkeep. This
   * could happen due to malicious keepers, racing keepers, or simply a state
   * change while the performUpkeep transaction is waiting for confirmation.
   * Always validate the data passed in.
   * @param performData is the data which was passed back from the checkData
   * simulation. If it is encoded, it can easily be decoded into other types by
   * calling `abi.decode`. This data should not be trusted, and should be
   * validated against the contract's current state.
   */
  function performUpkeep(bytes calldata performData) external;
}
"
    },
    "src/contracts/facilitators/gsm/interfaces/IGsm.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IAccessControl} from 'src/contracts/dependencies/openzeppelin-contracts/contracts/access/IAccessControl.sol';
import {IGhoFacilitator} from 'src/contracts/gho/interfaces/IGhoFacilitator.sol';

/**
 * @title IGsm
 * @author Aave
 * @notice Defines the behaviour of a GHO Stability Module
 */
interface IGsm is IAccessControl, IGhoFacilitator {
  /**
   * @dev Emitted when a user buys an asset (selling GHO) in the GSM
   * @param originator The address of the buyer originating the request
   * @param receiver The address of the receiver of the underlying asset
   * @param underlyingAmount The amount of the underlying asset bought
   * @param ghoAmount The amount of GHO sold, inclusive of fee
   * @param fee The fee paid by the buyer, in GHO
   */
  event BuyAsset(
    address indexed originator,
    address indexed receiver,
    uint256 underlyingAmount,
    uint256 ghoAmount,
    uint256 fee
  );

  /**
   * @dev Emitted when the GHO reserve is updated
   * @param oldReserve The address of the old reserve
   * @param newReserve The address of the new reserve
   */
  event GhoReserveUpdated(address oldReserve, address newReserve);

  /**
   * @dev Emitted when a user sells an asset (buying GHO) in the GSM
   * @param originator The address of the seller originating the request
   * @param receiver The address of the receiver of GHO
   * @param underlyingAmount The amount of the underlying asset sold
   * @param ghoAmount The amount of GHO bought, inclusive of fee
   * @param fee The fee paid by the buyer, in GHO
   */
  event SellAsset(
    address indexed originator,
    address indexed receiver,
    uint256 underlyingAmount,
    uint256 ghoAmount,
    uint256 fee
  );

  /**
   * @dev Emitted when the Swap Freezer freezes buys/sells
   * @param freezer The address of the Swap Freezer
   * @param enabled True if swap functions are frozen, False otherwise
   */
  event SwapFreeze(address indexed freezer, bool enabled);

  /**
   * @dev Emitted when a Liquidator seizes GSM funds
   * @param seizer The address originating the seizure request
   * @param recipient The address of the recipient of seized funds
   * @param underlyingAmount The amount of the underlying asset seized
   * @param ghoOutstanding The amount of remaining GHO that the GSM had minted
   */
  event Seized(
    address indexed seizer,
    address indexed recipient,
    uint256 underlyingAmount,
    uint256 ghoOutstanding
  );

  /**
   * @dev Emitted when burning GHO after a seizure of GSM funds
   * @param burner The address of the burner
   * @param amount The amount of GHO burned
   * @param ghoOutstanding The amount of remaining GHO that the GSM had minted
   */
  event BurnAfterSeize(address indexed burner, uint256 amount, uint256 ghoOutstanding);

  /**
   * @dev Emitted when the Fee Strategy is updated
   * @param oldFeeStrategy The address of the old Fee Strategy
   * @param newFeeStrategy The address of the new Fee Strategy
   */
  event FeeStrategyUpdated(address indexed oldFeeStrategy, address indexed newFeeStrategy);

  /**
   * @dev Emitted when the GSM underlying asset Exposure Cap is updated
   * @param oldExposureCap The amount of the old Exposure Cap
   * @param newExposureCap The amount of the new Exposure Cap
   */
  event ExposureCapUpdated(uint256 oldExposureCap, uint256 newExposureCap);

  /**
   * @dev Emitted when tokens are rescued from the GSM
   * @param tokenRescued The address of the rescued token
   * @param recipient The address that received the rescued tokens
   * @param amountRescued The amount of token rescued
   */
  event TokensRescued(
    address indexed tokenRescued,
    address indexed recipient,
    uint256 amountRescued
  );

  /**
   * @notice Buys the GSM underlying asset in exchange for selling GHO
   * @dev Use `getAssetAmountForBuyAsset` function to calculate the amount based on the GHO amount to sell
   * @param minAmount The minimum amount of the underlying asset to buy
   * @param receiver Recipient address of the underlying asset being purchased
   * @return The amount of underlying asset bought
   * @return The amount of GHO sold by the user
   */
  function buyAsset(uint256 minAmount, address receiver) external returns (uint256, uint256);

  /**
   * @notice Buys the GSM underlying asset in exchange for selling GHO, using an EIP-712 signature
   * @dev Use `getAssetAmountForBuyAsset` function to calculate the amount based on the GHO amount to sell
   * @param originator The signer of the request
   * @param minAmount The minimum amount of the underlying asset to buy
   * @param receiver Recipient address of the underlying asset being purchased
   * @param deadline Signature expiration deadline
   * @param signature Signature data
   * @return The amount of underlying asset bought
   * @return The amount of GHO sold by the user
   */
  function buyAssetWithSig(
    address originator,
    uint256 minAmount,
    address receiver,
    uint256 deadline,
    bytes calldata signature
  ) external returns (uint256, uint256);

  /**
   * @notice Sells the GSM underlying asset in exchange for buying GHO
   * @dev Use `getAssetAmountForSellAsset` function to calculate the amount based on the GHO amount to buy
   * @param maxAmount The maximum amount of the underlying asset to sell
   * @param receiver Recipient address of the GHO being purchased
   * @return The amount of underlying asset sold
   * @return The amount of GHO bought by the user
   */
  function sellAsset(uint256 maxAmount, address receiver) external returns (uint256, uint256);

  /**
   * @notice Sells the GSM underlying asset in exchange for buying GHO, using an EIP-712 signature
   * @dev Use `getAssetAmountForSellAsset` function to calculate the amount based on the GHO amount to buy
   * @param originator The signer of the request
   * @param maxAmount The maximum amount of the underlying asset to sell
   * @param receiver Recipient address of the GHO being purchased
   * @param deadline Signature expiration deadline
   * @param signature Signature data
   * @return The amount of underlying asset sold
   * @return The amount of GHO bought by the user
   */
  function sellAssetWithSig(
    address originator,
    uint256 maxAmount,
    address receiver,
    uint256 deadline,
    bytes calldata signature
  ) external returns (uint256, uint256);

  /**
   * @notice Rescue and transfer tokens locked in this contract
   * @dev In a Gsm4626 instance, distributeFeesToTreasury() must be called first to ensure the accounting of
   * accrued fees is up-to-date.
   * @param token The address of the token
   * @param to The address of the recipient
   * @param amount The amount of token to transfer
   */
  function rescueTokens(address token, address to, uint256 amount) external;

  /**
   * @notice Enable or disable the swap freeze
   * @param enable True to freeze swap functions, false otherwise
   */
  function setSwapFreeze(bool enable) external;

  /**
   * @notice Seizes all of the underlying asset from the GSM, sending to the Treasury
   * @dev Seizing is a last resort mechanism to provide the Treasury with the entire amount of underlying asset
   * so it can be used to backstop any potential event impacting the functionality of the Gsm.
   * @dev Seizing disables the swap feature
   * @return The amount of underlying asset seized and transferred to Treasury
   */
  function seize() external returns (uint256);

  /**
   * @notice Burns an amount of GHO after seizure reducing the facilitator bucket level effectively
   * @dev Passing an amount higher than the facilitator bucket level will result in burning all minted GHO
   * @dev Only callable if the GSM has assets seized, helpful to wind down the facilitator
   * @param amount The amount of GHO to burn
   * @return The amount of GHO burned
   */
  function burnAfterSeize(uint256 amount) external returns (uint256);

  /**
   * @notice Updates the address of the Fee Strategy
   * @param feeStrategy The address of the new FeeStrategy
   */
  function updateFeeStrategy(address feeStrategy) external;

  /**
   * @notice Updates the exposure cap of the underlying asset
   * @param exposureCap The new value for the exposure cap (in underlying asset terms)
   */
  function updateExposureCap(uint128 exposureCap) external;

  /**
   * @notice Updates the GHO reserve address
   * @dev It revokes the allowance to the old reserve and grants maximum allowance to the new one.
   * @param newGhoReserve The new address of the GHO reserve
   */
  function updateGhoReserve(address newGhoReserve) external;

  /**
   * @notice Returns the EIP712 domain separator
   * @return The EIP712 domain separator
   */
  function DOMAIN_SEPARATOR() external view returns (bytes32);

  /**
   * @notice Returns the total amount of GHO, gross amount and fee result of buying assets
   * @param minAssetAmount The minimum amount of underlying asset to buy
   * @return The exact amount of underlying asset to be bought
   * @return The total amount of GHO the user sells (gross amount in GHO plus fee)
   * @return The gross amount of GHO
   * @return The fee amount in GHO, applied on top of gross amount of GHO
   */
  function getGhoAmountForBuyAsset(
    uint256 minAssetAmount
  ) external view returns (uint256, uint256, uint256, uint256);

  /**
   * @notice Returns the total amount of GHO, gross amount and fee result of selling assets
   * @param maxAssetAmount The maximum amount of underlying asset to sell
   * @return The exact amount of underlying asset to sell
   * @return The total amount of GHO the user buys (gross amount in GHO minus fee)
   * @return The gross amount of GHO
   * @return The fee amount in GHO, applied to the gross amount of GHO
   */
  function getGhoAmountForSellAsset(
    uint256 maxAssetAmount
  ) external view returns (uint256, uint256, uint256, uint256);

  /**
   * @notice Returns the amount of underlying asset, gross amount of GHO and fee result of buying assets
   * @param maxGhoAmount The maximum amount of GHO the user provides for buying underlying asset
   * @return The amount of underlying asset the user buys
   * @return The exact amount of GHO the user provides
   * @return The gross amount of GHO corresponding to the given total amount of GHO
   * @return The fee amount in GHO, charged for buying assets
   */
  function getAssetAmountForBuyAsset(
    uint256 maxGhoAmount
  ) external view returns (uint256, uint256, uint256, uint256);

  /**
   * @notice Returns the amount of underlying asset, gross amount of GHO and fee result of selling assets
   * @param minGhoAmount The minimum amount of GHO the user must receive for selling underlying asset
   * @return The amount of underlying asset the user sells
   * @return The exact amount of GHO the user receives in exchange
   * @return The gross amount of GHO corresponding to the given total amount of GHO
   * @return The fee amount in GHO, charged for selling assets
   */
  function getAssetAmountForSellAsset(
    uint256 minGhoAmount
  ) external view returns (uint256, uint256, uint256, uint256);

  /**
   * @notice Returns the remaining GSM exposure capacity
   * @return The amount of underlying asset that can be sold to the GSM
   */
  function getAvailableUnderlyingExposure() external view returns (uint256);

  /**
   * @notice Returns the exposure limit to the underlying asset
   * @return The maximum amount of underlying asset that can be sold to the GSM
   */
  function getExposureCap() external view returns (uint128);

  /**
   * @notice Returns the actual underlying asset balance immediately available in the GSM
   * @return The amount of underlying asset that can be bought from the GSM
   */
  function getAvailableLiquidity() external view returns (uint256);

  /**
   * @notice Returns the Fee Strategy for the GSM
   * @dev It returns 0x0 in case of no fee strategy
   * @return The address of the FeeStrategy
   */
  function getFeeStrategy() external view returns (address);

  /**
   * @notice Returns the amount of current accrued fees
   * @dev It does not factor in potential fees that can be accrued upon distribution of fees
   * @return The amount of accrued fees
   */
  function getAccruedFees() external view returns (uint256);

  /**
   * @notice Returns the freeze status of the GSM
   * @return True if frozen, false if not
   */
  function getIsFrozen() external view returns (bool);

  /**
   * @notice Returns the current seizure status of the GSM
   * @return True if the GSM has been seized, false if not
   */
  function getIsSeized() external view returns (bool);

  /**
   * @notice Returns the address of the GHO reserve
   * @return The address of the GHO reserve
   */
  function getGhoReserve() external view returns (address);

  /**
   * @notice Returns the amount of GHO used by the GSM
   * @return The amount of GHO used
   */
  function getUsed() external view returns (uint256);

  /**
   * @notice Returns the maximum amount of GHO that can be used
   * @return The maximum amount of GHO that can be used
   */
  function getLimit() external view returns (uint256);

  /**
   * @notice Returns whether or not swaps via buyAsset/sellAsset are currently possible
   * @return True if the GSM has swapping enabled, false otherwise
   */
  function canSwap() external view returns (bool);

  /**
   * @notice Returns the GSM revision number
   * @return The revision number
   */
  function GSM_REVISION() external pure returns (uint256);

  /**
   * @notice Returns the address of the GHO token
   * @return The address of GHO token contract
   */
  function GHO_TOKEN() external view returns (address);

  /**
   * @notice Returns the underlying asset of the GSM
   * @return The address of the underlying asset
   */
  function UNDERLYING_ASSET() external view returns (address);

  /**
   * @notice Returns the price strategy of the GSM
   * @return The address of the price strategy
   */
  function PRICE_STRATEGY() external view returns (address);

  /**
   * @notice Returns the current nonce (for EIP-712 signature methods) of an address
   * @param user The address of the user
   * @return The current nonce of the user
   */
  function nonces(address user) external view returns (uint256);

  /**
   * @notice Returns the identifier of the Configurator Role
   * @return The bytes32 id hash of the Configurator role
   */
  function CONFIGURATOR_ROLE() external pure returns (bytes32);

  /**
   * @notice Returns the identifier of the Token Rescuer Role
   * @return The bytes32 id hash of the TokenRescuer role
   */
  function TOKEN_RESCUER_ROLE() external pure returns (bytes32);

  /**
   * @notice Returns the identifier of the Swap Freezer Role
   * @return The bytes32 id hash of the SwapFreezer role
   */
  function SWAP_FREEZER_ROLE() external pure returns (bytes32);

  /**
   * @notice Returns the identifier of the Liquidator Role
   * @return The bytes32 id hash of the Liquidator role
   */
  function LIQUIDATOR_ROLE() external pure returns (bytes32);

  /**
   * @notice Returns the EIP-712 signature typehash for buyAssetWithSig
   * @return The bytes32 signature typehash for buyAssetWithSig
   */
  function BUY_ASSET_WITH_SIG_TYPEHASH() external pure returns (bytes32);

  /**
   * @notice Returns the EIP-712 signature typehash for sellAssetWithSig
   * @return The bytes32 signature typehash for sellAssetWithSig
   */
  function SELL_ASSET_WITH_SIG_TYPEHASH() external pure returns (bytes32);
}
"
    },
    "src/contracts/dependencies/openzeppelin-contracts/contracts/access/IAccessControl.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}
"
    },
    "src/contracts/gho/interfaces/IGhoFacilitator.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title IGhoFacilitator
 * @author Aave
 * @notice Defines the behavior of a Gho Facilitator
 */
interface IGhoFacilitator {
  /**
   * @dev Emitted when fees are distributed to the GhoTreasury
   * @param ghoTreasury The address of the ghoTreasury
   * @param asset The address of the asset transferred to the ghoTreasury
   * @param amount The amount of the asset transferred to the ghoTreasury
   */
  event FeesDistributedToTreasury(
    address indexed ghoTreasury,
    address indexed asset,
    uint256 amount
  );

  /**
   * @dev Emitted when Gho Treasury address is updated
   * @param oldGhoTreasury The address of the old GhoTreasury contract
   * @param newGhoTreasury The address of the new GhoTreasury contract
   */
  event GhoTreasuryUpdated(address indexed oldGhoTreasury, address indexed newGhoTreasury);

  /**
   * @notice Distribute fees to the GhoTreasury
   */
  function distributeFeesToTreasury() external;

  /**
   * @notice Updates the address of the Gho Treasury
   * @dev WARNING: The GhoTreasury is where revenue fees are sent to. Update carefully
   * @param newGhoTreasury The address of the GhoTreasury
   */
  function updateGhoTreasury(address newGhoTreasury) external;

  /**
   * @notice Returns the address of the Gho Treasury
   * @return The address of the GhoTreasury contract
   */
  function getGhoTreasury() external view returns (address);
}
"
    }
  },
  "settings": {
    "remappings": [
      "forge-std/=lib/forge-std/src/",
      "aave-v3-origin/=lib/aave-v3-origin/src/",
      "aave-v3-origin-tests/=lib/aave-v3-origin/tests/",
      "solidity-utils/=lib/aave-v3-origin/lib/solidity-utils/src/",
      "@openzeppelin/contracts-upgradeable/=lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/contracts/",
      "@openzeppelin/contracts/=lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/",
      "ds-test/=lib/aave-v3-origin/lib/forge-std/lib/ds-test/src/",
      "erc4626-tests/=lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
      "halmos-cheatcodes/=lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
      "openzeppelin-contracts-upgradeable/=lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/",
      "openzeppelin-contracts/=lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/"
    ],
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "metadata": {
      "useLiteralContent": false,
      "bytecodeHash": "none",
      "appendCBOR": true
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "evmVersion": "paris",
    "viaIR": false
  }
}}

Tags:
Proxy, Swap, Upgradeable, Factory, Oracle|addr:0x1de76e3d0f1a3bf2dd64e676008727927bef0c40|verified:true|block:23628626|tx:0x31a14ad06d24ac52ad01e1f62437790549d4f4aa977d33aec3dbb69f6d8b8e45|first_check:1761230148

Submitted on: 2025-10-23 16:35:51

Comments

Log in to comment.

No comments yet.