Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
PoolFactory
Compiler Version
v0.8.16+commit.07a7930e
Optimization Enabled:
Yes with 10 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import "../Pool.sol"; import "../interfaces/IServiceConfigurationV3.sol"; import "./interfaces/IPoolFactory.sol"; import "../interfaces/IPoolRegistry.sol"; import {BeaconProxy} from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; import "../upgrades/BeaconProxyFactory.sol"; /** * @title A factory that emits Pool contracts. * @dev Acts as a beacon contract, emitting beacon proxies and holding a reference * to their implementation contract. */ contract PoolFactory is IPoolFactory, BeaconProxyFactory { /** * @dev Reference to the WithdrawControllerFactory contract */ address internal _withdrawControllerFactory; address private _poolAccessControlFactory; /** * @dev Reference to the PoolControllerFactory contract */ address internal _poolControllerFactory; /** * @dev Reference to the VaultFactory contract */ address internal _vaultFactory; function version() public pure returns (uint16) { return 256 * 2 + 0; } modifier onlyVerifiedPoolAdmin() { require( IServiceConfigurationV3(address(_serviceConfiguration)).isPoolAdmin( msg.sender ), "CALLER_NOT_ADMIN" ); _; } /** * @dev Constructor * @param serviceConfiguration Reference to the global service configuration. * @param withdrawControllerFactory Reference to the withdraw controller factory. * @param poolControllerFactory Reference to the pool controller factory. * @param vaultFactory Reference to the Vault factory. */ constructor( address serviceConfiguration, address withdrawControllerFactory, address poolControllerFactory, address vaultFactory, address poolAccessControlFactory ) { _serviceConfiguration = IServiceConfigurationV3(serviceConfiguration); _withdrawControllerFactory = withdrawControllerFactory; _poolControllerFactory = poolControllerFactory; _vaultFactory = vaultFactory; _poolAccessControlFactory = poolAccessControlFactory; } function getWithdrawControllerFactory() external view returns (address) { return _withdrawControllerFactory; } function getPoolControllerFactory() external view returns (address) { return _poolControllerFactory; } function getVaultFactory() external view returns (address) { return _vaultFactory; } function getPoolAccessControlFactory() external view returns (address) { return _poolAccessControlFactory; } /** * @inheritdoc IPoolFactory */ function createPool( address liquidityAsset, IPoolConfigurableSettings calldata settings, string calldata tokenName, string calldata tokenSymbol ) public onlyVerifiedPoolAdmin returns (address poolAddress) { require( implementation != address(0), "PoolFactory: no implementation set" ); require( _serviceConfiguration.paused() == false, "PoolFactory: Protocol paused" ); require( _serviceConfiguration.isLiquidityAsset(liquidityAsset), "PoolFactory: invalid asset" ); require( _serviceConfiguration.getPoolFactory() == address(this), "PoolFactory: not correct" ); // Create the pool address addr = initializePool( liquidityAsset, settings, tokenName, tokenSymbol ); IPoolRegistry(_serviceConfiguration.getPoolRegistry()).addPool(addr); emit PoolCreated(addr); return addr; } /** * @dev Creates the new Pool contract. */ function initializePool( address liquidityAsset, IPoolConfigurableSettings calldata settings, string calldata tokenName, string calldata tokenSymbol ) internal virtual returns (address) { PoolAddressList memory poolAddressList = PoolAddressList( liquidityAsset, msg.sender, address(_serviceConfiguration), _withdrawControllerFactory, _poolControllerFactory, _vaultFactory, _poolAccessControlFactory ); // Create beacon proxy BeaconProxy proxy = new BeaconProxy( address(this), abi.encodeWithSelector( Pool.initialize.selector, poolAddressList, settings, tokenName, tokenSymbol ) ); return address(proxy); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @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 Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 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 functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _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 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _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() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @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 { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20Upgradeable.sol"; import "./extensions/IERC20MetadataUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol"; import {Initializable} from "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing { __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer(address from, address to, uint256 amount) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[45] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20MetadataUpgradeable is IERC20Upgradeable { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20PermitUpgradeable { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; import "../extensions/IERC20PermitUpgradeable.sol"; import "../../../utils/AddressUpgradeable.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20Upgradeable { using AddressUpgradeable for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20PermitUpgradeable token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol) pragma solidity ^0.8.0; 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; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol) pragma solidity ^0.8.0; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. * * _Available since v4.8.3._ */ interface IERC1967 { /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (proxy/beacon/BeaconProxy.sol) pragma solidity ^0.8.0; import "./IBeacon.sol"; import "../Proxy.sol"; import "../ERC1967/ERC1967Upgrade.sol"; /** * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}. * * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't * conflict with the storage layout of the implementation behind the proxy. * * _Available since v3.4._ */ contract BeaconProxy is Proxy, ERC1967Upgrade { /** * @dev Initializes the proxy with `beacon`. * * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This * will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity * constructor. * * Requirements: * * - `beacon` must be a contract with the interface {IBeacon}. */ constructor(address beacon, bytes memory data) payable { _upgradeBeaconToAndCall(beacon, data, false); } /** * @dev Returns the current beacon address. */ function _beacon() internal view virtual returns (address) { return _getBeacon(); } /** * @dev Returns the current implementation address of the associated beacon. */ function _implementation() internal view virtual override returns (address) { return IBeacon(_getBeacon()).implementation(); } /** * @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}. * * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. * * Requirements: * * - `beacon` must be a contract. * - The implementation returned by `beacon` must be a contract. */ function _setBeacon(address beacon, bytes memory data) internal virtual { _upgradeBeaconToAndCall(beacon, data, false); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeacon.sol"; import "../../interfaces/IERC1967.sol"; import "../../interfaces/draft-IERC1822.sol"; import "../../utils/Address.sol"; import "../../utils/StorageSlot.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ */ abstract contract ERC1967Upgrade is IERC1967 { // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { Address.functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( Address.isContract(IBeacon(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol) pragma solidity ^0.8.0; /** * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to * be specified by overriding the virtual {_implementation} function. * * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a * different contract through the {_delegate} function. * * The success and return data of the delegated call will be returned back to the caller of the proxy. */ abstract contract Proxy { /** * @dev Delegates the current call to `implementation`. * * This function does not return to its internal call site, it will return directly to the external caller. */ function _delegate(address implementation) internal virtual { assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize()) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } /** * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function * and {_fallback} should delegate. */ function _implementation() internal view virtual returns (address); /** * @dev Delegates the current call to the address returned by `_implementation()`. * * This function does not return to its internal call site, it will return directly to the external caller. */ function _fallback() internal virtual { _beforeFallback(); _delegate(_implementation()); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other * function in the contract matches the call data. */ fallback() external payable virtual { _fallback(); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data * is empty. */ receive() external payable virtual { _fallback(); } /** * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback` * call, or as part of the Solidity `fallback` or `receive` functions. * * If overridden should call `super._beforeFallback()`. */ function _beforeFallback() internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer(address from, address to, uint256 amount) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/ERC721.sol) pragma solidity ^0.8.0; import "./IERC721.sol"; import "./IERC721Receiver.sol"; import "./extensions/IERC721Metadata.sol"; import "../../utils/Address.sol"; import "../../utils/Context.sol"; import "../../utils/Strings.sol"; import "../../utils/introspection/ERC165.sol"; /** * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including * the Metadata extension, but not including the Enumerable extension, which is available separately as * {ERC721Enumerable}. */ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { using Address for address; using Strings for uint256; // Token name string private _name; // Token symbol string private _symbol; // Mapping from token ID to owner address mapping(uint256 => address) private _owners; // Mapping owner address to token count mapping(address => uint256) private _balances; // Mapping from token ID to approved address mapping(uint256 => address) private _tokenApprovals; // Mapping from owner to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; /** * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view virtual override returns (uint256) { require(owner != address(0), "ERC721: address zero is not a valid owner"); return _balances[owner]; } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view virtual override returns (address) { address owner = _ownerOf(tokenId); require(owner != address(0), "ERC721: invalid token ID"); return owner; } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { _requireMinted(tokenId); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, can be overridden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ""; } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public virtual override { address owner = ERC721.ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require( _msgSender() == owner || isApprovedForAll(owner, _msgSender()), "ERC721: approve caller is not token owner or approved for all" ); _approve(to, tokenId); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view virtual override returns (address) { _requireMinted(tokenId); return _tokenApprovals[tokenId]; } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { _setApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom(address from, address to, uint256 tokenId) public virtual override { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); _transfer(from, to, tokenId); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual override { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); _safeTransfer(from, to, tokenId, data); } /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * `data` is additional data, it has no specified format and it is sent in call to `to`. * * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. * implement alternative mechanisms to perform token transfer, such as signature-based. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual { _transfer(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist */ function _ownerOf(uint256 tokenId) internal view virtual returns (address) { return _owners[tokenId]; } /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted (`_mint`), * and stop existing when they are burned (`_burn`). */ function _exists(uint256 tokenId) internal view virtual returns (bool) { return _ownerOf(tokenId) != address(0); } /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * * Requirements: * * - `tokenId` must exist. */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { address owner = ERC721.ownerOf(tokenId); return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender); } /** * @dev Safely mints `tokenId` and transfers it to `to`. * * Requirements: * * - `tokenId` must not exist. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual { _mint(to, tokenId); require( _checkOnERC721Received(address(0), to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer" ); } /** * @dev Mints `tokenId` and transfers it to `to`. * * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible * * Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * * Emits a {Transfer} event. */ function _mint(address to, uint256 tokenId) internal virtual { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _beforeTokenTransfer(address(0), to, tokenId, 1); // Check that tokenId was not minted by `_beforeTokenTransfer` hook require(!_exists(tokenId), "ERC721: token already minted"); unchecked { // Will not overflow unless all 2**256 token ids are minted to the same owner. // Given that tokens are minted one by one, it is impossible in practice that // this ever happens. Might change if we allow batch minting. // The ERC fails to describe this case. _balances[to] += 1; } _owners[tokenId] = to; emit Transfer(address(0), to, tokenId); _afterTokenTransfer(address(0), to, tokenId, 1); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * This is an internal function that does not check if the sender is authorized to operate on the token. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId) internal virtual { address owner = ERC721.ownerOf(tokenId); _beforeTokenTransfer(owner, address(0), tokenId, 1); // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook owner = ERC721.ownerOf(tokenId); // Clear approvals delete _tokenApprovals[tokenId]; unchecked { // Cannot overflow, as that would require more tokens to be burned/transferred // out than the owner initially received through minting and transferring in. _balances[owner] -= 1; } delete _owners[tokenId]; emit Transfer(owner, address(0), tokenId); _afterTokenTransfer(owner, address(0), tokenId, 1); } /** * @dev Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer(address from, address to, uint256 tokenId) internal virtual { require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); require(to != address(0), "ERC721: transfer to the zero address"); _beforeTokenTransfer(from, to, tokenId, 1); // Check that tokenId was not transferred by `_beforeTokenTransfer` hook require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); // Clear approvals from the previous owner delete _tokenApprovals[tokenId]; unchecked { // `_balances[from]` cannot overflow for the same reason as described in `_burn`: // `from`'s balance is the number of token held, which is at least one before the current // transfer. // `_balances[to]` could overflow in the conditions described in `_mint`. That would require // all 2**256 token ids to be minted, which in practice is impossible. _balances[from] -= 1; _balances[to] += 1; } _owners[tokenId] = to; emit Transfer(from, to, tokenId); _afterTokenTransfer(from, to, tokenId, 1); } /** * @dev Approve `to` to operate on `tokenId` * * Emits an {Approval} event. */ function _approve(address to, uint256 tokenId) internal virtual { _tokenApprovals[tokenId] = to; emit Approval(ERC721.ownerOf(tokenId), to, tokenId); } /** * @dev Approve `operator` to operate on all of `owner` tokens * * Emits an {ApprovalForAll} event. */ function _setApprovalForAll(address owner, address operator, bool approved) internal virtual { require(owner != operator, "ERC721: approve to caller"); _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); } /** * @dev Reverts if the `tokenId` has not been minted yet. */ function _requireMinted(uint256 tokenId) internal view virtual { require(_exists(tokenId), "ERC721: invalid token ID"); } /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. * The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param data bytes optional data to send along with the call * @return bool whether the call correctly returned the expected magic value */ function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory data ) private returns (bool) { if (to.isContract()) { try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) { return retval == IERC721Receiver.onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert("ERC721: transfer to non ERC721Receiver implementer"); } else { /// @solidity memory-safe-assembly assembly { revert(add(32, reason), mload(reason)) } } } } else { return true; } } /** * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`. * - When `from` is zero, the tokens will be minted for `to`. * - When `to` is zero, ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * - `batchSize` is non-zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {} /** * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`. * - When `from` is zero, the tokens were minted for `to`. * - When `to` is zero, ``from``'s tokens were burned. * - `from` and `to` are never both zero. * - `batchSize` is non-zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {} /** * @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override. * * WARNING: Anyone calling this MUST ensure that the balances remain consistent with the ownership. The invariant * being that for any address `a` the value returned by `balanceOf(a)` must be equal to the number of tokens such * that `ownerOf(tokenId)` is `a`. */ // solhint-disable-next-line func-name-mixedcase function __unsafe_increaseBalance(address account, uint256 amount) internal { _balances[account] += amount; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol) pragma solidity ^0.8.0; /** * @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 Context { 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; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 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); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * 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[EIP 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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol) pragma solidity ^0.8.0; // CAUTION // This version of SafeMath should only be used with Solidity 0.8 or later, // because it relies on the compiler's built in overflow checks. /** * @dev Wrappers over Solidity's arithmetic operations. * * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler * now has built in overflow checking. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { return a + b; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { return a * b; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b <= a, errorMessage); return a - b; } } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a / b; } } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a % b; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ```solidity * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._ * _Available since v4.9 for `string`, `bytes`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import "../../interfaces/IPool.sol"; import "../../interfaces/ILoan.sol"; /** * @dev Expresses the various states a pool can be in throughout its lifecycle. */ enum IPoolLifeCycleState { Initialized, Active, Closed, DisruptionOrDefault } /** * @title The various configurable settings that customize Pool behavior. */ struct IPoolConfigurableSettings { uint256 maxCapacity; // amount uint256 endDate; // epoch seconds address borrowerManager; address borrowerWalletAddress; uint256 closeOfBusinessTime; uint256 earlyWithdrawFeeBps; } /** * @title A Pool's Admin controller * @dev Pool Admin's interact with the pool via the controller, including funding loans and adjusting * settings. */ interface IPoolController { /** * @dev Emitted when pool settings are updated. */ event PoolSettingsUpdated(); /** * @dev Emitted when the pool transitions a lifecycle state. */ event LifeCycleStateTransition(IPoolLifeCycleState state); /** * @dev Emitted when a pool is marked as in DisruptionOrDefault. */ event DisruptionOrDefault(address indexed pool); event Rescheduled(address indexed pool); function version() external returns (uint16); /** * @dev The Pool's admin */ function admin() external view returns (address); /*////////////////////////////////////////////////////////////// Settings //////////////////////////////////////////////////////////////*/ /** * @dev The current configurable pool settings. */ function settings() external view returns (IPoolConfigurableSettings memory); function serviceConfiguration() external view returns (address); /** * @dev Allow the current pool admin to update the pool capacity at any * time. */ function setPoolCapacity(uint256) external; /** * @dev Allow the current pool admin to update the pool's end date. The end date can * only be moved earlier (but not in the past, as measured by the current block's timestamp). * Once the end date is reached, the Pool is closed. */ function setPoolEndDate(uint256) external; function closeOfBusinessTime() external view returns (uint256); function borrowerManager() external view returns (address); function borrowerWalletAddress() external view returns (address); /*////////////////////////////////////////////////////////////// State //////////////////////////////////////////////////////////////*/ function reschedule( address loan, uint256 accrualStartDayTimestamp, uint256 transferInWindowDurationDays, uint256 transferOutWindowDurationDays, uint256 durationDays ) external; /** * @dev Returns the current pool lifecycle state. */ function state() external view returns (IPoolLifeCycleState); function activatePool() external; /*////////////////////////////////////////////////////////////// Loans //////////////////////////////////////////////////////////////*/ function approveLoanForPool(address loan) external; function initiateRollover(address loan, address priorLoan) external; function completeRolloverNetPayment(address) external; function disruptionOrDefault() external; function releaseRolloverRedemption(address owner) external; /*////////////////////////////////////////////////////////////// Fees //////////////////////////////////////////////////////////////*/ /** * @dev Called by the pool admin, this claims fees that have accumulated * in the Pool's FeeVault from ongoing borrower payments. */ function withdrawFeeVault(uint256 amount, address receiver) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import "../../interfaces/IPool.sol"; struct IPoolRolloverWithdrawState { uint256 requestedShares; // Number of shares requested in the `latestPeriod` uint256 requestedAssets; uint256 redeemableShares; // The shares that are currently withdrawable uint256 withdrawableAssets; // The assets that are currently withdrawable uint256 earlyRequestedShares; // The period in which the shares were requested uint256 earlyRequestedAssets; uint256 earlyAcceptedShares; // The period in which the shares were requested uint256 earlyAcceptedAssets; } /** * @title A Pool's Withdraw controller * @dev Holds state related to withdraw requests, and logic for snapshotting the * pool's liquidity reserve at regular intervals, earmarking funds for lenders according * to their withdrawal requests. */ interface IWithdrawController { function version() external pure returns (uint16); function pool() external view returns (address); function feeVault() external view returns (address); function borrowerVault() external view returns (address); function borrowerWallet() external view returns (address); function withdrawFeeVault(uint256 amount, address receiver) external; /*////////////////////////////////////////////////////////////// Balance Views //////////////////////////////////////////////////////////////*/ function drawDownToBorrowerWallet(uint256 amount) external; function redemptionState() external view returns (IRedemptionState memory); function requestedSharesOf( address owner ) external view returns (uint256 shares); function requestedAssetsOf( address owner ) external view returns (uint256 assets); function redeemableSharesOf( address owner ) external view returns (uint256 shares); function withdrawableAssetsOf( address owner ) external view returns (uint256 assets); /** * @dev Returns the number of shares that are available to be redeemed by * the owner in the current block. */ function totalRequestedShares() external view returns (uint256); function totalRequestedAssets() external view returns (uint256 assets); /** * @dev Returns the number of shares that are available to be redeemed * overall in the current block. */ function totalRedeemableShares() external view returns (uint256); /** * @dev Returns the number of `assets` that are available to be withdrawn * overall in the current block. */ function totalWithdrawableAssets() external view returns (uint256); function releaseRolloverRedemption( address owner ) external returns (uint256 shares, uint256 assets); /*////////////////////////////////////////////////////////////// Max Methods //////////////////////////////////////////////////////////////*/ /** * @dev Returns the maximum number of `shares` that can be * requested to be redeemed from the owner balance with a single * `requestRedeem` call in the current block. * * Note: This is equivalent of EIP-4626 `maxRedeem` */ function maxRedeemRequest(address) external view returns (uint256); /** * @dev The maximum amount of shares that can be redeemed from the owner * balance through a redeem call. */ function maxRedeem(address) external view returns (uint256); /** * @dev Returns the maximum amount of underlying assets that can be * withdrawn from the owner balance with a single withdraw call. */ function maxWithdraw(address) external view returns (uint256); /*////////////////////////////////////////////////////////////// Preview Methods //////////////////////////////////////////////////////////////*/ /** * @dev Simulates the effects of their redeemption at the current block. * Per EIP4626, should round DOWN. */ function previewRedeem(address, uint256) external view returns (uint256); /** * @dev Simulate the effects of their withdrawal at the current block. * Per EIP4626, should round UP on the number of shares required for assets. */ function previewWithdraw(address, uint256) external view returns (uint256); /*////////////////////////////////////////////////////////////// Request Methods //////////////////////////////////////////////////////////////*/ /** * @dev Requests redeeming a specific number of `shares` and `assets` from * the pool. * * NOTE: The pool is responsible for handling any fees, and for providing * the proper shares/assets ratio. */ function performRequest(address, uint256, uint256) external; /*////////////////////////////////////////////////////////////// Early Withdraw Methods //////////////////////////////////////////////////////////////*/ function requestEarlyRedeem( address owner, uint256 shares ) external returns (uint256 principal); function acceptEarlyRedeemRequest( address investorAddr ) external returns (uint256 shares, uint256 principal); function repayEarlyWithdraw( address investorAddr, uint256 amount ) external returns ( uint256 principal, uint256 repayment, uint256 redeemedShares, uint256 fees, uint256 assetReduction ); function totalEarlyRequestedShares() external view returns (uint256 shares); function totalEarlyRequestedAssets() external view returns (uint256 assets); function totalEarlyAcceptedShares() external view returns (uint256 shares); function totalEarlyAcceptedAssets() external view returns (uint256 assets); function earlyRequestedSharesOf( address owner ) external view returns (uint256 shares); function earlyRequestedAssetsOf( address owner ) external view returns (uint256 assets); function earlyAcceptedSharesOf( address owner ) external view returns (uint256 shares); function earlyAcceptedAssetsOf( address owner ) external view returns (uint256 assets); /*////////////////////////////////////////////////////////////// Withdraw / Redeem //////////////////////////////////////////////////////////////*/ /** * @dev Redeems a specific number of shares from owner and send assets of underlying token from the vault to receiver. * * Per EIP4626, should round DOWN. */ function redeem(address, uint256) external returns (uint256); /** * @dev Burns shares from owner and send exactly assets token from the vault to receiver. * Should round UP for EIP4626. */ function withdraw(address, uint256) external returns (uint256); function payFees(uint256) external; function repayLoan(uint256) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import "../../interfaces/ILoan.sol"; /** * @title Interface for the LoanFactory. */ interface ILoanFactory { /** * @dev Emitted when a loan is created. */ event LoanCreated(address indexed addr, address indexed poolAddr); /** * @dev Creates a loan * @dev Emits `LoanCreated` event. */ function createLoan( address borrower, address pool, address liquidityAsset, ILoanSettings memory settings ) external returns (address); function version() external pure returns (uint16); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; /** * @title An interface for a factory that creates PoolAccessControl contracts. */ interface IPoolAccessControlFactory { /** * @dev Creates a new PoolAccessControl. */ function create(address pool) external returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import "../../interfaces/IPool.sol"; /** * @title Interface for the PoolController factory. */ interface IPoolControllerFactory { /** * @dev Emitted when a pool is created. */ event PoolControllerCreated(address indexed pool, address indexed addr); /** * @dev Creates a pool's PoolAdmin controller * @dev Emits `PoolControllerCreated` event. */ function createController( address pool, address serviceConfiguration, address admin, address liquidityAsset, IPoolConfigurableSettings memory poolSettings ) external returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import "../../interfaces/IPool.sol"; /** * @title Interface for the PoolFactory. */ interface IPoolFactory { /** * @dev Emitted when a pool is created. */ event PoolCreated(address indexed addr); /** * @dev Creates a Pool. * @dev Emits `PoolCreated` event. */ function createPool( address, IPoolConfigurableSettings calldata, string calldata, string calldata ) external returns (address); function getPoolControllerFactory() external view returns (address); function getWithdrawControllerFactory() external view returns (address); function getVaultFactory() external view returns (address); function getPoolAccessControlFactory() external view returns (address); function version() external pure returns (uint16); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; /** * @title Interface for the VaultFactory. */ enum IVaultType { Default, PoolVault, BorrowerVault, FeeVault, FundingVault } interface IVaultFactory { /** * @dev Emitted when a vault is created. */ event VaultCreated(address indexed owner); /** * @dev Creates a new vault. * @dev Emits a `VaultCreated` event. */ function createVault( address owner, IVaultType vaultType ) external returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; /** * @title Interface for the WithdrawController factory. */ interface IWithdrawControllerFactory { /** * @dev Emitted when a pool WithdrawController is created. */ event WithdrawControllerCreated(address indexed addr); /** * @dev Creates a pool's withdraw controller * @dev Emits `WithdrawControllerCreated` event. */ function createController( address pool, address vaultFactory, address borrowerWalletAddress ) external returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import "../interfaces/IServiceConfigurationV3.sol"; import "./interfaces/ILoanFactory.sol"; import "../interfaces/IPool.sol"; import "../Loan.sol"; import "../upgrades/BeaconProxyFactory.sol"; import {BeaconProxy} from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; /** * @title A factory that emits Loan contracts. * @dev Acts as a beacon contract, emitting beacon proxies and holding a reference * to their implementation contract. */ contract LoanFactory is ILoanFactory, BeaconProxyFactory { mapping(address => bool) public isLoan; /** * @dev A reference to the VaultFactory. */ address internal _vaultFactory; function version() public pure returns (uint16) { return 256 * 1 + 0; } /** * @dev Constructor for the LoanFactory. * @param serviceConfiguration Reference to the global service configuration. * @param vaultFactory Reference to a VaultFactory. */ constructor(address serviceConfiguration, address vaultFactory) { _serviceConfiguration = IServiceConfigurationV3(serviceConfiguration); _vaultFactory = vaultFactory; } /** * @dev Creates a Loan * @dev Emits `LoanCreated` event. */ function createLoan( address borrower, address pool, address liquidityAsset, ILoanSettings memory settings ) public returns (address) { require( _serviceConfiguration.paused() == false, "LoanFactory: Protocol paused" ); require(implementation != address(0), "LoanFactory: no implementation"); require( msg.sender == IPool(pool).borrowerManagerAddr(), "LoanFactory: Caller not borrowerManager" ); require( borrower == IPool(pool).borrowerManagerAddr(), "LoanFactory: Caller not borrowerManager" ); address addr = initializeLoan(borrower, pool, liquidityAsset, settings); IPool(pool).loanCreated(addr); emit LoanCreated(addr, pool); isLoan[addr] = true; return addr; } /** * @dev Internal initialization of Beacon proxy for Loans */ function initializeLoan( address borrower, address pool, address liquidityAsset, ILoanSettings memory settings_ ) internal returns (address) { BeaconProxy proxy = new BeaconProxy( address(this), abi.encodeWithSelector( Loan.initialize.selector, address(_serviceConfiguration), address(this), borrower, pool, liquidityAsset, _vaultFactory, settings_ ) ); return address(proxy); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; /** * @title The interface according to the ERC-4626 standard. */ interface IERC4626 is IERC20Upgradeable { /** * @dev Emitted when tokens are deposited into the vault via the mint and deposit methods. */ event Deposit( address indexed sender, address indexed owner, uint256 assets, uint256 shares ); /** * @dev Emitted when shares are withdrawn from the vault by a depositor in the redeem or withdraw methods. */ event Withdraw( address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares ); /** * @dev Return the address of the underlying ERC-20 token used for the vault for accounting, depositing, withdrawing. */ function asset() external view returns (address); /** * @dev Calculate the total amount of underlying assets held by the vault. * NOTE: This method includes assets that are marked for withdrawal. */ function totalAssets() external view returns (uint256); /** * @dev Calculates the amount of shares that would be exchanged by the vault for the amount of assets provided. * Rounds DOWN per EIP4626. */ function convertToShares(uint256 assets) external view returns (uint256); /** * @dev Calculates the amount of assets that would be exchanged by the vault for the amount of shares provided. * Rounds DOWN per EIP4626. */ function convertToAssets(uint256 shares) external view returns (uint256); /** * @dev Calculates the maximum amount of underlying assets that can be deposited in a single deposit call by the receiver. */ function maxDeposit(address receiver) external view returns (uint256); /** * @dev Allows users to simulate the effects of their deposit at the current block. */ function previewDeposit(uint256 assets) external view returns (uint256); /** * @dev Deposits assets of underlying tokens into the vault and grants ownership of shares to receiver. * Emits a {Deposit} event. */ function deposit( uint256 assets, address receiver ) external returns (uint256); /** * @dev Returns the maximum amount of shares that can be minted in a single mint call by the receiver. */ function maxMint(address receiver) external view returns (uint256); /** * @dev Allows users to simulate the effects of their mint at the current block. */ function previewMint(uint256 shares) external view returns (uint256); /** * @dev Mints exactly shares vault shares to receiver by depositing assets of underlying tokens. * Emits a {Deposit} event. */ function mint(uint256 shares, address receiver) external returns (uint256); /** * @dev Returns the maximum amount of underlying assets that can be withdrawn from the owner balance with a single withdraw call. */ function maxWithdraw(address owner) external view returns (uint256); /** * @dev Simulate the effects of their withdrawal at the current block. * Per EIP4626, should round UP on the number of shares required for assets. */ function previewWithdraw(uint256 assets) external view returns (uint256); /** * @dev Burns shares from owner and send exactly assets token from the vault to receiver. * Emits a {Withdraw} event. * Should round UP for EIP4626. */ function withdraw( uint256 assets, address receiver, address owner ) external returns (uint256); /** * @dev The maximum amount of shares that can be redeemed from the owner balance through a redeem call. */ function maxRedeem(address owner) external view returns (uint256); /** * @dev Simulates the effects of their redeemption at the current block. * Per EIP4626, should round DOWN. */ function previewRedeem(uint256 shares) external view returns (uint256); /** * @dev Redeems a specific number of shares from owner and send assets of underlying token from the vault to receiver. * Emits a {Withdraw} event. * Per EIP4626, should round DOWN. */ function redeem( uint256 shares, address receiver, address owner ) external returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import "./IServiceConfigurationV3.sol"; import "../interfaces/IVault.sol"; /** * @title An enum capturing the various states a Loan may be in. */ enum ILoanLifeCycleState { Requested, Canceled, Funded, Matured, Active, Settled } enum ILoanTransitionState { Created /* RequestedLoan */, ApprovedForDeposits /* RequestedLoan */, TransitioningFundsIn /* RequestedLoan */, AccruingInterest /* ActiveLoan */, RedemptionsClosed /* ActiveLoan */, TransitioningFundsOut /* MaturedLoan */, RedemptionsReleased /* Settled loan */ } struct ILoanCompleteState { address loanAddr; address borrowerAddr; address fundingVaultAddr; address poolAddr; uint256 state; uint256 transitionState; uint256 durationDays; uint256 principal; uint256 startingPrincipal; uint256 interest; uint256 indicativeInterest; uint256 originationFee; uint256 indicativeApr; uint256 finalizedApr; uint256 exchangeRateAtDeposit; uint256 exchangeRateAtMaturity; uint256 fundingVaultBalance; uint256 assetsRolloverToNextLoan; uint256 assetsToReturnToPool; uint256 assetsFromPool; uint256 accrualStartDayTimestamp; uint256 accrualStartTimestamp; uint256 transferInWindowDurationDays; uint256 transferOutWindowDurationDays; uint256 depositClosingTimestamp; uint256 redemptionRequestClosingTimestamp; uint256 maturingTimestamp; uint256 redemptionAvailableTimestamp; ILoanRolloverAccounting rolloverAccounting; bool canRequestRedemption; } /** * @title The various Loan terms. */ struct ILoanSettings { uint256 principal; uint256 indicativeApr; uint256 finalizedApr; uint256 durationDays; uint256 dropDeadTimestamp; uint256 originationBps; uint256 accrualStartDayTimestamp; uint256 transferInWindowDurationDays; uint256 transferOutWindowDurationDays; address priorLoan; uint256 startingPrincipal; } struct ILoanRolloverAccounting { uint256 totalSupply; uint256 assetsFromPool; uint256 assetsFromPriorLoan; uint256 assetToReturnToPool; uint256 exchangeRateAtDeposit; uint256 exchangeRateAtMaturity; } /** * @title The primary interface for Perimeter loans. */ interface ILoan { /** * @dev Emitted when loan is funded. */ event LoanFunded(address asset, uint256 amount); /** * @dev Emitted when a Loan's lifecycle state transitions */ event LifeCycleStateTransition(ILoanLifeCycleState state); function getRolloverAccounting() external view returns (ILoanRolloverAccounting memory); function approve() external; function canRequestRedemption() external view returns (bool); function inDepositWindow() external view returns (bool); function inInitiateRolloverWindow() external view returns (bool); function exchangeRateAtDeposit() external view returns (uint256); function exchangeRateAtMaturity() external view returns (uint256); function assetsRolloverToNextLoan() external view returns (uint256); function assetsFromPool() external view returns (uint256); function assetsToReturnToPool() external view returns (uint256); function accrualStartTimestamp() external view returns (uint256); function accrualStartDayTimestamp() external view returns (uint256); function transferInWindowDurationDays() external view returns (uint256); function transferOutWindowDurationDays() external view returns (uint256); function depositClosingTimestamp() external view returns (uint256); function earlyRedeemRequestClosingTimestamp() external view returns (uint256); function redemptionRequestClosingTimestamp() external view returns (uint256); function maturingTimestamp() external view returns (uint256); function redemptionAvailableTimestamp() external view returns (uint256); /** * @dev Current Loan lifecycle state. */ function state() external view returns (ILoanLifeCycleState); function transitionState() external view returns (ILoanTransitionState); /** * @dev The loan's borrower. */ function borrower() external view returns (address); /** * @dev The pool associated with a loan. */ function pool() external view returns (address); /** * @dev The factory that created the loan. */ function factory() external view returns (address); /** * @dev A timestamp that controls when the loan can be dissolved */ function dropDeadTimestamp() external view returns (uint256); /** * @dev Amount expected in each payment */ function interest() external view returns (uint256); function indicativeInterest() external view returns (uint256); function rolloverMaturedLoan() external; function rolloverAndFinalizeApr(uint256 apr) external; function rolloverAllocation( uint256 assetsRolloverToNextLoan_, uint256 assetToReturnToPool_ ) external; function completeRolloverNetPayment() external returns ( uint256 feeVaultAmount, uint256 assetsReturnedToPool, uint256 interestAccrued ); function fundRollover( uint256 assetsFromPool, uint256 assetsFromPriorLoan, uint256 totalSupply, address priorLoan ) external returns (ILoanLifeCycleState); function reschedule( uint256 accrualStartDayTimestamp_, uint256 transferInWindowDurationDays_, uint256 transferOutWindowDurationDays_, uint256 durationDays_ ) external; /** * @dev When the loan was created. */ function createdAt() external returns (uint256); /** * @dev Duration of the loan, after which the principal must be returned. */ function durationDays() external view returns (uint256); /** * @dev Interest rate for the loan. */ function finalizedApr() external view returns (uint256); function indicativeApr() external view returns (uint256); function originationFee() external view returns (uint256); /** * @dev Amount of loan principal. */ function principal() external view returns (uint256); function startingPrincipal() external view returns (uint256); /** * @dev Address of the loan's funding vault, which holds liquidity transferred from the pool. */ function fundingVault() external view returns (IVault); /** * @dev Liquidity asset of the loan or pool. */ function liquidityAsset() external view returns (address); /** * @dev Address of the global service configuration. */ function serviceConfiguration() external view returns (IServiceConfigurationV3); function repayEarlyWithdraw( uint256 principal, uint256 assetReduction ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import "./IERC4626.sol"; import "./IServiceConfiguration.sol"; import "../controllers/interfaces/IPoolController.sol"; import "./IPoolBase.sol"; import "../controllers/interfaces/IWithdrawController.sol"; import "./ILoan.sol"; import "../interfaces/IPoolAccessControl.sol"; /* Paired with rolloverTiming field */ enum IPoolRolloverState { EarlyRolloverInitiate, // 0 accept Deposits and WithdrawRequests, no early withdraws) transitionTiming = time to expected rollover */ RolloverInitiate, // 1 no deposits or withdrawRequests) transitionTiming = time left of expected rollover */ LateRolloverInitiate, // 2 transitionTiming = time expected rollover pastDue */ EarlyRolloverFinalize, // 3 Requested RolloverFinalize, // 4 Requested LateRolloverFinalize, // 5 Requested EarlyRepayWithdrawsAndFees, // 6 Matured loan RepayWithdrawsAndFees, // 7 Matured loan LateRepayWithdrawsAndFees, // 8 Matured loan EarlyReleaseRedemptions, // 9 Matured loan ReleaseRedemptions, // 10 Matured loan LateReleaseRedemptions, // 11 Matured loan CreateNextLoan, // 12 ApproveNextLoan, //13 LateApproveNextLoan, //14 LoanNeedsRescheduling, //15 NotRollingOver, //16 InvalidState // 17 } enum IPoolRolloverActor { PoolAdmin, // 0 BorrowerManager, //1 BorrowerWallet, //2 Investor // 3 } struct IPoolAccountings { uint256 totalAvailableAssets; uint256 outstandingLoanPrincipals; uint256 totalAssetsDeposited; uint256 totalAssetsWithdrawn; } struct IPoolRolloverStateStruct { IPoolRolloverState rolloverState; IPoolRolloverActor rolloverActor; uint256 rolloverTimeToActionWindow; uint256 rolloverTimeLeftInActionWindow; uint256 rolloverTimePastActionWindow; } struct IPoolConfigurationState { address poolAddr; address admin; address poolController; address feeVault; address withdrawController; string name; string symbol; address borrowerManager; address borrowerWallet; address borrowerVault; uint256 maxCapacity; uint256 closeOfBusinessTime; uint256 poolEndDate; address liquidityPoolAssetAddr; } struct IRedemptionState { address[] redemptionLenders; uint256[] requestedShares; uint256[] redeemableShares; } struct IPoolOverviewState { address poolAddr; address[] settledLoans; uint8 state; uint8 rolloverState; uint8 rolloverActor; uint256 rolloverTimeToActionWindow; uint256 rolloverTimeLeftInActionWindow; uint256 rolloverTimePastActionWindow; uint256 totalAvailableAssets; uint256 totalAvailableSupply; uint256 currentExpectedInterest; uint256 liquidityPoolAssets; uint256 totalAssets; uint256 totalOutstandingLoanPrincipal; uint256 totalAssetsDeposited; uint256 totalAssetsWithdrawn; uint256 totalRequestedShares; uint256 totalRedeemableShares; uint256 totalWithdrawableAssets; uint256 totalRequestedAssets; uint256 feeVaultBalance; uint256 borrowerVaultBalance; uint256 borrowerWalletBalance; uint256 poolBalance; uint256 exchangeRateAtMaturity; ILoanCompleteState requestedLoanState; ILoanCompleteState activeLoanState; ILoanCompleteState maturedLoanState; ILoanCompleteState createdLoanState; IRedemptionState redemptionState; uint256 totalEarlyRequestedShares; uint256 totalEarlyRequestedAssets; uint256 totalEarlyAcceptedShares; uint256 totalEarlyAcceptedAssets; } struct IPoolAccountState { address poolAddr; address accountAddr; uint256 balance; uint256 maxWithdrawRequest; uint256 maxRedeemRequest; uint256 maxWithdraw; uint256 maxRedeem; uint256 requestedSharesOf; uint256 redeemableSharesOf; uint256 requestedAssetsOf; uint256 withdrawableAssetsOf; uint256 earlyRequestedSharesOf; uint256 earlyRequestedAssetsOf; uint256 earlyAcceptedSharesOf; uint256 earlyAcceptedAssetsOf; } struct PoolAddressList { address liquidityAsset; address poolAdmin; address serviceConfiguration; address withdrawControllerFactory; address poolControllerFactory; address vaultFactory; address poolAccessControlFactory; } /** * @title The interface for liquidity pools. */ interface IPool is IPoolBase { event Deposit( address indexed sender, address indexed owner, uint256 assets, uint256 shares ); event Withdraw( address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares ); /** * @dev The PoolController contract */ function poolController() external view returns (IPoolController); /** * @dev The WithdrawController contract */ function withdrawController() external view returns (IWithdrawController); /** * @dev The current configurable pool settings. */ function settings() external view returns (IPoolConfigurableSettings calldata settings); /** * @dev The current pool state. */ function state() external view returns (IPoolLifeCycleState); /** * @dev The pool accounting variables; */ function accountings() external view returns (IPoolAccountings memory); function closeOfBusinessTime() external view returns (uint256); /** * @dev Callback from the pool controller when the pool is activated */ function onActivated() external; function initiateRollover(address loan, address priorLoan) external; function completeRolloverNetPayment(address) external; function withdrawFeeVault(uint256 amount, address receiver) external; function loanCreated(address loan) external; function reschedule( address loan, uint256 accrualStartDayTimestamp, uint256 transferInWindowDurationDays, uint256 transferOutWindowDurationDays, uint256 durationDays ) external; function redemptionState() external view returns (IRedemptionState memory _redemptionState); function releaseRolloverRedemption(address owner) external; function exchangeRateAtMaturity() external view returns (uint256 _exchangeRateAtMaturity); function exchangeRateAtDeposit() external view returns (uint256); /** * @dev Calculate the total amount of underlying assets held by the vault, * excluding any assets due for withdrawal. */ function totalAvailableAssets() external view returns (uint256); /** * @dev The total available supply that is not marked for withdrawal */ function totalAvailableSupply() external view returns (uint256); /** * @dev The accrued interest at the current block. */ function currentExpectedInterest() external view returns (uint256 interest); function rolloverAndFinalizeApr(uint256 _apr) external; /*////////////////////////////////////////////////////////////// LOAN SET OPERATIONS //////////////////////////////////////////////////////////////*/ function approveLoanForPool(address loan) external; function createdLoan() external view returns (address); function activeLoan() external view returns (address); function requestedLoan() external view returns (address); function maturedLoan() external view returns (address); function settledLoans() external view returns (address[] memory); /*////////////////////////////////////////////////////////////// Early Withdraw //////////////////////////////////////////////////////////////*/ function requestEarlyRedeem(uint256 shares) external; function acceptEarlyRedeemRequest( address investorAddr ) external returns (uint256 principal); function repayEarlyWithdraw( address investorAddr, uint256 amount ) external returns ( uint256 principal, uint256 repayment, uint256 redeemedShares, uint256 fees ); function deposit( uint256 assets, address lender ) external returns (uint256 shares); function convertToAssets( uint256 shares ) external view returns (uint256 assets); function convertToShares( uint256 assets ) external view returns (uint256 shares); function maxWithdraw(address owner) external view returns (uint256 assets); function maxRedeem(address owner) external view returns (uint256 maxShares); function totalAssets() external view returns (uint256); function asset() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; /** * @title The interface for controlling access to Pools */ interface IPoolAccessControl { /** * @dev Check if an address is allowed as a participant in the pool * @param addr The address to verify * @return whether the address is allowed as a participant */ function isAllowed(address addr) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import "./IRequestWithdrawable.sol"; import "./IServiceConfigurationV3.sol"; import "./IPoolAccessControl.sol"; import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; enum IPoolType { TermPool, FlexRatePool } interface IPoolBase is IERC20Upgradeable, IRequestWithdrawable { function poolType() external view returns (IPoolType); function liquidityAssetAddr() external view returns (address); function version() external view returns (uint16); /** * @dev The ServiceConfiguration. */ function serviceConfiguration() external view returns (IServiceConfigurationV3); /** * @dev The admin for the pool. */ function admin() external view returns (address); function borrowerManagerAddr() external view returns (address); function borrowerWalletAddr() external view returns (address); /** * @dev The activation timestamp of the pool. */ function activatedAt() external view returns (uint256); function poolAccessControl() external view returns (IPoolAccessControl); /** * @dev The sum of all assets available in the liquidity pool, excluding * any assets that are marked for withdrawal. */ function liquidityPoolAssets() external view returns (uint256); function isPermittedLender(address) external view returns (bool); function maxDeposit(address owner) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; /** * @title The interface for interacting with Terms of Service Acceptance Registry. */ interface IPoolRegistry { function version() external pure returns (uint16); function addPool(address pool) external; function pools() external returns (address[] memory); function updatePoolData(address poolAddr) external; function isPoolRegistered(address poolAddr) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; /** * @title Interface that exposes methods to request withdraws / redeems. * @dev Terminology and design informed to complement ERC4626. */ interface IRequestWithdrawable { /** * @dev Returns the maximum number of `shares` that can be * requested to be redeemed from the owner balance with a single * `requestRedeem` call in the current block. * * Note: This is equivalent of EIP-4626 `maxRedeem` */ function maxRedeemRequest( address owner ) external view returns (uint256 maxShares); /** * @dev Returns the maximum amount of underlying `assets` that can be * requested to be withdrawn from the owner balance with a single * `requestWithdraw` call in the current block. * * Note: This is equivalent of EIP-4626 `maxWithdraw` */ function maxWithdrawRequest( address owner ) external view returns (uint256 maxAssets); /** * @dev Simulate the effects of a redeem request at the current block. * Returns the amount of underlying assets that would be requested if this * entire redeem request were to be processed at the current block. * * Note: This is equivalent of EIP-4626 `previewRedeem` */ function previewRedeemRequest( uint256 shares ) external view returns (uint256 assets); /** * @dev Simulate the effects of a withdrawal request at the current block. * Returns the amount of `shares` that would be burned if this entire * withdrawal request were to be processed at the current block. * * Note: This is equivalent of EIP-4626 `previewWithdraw` */ function previewWithdrawRequest( uint256 assets ) external view returns (uint256 shares); /** * @dev Submits a withdrawal request, incurring a fee. */ function requestRedeem(uint256 shares) external returns (uint256 assets); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; struct SerivceAddressList { address[] liquidityAssets; address tosAcceptanceRegistry; address loanFactory; address poolFactoryAddress; address queryLibAddress; address poolLibAddress; address loanLibAddress; address poolControllerFactoryAddress; address withdrawControllerFactoryAddress; address vaultFactoryAddress; address poolAccessControlFactoryAddress; } /** * @title The protocol global Service Configuration */ interface IServiceConfiguration { /** * @dev Emitted when an address is changed. */ event AddressSet(bytes32 which, address addr); /** * @dev Emitted when a liquidity asset is set. */ event LiquidityAssetSet(address addr, bool value); /** * @dev Emitted when a parameter is set. */ event ParameterSet(bytes32, uint256 value); /** * @dev Emitted when the protocol is paused. */ event ProtocolPaused(bool paused); /** * @dev Emitted when a loan factory is set */ event LoanFactorySet(address indexed factory); event PoolFactorySet(address indexed factory); event QueryLibSet(address indexed factory); event LoanLibSet(address indexed factory); event PoolLibSet(address indexed factory); event PoolAdminWalletSet(address indexed factory); /** * @dev Emitted when the TermsOfServiceRegistry is set */ event TermsOfServiceRegistrySet(address indexed registry); /** * @dev checks if a given address has the Operator role */ function isOperator(address addr) external view returns (bool); /** * @dev checks if a given address has the Deployer role */ function isDeployer(address addr) external view returns (bool); /** * @dev checks if a given address has the Deployer role */ function isPoolAdmin(address addr) external view returns (bool); /** * @dev checks if a given address has the Deployer role */ function isBorrower(address addr) external view returns (bool); /** * @dev Whether the protocol is paused. */ function paused() external view returns (bool); /** * @dev Whether an address is supported as a liquidity asset. */ function isLiquidityAsset(address addr) external view returns (bool); /** * @dev Address of the Terms of Service acceptance registry. */ function tosAcceptanceRegistry() external view returns (address); /** * @dev Sets whether a loan factory is valid * @param addr Address of loan factory */ function setLoanFactory(address addr) external; function setPoolFactory(address addr) external; function setQueryLib(address addr) external; function setPoolLib(address addr) external; function setLoanLib(address addr) external; function getLoanFactory() external view returns (address); function getPoolFactory() external view returns (address); function getQueryLib() external view returns (address); function getLoanLib() external view returns (address); function getPoolLib() external view returns (address); function setPoolAdminWallet(address addr) external; function getPoolAdminWallet() external view returns (address); /** * @dev Sets the ToSAcceptanceRegistry for the protocol * @param addr Address of registry */ function setToSAcceptanceRegistry(address addr) external; /** * @dev Sets supported liquidity assets for the protocol. Callable by the operator. * @param addr Address of liquidity asset * @param value Whether supported or not */ function setLiquidityAsset(address addr, bool value) external; function getServiceAddressList() external view returns (SerivceAddressList memory setLoanFactoryerivceAddressList); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import "./IServiceConfiguration.sol"; struct SerivceAddressListV3 { address[] liquidityAssets; address tosAcceptanceRegistry; address loanFactory; address poolFactoryAddress; address poolFactoryFlexAddress; address queryLibAddress; address poolLibAddress; address poolLibFlexAddress; address loanLibAddress; address poolControllerFactoryAddress; address withdrawControllerFactoryAddress; address vaultFactoryAddress; address poolAccessControlFactoryAddress; address poolControllerFactoryFlexAddress; address withdrawDepositControllerFactoryFlexAddress; address poolRegistryAddress; } enum IFactoryType { PoolFactory, LoanFactory, VaultFactory, PoolFactoryFlex, PoolControllerFactory, PoolLibFlex, PoolControllerFactoryFlex, WithdrawDepositControllerFactoryFlex, WithdrawControllerFactory, PoolAccessControlFactory } struct LegacyFactoryStruct { IFactoryType factoryType; address factoryAddress; } /** * @title The protocol global Service Configuration */ interface IServiceConfigurationV3 is IServiceConfiguration { event PoolFactoryFlexSet(address indexed factory); event PoolLibFlexSet(address indexed factory); event PoolRegistrySet(address indexed factory); function version() external pure returns (uint16); function isAutomation(address addr) external view returns (bool); function setPoolFactoryFlex(address addr) external; function setPoolLibFlex(address addr) external; function setPoolRegistry(address addr) external; function getPoolRegistry() external view returns (address); function getPoolFactoryFlex() external view returns (address); function getPoolLibFlex() external view returns (address); function getLegacyFactories() external view returns (LegacyFactoryStruct[] memory legacyFactories); function getServiceAddressListV3() external view returns (SerivceAddressListV3 memory addressList); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; /** * @title Interface for the Vault. * @dev Vaults simply hold a balance, and allow withdrawals by the Vault's owner. */ interface IVault { /** * @dev Emitted on ERC20 withdrawals */ event WithdrewERC20( address indexed asset, uint256 amount, address indexed receiver ); /** * @dev Emitted on ERC721 withdrawals */ event WithdrewERC721( address indexed asset, uint256 tokenId, address receiver ); /** * @dev Withdraws ERC20 of a given asset */ function withdrawERC20( address asset, uint256 amount, address receiver ) external; /** * @dev Withdraws ERC20 of a given asset */ function withdrawERC20ToBorrowerWallet( address asset, uint256 amount ) external; function payFees(address asset, uint256 amount) external; function repayLoan(address asset, uint256 amount) external; /** * @dev Withdraws ERC721 with specified tokenId */ function withdrawERC721( address asset, uint256 tokenId, address receiver ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import {IERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {IERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "../interfaces/ILoan.sol"; import "../interfaces/IPool.sol"; import "../interfaces/IServiceConfigurationV3.sol"; import "../interfaces/IVault.sol"; library LoanLib { using SafeERC20 for IERC20; using SafeMath for uint256; uint256 public constant RAY = 10 ** 27; function version() public pure returns (uint16) { return 256 * 1 + 0; } /** * @dev Emitted when loan is funded. */ event LoanFunded(address asset, uint256 amount); /** * @dev Emitted when loan principal is repaid ahead of schedule. */ event LoanPrincipalPaid( address asset, uint256 amount, address fundingVault ); /** * @dev Emitted when a loan payment is made. */ event LoanPaymentMade(address pool, address liquidityAsset, uint256 amount); /** * @dev See ILoan */ /** * @dev Validate Loan constructor arguments */ function validateLoan( IServiceConfigurationV3 config, IPool pool, ILoanSettings memory loanSettings, address liquidityAsset ) external view { require( loanSettings.durationDays > 0, "LoanLib: Duration cannot be zero" ); require( config.isLiquidityAsset(liquidityAsset), "LoanLib: Liquidity asset not allowed" ); require( pool.asset() == liquidityAsset, "LoanLib: Not allowed asset for pool" ); } /** * @dev Called on loan fundings, pulls funds from the pool into the * loan's funding vault. */ function fundRolloverLoan( address liquidityAsset, IVault borrowerVault, uint256 amount ) public returns (ILoanLifeCycleState) { if (amount > 0) { IERC20(liquidityAsset).safeTransferFrom( msg.sender, address(borrowerVault), amount ); } emit LoanFunded(liquidityAsset, amount); return ILoanLifeCycleState.Funded; } function previewOriginationFee( ILoanSettings calldata settings, uint256 scalingValue ) public pure returns (uint256) { return settings .startingPrincipal .mul(settings.originationBps) .mul(settings.durationDays.mul(scalingValue).div(360)) .div(RAY) .div(10000); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "../interfaces/ILoan.sol"; import "../interfaces/IPool.sol"; import "../interfaces/IPoolRegistry.sol"; import "../interfaces/ILoan.sol"; import "../interfaces/IServiceConfigurationV3.sol"; import "../interfaces/IVault.sol"; import "../factories/LoanFactory.sol"; /** * @title Collection of functions used by the Pool and PoolController. */ library PoolLib { using SafeERC20 for IERC20; using SafeMath for uint256; using EnumerableSet for EnumerableSet.AddressSet; uint256 public constant RAY = 10 ** 27; /** * @dev See IERC4626 */ event Deposit( address indexed sender, address indexed owner, uint256 assets, uint256 shares ); /** * @dev See IPoolController */ event PoolSettingsUpdated(); function version() public pure returns (uint16) { return 256 * 1 + 0; } /** * @dev Divide two numbers and round the result up */ function divideCeil( uint256 lhs, uint256 rhs ) internal pure returns (uint256) { return (lhs + rhs - 1) / rhs; } /** * @dev Computes the exchange rate for converting assets to shares * @param input The input to the conversion * @param numerator Numerator of the conversion rate * @param denominator Denominator of the conversion rate * @param roundUp Whether it should be rounded up or down. * @return output The converted amount */ function calculateConversion( uint256 input, uint256 numerator, uint256 denominator, bool roundUp ) public pure returns (uint256 output) { if (numerator == 0 || denominator == 0) { return input; } uint256 rate = numerator.mul(RAY).div(denominator); if (roundUp) { return divideCeil(rate.mul(input), RAY); } else { return rate.mul(input).div(RAY); } } /** * @dev Private method to determine if a pool is solvent given * the parameters. * * If the pool has assets, it is solvent. If no assets are available, * but no shares have been issued, it is solvent. Otherwise, it is insolvent. */ function isSolvent( uint256 totalAssets, uint256 totalShares ) private pure returns (bool) { return totalAssets > 0 || totalShares == 0; } /** * @dev Calculates total assets held by Vault (including those marked for withdrawal) * @param asset Amount of total assets held by the Vault * @param vault Address of the ERC4626 vault * @param outstandingLoanPrincipals Sum of all outstanding loan principals * @return totalAssets Total assets */ function calculateTotalAssets( address asset, address vault, uint256 outstandingLoanPrincipals, uint256 currentExpectedInterest ) public view returns (uint256 totalAssets) { totalAssets = IERC20(asset).balanceOf(vault) + outstandingLoanPrincipals + currentExpectedInterest; } /** * @dev Calculates total assets held by Vault (excluding marked for withdrawal) * @param asset Amount of total assets held by the Vault * @param vault Address of the ERC4626 vault * @param outstandingLoanPrincipals Sum of all outstanding loan principals * @param withdrawableAssets Sum of all withdrawable assets * @return totalAvailableAssets Total available assets (excluding marked for withdrawal) */ function calculateTotalAvailableAssets( address asset, address vault, uint256 outstandingLoanPrincipals, uint256 withdrawableAssets, address loanAddr ) external view returns (uint256 totalAvailableAssets) { if (loanAddr != address(0)) { ILoan loan = ILoan(loanAddr); totalAvailableAssets = IERC20(asset).balanceOf(vault) + //loan.outstandingPrincipal() + outstandingLoanPrincipals + loan.interest() - withdrawableAssets; } else { totalAvailableAssets = calculateTotalAssets( asset, vault, outstandingLoanPrincipals, 0 ) - withdrawableAssets; } } /** * @dev Calculates total shares held by Vault (excluding marked for redemption) * @param vault Address of the ERC4626 vault * @param redeemableShares Sum of all withdrawable assets * @return totalAvailableShares Total redeemable shares (excluding marked for redemption) */ function calculateTotalAvailableShares( address vault, uint256 redeemableShares ) external view returns (uint256 totalAvailableShares) { totalAvailableShares = IERC20(vault).totalSupply() - redeemableShares; } /** * @dev Calculates the max deposit allowed in the pool * @param poolLifeCycleState The current pool lifecycle state * @param poolMaxCapacity Max pool capacity allowed per the pool settings * @param totalAvailableAssets Sum of all pool assets (excluding marked for withdrawal) * @return Max deposit allowed */ function calculateMaxDeposit( IPoolLifeCycleState poolLifeCycleState, uint256 poolMaxCapacity, uint256 totalAvailableAssets ) external pure returns (uint256) { uint256 remainingCapacity = poolMaxCapacity > totalAvailableAssets ? poolMaxCapacity - totalAvailableAssets : 0; return poolLifeCycleState == IPoolLifeCycleState.Active ? remainingCapacity : 0; } /** * @dev Executes a deposit into the pool * @param asset Pool liquidity asset * @param vault Address of ERC4626 vault * @param lender Address of receiver of shares * @param assets Amount of assets being deposited * @param shares Amount of shares being minted * @param maxDeposit Max allowed deposit into the pool * @param mint A pointer to the mint function * @return The amount of shares being minted */ function executeDeposit( address asset, address vault, address lender, uint256 assets, uint256 shares, uint256 maxDeposit, function(address, uint256) mint, IPoolAccountings storage accountings ) internal returns (uint256) { require(shares > 0, "Pool: 0 deposit not allowed"); require(assets <= maxDeposit, "Pool: Exceeds max deposit"); IERC20(asset).safeTransferFrom(msg.sender, vault, assets); mint(lender, shares); emit Deposit(msg.sender, lender, assets, shares); accountings.totalAvailableAssets += assets; accountings.totalAssetsDeposited += assets; return shares; } /*////////////////////////////////////////////////////////////// Withdrawal Request Methods //////////////////////////////////////////////////////////////*/ function calculateRollover( address priorLoan, address _liquidityAsset, address pool, uint256 outstandingLoanPrincipals_ ) external view returns ( uint256 outstandingLoanPrincipals, uint256 assetsFromPool, uint256 assetsFromPriorToNextLoan, uint256 totalSupply, uint256 assetToAReturnToPool ) { require( address(IPool(pool).poolController()) != address(0) && msg.sender == address(IPool(pool).poolController()), "PoolLib: caller is not pool controller" ); if (priorLoan == address(0)) { outstandingLoanPrincipals = IERC20(_liquidityAsset).balanceOf(pool); require( IPool(pool).totalAvailableSupply() > 0, "No Funds to start loan" ); assetsFromPool = outstandingLoanPrincipals; assetsFromPriorToNextLoan = 0; totalSupply = IPool(pool).totalAvailableSupply(); assetToAReturnToPool = 0; } else { uint256 requestedAssets = ( IPool(pool).withdrawController().totalRequestedShares().mul( IPool(pool).exchangeRateAtMaturity() ) ).div(1e18); uint256 poolBalance = IERC20(_liquidityAsset).balanceOf(pool); totalSupply = IPool(pool).totalAvailableSupply() - IPool(pool).withdrawController().totalRequestedShares(); if (requestedAssets < poolBalance) { assetsFromPool = poolBalance - requestedAssets; assetsFromPriorToNextLoan = ILoan(priorLoan).principal() + ILoan(priorLoan).interest(); assetToAReturnToPool = 0; outstandingLoanPrincipals = outstandingLoanPrincipals_ + assetsFromPool; } else { assetsFromPool = 0; assetsFromPriorToNextLoan = poolBalance + ILoan(priorLoan).principal() + ILoan(priorLoan).interest() - requestedAssets; assetToAReturnToPool = requestedAssets - IERC20(_liquidityAsset).balanceOf(pool); outstandingLoanPrincipals = outstandingLoanPrincipals_ + IERC20(_liquidityAsset).balanceOf(pool); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "./interfaces/ILoan.sol"; import "./interfaces/IPool.sol"; import "./interfaces/IServiceConfigurationV3.sol"; import "./interfaces/IVault.sol"; import "./factories/interfaces/IVaultFactory.sol"; import "./libraries/LoanLib.sol"; import "./upgrades/BeaconImplementation.sol"; import "./Pool.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "./interfaces/IPoolAccessControl.sol"; /** * @title Perimeter Loan contract. */ contract Loan is ILoan, BeaconImplementation { using SafeMath for uint256; using SafeERC20 for IERC20; IServiceConfigurationV3 private _serviceConfiguration; /** * @dev The reference to the access control contract */ IPoolAccessControl public poolAccessControl; address private _factory; ILoanLifeCycleState private _state = ILoanLifeCycleState.Requested; ILoanTransitionState private _transitionState = ILoanTransitionState.Created; address private _borrower; address private _pool; IVault public fundingVault; uint256 public createdAt; address public liquidityAsset; uint256 public interest; uint256 public indicativeInterest; uint256 public originationFee; ILoanRolloverAccounting public rolloverAccounting; uint256 public accrualStartTimestamp; uint256 public depositClosingTimestamp; uint256 public redemptionRequestClosingTimestamp; uint256 public earlyRedeemRequestClosingTimestamp; uint256 public maturingTimestamp; uint256 public redemptionAvailableTimestamp; uint256 public _assetsRolloverToNextLoan; uint256 public _assetsToReturnToPool; ILoanSettings public settings; event FundsReclaimed(uint256 amount, address pool); event LoanScheduleViolation( ILoanTransitionState transitionState, uint256 timestamp, uint256 windowStart, uint256 windowEnd ); /** * @dev Modifier that requires the protocol not be paused. */ modifier onlyNotPaused() { require( IServiceConfigurationV3(_serviceConfiguration).paused() == false, "Loan: Protocol paused" ); _; } /** * @dev Modifier that requires the Loan be in the given `state_` */ modifier onlyLifeCycleState(ILoanLifeCycleState state_) { require( _state == state_, "Loan: FunctionInvalidAtThisILoanLifeCycleState" ); _; } modifier onlyTransitionState(ILoanTransitionState transitionState_) { require( _transitionState == transitionState_, "Loan: FunctionInvalidAtThisILoanLifeCycleState" ); _; } /** * @dev Modifier that requires `msg.sender` to be the pool. Loan assumes the pool has performed access checks */ modifier onlyPool() { require(msg.sender == _pool, "Loan: caller is not pool"); _; } /** * @dev Modifier that can be overriden by derived classes to enforce * access control. */ modifier onlyPermittedBorrower() { require( poolAccessControl.isAllowed(msg.sender), "Loan: Only Permitted Borrower allowed" ); _; } function version() public pure returns (uint16) { return 256 * 1 + 0; } function roundToDays(uint256 timestamp) public pure returns (uint256) { return timestamp.div(1 days).mul(1 days); } function inDepositWindow() external view override returns (bool) { return block.timestamp < depositClosingTimestamp; } function canRequestRedemption() external view override returns (bool) { return _transitionState == ILoanTransitionState.Created || _transitionState == ILoanTransitionState.ApprovedForDeposits || _transitionState == ILoanTransitionState.AccruingInterest; } function inInitiateRolloverWindow() external view override returns (bool) { return block.timestamp > depositClosingTimestamp && block.timestamp < accrualStartTimestamp; } function initialize( address serviceConfiguration_, address factory_, address borrower_, address pool_, address liquidityAsset_, address vaultFactory, ILoanSettings memory settings_ ) public virtual initializer { require(settings_.indicativeApr > 0, "Loan: APR cannot be zero"); require(settings_.durationDays > 0, "Loan: Duration cannot be zero"); require( settings_.transferInWindowDurationDays > 0, "Loan: transferInWindowDurationDays cannot be zero" ); require( settings_.transferOutWindowDurationDays > 0, "Loan: transition cannot be zero" ); require( settings_.accrualStartDayTimestamp > block.timestamp + settings_.transferInWindowDurationDays * (1 days), "Loan: accrualStartDayTimestamp must be greater than now plus transferInWindowDurationDays" ); require(factory_ != address(0), "Loan: Factory cannot be zero"); require(pool_ != address(0), "Loan: Factory cannot be zero"); require( vaultFactory != address(0), "Loan: VaultFactory cannot be zero" ); require( borrower_ == IPool(pool_).borrowerManagerAddr(), "Loan: Borrower must be pool borrower manager" ); _serviceConfiguration = IServiceConfigurationV3(serviceConfiguration_); poolAccessControl = IPool(pool_).poolAccessControl(); _factory = factory_; _borrower = borrower_; _pool = pool_; fundingVault = IVault( IVaultFactory(vaultFactory).createVault( address(this), IVaultType.FundingVault ) ); createdAt = block.timestamp; liquidityAsset = liquidityAsset_; settings = settings_; calculateSchedule(); LoanLib.validateLoan( _serviceConfiguration, IPool(_pool), settings, liquidityAsset ); } function calculateSchedule() internal { accrualStartTimestamp = roundToDays(settings.accrualStartDayTimestamp) + IPool(_pool).closeOfBusinessTime(); depositClosingTimestamp = accrualStartTimestamp - settings.transferInWindowDurationDays * (1 days); redemptionRequestClosingTimestamp = accrualStartTimestamp + (settings.durationDays - settings.transferInWindowDurationDays) * (1 days); maturingTimestamp = accrualStartTimestamp + settings.durationDays * (1 days); redemptionAvailableTimestamp = accrualStartTimestamp + (settings.durationDays + settings.transferOutWindowDurationDays) * (1 days); earlyRedeemRequestClosingTimestamp = accrualStartTimestamp + (settings.durationDays - settings.transferInWindowDurationDays - settings.transferOutWindowDurationDays) * (1 days); } function reschedule( uint256 accrualStartDayTimestamp_, uint256 transferInWindowDurationDays_, uint256 transferOutWindowDurationDays_, uint256 durationDays_ ) external override onlyPool onlyNotPaused { require( _state != ILoanLifeCycleState.Settled && _state != ILoanLifeCycleState.Canceled, "Loan: can not be settled or canceled" ); require( transferInWindowDurationDays_ > 0, "Loan: transferInWindowDurationDays cannot be zero" ); require( transferOutWindowDurationDays_ > 0, "Loan: transferOutWindowDurationDays cannot be zero" ); require( durationDays_ > 0, "Loan: transferOutWindowDurationDays cannot be zero" ); settings.accrualStartDayTimestamp = accrualStartDayTimestamp_; settings.transferInWindowDurationDays = transferInWindowDurationDays_; settings.transferOutWindowDurationDays = transferOutWindowDurationDays_; settings.durationDays = durationDays_; calculateSchedule(); } function getRolloverAccounting() external view returns (ILoanRolloverAccounting memory) { return rolloverAccounting; } function approve() external override onlyPool onlyNotPaused onlyTransitionState(ILoanTransitionState.Created) { _transitionState = ILoanTransitionState.ApprovedForDeposits; } /** * @inheritdoc ILoan */ function rolloverAllocation( uint256 assetsRolloverToNextLoan_, uint256 assetToReturnToPool_ ) external onlyPool onlyNotPaused onlyTransitionState(ILoanTransitionState.AccruingInterest) onlyLifeCycleState(ILoanLifeCycleState.Active) { _transitionState = ILoanTransitionState.RedemptionsClosed; _assetsRolloverToNextLoan = assetsRolloverToNextLoan_; _assetsToReturnToPool = assetToReturnToPool_; } // function checkExchangeRate(uint256 _apr) internal view { // uint256 exchangeRate = rolloverAccounting.exchangeRateAtDeposit.add( // rolloverAccounting // .exchangeRateAtDeposit // .mul(_apr) // .mul(settings.durationDays) // .div(3600000) // ); // // // require(exchangeRate == rolloverAccounting.exchangeRateAtMaturity, // // "Loan: Exchange rate is not equal to the exchange rate at maturity"); // } /** * @inheritdoc ILoan */ function fundRollover( uint256 assetsFromPool_, uint256 assetsFromPriorLoan, uint256 totalSupply, address priorLoan ) external onlyPool onlyNotPaused onlyLifeCycleState(ILoanLifeCycleState.Requested) onlyTransitionState(ILoanTransitionState.ApprovedForDeposits) returns (ILoanLifeCycleState) { _transitionState = ILoanTransitionState.TransitioningFundsIn; rolloverAccounting.totalSupply = totalSupply; rolloverAccounting.assetsFromPool = assetsFromPool_; rolloverAccounting.assetsFromPriorLoan = assetsFromPriorLoan; // rolloverAccounting.assetToReturnToPool = assetToReturnToPool_; uint256 totalAsset = assetsFromPool_ + assetsFromPriorLoan; settings.principal = totalAsset; settings.startingPrincipal = totalAsset; IVault borrowerVault = IVault( IPool(_pool).withdrawController().borrowerVault() ); _state = LoanLib.fundRolloverLoan( liquidityAsset, borrowerVault, assetsFromPool_ ); // if (priorLoan != address(0)) { // ILoan(priorLoan).rolloverAllocation( // assetsFromPriorLoan, // assetToReturnToPool_ // ); // } indicativeInterest = settings .principal .mul(settings.indicativeApr) .mul(settings.durationDays.mul(LoanLib.RAY).div(360)) .div(LoanLib.RAY) .div(10000); originationFee = totalAsset .mul(settings.originationBps) .mul(settings.durationDays.mul(LoanLib.RAY).div(360)) .div(LoanLib.RAY) .div(10000); if (priorLoan == address(0)) { rolloverAccounting.exchangeRateAtDeposit = 1e18; } else { rolloverAccounting.exchangeRateAtDeposit = ILoan(priorLoan) .exchangeRateAtMaturity(); } rolloverAccounting.exchangeRateAtMaturity = rolloverAccounting .exchangeRateAtDeposit .add( rolloverAccounting .exchangeRateAtDeposit .mul(settings.indicativeApr) .mul(settings.durationDays) .div(3600000) ); // checkExchangeRate(settings.indicativeApr); IPool(_pool).withdrawController().drawDownToBorrowerWallet( assetsFromPool_ ); _state = ILoanLifeCycleState.Funded; return _state; } function changeIndicativeApr(uint256 _apr) internal { require( _transitionState == ILoanTransitionState.ApprovedForDeposits || _transitionState == ILoanTransitionState.Created, "Loan: RollOver already started" ); require(_apr > 0, "Loan: APR cannot be zero"); settings.indicativeApr = _apr; } function finalizeApr(uint256 _apr) internal { require(_apr > 0, "Loan: APR cannot be zero"); settings.finalizedApr = _apr; interest = settings .principal .mul(settings.finalizedApr) .mul(settings.durationDays.mul(LoanLib.RAY).div(360)) .div(LoanLib.RAY) .div(10000); uint256 totalAsset = rolloverAccounting.assetsFromPool + rolloverAccounting.assetsFromPriorLoan; originationFee = totalAsset .mul(settings.originationBps) .mul(settings.durationDays.mul(LoanLib.RAY).div(360)) .div(LoanLib.RAY) .div(10000); // if (rolloverAccounting.totalSupply == 0) { // rolloverAccounting.exchangeRateAtMaturity = 1e18; // } else { rolloverAccounting.exchangeRateAtMaturity = rolloverAccounting.exchangeRateAtDeposit + rolloverAccounting .exchangeRateAtDeposit .mul(_apr) .mul(settings.durationDays) .div(3600000); // rolloverAccounting.exchangeRateAtMaturity = (rolloverAccounting // .assetsFromPool + // interest + // rolloverAccounting.assetsFromPriorLoan).mul(1e18).div( // rolloverAccounting.totalSupply // ); // } //checkExchangeRate(_apr); } function rolloverMaturedLoan() external onlyNotPaused onlyPool onlyTransitionState(ILoanTransitionState.RedemptionsClosed) { if ( !(maturingTimestamp < block.timestamp && block.timestamp < maturingTimestamp + (1 days)) ) { emit LoanScheduleViolation( _transitionState, block.timestamp, maturingTimestamp, maturingTimestamp + (1 days) ); } _transitionState = ILoanTransitionState.TransitioningFundsOut; _state = ILoanLifeCycleState.Matured; } /** * @inheritdoc ILoan */ function rolloverAndFinalizeApr( uint256 _apr ) external onlyNotPaused onlyPool onlyTransitionState(ILoanTransitionState.TransitioningFundsIn) { _transitionState = ILoanTransitionState.AccruingInterest; finalizeApr(_apr); _state = ILoanLifeCycleState.Active; } function accrualStartDayTimestamp() external view returns (uint256) { return settings.accrualStartDayTimestamp; } function transferInWindowDurationDays() external view returns (uint256) { return settings.transferInWindowDurationDays; } function transferOutWindowDurationDays() external view returns (uint256) { return settings.transferOutWindowDurationDays; } function assetsRolloverToNextLoan() external view returns (uint256) { return _assetsRolloverToNextLoan; } function assetsToReturnToPool() public view returns (uint256) { return _assetsToReturnToPool; } function assetsFromPool() external view returns (uint256) { return rolloverAccounting.assetsFromPool; } function completeRolloverNetPayment() external override onlyNotPaused onlyPool onlyTransitionState(ILoanTransitionState.TransitioningFundsOut) onlyLifeCycleState(ILoanLifeCycleState.Matured) returns ( uint256 feeVaultAmount, uint256 assetsReturnedToPool, uint256 interestAccrued ) { if ( !(maturingTimestamp < block.timestamp && block.timestamp < redemptionAvailableTimestamp) ) { emit LoanScheduleViolation( _transitionState, block.timestamp, maturingTimestamp, redemptionAvailableTimestamp ); } uint256 scalingValue = LoanLib.RAY; feeVaultAmount = LoanLib.previewOriginationFee(settings, scalingValue); IPool(_pool).withdrawController().payFees(feeVaultAmount); assetsReturnedToPool = assetsToReturnToPool(); if (assetsReturnedToPool > 0) { IPool(_pool).withdrawController().repayLoan(assetsReturnedToPool); } interestAccrued = interest; _transitionState = ILoanTransitionState.RedemptionsReleased; _state = ILoanLifeCycleState.Settled; } function exchangeRateAtDeposit() external view returns (uint256) { return rolloverAccounting.exchangeRateAtDeposit; } function exchangeRateAtMaturity() external view returns (uint256) { if ( _transitionState == ILoanTransitionState.Created || _transitionState == ILoanTransitionState.ApprovedForDeposits ) { return 1e18; } return rolloverAccounting.exchangeRateAtMaturity; } /** * @inheritdoc ILoan */ function state() external view returns (ILoanLifeCycleState) { return _state; } function transitionState() external view returns (ILoanTransitionState) { return _transitionState; } /** * @inheritdoc ILoan */ function borrower() external view returns (address) { return _borrower; } /** * @inheritdoc ILoan */ function pool() external view returns (address) { return _pool; } /** * @inheritdoc ILoan */ function factory() external view returns (address) { return _factory; } /** * @inheritdoc ILoan */ function dropDeadTimestamp() external view returns (uint256) { return settings.dropDeadTimestamp; } /** * @inheritdoc ILoan */ function durationDays() external view returns (uint256) { return settings.durationDays; } /** * @inheritdoc ILoan */ function finalizedApr() external view returns (uint256) { return settings.finalizedApr; } function indicativeApr() external view returns (uint256) { return settings.indicativeApr; } /** * @inheritdoc ILoan */ function principal() external view returns (uint256) { return settings.principal; } function startingPrincipal() external view returns (uint256) { return settings.startingPrincipal; } /** * @inheritdoc ILoan */ function serviceConfiguration() external view returns (IServiceConfigurationV3) { return _serviceConfiguration; } function repayEarlyWithdraw( uint256 principal_, uint256 assetReduction ) external onlyPool { settings.principal -= principal_; interest -= assetReduction - principal_; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import "./interfaces/ILoan.sol"; import "./interfaces/IPool.sol"; import "./interfaces/IVault.sol"; import "./interfaces/IServiceConfiguration.sol"; import "./interfaces/IPoolRegistry.sol"; import "./interfaces/IPoolAccessControl.sol"; import "./factories/interfaces/IPoolAccessControlFactory.sol"; import "./controllers/interfaces/IWithdrawController.sol"; import "./controllers/interfaces/IPoolController.sol"; import "./factories/interfaces/IWithdrawControllerFactory.sol"; import "./factories/interfaces/IPoolControllerFactory.sol"; import "./factories/interfaces/IVaultFactory.sol"; import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import "./libraries/PoolLib.sol"; import "./upgrades/BeaconImplementation.sol"; /** * @title Liquidity pool for Perimeter. * @dev Used through a beacon proxy. */ contract Pool is IPool, ERC20Upgradeable, BeaconImplementation { using SafeERC20Upgradeable for IERC20Upgradeable; using SafeMath for uint256; using EnumerableSet for EnumerableSet.AddressSet; /** * @dev The reference to the access control contract */ IPoolAccessControl public poolAccessControl; event PoolCreated(); event LoanCreated(address indexed loan); event PoolDeposit( address indexed lender, address indexed loan, uint256 assets, uint256 shares ); event LoanApproved(address indexed loan); event LoanRolloverInitiated( address indexed loan, address indexed priorLoan, uint256 assetsFromPriorToNextLoan, uint256 assetsFromPool, uint256 assetToAReturnToPool ); event LoanRolloverFinalized( address indexed loan, address indexed priorLoan ); event LoanMatured(address indexed loan); event LoanRepayment( address indexed loan, uint256 feeAmount, uint256 assetsReturnedToPool ); event RedeemRequested( address indexed lender, address indexed loan, uint256 assets, uint256 shares ); event RedeemReleased( address indexed lender, address indexed loan, uint256 shares, uint256 assets ); event Redeem( address indexed lender, address indexed loan, uint256 shares, uint256 assets ); event WithdrawEarlyRequested( address indexed lender, address indexed loan, uint256 shares, uint256 principal ); event WithdrawEarlyAccepted( address indexed lender, address indexed loan, uint256 shares, uint256 principal ); event WithdrawEarlyRepay( address indexed lender, address indexed loan, uint256 shares, uint256 principal, uint256 repayment, uint256 fees ); event RequestFeePaid(address indexed lender, uint256 feeShares); event WithdrawFeeVault(address indexed receiver, uint256 amount); /** * @dev Reference to the global service configuration. */ IServiceConfigurationV3 private _serviceConfiguration; /** * @dev Reference to the underlying liquidity asset for the pool. */ IERC20Upgradeable private _liquidityAsset; /** * @dev Various accounting statistics updated throughout the pool lifetime. */ IPoolAccountings private _accountings; /** * @dev Reference to the withdraw controller for the pool. */ IWithdrawController public withdrawController; /** * @dev Reference to the admin's controller for the pool. */ IPoolController public poolController; address public createdLoan; address public activeLoan; address public requestedLoan; address public maturedLoan; EnumerableSet.AddressSet private _settledLoans; uint256 public activatedAt; error NotPoolController(); error NotLender(); error NotBorrowerManager(); error PoolNotActive(); error InvalidAccess(); error InvalidLoan(); error PoolInvalidState(); error PoolPaused(); error TransferDisabled(); /** * @dev Modifier to ensure only the PoolController calls a method. */ modifier onlyPoolController() { if (msg.sender != address(poolController)) revert NotPoolController(); _; } /** * @dev Modifier that checks that the caller is a pool lender */ modifier onlyLenderWithPPT() { if (balanceOf(msg.sender) <= 0) revert NotLender(); _; } /** * @dev Modifier to check that the pool has ever been activated */ modifier onlyActivatedPool() { if (activatedAt == 0) revert PoolNotActive(); _; } /** * @dev Modifier to check that the protocol is not paused */ modifier onlyNotPaused() { if (_serviceConfiguration.paused() == true) revert PoolPaused(); _; } /** * @dev Modifier that checks that the pool is Initialized or Active */ modifier atState(IPoolLifeCycleState state_) { if (poolController.state() != state_) revert PoolInvalidState(); _; } function version() public pure returns (uint16) { return 256 * 1 + 0; } function decimals() public pure override returns (uint8) { return 6; } /*////////////////////////////////////////////////////////////// LOAN SET OPERATIONS //////////////////////////////////////////////////////////////*/ function rolloverAndFinalizeApr( uint256 _apr ) external onlyNotPaused onlyBorrowerManger { if (activeLoan != address(0)) { ILoan(activeLoan).rolloverMaturedLoan(); emit LoanMatured(msg.sender); maturedLoan = activeLoan; } ILoan(requestedLoan).rolloverAndFinalizeApr(_apr); activeLoan = requestedLoan; _accountings.totalAvailableAssets += ILoan(activeLoan).interest(); requestedLoan = address(0); emit LoanRolloverFinalized(activeLoan, maturedLoan); updatePoolData(); } function settledLoans() external view returns (address[] memory) { return _settledLoans.values(); } function loanCreated(address loan) external { if (msg.sender != serviceConfiguration().getLoanFactory()) revert InvalidAccess(); emit LoanCreated(loan); createdLoan = loan; updatePoolData(); } function approveLoanForPool( address loan ) external onlyNotPaused onlyPoolController { if (requestedLoan != address(0) || ILoan(loan).pool() != address(this)) revert InvalidLoan(); ILoan(loan).approve(); emit LoanApproved(loan); requestedLoan = loan; createdLoan = address(0); updatePoolData(); } function currentExpectedInterest() external view override returns (uint256) { if (activeLoan != address(0)) { return ILoan(activeLoan).interest(); } return 0; } modifier onlyDepositWindow() { if ( requestedLoan == address(0) || !ILoan(requestedLoan).inDepositWindow() ) revert InvalidLoan(); _; } modifier onlyPermittedLender() { if (!poolAccessControl.isAllowed(msg.sender)) revert NotLender(); if (IPoolController(poolController).borrowerManager() == msg.sender) revert NotLender(); _; } modifier onlyBorrowerManger() { if ( IPoolController(poolController).borrowerManager() != msg.sender || !poolAccessControl.isAllowed(msg.sender) ) revert NotBorrowerManager(); _; } function isPermittedLender(address receiver) public view returns (bool) { return poolAccessControl.isAllowed(receiver); } /** * @dev Initializer for Pool * @param poolSettings configurable settings for the pool * @param tokenName Name used for issued pool tokens * @param tokenSymbol Symbol used for issued pool tokens */ function initialize( PoolAddressList memory poolAddressList, IPoolConfigurableSettings memory poolSettings, string memory tokenName, string memory tokenSymbol ) public initializer { __ERC20_init(tokenName, tokenSymbol); _serviceConfiguration = IServiceConfigurationV3( poolAddressList.serviceConfiguration ); _liquidityAsset = IERC20Upgradeable(poolAddressList.liquidityAsset); // Build the withdraw controller // Build the admin controller poolController = IPoolController( IPoolControllerFactory(poolAddressList.poolControllerFactory) .createController( address(this), poolAddressList.serviceConfiguration, poolAddressList.poolAdmin, poolAddressList.liquidityAsset, poolSettings ) ); poolAccessControl = IPoolAccessControl( IPoolAccessControlFactory(poolAddressList.poolAccessControlFactory) .create(address(this)) ); withdrawController = IWithdrawController( IWithdrawControllerFactory( poolAddressList.withdrawControllerFactory ).createController( address(this), address(poolAddressList.vaultFactory), address(poolSettings.borrowerWalletAddress) ) ); // Allow the contract to move infinite amount of vault liquidity assets _liquidityAsset.safeApprove(address(this), type(uint256).max); emit PoolCreated(); } /** * @inheritdoc IPoolBase */ function serviceConfiguration() public view returns (IServiceConfigurationV3) { return _serviceConfiguration; } /** * @inheritdoc IPool */ function settings() public view returns (IPoolConfigurableSettings memory poolSettings) { return poolController.settings(); } /** * @inheritdoc IPool */ function state() public view returns (IPoolLifeCycleState) { return poolController.state(); } /** * @inheritdoc IPoolBase */ function admin() external view override returns (address) { return poolController.admin(); } function borrowerManagerAddr() external view override returns (address) { return poolController.borrowerManager(); } function borrowerWalletAddr() external view override returns (address) { return poolController.borrowerWalletAddress(); } /** * @inheritdoc IPool */ function accountings() external view override returns (IPoolAccountings memory) { return _accountings; } /** * @inheritdoc IPool */ function onActivated() external onlyPoolController { activatedAt = block.timestamp; } function liquidityAssetAddr() public view returns (address) { return address(_liquidityAsset); } function asset() public view returns (address) { return address(_liquidityAsset); } function initiateRollover( address loan, address priorLoan ) external onlyNotPaused onlyPoolController { if (!(loan == requestedLoan && priorLoan == activeLoan)) revert InvalidLoan(); uint256 _outstandingLoanPrincipals; uint256 assetsFromPool; uint256 assetsFromPriorToNextLoan; uint256 totalSupply_; uint256 assetToAReturnToPool; ( _outstandingLoanPrincipals, assetsFromPool, assetsFromPriorToNextLoan, totalSupply_, assetToAReturnToPool ) = PoolLib.calculateRollover( priorLoan, address(_liquidityAsset), address(this), _accountings.outstandingLoanPrincipals ); _liquidityAsset.safeApprove(loan, assetsFromPool); ILoan(loan).fundRollover( assetsFromPool, assetsFromPriorToNextLoan, totalSupply_, priorLoan ); if (priorLoan != address(0)) { ILoan(priorLoan).rolloverAllocation( assetsFromPriorToNextLoan, assetToAReturnToPool ); } _accountings.outstandingLoanPrincipals = _outstandingLoanPrincipals; emit LoanRolloverInitiated( loan, priorLoan, assetsFromPriorToNextLoan, assetsFromPool, assetToAReturnToPool ); updatePoolData(); } function completeRolloverNetPayment( address settlingLoan ) external onlyNotPaused onlyPoolController { uint256 feeVaultAmount; uint256 assetsReturnedToPool; uint256 interestAccrued; (feeVaultAmount, assetsReturnedToPool, interestAccrued) = ILoan( settlingLoan ).completeRolloverNetPayment(); if (maturedLoan != settlingLoan) revert InvalidLoan(); maturedLoan = address(0); _settledLoans.add(settlingLoan); _accountings.outstandingLoanPrincipals += interestAccrued; _accountings.outstandingLoanPrincipals -= assetsReturnedToPool; emit LoanRepayment(settlingLoan, feeVaultAmount, assetsReturnedToPool); address receiver = serviceConfiguration().getPoolAdminWallet(); uint256 amount = _liquidityAsset.balanceOf( withdrawController.feeVault() ); withdrawController.withdrawFeeVault(amount, receiver); emit WithdrawFeeVault(receiver, amount); updatePoolData(); } function redemptionState() public view returns (IRedemptionState memory _redemptionState) { return withdrawController.redemptionState(); } function releaseRolloverRedemption( address owner ) external onlyPoolController { uint256 shares; uint256 assets; (shares, assets) = withdrawController.releaseRolloverRedemption(owner); emit RedeemReleased(owner, maturedLoan, shares, assets); updatePoolData(); } /** * @inheritdoc IPool */ function totalAvailableAssets() public view returns (uint256 assets) { return _accountings.totalAvailableAssets; } /** * @inheritdoc IPool */ function totalAvailableSupply() public view override returns (uint256 shares) { shares = PoolLib.calculateTotalAvailableShares( address(this), withdrawController.totalRedeemableShares() ); } /** * @inheritdoc IPoolBase */ function liquidityPoolAssets() public view returns (uint256 assets) { uint256 interest = 0; if (activeLoan != address(0)) { interest = ILoan(activeLoan).interest(); } return PoolLib.calculateTotalAssets( address(_liquidityAsset), address(this), 0, interest ); // return // _accountings.totalAvailableAssets - // withdrawController.totalWithdrawableAssets(); } function reschedule( address loan, uint256 accrualStartDayTimestamp, uint256 transferInWindowDurationDays, uint256 transferOutWindowDurationDays, uint256 durationDays ) external override onlyPoolController onlyNotPaused { if (!(activeLoan == loan || requestedLoan == loan)) revert InvalidLoan(); ILoan(loan).reschedule( accrualStartDayTimestamp, transferInWindowDurationDays, transferOutWindowDurationDays, durationDays ); updatePoolData(); } /** * @inheritdoc IRequestWithdrawable */ function previewRedeemRequest( uint256 shares ) external view returns (uint256 assets) { assets = convertToAssets(shares); } /** * @inheritdoc IRequestWithdrawable */ function previewWithdrawRequest( uint256 assets ) external view returns (uint256 shares) { shares = convertToShares(assets); } /** * @inheritdoc IRequestWithdrawable */ function requestRedeem( uint256 shares ) external onlyNotPaused onlyActivatedPool onlyPermittedLender onlyLenderWithPPT returns (uint256 assets) { assets = convertToAssets(shares); withdrawController.performRequest(msg.sender, shares, assets); emit RedeemRequested(msg.sender, activeLoan, assets, shares); updatePoolData(); } /** * @inheritdoc IRequestWithdrawable */ function maxRedeemRequest( address owner ) public view returns (uint256 maxShares) { maxShares = withdrawController.maxRedeemRequest(owner); } /** * @inheritdoc IRequestWithdrawable */ function maxWithdrawRequest( address owner ) public view returns (uint256 maxAssets) { maxAssets = convertToAssets(maxRedeemRequest(owner)); } /*////////////////////////////////////////////////////////////// ERC-4626 Methods //////////////////////////////////////////////////////////////*/ function totalAssets() public view returns (uint256) { uint256 interest = 0; if (activeLoan != address(0)) { interest = ILoan(activeLoan).interest(); } return PoolLib.calculateTotalAssets( address(_liquidityAsset), address(this), _accountings.outstandingLoanPrincipals, interest ); } function convertToShares( uint256 assets ) public view override returns (uint256 shares) { if (activeLoan == address(0)) { shares = assets; } else { shares = assets.mul(1e18).div(exchangeRateAtMaturity()); } } function exchangeRateAtDeposit() public view override returns (uint256 _exchangeRateAtDeposit) { if (activeLoan != address(0)) { ILoan loan = ILoan(activeLoan); _exchangeRateAtDeposit = loan.exchangeRateAtDeposit(); } else { _exchangeRateAtDeposit = 1e18; } } function exchangeRateAtMaturity() public view override returns (uint256 _exchangeRateAtMaturity) { if (activeLoan != address(0)) { ILoan loan = ILoan(activeLoan); _exchangeRateAtMaturity = loan.exchangeRateAtMaturity(); } else { _exchangeRateAtMaturity = 1e18; } } function convertToAssets( uint256 shares ) public view override returns (uint256 assets) { if (activeLoan == address(0)) { assets = shares; } else { assets = exchangeRateAtMaturity().mul(shares).div(1e18); } } function closeOfBusinessTime() external view returns (uint256) { return poolController.closeOfBusinessTime(); } function maxDeposit(address owner) public view override returns (uint256) { if ( _serviceConfiguration.paused() == true || !isPermittedLender(owner) || poolController.state() != IPoolLifeCycleState.Active ) { return 0; } return PoolLib.calculateMaxDeposit( poolController.state(), settings().maxCapacity, totalAvailableAssets() ); } function deposit( uint256 assets, address lender ) public virtual override onlyNotPaused atState(IPoolLifeCycleState.Active) onlyPermittedLender onlyDepositWindow returns (uint256 shares) { if ( poolController.state() == IPoolLifeCycleState.DisruptionOrDefault || msg.sender != lender ) revert PoolInvalidState(); shares = PoolLib.executeDeposit( liquidityAssetAddr(), address(this), lender, assets, convertToShares(assets), maxDeposit(lender), _mint, _accountings ); emit PoolDeposit(lender, requestedLoan, assets, shares); updatePoolData(); } function maxWithdraw( address owner ) public view override returns (uint256 assets) { if ( _serviceConfiguration.paused() == true || !isPermittedLender(owner) ) { return 0; } assets = withdrawController.maxWithdraw(owner); } function withdraw( uint256 assets, address receiver, address owner ) public virtual onlyNotPaused onlyPermittedLender returns (uint256 shares) { if (receiver != owner || receiver != msg.sender) revert InvalidAccess(); // Update the withdraw state shares = withdrawController.withdraw(owner, assets); // transfer assets, and burn the shares _performWithdrawTransfer(owner, shares, assets); updatePoolData(); } function withdrawFeeVault( uint256 amount, address receiver ) external onlyNotPaused onlyPoolController { withdrawController.withdrawFeeVault(amount, receiver); emit WithdrawFeeVault(receiver, amount); updatePoolData(); } function maxRedeem( address owner ) public view override returns (uint256 maxShares) { if ( _serviceConfiguration.paused() == true || !isPermittedLender(owner) ) { return 0; } maxShares = withdrawController.maxRedeem(owner); } function redeem( uint256 shares, address receiver, address owner ) public virtual onlyNotPaused onlyPermittedLender returns (uint256 assets) { if (receiver != owner || receiver != msg.sender) revert InvalidAccess(); // Update the withdraw state assets = withdrawController.redeem(owner, shares); // transfer assets, and burn the shares _performWithdrawTransfer(owner, shares, assets); emit Redeem(owner, maturedLoan, shares, assets); updatePoolData(); } /** * @dev Redeem a number of shares for a given number of assets. This method * will transfer `assets` from the vault to the `receiver`, and burn `shares` * from `owner`. */ function _performWithdrawTransfer( address owner, uint256 shares, uint256 assets ) internal { // Transfer assets _liquidityAsset.safeTransferFrom(address(this), owner, assets); // Burn the shares _burn(owner, shares); _accountings.totalAvailableAssets -= assets; // Updating accountings _accountings.totalAssetsWithdrawn += assets; emit Withdraw(owner, owner, owner, assets, shares); } /*////////////////////////////////////////////////////////////// ERC-20 Overrides //////////////////////////////////////////////////////////////*/ /** * @dev Disables Perimeter Pool Token transfers. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual override { super._beforeTokenTransfer(from, to, amount); if (to != address(0) && from != address(0)) { if ( !poolAccessControl.isAllowed(from) || !poolAccessControl.isAllowed(to) ) { revert TransferDisabled(); } if (maxRedeemRequest(from) < amount) { revert TransferDisabled(); } } } /*////////////////////////////////////////////////////////////// Early Withdraws //////////////////////////////////////////////////////////////*/ function requestEarlyRedeem( uint256 shares ) external onlyNotPaused onlyActivatedPool onlyPermittedLender onlyLenderWithPPT { uint256 principal = withdrawController.requestEarlyRedeem( msg.sender, shares ); emit WithdrawEarlyRequested(msg.sender, activeLoan, shares, principal); updatePoolData(); } function acceptEarlyRedeemRequest( address investorAddr ) external override onlyNotPaused onlyBorrowerManger returns (uint256 principal) { uint256 shares; (shares, principal) = withdrawController.acceptEarlyRedeemRequest( investorAddr ); emit WithdrawEarlyAccepted(investorAddr, activeLoan, shares, principal); updatePoolData(); } function repayEarlyWithdraw( address investorAddr, uint256 amount ) external override onlyNotPaused onlyBorrowerManger returns ( uint256 principal, uint256 repayment, uint256 redeemedShares, uint256 fees ) { uint256 assetReduction; ( principal, repayment, redeemedShares, fees, assetReduction ) = withdrawController.repayEarlyWithdraw(investorAddr, amount); _burn(investorAddr, redeemedShares); _liquidityAsset.safeTransferFrom( address(this), investorAddr, repayment ); ILoan(activeLoan).repayEarlyWithdraw(principal, assetReduction); _accountings.outstandingLoanPrincipals -= principal; _accountings.totalAvailableAssets -= assetReduction; // Updating accountings _accountings.totalAssetsWithdrawn += repayment; emit WithdrawEarlyRepay( investorAddr, activeLoan, redeemedShares, principal, repayment, fees ); address receiver = serviceConfiguration().getPoolAdminWallet(); withdrawController.withdrawFeeVault(fees, receiver); emit WithdrawFeeVault(receiver, fees); updatePoolData(); } /*** * V3 */ function poolType() external pure returns (IPoolType) { return IPoolType.TermPool; } function updatePoolData() internal { address poolRegistryAddr = _serviceConfiguration.getPoolRegistry(); IPoolRegistry(poolRegistryAddr).updatePoolData(address(this)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; /** * @title BeaconImplementation base contract * @dev Base contract that overrides the constructor to disable initialization. */ abstract contract BeaconImplementation is Initializable { /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import "../interfaces/IServiceConfigurationV3.sol"; import "./interfaces/IBeacon.sol"; /** * @title Factory for emitting beacon proxies. * @dev Base contract for emitting new Beacon proxy contracts. Allows setting new * implementations by the global deployer. */ abstract contract BeaconProxyFactory is IBeacon { /** * @dev Address of the protocol service configuration */ IServiceConfigurationV3 internal _serviceConfiguration; /** * @dev Modifier that requires that the sender is registered as a protocol deployer. */ modifier onlyDeployer() { require( _serviceConfiguration.isDeployer(msg.sender), "Upgrade: unauthorized" ); _; } /** * @inheritdoc IBeacon */ address public implementation; /** * @inheritdoc IBeacon */ function setImplementation( address newImplementation ) external onlyDeployer { implementation = newImplementation; emit ImplementationSet(newImplementation); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; /** * @title Interface for Beacon contracts. * @dev Holds a reference to the implementation, and allows setting new ones. */ interface IBeacon { /** * @dev Emitted when a new implementation is set. */ event ImplementationSet(address indexed implementation); /** * @dev Returns an address used by BeaconProxy contracts for delegated calls. */ function implementation() external view returns (address); /** * @dev Updates the implementation. */ function setImplementation(address implementation) external; }
{ "optimizer": { "enabled": true, "runs": 10 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"serviceConfiguration","type":"address"},{"internalType":"address","name":"withdrawControllerFactory","type":"address"},{"internalType":"address","name":"poolControllerFactory","type":"address"},{"internalType":"address","name":"vaultFactory","type":"address"},{"internalType":"address","name":"poolAccessControlFactory","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"ImplementationSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addr","type":"address"}],"name":"PoolCreated","type":"event"},{"inputs":[{"internalType":"address","name":"liquidityAsset","type":"address"},{"components":[{"internalType":"uint256","name":"maxCapacity","type":"uint256"},{"internalType":"uint256","name":"endDate","type":"uint256"},{"internalType":"address","name":"borrowerManager","type":"address"},{"internalType":"address","name":"borrowerWalletAddress","type":"address"},{"internalType":"uint256","name":"closeOfBusinessTime","type":"uint256"},{"internalType":"uint256","name":"earlyWithdrawFeeBps","type":"uint256"}],"internalType":"struct IPoolConfigurableSettings","name":"settings","type":"tuple"},{"internalType":"string","name":"tokenName","type":"string"},{"internalType":"string","name":"tokenSymbol","type":"string"}],"name":"createPool","outputs":[{"internalType":"address","name":"poolAddress","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getPoolAccessControlFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPoolControllerFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVaultFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawControllerFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"setImplementation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"pure","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b5060405161155b38038061155b83398101604081905261002f916100ad565b600080546001600160a01b03199081166001600160a01b03978816179091556002805482169587169590951790945560048054851693861693909317909255600580548416918516919091179055600380549092169216919091179055610112565b80516001600160a01b03811681146100a857600080fd5b919050565b600080600080600060a086880312156100c557600080fd5b6100ce86610091565b94506100dc60208701610091565b93506100ea60408701610091565b92506100f860608701610091565b915061010660808701610091565b90509295509295909350565b61143a806101216000396000f3fe60806040523480156200001157600080fd5b5060043610620000825760003560e01c806318bcb284146200008757806338b5ea6614620000ac57806354fd4d5014620000c35780635c60da1b14620000d4578063886ce40414620000e8578063d784d42614620000fa578063dbf07b181462000113578063f3c517881462000125575b600080fd5b6005546001600160a01b03165b604051620000a39190620007df565b60405180910390f35b62000094620000bd36600462000857565b62000137565b6040516102008152602001620000a3565b60015462000094906001600160a01b031681565b6002546001600160a01b031662000094565b620001116200010b36600462000901565b620005ce565b005b6004546001600160a01b031662000094565b6003546001600160a01b031662000094565b60008054604051637be53ca160e01b81526001600160a01b0390911690637be53ca1906200016a903390600401620007df565b602060405180830381865afa15801562000188573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ae919062000928565b620001f35760405162461bcd60e51b815260206004820152601060248201526f21a0a62622a92fa727aa2fa0a226a4a760811b60448201526064015b60405180910390fd5b6001546001600160a01b0316620002585760405162461bcd60e51b815260206004820152602260248201527f506f6f6c466163746f72793a206e6f20696d706c656d656e746174696f6e2073604482015261195d60f21b6064820152608401620001ea565b60008054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002aa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002d0919062000928565b156200031e5760405162461bcd60e51b815260206004820152601c60248201527b141bdbdb119858dd1bdc9e4e88141c9bdd1bd8dbdb081c185d5cd95960221b6044820152606401620001ea565b60005460405163e633ea7360e01b81526001600160a01b039091169063e633ea739062000350908a90600401620007df565b602060405180830381865afa1580156200036e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000394919062000928565b620003df5760405162461bcd60e51b815260206004820152601a602482015279141bdbdb119858dd1bdc9e4e881a5b9d985b1a5908185cdcd95d60321b6044820152606401620001ea565b60005460408051636bd969b360e01b8152905130926001600160a01b031691636bd969b39160048083019260209291908290030181865afa15801562000429573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200044f91906200094c565b6001600160a01b031614620004a25760405162461bcd60e51b8152602060048201526018602482015277141bdbdb119858dd1bdc9e4e881b9bdd0818dbdc9c9958dd60421b6044820152606401620001ea565b6000620004b4888888888888620006d4565b905060008054906101000a90046001600160a01b03166001600160a01b0316637a9bd5e46040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000508573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200052e91906200094c565b6001600160a01b031663d914cd4b826040518263ffffffff1660e01b81526004016200055b9190620007df565b600060405180830381600087803b1580156200057657600080fd5b505af11580156200058b573d6000803e3d6000fd5b50506040516001600160a01b03841692507f83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc9150600090a2979650505050505050565b600054604051631430d62960e21b81526001600160a01b03909116906350c358a49062000600903390600401620007df565b602060405180830381865afa1580156200061e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000644919062000928565b6200068a5760405162461bcd60e51b8152602060048201526015602482015274155c19dc9859194e881d5b985d5d1a1bdc9a5e9959605a1b6044820152606401620001ea565b600180546001600160a01b0319166001600160a01b0383169081179091556040517fab64f92ab780ecbf4f3866f57cee465ff36c89450dcce20237ca7a8d81fb7d1390600090a250565b6040805160e0810182526001600160a01b038089168252336020830152600080548216838501526002548216606084015260045482166080840152600554821660a084015260035490911660c0830152915182903090637f2fa67760e11b906200074d9085908c908c908c908c908c90602401620009ef565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516200078c90620007c4565b6200079992919062000aa6565b604051809103906000f080158015620007b6573d6000803e3d6000fd5b509998505050505050505050565b6108fe8062000b0783390190565b6001600160a01b03169052565b6001600160a01b0391909116815260200190565b6001600160a01b03811681146200080957600080fd5b50565b60008083601f8401126200081f57600080fd5b5081356001600160401b038111156200083757600080fd5b6020830191508360208285010111156200085057600080fd5b9250929050565b6000806000806000808688036101208112156200087357600080fd5b87356200088081620007f3565b965060c0601f19820112156200089557600080fd5b5060208701945060e08701356001600160401b0380821115620008b757600080fd5b620008c58a838b016200080c565b9096509450610100890135915080821115620008e057600080fd5b50620008ef89828a016200080c565b979a9699509497509295939492505050565b6000602082840312156200091457600080fd5b81356200092181620007f3565b9392505050565b6000602082840312156200093b57600080fd5b815180151581146200092157600080fd5b6000602082840312156200095f57600080fd5b81516200092181620007f3565b803582526020810135602083015260408101356200098a81620007f3565b6001600160a01b039081166040840152606082013590620009ab82620007f3565b1660608301526080818101359083015260a090810135910152565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60006101e060018060a01b03808a511684528060208b01511660208501528060408b01511660408501528060608b01511660608501528060808b01511660808501525060a089015162000a4660a0850182620007d2565b5060c089015162000a5b60c0850182620007d2565b5062000a6b60e08401896200096c565b806101a084015262000a818184018789620009c6565b90508281036101c084015262000a99818587620009c6565b9998505050505050505050565b60018060a01b038316815260006020604081840152835180604085015260005b8181101562000ae45785810183015185820160600152820162000ac6565b506000606082860101526060601f19601f83011685010192505050939250505056fe60806040526040516108fe3803806108fe8339810160408190526100229161045b565b61002e82826000610035565b5050610585565b61003e83610100565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a260008251118061007f5750805b156100fb576100f9836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e9919061051b565b836102a360201b6100291760201c565b505b505050565b610113816102cf60201b6100551760201c565b6101725760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b60648201526084015b60405180910390fd5b6101e6816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d7919061051b565b6102cf60201b6100551760201c565b61024b5760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b6064820152608401610169565b806102827fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5060001b6102de60201b6100641760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60606102c883836040518060600160405280602781526020016108d7602791396102e1565b9392505050565b6001600160a01b03163b151590565b90565b6060600080856001600160a01b0316856040516102fe9190610536565b600060405180830381855af49150503d8060008114610339576040519150601f19603f3d011682016040523d82523d6000602084013e61033e565b606091505b5090925090506103508683838761035a565b9695505050505050565b606083156103c95782516000036103c2576001600160a01b0385163b6103c25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610169565b50816103d3565b6103d383836103db565b949350505050565b8151156103eb5781518083602001fd5b8060405162461bcd60e51b81526004016101699190610552565b80516001600160a01b038116811461041c57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561045257818101518382015260200161043a565b50506000910152565b6000806040838503121561046e57600080fd5b61047783610405565b60208401519092506001600160401b038082111561049457600080fd5b818501915085601f8301126104a857600080fd5b8151818111156104ba576104ba610421565b604051601f8201601f19908116603f011681019083821181831017156104e2576104e2610421565b816040528281528860208487010111156104fb57600080fd5b61050c836020830160208801610437565b80955050505050509250929050565b60006020828403121561052d57600080fd5b6102c882610405565b60008251610548818460208701610437565b9190910192915050565b6020815260008251806020840152610571816040850160208701610437565b601f01601f19169190910160400192915050565b610343806105946000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610067565b610100565b565b606061004e83836040518060600160405280602781526020016102e760279139610124565b9392505050565b6001600160a01b03163b151590565b90565b600061009a7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50546001600160a01b031690565b6001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fb919061024a565b905090565b3660008037600080366000845af43d6000803e80801561011f573d6000f35b3d6000fd5b6060600080856001600160a01b0316856040516101419190610297565b600060405180830381855af49150503d806000811461017c576040519150601f19603f3d011682016040523d82523d6000602084013e610181565b606091505b50915091506101928683838761019c565b9695505050505050565b6060831561020e578251600003610207576101b685610055565b6102075760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064015b60405180910390fd5b5081610218565b6102188383610220565b949350505050565b8151156102305781518083602001fd5b8060405162461bcd60e51b81526004016101fe91906102b3565b60006020828403121561025c57600080fd5b81516001600160a01b038116811461004e57600080fd5b60005b8381101561028e578181015183820152602001610276565b50506000910152565b600082516102a9818460208701610273565b9190910192915050565b60208152600082518060208401526102d2816040850160208701610273565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220d7ce1835befd5faecbfea1c57664062796dc15afe2c20b368807d14fc6aa703b64736f6c63430008100033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220b9695422cdc7e4423453e55e168d7fc09707f2e59ff1bce987cb6ca9b79dfeb164736f6c63430008100033000000000000000000000000ec4f65e0a0268ff38ecec711ad5159b96dabab980000000000000000000000000eba83c7b2122e347eeafdc37edf9ed856f0ac4600000000000000000000000066be61e109ecff0e829313b605904cddeb88fff80000000000000000000000005dd6710fed29132325d3fe1aa138046dab641abc000000000000000000000000c641de59d9a55b6657e4bca9bb62822c8bb09ed3
Deployed Bytecode
0x60806040523480156200001157600080fd5b5060043610620000825760003560e01c806318bcb284146200008757806338b5ea6614620000ac57806354fd4d5014620000c35780635c60da1b14620000d4578063886ce40414620000e8578063d784d42614620000fa578063dbf07b181462000113578063f3c517881462000125575b600080fd5b6005546001600160a01b03165b604051620000a39190620007df565b60405180910390f35b62000094620000bd36600462000857565b62000137565b6040516102008152602001620000a3565b60015462000094906001600160a01b031681565b6002546001600160a01b031662000094565b620001116200010b36600462000901565b620005ce565b005b6004546001600160a01b031662000094565b6003546001600160a01b031662000094565b60008054604051637be53ca160e01b81526001600160a01b0390911690637be53ca1906200016a903390600401620007df565b602060405180830381865afa15801562000188573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ae919062000928565b620001f35760405162461bcd60e51b815260206004820152601060248201526f21a0a62622a92fa727aa2fa0a226a4a760811b60448201526064015b60405180910390fd5b6001546001600160a01b0316620002585760405162461bcd60e51b815260206004820152602260248201527f506f6f6c466163746f72793a206e6f20696d706c656d656e746174696f6e2073604482015261195d60f21b6064820152608401620001ea565b60008054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002aa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002d0919062000928565b156200031e5760405162461bcd60e51b815260206004820152601c60248201527b141bdbdb119858dd1bdc9e4e88141c9bdd1bd8dbdb081c185d5cd95960221b6044820152606401620001ea565b60005460405163e633ea7360e01b81526001600160a01b039091169063e633ea739062000350908a90600401620007df565b602060405180830381865afa1580156200036e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000394919062000928565b620003df5760405162461bcd60e51b815260206004820152601a602482015279141bdbdb119858dd1bdc9e4e881a5b9d985b1a5908185cdcd95d60321b6044820152606401620001ea565b60005460408051636bd969b360e01b8152905130926001600160a01b031691636bd969b39160048083019260209291908290030181865afa15801562000429573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200044f91906200094c565b6001600160a01b031614620004a25760405162461bcd60e51b8152602060048201526018602482015277141bdbdb119858dd1bdc9e4e881b9bdd0818dbdc9c9958dd60421b6044820152606401620001ea565b6000620004b4888888888888620006d4565b905060008054906101000a90046001600160a01b03166001600160a01b0316637a9bd5e46040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000508573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200052e91906200094c565b6001600160a01b031663d914cd4b826040518263ffffffff1660e01b81526004016200055b9190620007df565b600060405180830381600087803b1580156200057657600080fd5b505af11580156200058b573d6000803e3d6000fd5b50506040516001600160a01b03841692507f83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc9150600090a2979650505050505050565b600054604051631430d62960e21b81526001600160a01b03909116906350c358a49062000600903390600401620007df565b602060405180830381865afa1580156200061e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000644919062000928565b6200068a5760405162461bcd60e51b8152602060048201526015602482015274155c19dc9859194e881d5b985d5d1a1bdc9a5e9959605a1b6044820152606401620001ea565b600180546001600160a01b0319166001600160a01b0383169081179091556040517fab64f92ab780ecbf4f3866f57cee465ff36c89450dcce20237ca7a8d81fb7d1390600090a250565b6040805160e0810182526001600160a01b038089168252336020830152600080548216838501526002548216606084015260045482166080840152600554821660a084015260035490911660c0830152915182903090637f2fa67760e11b906200074d9085908c908c908c908c908c90602401620009ef565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516200078c90620007c4565b6200079992919062000aa6565b604051809103906000f080158015620007b6573d6000803e3d6000fd5b509998505050505050505050565b6108fe8062000b0783390190565b6001600160a01b03169052565b6001600160a01b0391909116815260200190565b6001600160a01b03811681146200080957600080fd5b50565b60008083601f8401126200081f57600080fd5b5081356001600160401b038111156200083757600080fd5b6020830191508360208285010111156200085057600080fd5b9250929050565b6000806000806000808688036101208112156200087357600080fd5b87356200088081620007f3565b965060c0601f19820112156200089557600080fd5b5060208701945060e08701356001600160401b0380821115620008b757600080fd5b620008c58a838b016200080c565b9096509450610100890135915080821115620008e057600080fd5b50620008ef89828a016200080c565b979a9699509497509295939492505050565b6000602082840312156200091457600080fd5b81356200092181620007f3565b9392505050565b6000602082840312156200093b57600080fd5b815180151581146200092157600080fd5b6000602082840312156200095f57600080fd5b81516200092181620007f3565b803582526020810135602083015260408101356200098a81620007f3565b6001600160a01b039081166040840152606082013590620009ab82620007f3565b1660608301526080818101359083015260a090810135910152565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60006101e060018060a01b03808a511684528060208b01511660208501528060408b01511660408501528060608b01511660608501528060808b01511660808501525060a089015162000a4660a0850182620007d2565b5060c089015162000a5b60c0850182620007d2565b5062000a6b60e08401896200096c565b806101a084015262000a818184018789620009c6565b90508281036101c084015262000a99818587620009c6565b9998505050505050505050565b60018060a01b038316815260006020604081840152835180604085015260005b8181101562000ae45785810183015185820160600152820162000ac6565b506000606082860101526060601f19601f83011685010192505050939250505056fe60806040526040516108fe3803806108fe8339810160408190526100229161045b565b61002e82826000610035565b5050610585565b61003e83610100565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a260008251118061007f5750805b156100fb576100f9836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e9919061051b565b836102a360201b6100291760201c565b505b505050565b610113816102cf60201b6100551760201c565b6101725760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b60648201526084015b60405180910390fd5b6101e6816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d7919061051b565b6102cf60201b6100551760201c565b61024b5760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b6064820152608401610169565b806102827fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5060001b6102de60201b6100641760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60606102c883836040518060600160405280602781526020016108d7602791396102e1565b9392505050565b6001600160a01b03163b151590565b90565b6060600080856001600160a01b0316856040516102fe9190610536565b600060405180830381855af49150503d8060008114610339576040519150601f19603f3d011682016040523d82523d6000602084013e61033e565b606091505b5090925090506103508683838761035a565b9695505050505050565b606083156103c95782516000036103c2576001600160a01b0385163b6103c25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610169565b50816103d3565b6103d383836103db565b949350505050565b8151156103eb5781518083602001fd5b8060405162461bcd60e51b81526004016101699190610552565b80516001600160a01b038116811461041c57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561045257818101518382015260200161043a565b50506000910152565b6000806040838503121561046e57600080fd5b61047783610405565b60208401519092506001600160401b038082111561049457600080fd5b818501915085601f8301126104a857600080fd5b8151818111156104ba576104ba610421565b604051601f8201601f19908116603f011681019083821181831017156104e2576104e2610421565b816040528281528860208487010111156104fb57600080fd5b61050c836020830160208801610437565b80955050505050509250929050565b60006020828403121561052d57600080fd5b6102c882610405565b60008251610548818460208701610437565b9190910192915050565b6020815260008251806020840152610571816040850160208701610437565b601f01601f19169190910160400192915050565b610343806105946000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610067565b610100565b565b606061004e83836040518060600160405280602781526020016102e760279139610124565b9392505050565b6001600160a01b03163b151590565b90565b600061009a7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50546001600160a01b031690565b6001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fb919061024a565b905090565b3660008037600080366000845af43d6000803e80801561011f573d6000f35b3d6000fd5b6060600080856001600160a01b0316856040516101419190610297565b600060405180830381855af49150503d806000811461017c576040519150601f19603f3d011682016040523d82523d6000602084013e610181565b606091505b50915091506101928683838761019c565b9695505050505050565b6060831561020e578251600003610207576101b685610055565b6102075760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064015b60405180910390fd5b5081610218565b6102188383610220565b949350505050565b8151156102305781518083602001fd5b8060405162461bcd60e51b81526004016101fe91906102b3565b60006020828403121561025c57600080fd5b81516001600160a01b038116811461004e57600080fd5b60005b8381101561028e578181015183820152602001610276565b50506000910152565b600082516102a9818460208701610273565b9190910192915050565b60208152600082518060208401526102d2816040850160208701610273565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220d7ce1835befd5faecbfea1c57664062796dc15afe2c20b368807d14fc6aa703b64736f6c63430008100033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220b9695422cdc7e4423453e55e168d7fc09707f2e59ff1bce987cb6ca9b79dfeb164736f6c63430008100033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ec4f65e0a0268ff38ecec711ad5159b96dabab980000000000000000000000000eba83c7b2122e347eeafdc37edf9ed856f0ac4600000000000000000000000066be61e109ecff0e829313b605904cddeb88fff80000000000000000000000005dd6710fed29132325d3fe1aa138046dab641abc000000000000000000000000c641de59d9a55b6657e4bca9bb62822c8bb09ed3
-----Decoded View---------------
Arg [0] : serviceConfiguration (address): 0xec4F65e0A0268ff38ECEc711AD5159b96dAbaB98
Arg [1] : withdrawControllerFactory (address): 0x0eBa83c7b2122e347eEAfDc37Edf9Ed856F0AC46
Arg [2] : poolControllerFactory (address): 0x66be61E109ecff0E829313B605904CDDEb88ffF8
Arg [3] : vaultFactory (address): 0x5dD6710feD29132325d3Fe1aA138046DAB641AbC
Arg [4] : poolAccessControlFactory (address): 0xC641DE59d9A55B6657e4BCa9bB62822c8BB09ED3
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000ec4f65e0a0268ff38ecec711ad5159b96dabab98
Arg [1] : 0000000000000000000000000eba83c7b2122e347eeafdc37edf9ed856f0ac46
Arg [2] : 00000000000000000000000066be61e109ecff0e829313b605904cddeb88fff8
Arg [3] : 0000000000000000000000005dd6710fed29132325d3fe1aa138046dab641abc
Arg [4] : 000000000000000000000000c641de59d9a55b6657e4bca9bb62822c8bb09ed3
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.