PoolConfiguration

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "settings": {
    "evmVersion": "cancun",
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "remappings": [
      "npm/@openzeppelin/contracts-upgradeable@5.4.0/:@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.4.0/",
      "npm/@openzeppelin/contracts-upgradeable@5.4.0/:@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.4.0/",
      "npm/@openzeppelin/contracts-upgradeable@5.4.0/:@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.4.0/",
      "project/:@openzeppelin/contracts-upgradeable/=npm/@openzeppelin/contracts-upgradeable@5.4.0/"
    ]
  },
  "sources": {
    "npm/@openzeppelin/contracts-upgradeable@5.4.0/access/AccessControlUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```solidity
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```solidity
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
 * to enforce additional security measures for this role.
 */
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {
    struct RoleData {
        mapping(address account => bool) hasRole;
        bytes32 adminRole;
    }

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;


    /// @custom:storage-location erc7201:openzeppelin.storage.AccessControl
    struct AccessControlStorage {
        mapping(bytes32 role => RoleData) _roles;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;

    function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
        assembly {
            $.slot := AccessControlStorageLocation
        }
    }

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with an {AccessControlUnauthorizedAccount} error including the required role.
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    function __AccessControl_init() internal onlyInitializing {
    }

    function __AccessControl_init_unchained() internal onlyInitializing {
    }
    /// @inheritdoc IERC165
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        return $._roles[role].hasRole[account];
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
     * is missing `role`.
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert AccessControlUnauthorizedAccount(account, role);
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        return $._roles[role].adminRole;
    }

    /**
     * @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.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

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

    /**
     * @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 revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address callerConfirmation) public virtual {
        if (callerConfirmation != _msgSender()) {
            revert AccessControlBadConfirmation();
        }

        _revokeRole(role, callerConfirmation);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        AccessControlStorage storage $ = _getAccessControlStorage();
        bytes32 previousAdminRole = getRoleAdmin(role);
        $._roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        if (!hasRole(role, account)) {
            $._roles[role].hasRole[account] = true;
            emit RoleGranted(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        if (hasRole(role, account)) {
            $._roles[role].hasRole[account] = false;
            emit RoleRevoked(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }
}
"
    },
    "npm/@openzeppelin/contracts-upgradeable@5.4.0/proxy/utils/Initializable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Storage of the initializable contract.
     *
     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
     * when using with upgradeable contracts.
     *
     * @custom:storage-location erc7201:openzeppelin.storage.Initializable
     */
    struct InitializableStorage {
        /**
         * @dev Indicates that the contract has been initialized.
         */
        uint64 _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool _initializing;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint64 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reinitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._initialized = 1;
        if (isTopLevelCall) {
            $._initializing = true;
        }
        _;
        if (isTopLevelCall) {
            $._initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._initialized = version;
        $._initializing = true;
        _;
        $._initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint64) {
        return _getInitializableStorage()._initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _getInitializableStorage()._initializing;
    }

    /**
     * @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
     *
     * NOTE: Consider following the ERC-7201 formula to derive storage locations.
     */
    function _initializableStorageSlot() internal pure virtual returns (bytes32) {
        return INITIALIZABLE_STORAGE;
    }

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        bytes32 slot = _initializableStorageSlot();
        assembly {
            $.slot := slot
        }
    }
}
"
    },
    "npm/@openzeppelin/contracts-upgradeable@5.4.0/utils/ContextUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}
"
    },
    "npm/@openzeppelin/contracts-upgradeable@5.4.0/utils/introspection/ERC165Upgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165Upgradeable is Initializable, IERC165 {
    function __ERC165_init() internal onlyInitializing {
    }

    function __ERC165_init_unchained() internal onlyInitializing {
    }
    /// @inheritdoc IERC165
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}
"
    },
    "npm/@openzeppelin/contracts@5.4.0/access/IAccessControl.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/IAccessControl.sol)

pragma solidity >=0.8.4;

/**
 * @dev External interface of AccessControl declared to support ERC-165 detection.
 */
interface IAccessControl {
    /**
     * @dev The `account` is missing a role.
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @dev The caller of a function is not the expected one.
     *
     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
     */
    error AccessControlBadConfirmation();

    /**
     * @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 to signal this.
     */
    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. This account bears the admin role (for the granted role).
     * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
     */
    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 `callerConfirmation`.
     */
    function renounceRole(bytes32 role, address callerConfirmation) external;
}
"
    },
    "npm/@openzeppelin/contracts@5.4.0/utils/introspection/IERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev 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[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
"
    },
    "project/contracts/common/codec/WordCodec.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

// solhint-disable no-inline-assembly

/// @dev A subset copied from the following contracts:
///
/// + `balancer-labs/v2-solidity-utils/contracts/helpers/WordCodec.sol`
/// + `balancer-labs/v2-solidity-utils/contracts/helpers/WordCodecHelpers.sol`
library WordCodec {
  /// @dev Inserts an unsigned integer of bitLength, shifted by an offset, into a 256 bit word,
  /// replacing the old value. Returns the new word.
  function insertUint(
    bytes32 word,
    uint256 value,
    uint256 offset,
    uint256 bitLength
  ) internal pure returns (bytes32 result) {
    // Equivalent to:
    // uint256 mask = (1 << bitLength) - 1;
    // bytes32 clearedWord = bytes32(uint256(word) & ~(mask << offset));
    // result = clearedWord | bytes32(value << offset);
    assembly {
      let mask := sub(shl(bitLength, 1), 1)
      let clearedWord := and(word, not(shl(offset, mask)))
      result := or(clearedWord, shl(offset, value))
    }
  }

  /// @dev Decodes and returns an unsigned integer with `bitLength` bits, shifted by an offset, from a 256 bit word.
  function decodeUint(
    bytes32 word,
    uint256 offset,
    uint256 bitLength
  ) internal pure returns (uint256 result) {
    // Equivalent to:
    // result = uint256(word >> offset) & ((1 << bitLength) - 1);
    assembly {
      result := and(shr(offset, word), sub(shl(bitLength, 1), 1))
    }
  }

  /// @dev Inserts a signed integer shifted by an offset into a 256 bit word, replacing the old value. Returns
  /// the new word.
  ///
  /// Assumes `value` can be represented using `bitLength` bits.
  function insertInt(
    bytes32 word,
    int256 value,
    uint256 offset,
    uint256 bitLength
  ) internal pure returns (bytes32) {
    unchecked {
      uint256 mask = (1 << bitLength) - 1;
      bytes32 clearedWord = bytes32(uint256(word) & ~(mask << offset));
      // Integer values need masking to remove the upper bits of negative values.
      return clearedWord | bytes32((uint256(value) & mask) << offset);
    }
  }

  /// @dev Decodes and returns a signed integer with `bitLength` bits, shifted by an offset, from a 256 bit word.
  function decodeInt(
    bytes32 word,
    uint256 offset,
    uint256 bitLength
  ) internal pure returns (int256 result) {
    unchecked {
      int256 maxInt = int256((1 << (bitLength - 1)) - 1);
      uint256 mask = (1 << bitLength) - 1;

      int256 value = int256(uint256(word >> offset) & mask);
      // In case the decoded value is greater than the max positive integer that can be represented with bitLength
      // bits, we know it was originally a negative integer. Therefore, we mask it to restore the sign in the 256 bit
      // representation.
      //
      // Equivalent to:
      // result = value > maxInt ? (value | int256(~mask)) : value;
      assembly {
        result := or(mul(gt(value, maxInt), not(mask)), value)
      }
    }
  }

  /// @dev Decodes and returns a boolean shifted by an offset from a 256 bit word.
  function decodeBool(bytes32 word, uint256 offset) internal pure returns (bool result) {
    // Equivalent to:
    // result = (uint256(word >> offset) & 1) == 1;
    assembly {
      result := and(shr(offset, word), 1)
    }
  }

  /// @dev Inserts a boolean value shifted by an offset into a 256 bit word, replacing the old value. Returns the new
  /// word.
  function insertBool(
    bytes32 word,
    bool value,
    uint256 offset
  ) internal pure returns (bytes32 result) {
    // Equivalent to:
    // bytes32 clearedWord = bytes32(uint256(word) & ~(1 << offset));
    // bytes32 referenceInsertBool = clearedWord | bytes32(uint256(value ? 1 : 0) << offset);
    assembly {
      let clearedWord := and(word, not(shl(offset, 1)))
      result := or(clearedWord, shl(offset, value))
    }
  }

  function clearWordAtPosition(
    bytes32 word,
    uint256 offset,
    uint256 bitLength
  ) internal pure returns (bytes32 clearedWord) {
    unchecked {
      uint256 mask = (1 << bitLength) - 1;
      clearedWord = bytes32(uint256(word) & ~(mask << offset));
    }
  }
}
"
    },
    "project/contracts/core/PoolConfiguration.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.26;

import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";

import { IAaveV3Pool } from "../interfaces/Aave/IAaveV3Pool.sol";
import { IFxUSDBasePool } from "../interfaces/IFxUSDBasePool.sol";
import { IPoolConfiguration } from "../interfaces/IPoolConfiguration.sol";
import { IFxUSDPriceOracle } from "../interfaces/IFxUSDPriceOracle.sol";
import { ILongPool } from "../interfaces/ILongPool.sol";
import { IShortPool } from "../interfaces/IShortPool.sol";
import { ILongPoolManager } from "../interfaces/ILongPoolManager.sol";
import { IShortPoolManager } from "../interfaces/IShortPoolManager.sol";

import { WordCodec } from "../common/codec/WordCodec.sol";

contract PoolConfiguration is AccessControlUpgradeable, IPoolConfiguration {
  using WordCodec for bytes32;

  /**********
   * Errors *
   **********/

  /// @dev Thrown when the value is too large.
  error ErrorValueTooLarge();

  /// @dev Thrown when the pool is invalid.
  error ErrorInvalidPool();

  /// @dev Thrown when the pool manager is locked.
  error ErrorPoolManagerLocked();

  /*************
   * Constants *
   *************/

  /// @dev The minimum Aave borrow index snapshot delay.
  uint256 private constant MIN_SNAPSHOT_DELAY = 30 minutes;

  /// @dev The precision used for fee ratio calculation.
  uint256 internal constant FEE_PRECISION = 1e9;

  /// @dev The precision used for various calculation.
  uint256 internal constant PRECISION = 1e18;

  /// @dev The offset of *supply ratio* in pool fee data.
  uint256 private constant SUPPLY_RATIO_OFFSET = 0;
  /// @dev The offset of *supply ratio step* in pool fee data
  uint256 private constant SUPPLY_RATIO_STEP_OFFSET = 30;
  /// @dev The offset of *withdraw fee ratio* in pool fee data.
  uint256 private constant WITHDRAW_FEE_RATIO_OFFSET = 90;
  /// @dev The offset of *borrow fee ratio* in pool fee data.
  uint256 private constant BORROW_FEE_RATIO_OFFSET = 120;
  /// @dev The offset of *repay fee ratio* in pool fee data.
  uint256 private constant REPAY_FEE_RATIO_OFFSET = 150;

  /// @dev The offset of *scalar A* in long funding ratio parameter.
  uint256 private constant SCALAR_A_OFFSET = 0;
  /// @dev The offset of *scalar B* in long funding ratio parameter.
  uint256 private constant SCALAR_B_OFFSET = 64;
  /// @dev The offset of *max fxUSD ratio* in long funding ratio parameter.
  uint256 private constant MAX_FXUSD_RATIO_OFFSET = 128;

  /// @dev The offset of *scalar C* in short funding ratio parameter.
  uint256 private constant SCALAR_C_OFFSET = 0;
  /// @dev The offset of *max borrow ratio* in short funding ratio parameter.
  uint256 private constant MAX_BORROW_RATIO_OFFSET = 64;

  /// @dev The key for pool manager lock.
  bytes32 private constant POOL_MANAGER_LOCK_KEY = keccak256("POOL_MANAGER_LOCK_KEY");

  /// @dev The role to unlock the pool manager.
  bytes32 public constant UNLOCK_ROLE = keccak256("UNLOCK_ROLE");

  /***********************
   * Immutable Variables *
   ***********************/

  /// @notice The address of the Aave lending pool.
  address public immutable AAVE_LENDING_POOL;

  /// @notice The address of the Aave base asset.
  address public immutable AAVE_BASE_ASSET;

  /// @notice The address of the FxUSDBasePool contract.
  address public immutable FXUSD_BASE_POOL;

  /// @notice The address of the pool manager.
  address public immutable POOL_MANAGER;

  /// @notice The address of the short pool manager.
  address public immutable SHORT_POOL_MANAGER;

  /***********
   * Structs *
   ***********/

  /// @dev The struct for AAVE borrow rate snapshot.
  /// @param borrowIndex The current borrow index of AAVE, multiplied by 1e27.
  /// @param lastInterestRate The last recorded interest rate, multiplied by 1e18.
  /// @param timestamp The timestamp when the snapshot is taken.
  struct BorrowRateSnapshot {
    // The initial value of `borrowIndex` is `10^27`, it is very unlikely this value will exceed `2^128`.
    uint128 borrowIndex;
    uint80 lastInterestRate;
    uint48 timestamp;
  }

  /// @dev The encoding of pool fee ratio data.
  /// - The *supply ratio* is the fee ratio for opening position, multiplied by 1e9.
  /// - The *supply ratio step* is the fee ratio step for opening position, multiplied by 1e18.
  /// - The *withdraw fee ratio* is the fee ratio for closing position, multiplied by 1e9.
  /// - The *borrow fee ratio* is the borrow fee ratio for opening position, multiplied by 1e9.
  /// - The *repay fee ratio* is the repay fee ratio for closing position, multiplied by 1e9.
  ///
  /// [ supply ratio | supply ratio step | withdraw fee ratio | borrow fee ratio | repay fee ratio | reserved ]
  /// [   30  bits   |      60 bits      |      30  bits      |     30  bits     |     30 bits     | 76  bits ]
  /// [ MSB                                                                                               LSB ]
  struct PoolFeeRatioStruct {
    // no supply/withdraw fee, but with borrow and repay fee
    bytes32 defaultFeeRatio;
    mapping(address => bytes32) custom;
  }

  /*********************
   * Storage Variables *
   *********************/

  /// @notice The address of the oracle for fxUSD price.
  address public oracle;

  /// @notice The borrow rate snapshot.
  BorrowRateSnapshot public borrowRateSnapshot;

  /// @dev Mapping from pool address to the pool fee ratio.
  mapping(address => PoolFeeRatioStruct) private poolFeeRatio;

  /// @dev Mapping from pool address to the long funding ratio parameter.
  /// 1. When fxUSD price is below max price deviation (down depeg), the funding ratio is calculated by:
  /// ```
  /// funding_ratio = scalar_b * interest_rate
  /// ```
  /// 2. When the ratio of fxUSD in FxUSDBasePool is above `max_fxUSD_ratio`, the funding ratio is calculated by:
  /// ```
  /// funding_ratio = scalar_a * interest_rate
  /// ```
  ///
  /// The encoding is:
  /// - The *scalar A* is the scalar for funding ratio, multiplied by 1e18.
  /// - The *scalar B* is the scalar for funding ratio, multiplied by 1e18.
  /// - The *max fxUSD ratio* is the max fxUSD ratio in FxUSDBasePool, multiplied by 1e18.
  ///
  /// [ scalar_a | scalar_b | max_fxUSD_ratio | reserved ]
  /// [ 64  bits | 64  bits | 64  bits | 64  bits ]
  /// [ MS                                    LSB ]
  mapping(address => bytes32) private longFundingRatioParameter;

  /// @dev Mapping from pool address to the short funding ratio parameter.
  /// 1. When the ratio of borrowed collateral is above `max_borrow_ratio`, the funding ratio is calculated by:
  /// ```
  /// funding_ratio = scalar_c * interest_rate
  /// ```
  ///
  /// The encoding is:
  /// - The *scalar C* is the scalar for funding ratio, multiplied by 1e18.
  /// - The *max borrow ratio* is the max borrow ratio for funding ratio, multiplied by 1e18.
  ///
  /// [ scalar_c | max_borrow_ratio | reserved ]
  /// [ 64  bits |     64  bits     | 128 bits ]
  /// [ MS                                 LSB ]
  mapping(address => bytes32) private shortFundingRatioParameter;

  /// @notice The depeg price for stable token.
  uint256 public stableDepegPrice;

  /// @inheritdoc IPoolConfiguration
  mapping(bytes32 => address) public registry;

  /***************
   * Constructor *
   ***************/

  /// @notice Constructor.
  /// @param _fxUSDBasePool The address of the FxUSDBasePool contract.
  /// @param _aaveLendingPool The address of the Aave lending pool.
  /// @param _aaveBaseAsset The address of the Aave base asset.
  /// @param _poolManager The address of the pool manager.
  /// @param _shortPoolManager The address of the short pool manager.
  constructor(
    address _fxUSDBasePool,
    address _aaveLendingPool,
    address _aaveBaseAsset,
    address _poolManager,
    address _shortPoolManager
  ) {
    FXUSD_BASE_POOL = _fxUSDBasePool;
    AAVE_LENDING_POOL = _aaveLendingPool;
    AAVE_BASE_ASSET = _aaveBaseAsset;
    POOL_MANAGER = _poolManager;
    SHORT_POOL_MANAGER = _shortPoolManager;
  }

  /// @notice Initialize the contract storage.
  /// @param admin The address of the admin.
  /// @param _oracle The address of the oracle.
  function initialize(address admin, address _oracle) external initializer {
    __Context_init();
    __ERC165_init();
    __AccessControl_init();

    _grantRole(DEFAULT_ADMIN_ROLE, admin);
    _updateOracle(_oracle);

    uint256 borrowIndex = IAaveV3Pool(AAVE_LENDING_POOL).getReserveNormalizedVariableDebt(AAVE_BASE_ASSET);
    IAaveV3Pool.ReserveDataLegacy memory reserveData = IAaveV3Pool(AAVE_LENDING_POOL).getReserveData(AAVE_BASE_ASSET);
    _updateBorrowRateSnapshot(borrowIndex, reserveData.currentVariableBorrowRate / 1e9);
  }

  /*************************
   * Public View Functions *
   *************************/

  /// @inheritdoc IPoolConfiguration
  function isBorrowAllowed() external view returns (bool) {
    return !IFxUSDPriceOracle(oracle).isPriceBelowMaxDeviation();
  }

  /// @inheritdoc IPoolConfiguration
  function isRedeemAllowed() external view returns (bool) {
    return IFxUSDPriceOracle(oracle).isPriceBelowMaxDeviation();
  }

  /// @inheritdoc IPoolConfiguration
  function isFundingEnabled() external view returns (bool) {
    return IFxUSDPriceOracle(oracle).isPriceBelowMaxDeviation();
  }

  /// @inheritdoc IPoolConfiguration
  function isStableRepayAllowed() external view returns (bool) {
    uint256 stablePrice = IFxUSDBasePool(FXUSD_BASE_POOL).getStableTokenPrice();
    return IFxUSDPriceOracle(oracle).isPriceAboveMaxDeviation() && stablePrice > stableDepegPrice;
  }

  /// @inheritdoc IPoolConfiguration
  function getPoolFeeRatio(
    address pool,
    address recipient
  )
    external
    view
    returns (uint256 supplyFeeRatio, uint256 withdrawFeeRatio, uint256 borrowFeeRatio, uint256 repayFeeRatio)
  {
    bytes32 data = poolFeeRatio[pool].custom[recipient];
    if (data == bytes32(0)) {
      data = poolFeeRatio[pool].defaultFeeRatio;
    }

    uint256 supplyRatio = data.decodeUint(SUPPLY_RATIO_OFFSET, 30);
    uint256 supplyRatioStep = data.decodeUint(SUPPLY_RATIO_STEP_OFFSET, 60);
    uint256 interestRate = _getAverageInterestRate(borrowRateSnapshot);
    unchecked {
      uint256 aaveRatio = interestRate <= supplyRatioStep ? 1 : (interestRate - 1) / supplyRatioStep;
      supplyFeeRatio = aaveRatio * supplyRatio;
    }
    withdrawFeeRatio = data.decodeUint(WITHDRAW_FEE_RATIO_OFFSET, 30);
    borrowFeeRatio = data.decodeUint(BORROW_FEE_RATIO_OFFSET, 30);
    repayFeeRatio = data.decodeUint(REPAY_FEE_RATIO_OFFSET, 30);
  }

  /// @inheritdoc IPoolConfiguration
  function getLongPoolFundingRatio(address pool) external view returns (uint256 fundingRatio) {
    bytes32 parameter = longFundingRatioParameter[pool];
    uint256 scalarA = parameter.decodeUint(SCALAR_A_OFFSET, 64);
    uint256 scalarB = parameter.decodeUint(SCALAR_B_OFFSET, 64);
    uint256 maxFxUSDratio = parameter.decodeUint(MAX_FXUSD_RATIO_OFFSET, 64);

    uint256 interestRate = _getAverageInterestRate(borrowRateSnapshot);
    if (IFxUSDPriceOracle(oracle).isPriceBelowMaxDeviation()) {
      fundingRatio = (scalarB * interestRate) / PRECISION;
    } else {
      // @dev This balance can be manipulated. However in order to manipulate the balance,
      // the user need to lock the funds into FxUSDBasePool for a certain duration. So it
      // is ok to use the balance directly.
      uint256 balanceFxUSD = IFxUSDBasePool(FXUSD_BASE_POOL).totalYieldToken();
      uint256 balanceStable = IFxUSDBasePool(FXUSD_BASE_POOL).totalStableToken();
      uint256 fxusdRatio;
      if (balanceStable == 0 && balanceFxUSD == 0) {
        fxusdRatio = maxFxUSDratio;
      } else {
        // we are using USDC as the stable token, the decimal is 6
        fxusdRatio = (balanceFxUSD * PRECISION) / (balanceStable * 1e12 + balanceFxUSD);
      }
      if (fxusdRatio >= maxFxUSDratio) {
        fundingRatio = (scalarA * interestRate) / PRECISION;
      } else {
        fundingRatio = 0;
      }
    }
  }

  /// @inheritdoc IPoolConfiguration
  function getShortPoolFundingRatio(address pool) external view returns (uint256 fundingRatio) {
    bytes32 parameter = shortFundingRatioParameter[pool];
    uint256 scalarC = parameter.decodeUint(SCALAR_C_OFFSET, 64);
    uint256 maxBorrowRatio = parameter.decodeUint(MAX_BORROW_RATIO_OFFSET, 64);

    uint256 interestRate = _getAverageInterestRate(borrowRateSnapshot);
    address counterparty = IShortPool(pool).counterparty();
    address collateralToken = ILongPool(counterparty).collateralToken();
    uint256 longScalingFactor = ILongPoolManager(POOL_MANAGER).getTokenScalingFactor(collateralToken);
    uint256 collateral = _scaleDown(ILongPool(counterparty).getTotalRawCollaterals(), longScalingFactor);
    uint256 shortScalingFactor = IShortPoolManager(SHORT_POOL_MANAGER).getTokenScalingFactor(collateralToken);
    uint256 debts = _scaleDown(IShortPool(pool).getTotalRawDebts(), shortScalingFactor);

    uint256 debtRatio;
    if (collateral == 0) {
      debtRatio = 0;
    } else {
      debtRatio = (debts * PRECISION) / collateral;
    }
    if (debtRatio >= maxBorrowRatio) {
      fundingRatio = (scalarC * interestRate) / PRECISION;
    } else {
      fundingRatio = 0;
    }
  }

  /// @notice Get the average interest rate.
  /// @return rate The average interest rate, multiplied by 1e18.
  function getAverageInterestRate() external view returns (uint256) {
    return _getAverageInterestRate(borrowRateSnapshot);
  }

  /****************************
   * Public Mutated Functions *
   ****************************/

  /// @inheritdoc IPoolConfiguration
  /// @dev It is ok to let anyone call this function. However to reduce the unknown risk, we require the pool address is
  /// the same as the caller and the pool is whitelisted.
  function checkpoint(address pool) external {
    if (pool != _msgSender()) revert ErrorInvalidPool();
    if (poolFeeRatio[pool].defaultFeeRatio == bytes32(0)) revert ErrorInvalidPool();

    BorrowRateSnapshot memory snapshot = borrowRateSnapshot;
    uint256 duration = block.timestamp - snapshot.timestamp;
    if (duration >= MIN_SNAPSHOT_DELAY) {
      uint256 newBorrowIndex = IAaveV3Pool(AAVE_LENDING_POOL).getReserveNormalizedVariableDebt(AAVE_BASE_ASSET);
      uint256 lastInterestRate = _computeAverageInterestRate(snapshot.borrowIndex, newBorrowIndex, duration);
      if (lastInterestRate == 0) lastInterestRate = snapshot.lastInterestRate;

      _updateBorrowRateSnapshot(newBorrowIndex, lastInterestRate);
    }
  }

  /// @inheritdoc IPoolConfiguration
  /// @dev This function can be called by anyone. The state will be automatically cleared when the tx is over.
  function lock(address manager, bytes4 selector) external {
    bytes32 key = POOL_MANAGER_LOCK_KEY;
    bytes32 value;
    assembly {
      value := tload(key)
    }
    if (value != 0) {
      revert ErrorPoolManagerLocked();
    }
    assembly {
      tstore(key, 1)
    }
  }

  /// @inheritdoc IPoolConfiguration
  function unlock(address manager, bytes4 selector) external onlyRole(UNLOCK_ROLE) {
    bytes32 key = POOL_MANAGER_LOCK_KEY;
    assembly {
      tstore(key, 0)
    }
  }

  /************************
   * Restricted Functions *
   ************************/

  /// @notice Update the pool fee ratio for a specific recipient.
  /// @param pool The address of the pool.
  /// @param recipient The address of the recipient.
  /// @param supplyRatio The supply ratio, multiplied by 1e9.
  /// @param supplyRatioStep The supply ratio step, multiplied by 1e18.
  /// @param withdrawFeeRatio The withdraw fee ratio, multiplied by 1e9.
  /// @param borrowFeeRatio The borrow fee ratio, multiplied by 1e9.
  /// @param repayFeeRatio The repay fee ratio, multiplied by 1e9.
  function updatePoolFeeRatio(
    address pool,
    address recipient,
    uint256 supplyRatio,
    uint256 supplyRatioStep,
    uint256 withdrawFeeRatio,
    uint256 borrowFeeRatio,
    uint256 repayFeeRatio
  ) external onlyRole(DEFAULT_ADMIN_ROLE) {
    _checkValueTooLarge(supplyRatio, 1e9);
    _checkValueTooLarge(supplyRatioStep, 1e18);
    _checkValueTooLarge(withdrawFeeRatio, 1e9);
    _checkValueTooLarge(borrowFeeRatio, 1e9);
    _checkValueTooLarge(repayFeeRatio, 1e9);

    bytes32 data;
    data = data.insertUint(supplyRatio, SUPPLY_RATIO_OFFSET, 30);
    data = data.insertUint(supplyRatioStep, SUPPLY_RATIO_STEP_OFFSET, 60);
    data = data.insertUint(withdrawFeeRatio, WITHDRAW_FEE_RATIO_OFFSET, 30);
    data = data.insertUint(borrowFeeRatio, BORROW_FEE_RATIO_OFFSET, 30);
    data = data.insertUint(repayFeeRatio, REPAY_FEE_RATIO_OFFSET, 30);

    if (recipient == address(0)) {
      poolFeeRatio[pool].defaultFeeRatio = data;
    } else {
      poolFeeRatio[pool].custom[recipient] = data;
    }

    emit UpdatePoolFeeRatio(
      pool,
      recipient,
      supplyRatio,
      supplyRatioStep,
      withdrawFeeRatio,
      borrowFeeRatio,
      repayFeeRatio
    );
  }

  /// @notice Update the funding ratio parameter.
  /// @param pool The address of the pool.
  /// @param scalarA The scalar A, multiplied by 1e18.
  /// @param scalarB The scalar B, multiplied by 1e18.
  /// @param maxFxUSDratio The max fxUSD ratio, multiplied by 1e18.
  function updateLongFundingRatioParameter(
    address pool,
    uint64 scalarA,
    uint64 scalarB,
    uint64 maxFxUSDratio
  ) external onlyRole(DEFAULT_ADMIN_ROLE) {
    bytes32 parameter;
    parameter = parameter.insertUint(scalarA, SCALAR_A_OFFSET, 64);
    parameter = parameter.insertUint(scalarB, SCALAR_B_OFFSET, 64);
    parameter = parameter.insertUint(maxFxUSDratio, MAX_FXUSD_RATIO_OFFSET, 64);
    longFundingRatioParameter[pool] = parameter;

    emit UpdateLongFundingRatioParameter(scalarA, scalarB, maxFxUSDratio);
  }

  /// @notice Update the short funding ratio parameter.
  /// @param pool The address of the pool.
  /// @param scalarC The scalar C, multiplied by 1e18.
  /// @param maxBorrowRatio The max borrow ratio, multiplied by 1e18.
  function updateShortFundingRatioParameter(
    address pool,
    uint64 scalarC,
    uint64 maxBorrowRatio
  ) external onlyRole(DEFAULT_ADMIN_ROLE) {
    bytes32 parameter;
    parameter = parameter.insertUint(scalarC, SCALAR_C_OFFSET, 64);
    parameter = parameter.insertUint(maxBorrowRatio, MAX_BORROW_RATIO_OFFSET, 64);
    shortFundingRatioParameter[pool] = parameter;

    emit UpdateShortFundingRatioParameter(scalarC, maxBorrowRatio);
  }

  /// @notice Update the address of oracle.
  /// @param newOracle The address of new oracle.
  function updateOracle(address newOracle) external onlyRole(DEFAULT_ADMIN_ROLE) {
    _updateOracle(newOracle);
  }

  /// @notice Update the stable depeg price.
  /// @param newStableDepegPrice The new stable depeg price.
  function updateStableDepegPrice(uint256 newStableDepegPrice) external onlyRole(DEFAULT_ADMIN_ROLE) {
    uint256 oldStableDepegPrice = stableDepegPrice;
    stableDepegPrice = newStableDepegPrice;
    emit UpdateStableDepegPrice(oldStableDepegPrice, newStableDepegPrice);
  }

  /// @notice Register an address.
  /// @param key The key of the registered address.
  /// @param addr The address to register.
  function register(bytes32 key, address addr) external onlyRole(DEFAULT_ADMIN_ROLE) {
    registry[key] = addr;

    emit Register(key, addr);
  }

  /**********************
   * Internal Functions *
   **********************/

  /// @dev Internal function to update the address of oracle.
  /// @param newOracle The address of new oracle.
  function _updateOracle(address newOracle) internal {
    address oldOracle = oracle;
    oracle = newOracle;

    emit UpdateOracle(oldOracle, newOracle);
  }

  /// @dev Internal function to return interest rate snapshot.
  /// @param snapshot The previous borrow index snapshot.
  /// @return rate The annual interest rate, multiplied by 1e18.
  function _getAverageInterestRate(BorrowRateSnapshot memory snapshot) internal view returns (uint256 rate) {
    // absolute rate change is (new - prev) / prev
    // annual interest rate is (new - prev) / prev / duration * 365 days
    uint256 duration = block.timestamp - snapshot.timestamp;
    // @note Users can trigger this every `MIN_SNAPSHOT_DELAY` seconds and make the interest rate never change.
    // We allow users to do so, since the risk is not very high. And if we remove this if, the computed interest
    // rate may not correct due to small `duration`.
    if (duration < MIN_SNAPSHOT_DELAY) {
      rate = snapshot.lastInterestRate;
    } else {
      uint256 prevBorrowIndex = snapshot.borrowIndex;
      uint256 newBorrowIndex = IAaveV3Pool(AAVE_LENDING_POOL).getReserveNormalizedVariableDebt(AAVE_BASE_ASSET);
      rate = _computeAverageInterestRate(prevBorrowIndex, newBorrowIndex, duration);
      if (rate == 0) rate = snapshot.lastInterestRate;
    }
  }

  /// @dev Internal function to compute the average interest rate.
  /// @param prevBorrowIndex The previous borrow index.
  /// @param newBorrowIndex The new borrow index.
  /// @param duration The duration of the snapshot.
  /// @return rate The average interest rate, multiplied by 1e18.
  function _computeAverageInterestRate(
    uint256 prevBorrowIndex,
    uint256 newBorrowIndex,
    uint256 duration
  ) internal pure returns (uint256 rate) {
    rate = ((newBorrowIndex - prevBorrowIndex) * 365 days * PRECISION) / (prevBorrowIndex * duration);
  }

  /// @dev Internal function to update the borrow rate snapshot.
  /// @param borrowIndex The borrow index to update.
  /// @param interestRate The interest rate to update.
  function _updateBorrowRateSnapshot(uint256 borrowIndex, uint256 interestRate) internal {
    borrowRateSnapshot = BorrowRateSnapshot({
      borrowIndex: uint128(borrowIndex),
      lastInterestRate: uint80(interestRate),
      timestamp: uint48(block.timestamp)
    });

    emit Snapshot(borrowIndex, interestRate, block.timestamp);
  }

  /// @dev Internal function to check value not too large.
  /// @param value The value to check.
  /// @param upperBound The upper bound for the given value.
  function _checkValueTooLarge(uint256 value, uint256 upperBound) internal pure {
    if (value > upperBound) revert ErrorValueTooLarge();
  }

  /// @dev Internal function to scaler down for `uint256`, rounding down.
  function _scaleDown(uint256 value, uint256 scale) internal pure returns (uint256) {
    return (value * PRECISION) / scale;
  }
}
"
    },
    "project/contracts/interfaces/Aave/IAaveV3Pool.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IAaveV3Pool {
  struct ReserveConfigurationMap {
    //bit 0-15: LTV
    //bit 16-31: Liq. threshold
    //bit 32-47: Liq. bonus
    //bit 48-55: Decimals
    //bit 56: reserve is active
    //bit 57: reserve is frozen
    //bit 58: borrowing is enabled
    //bit 59: DEPRECATED: stable rate borrowing enabled
    //bit 60: asset is paused
    //bit 61: borrowing in isolation mode is enabled
    //bit 62: siloed borrowing enabled
    //bit 63: flashloaning enabled
    //bit 64-79: reserve factor
    //bit 80-115: borrow cap in whole tokens, borrowCap == 0 => no cap
    //bit 116-151: supply cap in whole tokens, supplyCap == 0 => no cap
    //bit 152-167: liquidation protocol fee
    //bit 168-175: DEPRECATED: eMode category
    //bit 176-211: unbacked mint cap in whole tokens, unbackedMintCap == 0 => minting disabled
    //bit 212-251: debt ceiling for isolation mode with (ReserveConfiguration::DEBT_CEILING_DECIMALS) decimals
    //bit 252: virtual accounting is enabled for the reserve
    //bit 253-255 unused

    uint256 data;
  }

  /**
   * This exists specifically to maintain the `getReserveData()` interface, since the new, internal
   * `ReserveData` struct includes the reserve's `virtualUnderlyingBalance`.
   */
  struct ReserveDataLegacy {
    //stores the reserve configuration
    ReserveConfigurationMap configuration;
    //the liquidity index. Expressed in ray
    uint128 liquidityIndex;
    //the current supply rate. Expressed in ray
    uint128 currentLiquidityRate;
    //variable borrow index. Expressed in ray
    uint128 variableBorrowIndex;
    //the current variable borrow rate. Expressed in ray
    uint128 currentVariableBorrowRate;
    // DEPRECATED on v3.2.0
    uint128 currentStableBorrowRate;
    //timestamp of last update
    uint40 lastUpdateTimestamp;
    //the id of the reserve. Represents the position in the list of the active reserves
    uint16 id;
    //aToken address
    address aTokenAddress;
    // DEPRECATED on v3.2.0
    address stableDebtTokenAddress;
    //variableDebtToken address
    address variableDebtTokenAddress;
    //address of the interest rate strategy
    address interestRateStrategyAddress;
    //the current treasury balance, scaled
    uint128 accruedToTreasury;
    //the outstanding unbacked aTokens minted through the bridging feature
    uint128 unbacked;
    //the outstanding debt borrowed against this asset in isolation mode
    uint128 isolationModeTotalDebt;
  }

  /**
   * @notice Returns the state and configuration of the reserve
   * @param asset The address of the underlying asset of the reserve
   * @return The state and configuration data of the reserve
   */
  function getReserveData(address asset) external view returns (ReserveDataLegacy memory);

  /**
   * @notice Returns the normalized variable debt per unit of asset
   * @dev WARNING: This function is intended to be used primarily by the protocol itself to get a
   * "dynamic" variable index based on time, current stored index and virtual rate at the current
   * moment (approx. a borrower would get if opening a position). This means that is always used in
   * combination with variable debt supply/balances.
   * If using this function externally, consider that is possible to have an increasing normalized
   * variable debt that is not equivalent to how the variable debt index would be updated in storage
   * (e.g. only updates with non-zero variable debt supply)
   * @param asset The address of the underlying asset of the reserve
   * @return The reserve normalized variable debt
   */
  function getReserveNormalizedVariableDebt(address asset) external view returns (uint256);

  /**
   * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
   * - E.g. User supplies 100 USDC and gets in return 100 aUSDC
   * @param asset The address of the underlying asset to supply
   * @param amount The amount to be supplied
   * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
   *   wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
   *   is a different wallet
   * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
   *   0 if the action is executed directly by the user, without any middle-man
   */
  function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;

  /**
   * @notice Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned
   * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC
   * @param asset The address of the underlying asset to withdraw
   * @param amount The underlying amount to be withdrawn
   *   - Send the value type(uint256).max in order to withdraw the whole aToken balance
   * @param to The address that will receive the underlying, same as msg.sender if the user
   *   wants to receive it on his own wallet, or a different address if the beneficiary is a
   *   different wallet
   * @return The final amount withdrawn
   */
  function withdraw(address asset, uint256 amount, address to) external returns (uint256);
}
"
    },
    "project/contracts/interfaces/IFxUSDBasePool.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IFxUSDBasePool {
  /**********
   * Events *
   **********/

  /// @notice Emitted when the stable depeg price is updated.
  /// @param oldPrice The value of previous depeg price, multiplied by 1e18.
  /// @param newPrice The value of current depeg price, multiplied by 1e18.
  event UpdateStableDepegPrice(uint256 oldPrice, uint256 newPrice);

  /// @notice Emitted when the redeem cool down period is updated.
  /// @param oldPeriod The value of previous redeem cool down period.
  /// @param newPeriod The value of current redeem cool down period.
  event UpdateRedeemCoolDownPeriod(uint256 oldPeriod, uint256 newPeriod);

  /// @notice Emitted when the instant redeem fee ratio is updated.
  /// @param oldRatio The value of previous instant redeem fee ratio, multiplied by 1e18.
  /// @param newRatio The value of current instant redeem fee ratio, multiplied by 1e18.
  event UpdateInstantRedeemFeeRatio(uint256 oldRatio, uint256 newRatio);

  /// @notice Emitted when deposit tokens.
  /// @param caller The address of caller.
  /// @param receiver The address of pool share recipient.
  /// @param tokenIn The address of input token.
  /// @param amountDeposited The amount of input tokens.
  /// @param amountSharesOut The amount of pool shares minted.
  event Deposit(
    address indexed caller,
    address indexed receiver,
    address indexed tokenIn,
    uint256 amountDeposited,
    uint256 amountSharesOut
  );
  
  /// @notice Emitted when users request redeem.
  /// @param caller The address of caller.
  /// @param shares The amount of shares to redeem.
  /// @param unlockAt The timestamp when this share can be redeemed.
  event RequestRedeem(address indexed caller, uint256 shares, uint256 unlockAt);

  /// @notice Emitted when redeem pool shares.
  /// @param caller The address of caller.
  /// @param receiver The address of pool share recipient.
  /// @param amountSharesToRedeem The amount of pool shares burned.
  /// @param amountYieldTokenOut The amount of yield tokens redeemed.
  /// @param amountStableTokenOut The amount of stable tokens redeemed.
  event Redeem(
    address indexed caller,
    address indexed receiver,
    uint256 amountSharesToRedeem,
    uint256 amountYieldTokenOut,
    uint256 amountStableTokenOut
  );

  /// @notice Emitted when instant redeem pool shares.
  /// @param caller The address of caller.
  /// @param receiver The address of pool share recipient.
  /// @param amountSharesToRedeem The amount of pool shares burned.
  /// @param amountYieldTokenOut The amount of yield tokens redeemed.
  /// @param amountStableTokenOut The amount of stable tokens redeemed.
  event InstantRedeem(
    address indexed caller,
    address indexed receiver,
    uint256 amountSharesToRedeem,
    uint256 amountYieldTokenOut,
    uint256 amountStableTokenOut
  );

  /// @notice Emitted when rebalance or liquidate.
  /// @param caller The address of caller.
  /// @param tokenIn The address of input token.
  /// @param amountTokenIn The amount of input token used.
  /// @param amountCollateral The amount of collateral token rebalanced.
  /// @param amountYieldToken The amount of yield token used.
  /// @param amountStableToken The amount of stable token used.
  event Rebalance(
    address indexed caller,
    address indexed tokenIn,
    uint256 amountTokenIn,
    uint256 amountCollateral,
    uint256 amountYieldToken,
    uint256 amountStableToken
  );

  /// @notice Emitted when arbitrage in curve pool.
  /// @param caller The address of caller.
  /// @param tokenIn The address of input token.
  /// @param amountIn The amount of input token used.
  /// @param amountOut The amount of output token swapped.
  /// @param bonusOut The amount of bonus token.
  event Arbitrage(
    address indexed caller,
    address indexed tokenIn,
    uint256 amountIn,
    uint256 amountOut,
    uint256 bonusOut
  );

  /*************************
   * Public View Functions *
   *************************/

  /// @notice The address of yield token.
  function yieldToken() external view returns (address);

  /// @notice The address of stable token.
  function stableToken() external view returns (address);

  /// @notice The total amount of yield token managed in this contract
  function totalYieldToken() external view returns (uint256);

  /// @notice The total amount of stable token managed in this contract
  function totalStableToken() external view returns (uint256);

  /// @notice The net asset value, multiplied by 1e18.
  function nav() external view returns (uint256);

  /// @notice Return the stable token price, multiplied by 1e18.
  function getStableTokenPrice() external view returns (uint256);

  /// @notice Return the stable token price with scaling to 18 decimals, multiplied by 1e18.
  function getStableTokenPriceWithScale() external view returns (uint256);

  /// @notice Preview the result of deposit.
  /// @param tokenIn The address of input token.
  /// @param amount The amount of input tokens to deposit.
  /// @return amountSharesOut The amount of pool shares should receive.
  function previewDeposit(address tokenIn, uint256 amount) external view returns (uint256 amountSharesOut);

  /// @notice Preview the result of redeem.
  /// @param amountSharesToRedeem The amount of pool shares to redeem.
  /// @return amountYieldOut The amount of yield token should receive.
  /// @return amountStableOut The amount of stable token should receive.
  function previewRedeem(
    uint256 amountSharesToRedeem
  ) external view returns (uint256 amountYieldOut, uint256 amountStableOut);

  /****************************
   * Public Mutated Functions *
   ****************************/

  /// @notice Deposit token.
  /// @param receiver The address of pool shares recipient.
  /// @param tokenIn The address of input token.
  /// @param amountTokenToDepo

Tags:
ERC165, Multisig, Swap, Liquidity, Yield, Upgradeable, Multi-Signature, Factory, Oracle|addr:0x69c40892c814fbb6fcdcbeb034e3dc854f3d7e10|verified:true|block:23697801|tx:0x9899ba6ddc6d9d223efae8c5c1b9c6b54d290b0ec66533acf235365e26728616|first_check:1761922941

Submitted on: 2025-10-31 16:02:22

Comments

Log in to comment.

No comments yet.