fluid-contracts-public/deployments/mainnet/solcInputs/c36d0262518c8feade0bff1a0372602d.json
2024-07-11 13:05:09 +00:00

51 lines
42 KiB
JSON

{
"language": "Solidity",
"sources": {
"contracts/libraries/storageRead.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\n/// @notice implements a method to read uint256 data from storage at a bytes32 storage slot key.\ncontract StorageRead {\n function readFromStorage(bytes32 slot_) public view returns (uint256 result_) {\n assembly {\n result_ := sload(slot_) // read value from the storage slot\n }\n }\n}\n"
},
"contracts/protocols/vault/error.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\ncontract Error {\n error FluidVaultError(uint256 errorId_);\n\n /// @notice used to simulate liquidation to find the maximum liquidatable amounts\n error FluidLiquidateResult(uint256 colLiquidated, uint256 debtLiquidated);\n}\n"
},
"contracts/protocols/vault/errorTypes.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nlibrary ErrorTypes {\n /***********************************|\n | Vault Factory | \n |__________________________________*/\n\n uint256 internal constant VaultFactory__InvalidOperation = 30001;\n uint256 internal constant VaultFactory__Unauthorized = 30002;\n uint256 internal constant VaultFactory__SameTokenNotAllowed = 30003;\n uint256 internal constant VaultFactory__InvalidParams = 30004;\n uint256 internal constant VaultFactory__InvalidVault = 30005;\n uint256 internal constant VaultFactory__InvalidVaultAddress = 30006;\n uint256 internal constant VaultFactory__OnlyDelegateCallAllowed = 30007;\n\n /***********************************|\n | VaultT1 | \n |__________________________________*/\n\n /// @notice thrown at reentrancy\n uint256 internal constant VaultT1__AlreadyEntered = 31001;\n\n /// @notice thrown when user sends deposit & borrow amount as 0\n uint256 internal constant VaultT1__InvalidOperateAmount = 31002;\n\n /// @notice thrown when msg.value is not in sync with native token deposit or payback\n uint256 internal constant VaultT1__InvalidMsgValueOperate = 31003;\n\n /// @notice thrown when msg.sender is not the owner of the vault\n uint256 internal constant VaultT1__NotAnOwner = 31004;\n\n /// @notice thrown when user's position does not exist. Sending the wrong index from the frontend\n uint256 internal constant VaultT1__TickIsEmpty = 31005;\n\n /// @notice thrown when the user's position is above CF and the user tries to make it more risky by trying to withdraw or borrow\n uint256 internal constant VaultT1__PositionAboveCF = 31006;\n\n /// @notice thrown when the top tick is not initialized. Happens if the vault is totally new or all the user's left\n uint256 internal constant VaultT1__TopTickDoesNotExist = 31007;\n\n /// @notice thrown when msg.value in liquidate is not in sync payback\n uint256 internal constant VaultT1__InvalidMsgValueLiquidate = 31008;\n\n /// @notice thrown when slippage is more on liquidation than what the liquidator sent\n uint256 internal constant VaultT1__ExcessSlippageLiquidation = 31009;\n\n /// @notice thrown when msg.sender is not the rebalancer/reserve contract\n uint256 internal constant VaultT1__NotRebalancer = 31010;\n\n /// @notice thrown when NFT of one vault interacts with the NFT of other vault\n uint256 internal constant VaultT1__NftNotOfThisVault = 31011;\n\n /// @notice thrown when the token is not initialized on the liquidity contract\n uint256 internal constant VaultT1__TokenNotInitialized = 31012;\n\n /// @notice thrown when admin updates fallback if a non-auth calls vault\n uint256 internal constant VaultT1__NotAnAuth = 31013;\n\n /// @notice thrown in operate when user tries to witdhraw more collateral than deposited\n uint256 internal constant VaultT1__ExcessCollateralWithdrawal = 31014;\n\n /// @notice thrown in operate when user tries to payback more debt than borrowed\n uint256 internal constant VaultT1__ExcessDebtPayback = 31015;\n\n /// @notice thrown when user try to withdrawal more than operate's withdrawal limit\n uint256 internal constant VaultT1__WithdrawMoreThanOperateLimit = 31016;\n\n /// @notice thrown when caller of liquidityCallback is not Liquidity\n uint256 internal constant VaultT1__InvalidLiquidityCallbackAddress = 31017;\n\n /// @notice thrown when reentrancy is not already on\n uint256 internal constant VaultT1__NotEntered = 31018;\n\n /// @notice thrown when someone directly calls secondary implementation contract\n uint256 internal constant VaultT1__OnlyDelegateCallAllowed = 31019;\n\n /// @notice thrown when the safeTransferFrom for a token amount failed\n uint256 internal constant VaultT1__TransferFromFailed = 31020;\n\n /// @notice thrown when exchange price overflows while updating on storage\n uint256 internal constant VaultT1__ExchangePriceOverFlow = 31021;\n\n /// @notice thrown when debt to liquidate amt is sent wrong\n uint256 internal constant VaultT1__InvalidLiquidationAmt = 31022;\n\n /// @notice thrown when user debt or collateral goes above 2**128 or below -2**128\n uint256 internal constant VaultT1__UserCollateralDebtExceed = 31023;\n\n /// @notice thrown if on liquidation branch debt becomes lower than 100\n uint256 internal constant VaultT1__BranchDebtTooLow = 31024;\n\n /// @notice thrown when tick's debt is less than 10000\n uint256 internal constant VaultT1__TickDebtTooLow = 31025;\n\n /// @notice thrown when the received new liquidity exchange price is of unexpected value (< than the old one)\n uint256 internal constant VaultT1__LiquidityExchangePriceUnexpected = 31026;\n\n /// @notice thrown when user's debt is less than 10000\n uint256 internal constant VaultT1__UserDebtTooLow = 31027;\n\n /// @notice thrown when on only payback and only deposit the ratio of position increases\n uint256 internal constant VaultT1__InvalidPaybackOrDeposit = 31028;\n\n /***********************************|\n | ERC721 | \n |__________________________________*/\n\n uint256 internal constant ERC721__InvalidParams = 32001;\n uint256 internal constant ERC721__Unauthorized = 32002;\n uint256 internal constant ERC721__InvalidOperation = 32003;\n uint256 internal constant ERC721__UnsafeRecipient = 32004;\n uint256 internal constant ERC721__OutOfBoundsIndex = 32005;\n\n /***********************************|\n | Vault Admin | \n |__________________________________*/\n\n /// @notice thrown when admin tries to setup invalid value which are crossing limits\n uint256 internal constant VaultT1Admin__ValueAboveLimit = 33001;\n\n /// @notice when someone directly calls admin implementation contract\n uint256 internal constant VaultT1Admin__OnlyDelegateCallAllowed = 33002;\n\n /// @notice thrown when auth sends NFT ID as 0 while collecting dust debt\n uint256 internal constant VaultT1Admin__NftIdShouldBeNonZero = 33003;\n\n /// @notice thrown when trying to collect dust debt of NFT which is not of this vault\n uint256 internal constant VaultT1Admin__NftNotOfThisVault = 33004;\n\n /// @notice thrown when dust debt of NFT is 0, meaning nothing to collect\n uint256 internal constant VaultT1Admin__DustDebtIsZero = 33005;\n\n /// @notice thrown when final debt after liquidation is not 0, meaning position 100% liquidated\n uint256 internal constant VaultT1Admin__FinalDebtShouldBeZero = 33006;\n\n /// @notice thrown when NFT is not liquidated state\n uint256 internal constant VaultT1Admin__NftNotLiquidated = 33007;\n\n /// @notice thrown when total absorbed dust debt is 0\n uint256 internal constant VaultT1Admin__AbsorbedDustDebtIsZero = 33008;\n\n /// @notice thrown when address is set as 0\n uint256 internal constant VaultT1Admin__AddressZeroNotAllowed = 33009;\n\n /***********************************|\n | Vault Rewards | \n |__________________________________*/\n\n uint256 internal constant VaultRewards__Unauthorized = 34001;\n uint256 internal constant VaultRewards__AddressZero = 34002;\n uint256 internal constant VaultRewards__InvalidParams = 34003;\n uint256 internal constant VaultRewards__NewMagnifierSameAsOldMagnifier = 34004;\n uint256 internal constant VaultRewards__NotTheInitiator = 34005;\n uint256 internal constant VaultRewards__AlreadyStarted = 34006;\n uint256 internal constant VaultRewards__RewardsNotStartedOrEnded = 34007;\n}\n"
},
"contracts/protocols/vault/factory/ERC721/ERC721.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { ErrorTypes } from \"../../errorTypes.sol\";\nimport { Error } from \"../../error.sol\";\n\n/// @notice Fluid Vault Factory ERC721 base contract. Implements the ERC721 standard, based on Solmate.\n/// In addition, implements ERC721 Enumerable.\n/// Modern, minimalist, and gas efficient ERC-721 with Enumerable implementation.\n///\n/// @author Instadapp\n/// @author Modified Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721 is Error {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 indexed id);\n\n event Approval(address indexed owner, address indexed spender, uint256 indexed id);\n\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE/LOGIC\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n function tokenURI(uint256 id) public view virtual returns (string memory);\n\n /*//////////////////////////////////////////////////////////////\n ERC721 BALANCE/OWNER STORAGE\n //////////////////////////////////////////////////////////////*/\n\n // token id => token config\n // uint160 0 - 159: address:: owner\n // uint32 160 - 191: uint32:: index\n // uint32 192 - 223: uint32:: vaultId\n // uint32 224 - 255: uint32:: null\n mapping(uint256 => uint256) internal _tokenConfig;\n\n // owner => slot => index\n /*\n // slot 0: \n // uint32 0 - 31: uint32:: balanceOf\n // uint224 32 - 255: 7 tokenIds each of uint32 packed\n // slot N (N >= 1)\n // uint32 * 8 each tokenId\n */\n mapping(address => mapping(uint256 => uint256)) internal _ownerConfig;\n\n /// @notice returns `owner_` of NFT with `id_`\n function ownerOf(uint256 id_) public view virtual returns (address owner_) {\n if ((owner_ = address(uint160(_tokenConfig[id_]))) == address(0))\n revert FluidVaultError(ErrorTypes.ERC721__InvalidParams);\n }\n\n /// @notice returns total count of NFTs owned by `owner_`\n function balanceOf(address owner_) public view virtual returns (uint256) {\n if (owner_ == address(0)) revert FluidVaultError(ErrorTypes.ERC721__InvalidParams);\n\n return _ownerConfig[owner_][0] & type(uint32).max;\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721Enumerable STORAGE\n //////////////////////////////////////////////////////////////*/\n\n /// @notice total amount of tokens stored by the contract.\n uint256 public totalSupply;\n\n /*//////////////////////////////////////////////////////////////\n ERC721 APPROVAL STORAGE\n //////////////////////////////////////////////////////////////*/\n\n /// @notice trackes if a NFT id is approved for a certain address.\n mapping(uint256 => address) public getApproved;\n\n /// @notice trackes if all the NFTs of an owner are approved for a certain other address.\n mapping(address => mapping(address => bool)) public isApprovedForAll;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(string memory _name, string memory _symbol) {\n name = _name;\n symbol = _symbol;\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n /// @notice approves an NFT with `id_` to be spent (transferred) by `spender_`\n function approve(address spender_, uint256 id_) public virtual {\n address owner_ = address(uint160(_tokenConfig[id_]));\n if (!(msg.sender == owner_ || isApprovedForAll[owner_][msg.sender]))\n revert FluidVaultError(ErrorTypes.ERC721__Unauthorized);\n\n getApproved[id_] = spender_;\n\n emit Approval(owner_, spender_, id_);\n }\n\n /// @notice approves all NFTs owned by msg.sender to be spent (transferred) by `operator_`\n function setApprovalForAll(address operator_, bool approved_) public virtual {\n isApprovedForAll[msg.sender][operator_] = approved_;\n\n emit ApprovalForAll(msg.sender, operator_, approved_);\n }\n\n /// @notice transfers an NFT with `id_` `from_` address `to_` address without safe check\n function transferFrom(address from_, address to_, uint256 id_) public virtual {\n uint256 tokenConfig_ = _tokenConfig[id_];\n if (from_ != address(uint160(tokenConfig_))) revert FluidVaultError(ErrorTypes.ERC721__InvalidParams);\n\n if (!(msg.sender == from_ || isApprovedForAll[from_][msg.sender] || msg.sender == getApproved[id_]))\n revert FluidVaultError(ErrorTypes.ERC721__Unauthorized);\n\n // call _transfer with vaultId extracted from tokenConfig_\n _transfer(from_, to_, id_, (tokenConfig_ >> 192) & type(uint32).max);\n\n delete getApproved[id_];\n\n emit Transfer(from_, to_, id_);\n }\n\n /// @notice transfers an NFT with `id_` `from_` address `to_` address\n function safeTransferFrom(address from_, address to_, uint256 id_) public virtual {\n transferFrom(from_, to_, id_);\n\n if (\n !(to_.code.length == 0 ||\n ERC721TokenReceiver(to_).onERC721Received(msg.sender, from_, id_, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector)\n ) revert FluidVaultError(ErrorTypes.ERC721__UnsafeRecipient);\n }\n\n /// @notice transfers an NFT with `id_` `from_` address `to_` address, passing `data_` to `onERC721Received` callback\n function safeTransferFrom(address from_, address to_, uint256 id_, bytes calldata data_) public virtual {\n transferFrom(from_, to_, id_);\n\n if (\n !((to_.code.length == 0) ||\n ERC721TokenReceiver(to_).onERC721Received(msg.sender, from_, id_, data_) ==\n ERC721TokenReceiver.onERC721Received.selector)\n ) revert FluidVaultError(ErrorTypes.ERC721__UnsafeRecipient);\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721Enumerable LOGIC\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Returns a token ID at a given `index_` of all the tokens stored by the contract.\n /// Use along with {totalSupply} to enumerate all tokens.\n function tokenByIndex(uint256 index_) external view returns (uint256) {\n if (index_ >= totalSupply) {\n revert FluidVaultError(ErrorTypes.ERC721__OutOfBoundsIndex);\n }\n return index_ + 1;\n }\n\n /// @notice Returns a token ID owned by `owner_` at a given `index_` of its token list.\n /// Use along with {balanceOf} to enumerate all of `owner_`'s tokens.\n function tokenOfOwnerByIndex(address owner_, uint256 index_) external view returns (uint256) {\n if (index_ >= balanceOf(owner_)) {\n revert FluidVaultError(ErrorTypes.ERC721__OutOfBoundsIndex);\n }\n\n index_ = index_ + 1;\n return (_ownerConfig[owner_][index_ / 8] >> ((index_ % 8) * 32)) & type(uint32).max;\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC165 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function supportsInterface(bytes4 interfaceId_) public view virtual returns (bool) {\n return\n interfaceId_ == 0x01ffc9a7 || // ERC165 Interface ID for ERC165\n interfaceId_ == 0x80ac58cd || // ERC165 Interface ID for ERC721\n interfaceId_ == 0x5b5e139f || // ERC165 Interface ID for ERC721Metadata\n interfaceId_ == 0x780e9d63; // ERC165 Interface ID for ERC721Enumberable\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL TRANSFER LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _transfer(address from_, address to_, uint256 id_, uint256 vaultId_) internal {\n if (to_ == address(0)) {\n revert FluidVaultError(ErrorTypes.ERC721__InvalidOperation);\n } else if (from_ == address(0)) {\n _add(to_, id_, vaultId_);\n } else if (to_ != from_) {\n _remove(from_, id_);\n _add(to_, id_, vaultId_);\n }\n }\n\n function _add(address user_, uint256 id_, uint256 vaultId_) private {\n uint256 ownerConfig_ = _ownerConfig[user_][0];\n unchecked {\n // index starts from `1`\n uint256 balanceOf_ = (ownerConfig_ & type(uint32).max) + 1;\n\n _tokenConfig[id_] = (uint160(user_) | (balanceOf_ << 160) | (vaultId_ << 192));\n\n _ownerConfig[user_][0] = (ownerConfig_ & ~uint256(type(uint32).max)) | (balanceOf_);\n\n uint256 wordIndex_ = (balanceOf_ / 8);\n _ownerConfig[user_][wordIndex_] = _ownerConfig[user_][wordIndex_] | (id_ << ((balanceOf_ % 8) * 32));\n }\n }\n\n function _remove(address user_, uint256 id_) private {\n uint256 temp_ = _tokenConfig[id_];\n\n // fetching `id_` details and deleting it.\n uint256 tokenIndex_ = (temp_ >> 160) & type(uint32).max;\n _tokenConfig[id_] = 0;\n\n // fetching & updating balance\n temp_ = _ownerConfig[user_][0];\n uint256 lastTokenIndex_ = (temp_ & type(uint32).max); // (lastTokenIndex_ = balanceOf)\n _ownerConfig[user_][0] = (temp_ & ~uint256(type(uint32).max)) | (lastTokenIndex_ - 1);\n\n {\n unchecked {\n uint256 lastTokenWordIndex_ = (lastTokenIndex_ / 8);\n uint256 lastTokenBitShift_ = (lastTokenIndex_ % 8) * 32;\n temp_ = _ownerConfig[user_][lastTokenWordIndex_];\n\n // replace `id_` tokenId with `last` tokenId.\n if (lastTokenIndex_ != tokenIndex_) {\n uint256 wordIndex_ = (tokenIndex_ / 8);\n uint256 bitShift_ = (tokenIndex_ % 8) * 32;\n\n // temp_ here is _ownerConfig[user_][lastTokenWordIndex_];\n uint256 lastTokenId_ = uint256((temp_ >> lastTokenBitShift_) & type(uint32).max);\n if (wordIndex_ == lastTokenWordIndex_) {\n // this case, when lastToken and currentToken are in same slot.\n // updating temp_ as we will remove the lastToken from this slot itself\n temp_ = (temp_ & ~(uint256(type(uint32).max) << bitShift_)) | (lastTokenId_ << bitShift_);\n } else {\n _ownerConfig[user_][wordIndex_] =\n (_ownerConfig[user_][wordIndex_] & ~(uint256(type(uint32).max) << bitShift_)) |\n (lastTokenId_ << bitShift_);\n }\n _tokenConfig[lastTokenId_] =\n (_tokenConfig[lastTokenId_] & ~(uint256(type(uint32).max) << 160)) |\n (tokenIndex_ << 160);\n }\n\n // temp_ here is _ownerConfig[user_][lastTokenWordIndex_];\n _ownerConfig[user_][lastTokenWordIndex_] = temp_ & ~(uint256(type(uint32).max) << lastTokenBitShift_);\n }\n }\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to_, uint256 vaultId_) internal virtual returns (uint256 id_) {\n\n unchecked {\n ++totalSupply;\n }\n\n id_ = totalSupply;\n if (id_ >= type(uint32).max || _tokenConfig[id_] != 0) revert FluidVaultError(ErrorTypes.ERC721__InvalidParams);\n\n _transfer(address(0), to_, id_, vaultId_);\n\n emit Transfer(address(0), to_, id_);\n }\n}\n\nabstract contract ERC721TokenReceiver {\n function onERC721Received(address, address, uint256, bytes calldata) external virtual returns (bytes4) {\n return ERC721TokenReceiver.onERC721Received.selector;\n }\n}\n"
},
"contracts/protocols/vault/factory/main.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { Owned } from \"solmate/src/auth/Owned.sol\";\nimport { ERC721 } from \"./ERC721/ERC721.sol\";\nimport { ErrorTypes } from \"../errorTypes.sol\";\n\nimport { StorageRead } from \"../../../libraries/storageRead.sol\";\n\nabstract contract VaultFactoryVariables is Owned, ERC721, StorageRead {\n /// @dev ERC721 tokens name\n string internal constant ERC721_NAME = \"Fluid Vault\";\n /// @dev ERC721 tokens symbol\n string internal constant ERC721_SYMBOL = \"fVLT\";\n\n /*//////////////////////////////////////////////////////////////\n STORAGE VARIABLES\n //////////////////////////////////////////////////////////////*/\n\n // ------------ storage variables from inherited contracts (Owned and ERC721) come before vars here --------\n\n // ----------------------- slot 0 ---------------------------\n // address public owner; // from Owned\n\n // 12 bytes empty\n\n // ----------------------- slot 1 ---------------------------\n // string public name;\n\n // ----------------------- slot 2 ---------------------------\n // string public symbol;\n\n // ----------------------- slot 3 ---------------------------\n // mapping(uint256 => uint256) internal _tokenConfig;\n\n // ----------------------- slot 4 ---------------------------\n // mapping(address => mapping(uint256 => uint256)) internal _ownerConfig;\n\n // ----------------------- slot 5 ---------------------------\n // uint256 public totalSupply;\n\n // ----------------------- slot 6 ---------------------------\n // mapping(uint256 => address) public getApproved;\n\n // ----------------------- slot 7 ---------------------------\n // mapping(address => mapping(address => bool)) public isApprovedForAll;\n\n // ----------------------- slot 8 ---------------------------\n /// @dev deployer can deploy new Vault contract\n /// owner can add/remove deployer.\n /// Owner is deployer by default.\n mapping(address => bool) internal _deployers;\n\n // ----------------------- slot 9 ---------------------------\n /// @dev global auths can update any vault config.\n /// owner can add/remove global auths.\n /// Owner is global auth by default.\n mapping(address => bool) internal _globalAuths;\n\n // ----------------------- slot 10 ---------------------------\n /// @dev vault auths can update specific vault config.\n /// owner can add/remove vault auths.\n /// Owner is vault auth by default.\n /// vault => auth => add/remove\n mapping(address => mapping(address => bool)) internal _vaultAuths;\n\n // ----------------------- slot 11 ---------------------------\n /// @dev total no of vaults deployed by the factory\n /// only addresses that have deployer role or owner can deploy new vault.\n uint256 internal _totalVaults;\n\n // ----------------------- slot 12 ---------------------------\n /// @dev vault deployment logics for deploying vault\n /// These logic contracts hold the deployment logics of specific vaults and are called via .delegatecall inside deployVault().\n /// only addresses that have owner can add/remove new vault deployment logic.\n mapping(address => bool) internal _vaultDeploymentLogics;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n constructor(address owner_) Owned(owner_) ERC721(ERC721_NAME, ERC721_SYMBOL) {}\n}\n\nabstract contract VaultFactoryEvents {\n /// @dev Emitted when a new vault is deployed.\n /// @param vault The address of the newly deployed vault.\n /// @param vaultId The id of the newly deployed vault.\n event VaultDeployed(address indexed vault, uint256 indexed vaultId);\n\n /// @dev Emitted when a new token/position is minted by a vault.\n /// @param vault The address of the vault that minted the token.\n /// @param user The address of the user who received the minted token.\n /// @param tokenId The ID of the newly minted token.\n event NewPositionMinted(address indexed vault, address indexed user, uint256 indexed tokenId);\n\n /// @dev Emitted when the deployer is modified by owner.\n /// @param deployer Address whose deployer status is updated.\n /// @param allowed Indicates whether the address is authorized as a deployer or not.\n event LogSetDeployer(address indexed deployer, bool indexed allowed);\n\n /// @dev Emitted when the globalAuth is modified by owner.\n /// @param globalAuth Address whose globalAuth status is updated.\n /// @param allowed Indicates whether the address is authorized as a deployer or not.\n event LogSetGlobalAuth(address indexed globalAuth, bool indexed allowed);\n\n /// @dev Emitted when the vaultAuth is modified by owner.\n /// @param vaultAuth Address whose vaultAuth status is updated.\n /// @param allowed Indicates whether the address is authorized as a deployer or not.\n /// @param vault Address of the specific vault related to the authorization change.\n event LogSetVaultAuth(address indexed vaultAuth, bool indexed allowed, address indexed vault);\n\n /// @dev Emitted when the vault deployment logic is modified by owner.\n /// @param vaultDeploymentLogic The address of the vault deployment logic contract.\n /// @param allowed Indicates whether the address is authorized as a deployer or not.\n event LogSetVaultDeploymentLogic(address indexed vaultDeploymentLogic, bool indexed allowed);\n}\n\nabstract contract VaultFactoryCore is VaultFactoryVariables, VaultFactoryEvents {\n constructor(address owner_) validAddress(owner_) VaultFactoryVariables(owner_) {}\n\n /// @dev validates that an address is not the zero address\n modifier validAddress(address value_) {\n if (value_ == address(0)) {\n revert FluidVaultError(ErrorTypes.VaultFactory__InvalidParams);\n }\n _;\n }\n}\n\n/// @dev Implements Vault Factory auth-only callable methods. Owner / auths can set various config values and\n/// can define the allow-listed deployers.\nabstract contract VaultFactoryAuth is VaultFactoryCore {\n /// @notice Sets an address (`deployer_`) as allowed deployer or not.\n /// This function can only be called by the owner.\n /// @param deployer_ The address to be set as deployer.\n /// @param allowed_ A boolean indicating whether the specified address is allowed to deploy vaults.\n function setDeployer(address deployer_, bool allowed_) external onlyOwner validAddress(deployer_) {\n _deployers[deployer_] = allowed_;\n\n emit LogSetDeployer(deployer_, allowed_);\n }\n\n /// @notice Sets an address (`globalAuth_`) as a global authorization or not.\n /// This function can only be called by the owner.\n /// @param globalAuth_ The address to be set as global authorization.\n /// @param allowed_ A boolean indicating whether the specified address is allowed to update any vault config.\n function setGlobalAuth(address globalAuth_, bool allowed_) external onlyOwner validAddress(globalAuth_) {\n _globalAuths[globalAuth_] = allowed_;\n\n emit LogSetGlobalAuth(globalAuth_, allowed_);\n }\n\n /// @notice Sets an address (`vaultAuth_`) as allowed vault authorization or not for a specific vault (`vault_`).\n /// This function can only be called by the owner.\n /// @param vault_ The address of the vault for which the authorization is being set.\n /// @param vaultAuth_ The address to be set as vault authorization.\n /// @param allowed_ A boolean indicating whether the specified address is allowed to update the specific vault config.\n function setVaultAuth(\n address vault_,\n address vaultAuth_,\n bool allowed_\n ) external onlyOwner validAddress(vaultAuth_) {\n _vaultAuths[vault_][vaultAuth_] = allowed_;\n\n emit LogSetVaultAuth(vaultAuth_, allowed_, vault_);\n }\n\n /// @notice Sets an address as allowed vault deployment logic (`deploymentLogic_`) contract or not.\n /// This function can only be called by the owner.\n /// @param deploymentLogic_ The address of the vault deployment logic contract to be set.\n /// @param allowed_ A boolean indicating whether the specified address is allowed to deploy new type of vault.\n function setVaultDeploymentLogic(\n address deploymentLogic_,\n bool allowed_\n ) public onlyOwner validAddress(deploymentLogic_) {\n _vaultDeploymentLogics[deploymentLogic_] = allowed_;\n\n emit LogSetVaultDeploymentLogic(deploymentLogic_, allowed_);\n }\n\n /// @notice Checks if the provided address (`deployer_`) is authorized as a deployer.\n /// @param deployer_ The address to be checked for deployer authorization.\n /// @return Returns `true` if the address is a deployer, otherwise `false`.\n function isDeployer(address deployer_) public view returns (bool) {\n return _deployers[deployer_] || owner == deployer_;\n }\n\n /// @notice Checks if the provided address (`globalAuth_`) has global vault authorization privileges.\n /// @param globalAuth_ The address to be checked for global authorization privileges.\n /// @return Returns `true` if the given address has global authorization privileges, otherwise `false`.\n function isGlobalAuth(address globalAuth_) public view returns (bool) {\n return _globalAuths[globalAuth_] || owner == globalAuth_;\n }\n\n /// @notice Checks if the provided address (`vaultAuth_`) has vault authorization privileges for the specified vault (`vault_`).\n /// @param vault_ The address of the vault to check.\n /// @param vaultAuth_ The address to be checked for vault authorization privileges.\n /// @return Returns `true` if the given address has vault authorization privileges for the specified vault, otherwise `false`.\n function isVaultAuth(address vault_, address vaultAuth_) public view returns (bool) {\n return _vaultAuths[vault_][vaultAuth_] || owner == vaultAuth_;\n }\n\n /// @notice Checks if the provided (`vaultDeploymentLogic_`) address has authorization for vault deployment.\n /// @param vaultDeploymentLogic_ The address of the vault deploy logic to check for authorization privileges.\n /// @return Returns `true` if the given address has authorization privileges for vault deployment, otherwise `false`.\n function isVaultDeploymentLogic(address vaultDeploymentLogic_) public view returns (bool) {\n return _vaultDeploymentLogics[vaultDeploymentLogic_];\n }\n}\n\n/// @dev implements VaultFactory deploy vault related methods.\nabstract contract VaultFactoryDeployment is VaultFactoryCore, VaultFactoryAuth {\n /// @dev Deploys a contract using the CREATE opcode with the provided bytecode (`bytecode_`).\n /// This is an internal function, meant to be used within the contract to facilitate the deployment of other contracts.\n /// @param bytecode_ The bytecode of the contract to be deployed.\n /// @return address_ Returns the address of the deployed contract.\n function _deploy(bytes memory bytecode_) internal returns (address address_) {\n if (bytecode_.length == 0) {\n revert FluidVaultError(ErrorTypes.VaultFactory__InvalidOperation);\n }\n /// @solidity memory-safe-assembly\n assembly {\n address_ := create(0, add(bytecode_, 0x20), mload(bytecode_))\n }\n if (address_ == address(0)) {\n revert FluidVaultError(ErrorTypes.VaultFactory__InvalidOperation);\n }\n }\n\n /// @notice Deploys a new vault using the specified deployment logic `vaultDeploymentLogic_` and data `vaultDeploymentData_`.\n /// Only accounts with deployer access or the owner can deploy a new vault.\n /// @param vaultDeploymentLogic_ The address of the vault deployment logic contract.\n /// @param vaultDeploymentData_ The data to be used for vault deployment.\n /// @return vault_ Returns the address of the newly deployed vault.\n function deployVault(\n address vaultDeploymentLogic_,\n bytes calldata vaultDeploymentData_\n ) external returns (address vault_) {\n // Revert if msg.sender doesn't have deployer access or is an owner.\n if (!isDeployer(msg.sender)) revert FluidVaultError(ErrorTypes.VaultFactory__Unauthorized);\n // Revert if vaultDeploymentLogic_ is not whitelisted.\n if (!isVaultDeploymentLogic(vaultDeploymentLogic_))\n revert FluidVaultError(ErrorTypes.VaultFactory__Unauthorized);\n\n // Vault ID for the new vault and also acts as `nonce` for CREATE\n uint256 vaultId_ = ++_totalVaults;\n\n // compute vault address for vault id.\n vault_ = getVaultAddress(vaultId_);\n\n // deploy the vault using vault deployment logic by making .delegatecall\n (bool success_, bytes memory data_) = vaultDeploymentLogic_.delegatecall(vaultDeploymentData_);\n\n if (!(success_ && vault_ == _deploy(abi.decode(data_, (bytes))) && isVault(vault_))) {\n revert FluidVaultError(ErrorTypes.VaultFactory__InvalidVaultAddress);\n }\n\n emit VaultDeployed(vault_, vaultId_);\n }\n\n /// @notice Computes the address of a vault based on its given ID (`vaultId_`).\n /// @param vaultId_ The ID of the vault.\n /// @return vault_ Returns the computed address of the vault.\n function getVaultAddress(uint256 vaultId_) public view returns (address vault_) {\n // @dev based on https://ethereum.stackexchange.com/a/61413\n\n // nonce of smart contract always starts with 1. so, with nonce 0 there won't be any deployment\n // hence, nonce of vault deployment starts with 1.\n bytes memory data;\n if (vaultId_ == 0x00) {\n return address(0);\n } else if (vaultId_ <= 0x7f) {\n data = abi.encodePacked(bytes1(0xd6), bytes1(0x94), address(this), uint8(vaultId_));\n } else if (vaultId_ <= 0xff) {\n data = abi.encodePacked(bytes1(0xd7), bytes1(0x94), address(this), bytes1(0x81), uint8(vaultId_));\n } else if (vaultId_ <= 0xffff) {\n data = abi.encodePacked(bytes1(0xd8), bytes1(0x94), address(this), bytes1(0x82), uint16(vaultId_));\n } else if (vaultId_ <= 0xffffff) {\n data = abi.encodePacked(bytes1(0xd9), bytes1(0x94), address(this), bytes1(0x83), uint24(vaultId_));\n } else {\n data = abi.encodePacked(bytes1(0xda), bytes1(0x94), address(this), bytes1(0x84), uint32(vaultId_));\n }\n\n return address(uint160(uint256(keccak256(data))));\n }\n\n /// @notice Checks if a given address (`vault_`) corresponds to a valid vault.\n /// @param vault_ The vault address to check.\n /// @return Returns `true` if the given address corresponds to a valid vault, otherwise `false`.\n function isVault(address vault_) public view returns (bool) {\n if (vault_.code.length == 0) {\n return false;\n } else {\n // VAULT_ID() function signature is 0x540acabc\n (bool success_, bytes memory data_) = vault_.staticcall(hex\"540acabc\");\n return success_ && vault_ == getVaultAddress(abi.decode(data_, (uint256)));\n }\n }\n\n /// @notice Returns the total number of vaults deployed by the factory.\n /// @return Returns the total number of vaults.\n function totalVaults() external view returns (uint256) {\n return _totalVaults;\n }\n}\n\nabstract contract VaultFactoryERC721 is VaultFactoryCore, VaultFactoryDeployment {\n /// @notice Mints a new ERC721 token for a specific vault (`vaultId_`) to a specified user (`user_`).\n /// Only the corresponding vault is authorized to mint a token.\n /// @param vaultId_ The ID of the vault that's minting the token.\n /// @param user_ The address receiving the minted token.\n /// @return tokenId_ The ID of the newly minted token.\n function mint(uint256 vaultId_, address user_) external returns (uint256 tokenId_) {\n if (msg.sender != getVaultAddress(vaultId_)) revert FluidVaultError(ErrorTypes.VaultFactory__InvalidVault);\n\n // Using _mint() instead of _safeMint() to allow any msg.sender to receive ERC721 without onERC721Received holder.\n tokenId_ = _mint(user_, vaultId_);\n\n emit NewPositionMinted(msg.sender, user_, tokenId_);\n }\n\n /// @notice Returns the URI of the specified token ID (`id_`).\n /// In this implementation, an empty string is returned as no specific URI is defined.\n /// @param id_ The ID of the token to query.\n /// @return An empty string since no specific URI is defined in this implementation.\n function tokenURI(uint256 id_) public view virtual override returns (string memory) {\n return \"\";\n }\n}\n\n/// @title Fluid VaultFactory\n/// @notice creates Fluid vault protocol vaults, which are interacting with Fluid Liquidity to deposit / borrow funds.\n/// Vaults are created at a deterministic address, given an incrementing `vaultId` (see `getVaultAddress()`).\n/// Vaults can only be deployed by allow-listed deployer addresses.\n/// This factory also implements ERC721-Enumerable, the NFTs are used to represent created user positions. Only vaults\n/// can mint new NFTs.\n/// @dev Note the deployed vaults start out with no config at Liquidity contract.\n/// This must be done by Liquidity auths in a separate step, otherwise no deposits will be possible.\n/// This contract is not upgradeable. It supports adding new vault deployment logic contracts for new, future vaults.\ncontract FluidVaultFactory is VaultFactoryCore, VaultFactoryAuth, VaultFactoryDeployment, VaultFactoryERC721 {\n constructor(address owner_) VaultFactoryCore(owner_) {}\n}\n"
},
"solmate/src/auth/Owned.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Simple single owner authorization mixin.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol)\nabstract contract Owned {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event OwnershipTransferred(address indexed user, address indexed newOwner);\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP STORAGE\n //////////////////////////////////////////////////////////////*/\n\n address public owner;\n\n modifier onlyOwner() virtual {\n require(msg.sender == owner, \"UNAUTHORIZED\");\n\n _;\n }\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(address _owner) {\n owner = _owner;\n\n emit OwnershipTransferred(address(0), _owner);\n }\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function transferOwnership(address newOwner) public virtual onlyOwner {\n owner = newOwner;\n\n emit OwnershipTransferred(msg.sender, newOwner);\n }\n}\n"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 10000000
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates"
],
"": [
"ast"
]
}
},
"metadata": {
"useLiteralContent": true
}
}
}