interface IPerpetualManager {
	/// @notice Lets a HA join the protocol and create a perpetual
	/// @param owner Address of the future owner of the perpetual
	/// @param margin Amount of collateral brought by the HA
	/// @param committedAmount Amount of collateral hedged by the HA
	/// @param maxOracleRate Maximum oracle value that the HA wants to see stored in the perpetual
	/// @param minNetMargin Minimum net margin that the HA is willing to see stored in the perpetual
	/// @return perpetualID The ID of the perpetual opened by this HA
	/// @dev The future owner of the perpetual cannot be the zero address
	/// @dev It is possible to open a perpetual on behalf of someone else
	/// @dev The `maxOracleRate` parameter serves as a protection against oracle manipulations for HAs opening perpetuals
	/// @dev `minNetMargin` is a protection against too big variations in the fees for HAs
	function openPerpetual(
		address owner,
		uint256 margin,
		uint256 committedAmount,
		uint256 maxOracleRate,
		uint256 minNetMargin
	) external returns (uint256 perpetualID);

	/// @notice Lets a HA close a perpetual owned or controlled for the stablecoin/collateral pair associated
	/// to this `PerpetualManager` contract
	/// @param perpetualID ID of the perpetual to close
	/// @param to Address which will receive the proceeds from this perpetual
	/// @param minCashOutAmount Minimum net cash out amount that the HA is willing to get for closing the
	/// perpetual
	/// @dev The HA gets the current amount of her position depending on the entry oracle value
	/// and current oracle value minus some transaction fees computed on the committed amount
	/// @dev `msg.sender` should be the owner of `perpetualID` or be approved for this perpetual
	/// @dev If the `PoolManager` does not have enough collateral, the perpetual owner will be converted to a SLP and
	/// receive sanTokens
	/// @dev The `minCashOutAmount` serves as a protection for HAs closing their perpetuals: it protects them both
	/// from fees that would have become too high and from a too big decrease in oracle value
	function closePerpetual(
		uint256 perpetualID,
		address to,
		uint256 minCashOutAmount
	) external;

	/// @notice Lets a HA increase the `margin` in a perpetual she controls for this
	/// stablecoin/collateral pair
	/// @param perpetualID ID of the perpetual to which amount should be added to `margin`
	/// @param amount Amount to add to the perpetual's `margin`
	function addToPerpetual(uint256 perpetualID, uint256 amount) external;

	/// @notice Lets a HA decrease the `margin` in a perpetual she controls for this
	/// stablecoin/collateral pair
	/// @param perpetualID ID of the perpetual from which collateral should be removed
	/// @param amount Amount to remove from the perpetual's `margin`
	/// @param to Address which will receive the collateral removed from this perpetual
	function removeFromPerpetual(
		uint256 perpetualID,
		uint256 amount,
		address to
	) external;

	// =========================== External View Function ==========================

	/// @notice Returns the `cashOutAmount` of the perpetual owned by someone at a given oracle value
	/// @param perpetualID ID of the perpetual
	/// @param rate Oracle value
	/// @return The `cashOutAmount` of the perpetual
	/// @return Whether the position of the perpetual is now too small compared with its initial position
	function getCashOutAmount(uint256 perpetualID, uint256 rate) external view returns (uint256, uint256);

	// =========================== Reward Distribution =============================

	/// @notice Allows to check the amount of reward tokens earned by a perpetual
	/// @param perpetualID ID of the perpetual to check
	/// @return The earned tokens by the perpetual that have not been claimed yet
	function earned(uint256 perpetualID) external view returns (uint256);

	/// @notice Allows a perpetual owner to withdraw rewards
	/// @param perpetualID ID of the perpetual which accumulated tokens
	/// @dev Only an approved caller can claim the rewards for the perpetual with perpetualID
	function getReward(uint256 perpetualID) external;

	// =============================== ERC721 logic ================================

	/// @notice Gets the balance of an owner
	/// @param owner Address of the owner
	/// @return Balance (ie the number of perpetuals) owned by a HA
	function balanceOf(address owner) external view returns (uint256);

	/// @notice Gets the owner of the perpetual with ID perpetualID
	/// @param perpetualID ID of the perpetual
	/// @return Owner address
	function ownerOf(uint256 perpetualID) external view returns (address);

	/// @notice Approves to an address specified by `to` a perpetual specified by `perpetualID`
	/// @param to Address to approve the perpetual to
	/// @param perpetualID ID of the perpetual
	function approve(address to, uint256 perpetualID) external;

	/// @param perpetualID ID of the concerned perpetual
	/// @return Approved address by a perpetual owner
	function getApproved(uint256 perpetualID) external view returns (address);

	/// @notice Sets approval on all perpetuals owned by the owner to an operator
	/// @param operator Address to approve (or block) on all perpetuals
	/// @param approved Whether the sender wants to approve or block the operator
	function setApprovalForAll(address operator, bool approved) external;

	/// @param owner Owner of perpetuals
	/// @param operator Address to check if approved
	/// @return If the operator address is approved on all perpetuals by the owner
	function isApprovedForAll(address owner, address operator) external view returns (bool);

	/// @param perpetualID ID of the perpetual
	/// @return If the sender address is approved for the perpetualId
	function isApprovedOrOwner(address spender, uint256 perpetualID) external view returns (bool);

	/// @notice Transfers the `perpetualID` from an address to another
	/// @param from Source address
	/// @param to Destination a address
	/// @param perpetualID ID of the perpetual to transfer
	function transferFrom(
		address from,
		address to,
		uint256 perpetualID
	) external;

	/// @notice Safely transfers the `perpetualID` from an address to another without data in it
	/// @param from Source address
	/// @param to Destination a address
	/// @param perpetualID ID of the perpetual to transfer
	function safeTransferFrom(
		address from,
		address to,
		uint256 perpetualID
	) external;

	/// @notice Safely transfers the `perpetualID` from an address to another with data in the transfer
	/// @param from Source address
	/// @param to Destination a address
	/// @param perpetualID ID of the perpetual to transfer
	function safeTransferFrom(
		address from,
		address to,
		uint256 perpetualID,
		bytes memory _data
	) external;
}
/// @notice Interface for the contract managing perpetuals: there is one such contract per collateral/stablecoin
/// pair in the protocol
function openPerpetual(
	address owner,
	uint256 margin,
	uint256 committedAmount,
	uint256 maxOracleRate,
	uint256 minNetMargin
) external returns (uint256 perpetualID);

/// @notice Lets a HA join the protocol and create a perpetual
/// @param owner Address of the future owner of the perpetual
/// @param margin Amount of collateral brought by the HA
/// @param committedAmount Amount of collateral hedged by the HA
/// @param maxOracleRate Maximum oracle value that the HA wants to see stored in the perpetual
/// @param minNetMargin Minimum net margin that the HA is willing to see stored in the perpetual
/// @return perpetualID The ID of the perpetual opened by this HA
/// @dev The future owner of the perpetual cannot be the zero address
/// @dev It is possible to open a perpetual on behalf of someone else
/// @dev The `maxOracleRate` parameter serves as a protection against oracle manipulations for HAs opening perpetuals
/// @dev `minNetMargin` is a protection against too big variations in the fees for HAs