// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
import {IChromaticMarketFactory} from "@chromatic-protocol/contracts/core/interfaces/IChromaticMarketFactory.sol";
import {IChromaticRouter} from "@chromatic-protocol/contracts/periphery/interfaces/IChromaticRouter.sol";
import {ChromaticAccount} from "@chromatic-protocol/contracts/periphery/ChromaticAccount.sol";
/**
* @title AccountFactory
* @dev Abstract contract for creating and managing user accounts.
*/
abstract contract AccountFactory is IChromaticRouter {
ChromaticAccount public immutable accountBase;
address private marketFactory;
mapping(address => address) private accounts;
/**
* @dev Throws an error indicating that the caller is not the DAO.
*/
error OnlyAccessableByDao();
/**
* @dev Modifier to restrict access to only the DAO.
* Throws an `OnlyAccessableByDao` error if the caller is not the DAO.
*/
modifier onlyDao() {
if (msg.sender != IChromaticMarketFactory(marketFactory).dao())
revert OnlyAccessableByDao();
_;
}
/**
* @dev Initializes the AccountFactory contract with the provided router and market factory addresses.
* @param _marketFactory The address of the market factory contract.
*/
constructor(address _marketFactory) {
accountBase = new ChromaticAccount();
marketFactory = _marketFactory;
}
/**
* @inheritdoc IChromaticRouter
*/
function createAccount() external override {
_createAccount(msg.sender);
}
function _createAccount(address owner) private {
require(accounts[owner] == address(0));
ChromaticAccount newAccount = ChromaticAccount(Clones.clone(address(accountBase)));
accounts[owner] = address(newAccount);
emit AccountCreated(address(newAccount), owner);
newAccount.initialize(owner, address(this), marketFactory);
}
/**
* @inheritdoc IChromaticRouter
*/
function getAccount() external view override returns (address) {
return accounts[msg.sender];
}
/**
* @notice Retrieves the address of a user's account.
* @param accountAddress The address of the user's account.
* @return The address of the user's account.
*/
function getAccount(address accountAddress) internal view returns (address) {
return accounts[accountAddress];
}
}
// 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: BUSL-1.1
pragma solidity 0.8.19;
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
/**
* @dev The BinMargin struct represents the margin information for an LP bin.
* @param tradingFeeRate The trading fee rate associated with the LP bin
* @param amount The maker margin amount specified for the LP bin
*/
struct BinMargin {
uint16 tradingFeeRate;
uint256 amount;
}
using BinMarginLib for BinMargin global;
/**
* @title BinMarginLib
* @dev The BinMarginLib library provides functions to operate on BinMargin structs.
*/
library BinMarginLib {
using Math for uint256;
uint256 constant TRADING_FEE_RATE_PRECISION = 10000;
/**
* @notice Calculates the trading fee based on the margin amount and the trading fee rate.
* @param self The BinMargin struct
* @param _protocolFeeRate The protocol fee rate for the market
* @return The trading fee amount
*/
function tradingFee(
BinMargin memory self,
uint16 _protocolFeeRate
) internal pure returns (uint256) {
uint256 _tradingFee = self.amount.mulDiv(self.tradingFeeRate, TRADING_FEE_RATE_PRECISION);
return _tradingFee - _protocolFee(_tradingFee, _protocolFeeRate);
}
/**
* @notice Calculates the protocol fee based on the margin amount and the trading fee rate.
* @param self The BinMargin struct
* @param _protocolFeeRate The protocol fee rate for the market
* @return The protocol fee amount
*/
function protocolFee(
BinMargin memory self,
uint16 _protocolFeeRate
) internal pure returns (uint256) {
return
_protocolFee(
self.amount.mulDiv(self.tradingFeeRate, TRADING_FEE_RATE_PRECISION),
_protocolFeeRate
);
}
function _protocolFee(
uint256 _tradingFee,
uint16 _protocolFeeRate
) private pure returns (uint256) {
return _tradingFee.mulDiv(_protocolFeeRate, TRADING_FEE_RATE_PRECISION);
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;
import {SignedMath} from "@openzeppelin/contracts/utils/math/SignedMath.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {FEE_RATES_LENGTH} from "@chromatic-protocol/contracts/core/libraries/Constants.sol";
import {Errors} from "@chromatic-protocol/contracts/core/libraries/Errors.sol";
/**
* @title CLBTokenLib
* @notice Provides utility functions for working with CLB tokens.
*/
library CLBTokenLib {
using SignedMath for int256;
using SafeCast for uint256;
uint256 private constant DIRECTION_PRECISION = 10 ** 10;
uint16 private constant MIN_FEE_RATE = 1;
/**
* @notice Encode the CLB token ID of ERC1155 token type
* @dev If `tradingFeeRate` is negative, it adds `DIRECTION_PRECISION` to the absolute fee rate.
* Otherwise it returns the fee rate directly.
* @return id The ID of ERC1155 token
*/
function encodeId(int16 tradingFeeRate) internal pure returns (uint256) {
bool long = tradingFeeRate > 0;
return _encodeId(uint16(long ? tradingFeeRate : -tradingFeeRate), long);
}
/**
* @notice Decode the trading fee rate from the CLB token ID of ERC1155 token type
* @dev If `id` is greater than or equal to `DIRECTION_PRECISION`,
* then it substracts `DIRECTION_PRECISION` from `id`
* and returns the negation of the substracted value.
* Otherwise it returns `id` directly.
* @return tradingFeeRate The trading fee rate
*/
function decodeId(uint256 id) internal pure returns (int16 tradingFeeRate) {
if (id >= DIRECTION_PRECISION) {
tradingFeeRate = -int16((id - DIRECTION_PRECISION).toUint16());
} else {
tradingFeeRate = int16(id.toUint16());
}
}
/**
* @notice Retrieves the array of supported trading fee rates.
* @dev This function returns the array of supported trading fee rates,
* ranging from the minimum fee rate to the maximum fee rate with step increments.
* @return tradingFeeRates The array of supported trading fee rates.
*/
function tradingFeeRates() internal pure returns (uint16[FEE_RATES_LENGTH] memory) {
// prettier-ignore
return [
MIN_FEE_RATE, 2, 3, 4, 5, 6, 7, 8, 9, // 0.01% ~ 0.09%, step 0.01%
10, 20, 30, 40, 50, 60, 70, 80, 90, // 0.1% ~ 0.9%, step 0.1%
100, 200, 300, 400, 500, 600, 700, 800, 900, // 1% ~ 9%, step 1%
1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000 // 10% ~ 50%, step 5%
];
}
function feeRateIndex(uint16 feeRate) internal pure returns (uint256) {
require(feeRate >= MIN_FEE_RATE && feeRate <= 5000, Errors.UNSUPPORTED_TRADING_FEE_RATE);
if (feeRate < 10) {
// 0..8
return feeRate - 1;
} else if (feeRate < 100) {
// 9..17
return (feeRate / 10) + 8;
} else if (feeRate < 1000) {
// 18..26
return (feeRate / 100) + 17;
} else {
// 27..35
return (feeRate / 500) + 25;
}
}
function tokenIds() internal pure returns (uint256[] memory) {
uint16[FEE_RATES_LENGTH] memory feeRates = tradingFeeRates();
uint256[] memory ids = new uint256[](FEE_RATES_LENGTH * 2);
for (uint256 i; i < FEE_RATES_LENGTH; ) {
ids[i] = _encodeId(feeRates[i], true);
ids[i + FEE_RATES_LENGTH] = _encodeId(feeRates[i], false);
unchecked {
++i;
}
}
return ids;
}
function _encodeId(uint16 tradingFeeRate, bool long) private pure returns (uint256 id) {
id = long ? tradingFeeRate : tradingFeeRate + DIRECTION_PRECISION;
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {IChromaticMarket} from "@chromatic-protocol/contracts/core/interfaces/IChromaticMarket.sol";
import {IChromaticTradeCallback} from "@chromatic-protocol/contracts/core/interfaces/callback/IChromaticTradeCallback.sol";
import {Position} from "@chromatic-protocol/contracts/core/libraries/Position.sol";
import {IChromaticAccount} from "@chromatic-protocol/contracts/periphery/interfaces/IChromaticAccount.sol";
import {OpenPositionInfo, ClosePositionInfo, ClaimPositionInfo} from "@chromatic-protocol/contracts/core/interfaces/market/Types.sol";
import {VerifyCallback} from "@chromatic-protocol/contracts/periphery/base/VerifyCallback.sol";
/**
* @title ChromaticAccount
* @dev This contract manages user accounts and positions.
*/
contract ChromaticAccount is IChromaticAccount, VerifyCallback {
using EnumerableSet for EnumerableSet.UintSet;
address owner;
address private router;
bool isInitialized;
mapping(address => EnumerableSet.UintSet) private positionIds;
/**
* @dev Throws an error indicating that the caller is not the chromatic router contract.
*/
error NotRouter();
/**
* @dev Throws an error indicating that the caller is not the owner of this account contract.
*/
error NotOwner();
/**
* @dev Throws an error indicating that the account is already initialized, and calling the initialization function again is not allowed.
*/
error AlreadyInitialized();
/**
* @dev Throws an error indicating that the account does not have sufficient balance to perform a particular operation, such as withdrawing an amount of tokens.
*/
error NotEnoughBalance();
/**
* @dev Throws an error indicating that the caller is not the owner of this account contractthat the caller is not the owner of this account contract.
*/
error NotExistPosition();
/**
* @dev Modifier that allows only the router to call a function.
* Throws an `NotRouter` error if the caller is not the chromatic router contract.
*/
modifier onlyRouter() {
if (msg.sender != router) revert NotRouter();
_;
}
/**
* @dev Modifier that allows only the owner to call a function.
* Throws an `NotOwner` error if the caller is not the owner of this account contract.
*/
modifier onlyOwner() {
if (msg.sender != owner) revert NotOwner();
_;
}
/**
* @notice Initializes the account with the specified owner, router, and market factory addresses.
* @dev Throws an `AlreadyInitialized` error if the account has already been initialized.
* @param _owner The address of the account owner.
* @param _router The address of the router contract.
* @param _marketFactory The address of the market factory contract.
*/
function initialize(address _owner, address _router, address _marketFactory) external {
if (isInitialized) revert AlreadyInitialized();
require(_owner != address(0));
require(_router != address(0));
require(_marketFactory != address(0));
owner = _owner;
router = _router;
isInitialized = true;
marketFactory = _marketFactory;
}
/**
* @inheritdoc IChromaticAccount
*/
function balance(address token) public view returns (uint256) {
return IERC20(token).balanceOf(address(this));
}
/**
* @inheritdoc IChromaticAccount
* @dev This function can only be called by owner.
* Throws a `NotEnoughBalance` error if the account does not have enough balance of the specified token.
*/
function withdraw(address token, uint256 amount) external onlyOwner {
if (balance(token) < amount) revert NotEnoughBalance();
SafeERC20.safeTransfer(IERC20(token), owner, amount);
}
function addPositionId(address market, uint256 positionId) internal {
//slither-disable-next-line unused-return
positionIds[market].add(positionId);
}
function removePositionId(address market, uint256 positionId) internal {
//slither-disable-next-line unused-return
positionIds[market].remove(positionId);
}
/**
* @inheritdoc IChromaticAccount
*/
function hasPositionId(address market, uint256 id) public view returns (bool) {
return positionIds[market].contains(id);
}
/**
* @inheritdoc IChromaticAccount
*/
function getPositionIds(address market) external view returns (uint256[] memory) {
return positionIds[market].values();
}
/**
* @inheritdoc IChromaticAccount
* @dev This function can only be called by the chromatic router contract.
*/
function openPosition(
address marketAddress,
int256 qty,
uint256 takerMargin,
uint256 makerMargin,
uint256 maxAllowableTradingFee
) external onlyRouter returns (OpenPositionInfo memory position) {
position = IChromaticMarket(marketAddress).openPosition(
qty,
takerMargin,
makerMargin,
maxAllowableTradingFee,
bytes("")
);
addPositionId(marketAddress, position.id);
//slither-disable-next-line reentrancy-events
emit OpenPosition(
marketAddress,
position.id,
position.openVersion,
position.qty,
position.openTimestamp,
position.takerMargin,
position.makerMargin,
position.tradingFee
);
}
/**
* @inheritdoc IChromaticAccount
* @dev This function can only be called by the chromatic router contract.
* Throws a `NotExistPosition` error if the position does not exist.
*/
function closePosition(address marketAddress, uint256 positionId) external override onlyRouter {
if (!hasPositionId(marketAddress, positionId)) revert NotExistPosition();
ClosePositionInfo memory position = IChromaticMarket(marketAddress).closePosition(
positionId
);
//slither-disable-next-line reentrancy-events
emit ClosePosition(
marketAddress,
position.id,
position.closeVersion,
position.closeTimestamp
);
}
/**
* @inheritdoc IChromaticAccount
* @dev This function can only be called by the chromatic router contract.
* Throws a `NotExistPosition` error if the position does not exist.
*/
function claimPosition(address marketAddress, uint256 positionId) external override onlyRouter {
if (!hasPositionId(marketAddress, positionId)) revert NotExistPosition();
IChromaticMarket(marketAddress).claimPosition(positionId, address(this), bytes(""));
}
/**
* @inheritdoc IChromaticTradeCallback
* @dev Transfers the required margin from the account to the specified vault.
* Throws a `NotEnoughBalance` error if the account does not have enough balance of the settlement token.
*/
function openPositionCallback(
address settlementToken,
address vault,
uint256 marginRequired,
bytes calldata /* data */
) external override verifyCallback {
if (balance(settlementToken) < marginRequired) revert NotEnoughBalance();
SafeERC20.safeTransfer(IERC20(settlementToken), vault, marginRequired);
}
/**
* @inheritdoc IChromaticTradeCallback
*/
function claimPositionCallback(
Position memory position,
ClaimPositionInfo memory claimInfo,
bytes calldata /* data */
) external override verifyCallback {
removePositionId(msg.sender, position.id);
address marketAddress = msg.sender;
emit ClaimPosition(
marketAddress,
claimInfo.id,
claimInfo.entryPrice,
claimInfo.exitPrice,
claimInfo.realizedPnl,
claimInfo.interest,
claimInfo.cause
);
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {SignedMath} from "@openzeppelin/contracts/utils/math/SignedMath.sol";
import {IChromaticMarketFactory} from "@chromatic-protocol/contracts/core/interfaces/IChromaticMarketFactory.sol";
import {IChromaticMarket} from "@chromatic-protocol/contracts/core/interfaces/IChromaticMarket.sol";
import {ICLBToken} from "@chromatic-protocol/contracts/core/interfaces/ICLBToken.sol";
import {IChromaticLiquidityCallback} from "@chromatic-protocol/contracts/core/interfaces/callback/IChromaticLiquidityCallback.sol";
import {CLBTokenLib} from "@chromatic-protocol/contracts/core/libraries/CLBTokenLib.sol";
import {Position} from "@chromatic-protocol/contracts/core/libraries/Position.sol";
import {LpReceipt} from "@chromatic-protocol/contracts/core/libraries/LpReceipt.sol";
import {IChromaticRouter} from "@chromatic-protocol/contracts/periphery/interfaces/IChromaticRouter.sol";
import {AccountFactory} from "@chromatic-protocol/contracts/periphery/base/AccountFactory.sol";
import {VerifyCallback} from "@chromatic-protocol/contracts/periphery/base/VerifyCallback.sol";
import {ChromaticAccount} from "@chromatic-protocol/contracts/periphery/ChromaticAccount.sol";
import {OpenPositionInfo} from "@chromatic-protocol/contracts/core/interfaces/market/IMarketTradeOpenPosition.sol";
import {IOracleProvider} from "@chromatic-protocol/contracts/oracle/interfaces/IOracleProvider.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/interfaces/IERC20Metadata.sol";
/**
* @title ChromaticRouter
* @dev A router contract that facilitates liquidity provision and trading on Chromatic.
*/
contract ChromaticRouter is AccountFactory, VerifyCallback {
using Math for uint256;
using SignedMath for int256;
using EnumerableSet for EnumerableSet.UintSet;
/**
* @dev Struct representing the data for an addLiquidity callback.
* @param provider The address of the liquidity provider.
* @param amount The amount of tokens being added as liquidity.
*/
struct AddLiquidityCallbackData {
address provider;
uint256 amount;
}
/**
* @dev Struct representing the data for an addLiquidityBatch callback.
* @param provider The address of the liquidity provider.
* @param amount The amount of tokens being added as liquidity.
*/
struct AddLiquidityBatchCallbackData {
address provider;
uint256 amount;
}
/**
* @dev Struct representing the data for a removeLiquidity callback.
* @param provider The address of the liquidity provider.
* @param clbTokenAmount The amount of CLB tokens being removed.
*/
struct RemoveLiquidityCallbackData {
address provider;
uint256 clbTokenAmount;
}
/**
* @dev Struct representing the data for a removeLiquidityBatch callback.
* @param provider The address of the liquidity provider.
* @param clbTokenAmounts An array of CLB token amounts being removed.
*/
struct RemoveLiquidityBatchCallbackData {
address provider;
uint256[] clbTokenAmounts;
}
mapping(address => mapping(uint256 => address)) providerMap; // market => receiptId => provider
mapping(address => mapping(address => EnumerableSet.UintSet)) receiptIds; // market => provider => receiptIds
/**
* @dev Initializes the ChromaticRouter contract.
* @param _marketFactory The address of the ChromaticMarketFactory contract.
*/
constructor(address _marketFactory) AccountFactory(_marketFactory) {
require(_marketFactory != address(0));
marketFactory = _marketFactory;
}
/**
* @inheritdoc IChromaticLiquidityCallback
*/
function addLiquidityCallback(
address settlementToken,
address vault,
bytes calldata data
) external override verifyCallback {
AddLiquidityCallbackData memory callbackData = abi.decode(data, (AddLiquidityCallbackData));
//slither-disable-next-line arbitrary-send-erc20
SafeERC20.safeTransferFrom(
IERC20(settlementToken),
callbackData.provider,
vault,
callbackData.amount
);
}
/**
* @inheritdoc IChromaticLiquidityCallback
*/
function addLiquidityBatchCallback(
address settlementToken,
address vault,
bytes calldata data
) external override verifyCallback {
AddLiquidityBatchCallbackData memory callbackData = abi.decode(
data,
(AddLiquidityBatchCallbackData)
);
//slither-disable-next-line arbitrary-send-erc20
SafeERC20.safeTransferFrom(
IERC20(settlementToken),
callbackData.provider,
vault,
callbackData.amount
);
}
/**
* @inheritdoc IChromaticLiquidityCallback
*/
function claimLiquidityCallback(
uint256 receiptId,
int16,
uint256,
uint256,
bytes calldata
) external override verifyCallback {
// address market = msg.sender; // save gas : MSTORE,MLOAD - 3, CALLER(msg.sender) - 2
address provider = providerMap[msg.sender][receiptId];
//slither-disable-next-line unused-return
receiptIds[msg.sender][provider].remove(receiptId);
delete providerMap[msg.sender][receiptId];
}
/**
* @inheritdoc IChromaticLiquidityCallback
*/
function claimLiquidityBatchCallback(
uint256[] calldata _receiptIds,
int16[] calldata,
uint256[] calldata,
uint256[] calldata,
bytes calldata
) external override verifyCallback {
// address market = msg.sender; // save gas : MSTORE,MLOAD - 3, CALLER(msg.sender) - 2
for (uint256 i; i < _receiptIds.length; ) {
uint256 receiptId = _receiptIds[i];
address provider = providerMap[msg.sender][receiptId];
//slither-disable-next-line unused-return
receiptIds[msg.sender][provider].remove(_receiptIds[i]);
delete providerMap[msg.sender][receiptId];
unchecked {
++i;
}
}
}
/**
* @inheritdoc IChromaticLiquidityCallback
*/
function removeLiquidityCallback(
address clbToken,
uint256 clbTokenId,
bytes calldata data
) external override verifyCallback {
RemoveLiquidityCallbackData memory callbackData = abi.decode(
data,
(RemoveLiquidityCallbackData)
);
IERC1155(clbToken).safeTransferFrom(
callbackData.provider,
msg.sender, // market
clbTokenId,
callbackData.clbTokenAmount,
bytes("")
);
}
/**
* @inheritdoc IChromaticLiquidityCallback
*/
function removeLiquidityBatchCallback(
address clbToken,
uint256[] calldata clbTokenIds,
bytes calldata data
) external override verifyCallback {
RemoveLiquidityBatchCallbackData memory callbackData = abi.decode(
data,
(RemoveLiquidityBatchCallbackData)
);
IERC1155(clbToken).safeBatchTransferFrom(
callbackData.provider,
msg.sender, // market
clbTokenIds,
callbackData.clbTokenAmounts,
bytes("")
);
}
/**
* @inheritdoc IChromaticLiquidityCallback
*/
function withdrawLiquidityCallback(
uint256 receiptId,
int16,
uint256,
uint256,
bytes calldata
) external override verifyCallback {
// address market = msg.sender; // save gas : MSTORE,MLOAD - 3, CALLER(msg.sender) - 2
address provider = providerMap[msg.sender][receiptId];
//slither-disable-next-line unused-return
receiptIds[msg.sender][provider].remove(receiptId);
delete providerMap[msg.sender][receiptId];
}
/**
* @inheritdoc IChromaticLiquidityCallback
*/
function withdrawLiquidityBatchCallback(
uint256[] calldata _receiptIds,
int16[] calldata,
uint256[] calldata,
uint256[] calldata,
bytes calldata
) external override verifyCallback {
// address market = msg.sender; // save gas : MSTORE,MLOAD - 3, CALLER(msg.sender) - 2
for (uint256 i; i < _receiptIds.length; ) {
uint256 receiptId = _receiptIds[i];
address provider = providerMap[msg.sender][receiptId];
//slither-disable-next-line unused-return
receiptIds[msg.sender][provider].remove(_receiptIds[i]);
delete providerMap[msg.sender][receiptId];
unchecked {
++i;
}
}
}
/**
* @inheritdoc IChromaticRouter
*/
function openPosition(
address market,
int256 qty,
uint256 takerMargin,
uint256 makerMargin,
uint256 maxAllowableTradingFee
) external override returns (OpenPositionInfo memory) {
return _openPosition(market, qty, takerMargin, makerMargin, maxAllowableTradingFee);
}
function _openPosition(
address market,
int256 qty,
uint256 takerMargin,
uint256 makerMargin,
uint256 maxAllowableTradingFee
) internal returns (OpenPositionInfo memory openPositionInfo) {
ChromaticAccount account = _getAccount(msg.sender);
openPositionInfo = account.openPosition(
market,
qty,
takerMargin,
makerMargin,
maxAllowableTradingFee
);
//slither-disable-next-line reentrancy-events
emit OpenPosition(
market,
msg.sender,
address(account),
openPositionInfo.tradingFee,
_calcUsdPrice(market, openPositionInfo.tradingFee)
);
}
/**
* @dev Calculates the price in USD for a specified amount of the settlement token in a ChromaticMarket.
* @param market The address of the ChromaticMarket contract.
* @param amount The amount of the settlement token.
* @return The price in USD as an int256.
*/
function _calcUsdPrice(address market, uint256 amount) internal view returns (uint256) {
IERC20Metadata settlementToken = IChromaticMarket(market).settlementToken();
IOracleProvider oracleProvider = IOracleProvider(
IChromaticMarketFactory(marketFactory).getSettlementTokenOracleProvider(
address(settlementToken)
)
);
int256 latestPrice = oracleProvider.currentVersion().price;
uint256 unsignedLatestPrice = uint256(latestPrice.max(0));
// token amount * oracle price / token decimals
return amount.mulDiv(unsignedLatestPrice, 10 ** settlementToken.decimals());
}
/**
* @inheritdoc IChromaticRouter
*/
function closePosition(address market, uint256 positionId) external override {
_getAccount(msg.sender).closePosition(market, positionId);
}
/**
* @inheritdoc IChromaticRouter
*/
function claimPosition(address market, uint256 positionId) external override {
_getAccount(msg.sender).claimPosition(market, positionId);
}
/**
* @inheritdoc IChromaticRouter
*/
function addLiquidity(
address market,
int16 feeRate,
uint256 amount,
address recipient
) external override returns (LpReceipt memory receipt) {
// address provider = msg.sender; // save gas : MSTORE,MLOAD - 3, CALLER(msg.sender) - 2
providerMap[market][receipt.id] = msg.sender;
receipt = IChromaticMarket(market).addLiquidity(
recipient,
feeRate,
abi.encode(AddLiquidityCallbackData({provider: msg.sender, amount: amount}))
);
//slither-disable-next-line unused-return
receiptIds[market][msg.sender].add(receipt.id);
}
/**
* @inheritdoc IChromaticRouter
* @dev This function allows the liquidity provider to claim their liquidity by calling the `claimLiquidity` function in the specified market contract.
*/
function claimLiquidity(address market, uint256 receiptId) external override {
IChromaticMarket(market).claimLiquidity(receiptId, bytes(""));
}
/**
* @inheritdoc IChromaticRouter
*/
function removeLiquidity(
address market,
int16 feeRate,
uint256 clbTokenAmount,
address recipient
) external override returns (LpReceipt memory receipt) {
// address provider = msg.sender; // save gas : MSTORE,MLOAD - 3, CALLER(msg.sender) - 2
providerMap[market][receipt.id] = msg.sender;
receipt = IChromaticMarket(market).removeLiquidity(
recipient,
feeRate,
abi.encode(
RemoveLiquidityCallbackData({provider: msg.sender, clbTokenAmount: clbTokenAmount})
)
);
//slither-disable-next-line unused-return
receiptIds[market][msg.sender].add(receipt.id);
}
/**
* @inheritdoc IChromaticRouter
* @dev This function allows the liquidity provider to withdraw their liquidity by calling the `withdrawLiquidity` function in the specified market contract.
*/
function withdrawLiquidity(address market, uint256 receiptId) external override {
IChromaticMarket(market).withdrawLiquidity(receiptId, bytes(""));
}
/**
* @dev Retrieves the account of the specified owner.
* @param owner The owner of the account.
* @return The account address.
*/
function _getAccount(address owner) internal view returns (ChromaticAccount) {
return ChromaticAccount(getAccount(owner));
}
/**
* @inheritdoc IChromaticRouter
*/
function getLpReceiptIds(address market) external view override returns (uint256[] memory) {
return getLpReceiptIds(market, msg.sender);
}
/**
* @inheritdoc IChromaticRouter
*/
function getLpReceiptIds(
address market,
address owner
) public view override returns (uint256[] memory) {
return receiptIds[market][owner].values();
}
/**
* @inheritdoc IChromaticRouter
*/
function addLiquidityBatch(
address market,
address recipient,
int16[] calldata feeRates,
uint256[] calldata amounts
) external override returns (LpReceipt[] memory lpReceipts) {
require(feeRates.length == amounts.length, "TradeRouter: invalid arguments");
uint256 totalAmount;
for (uint256 i; i < amounts.length; ) {
totalAmount += amounts[i];
unchecked {
++i;
}
}
// address provider = msg.sender; // save gas : MSTORE,MLOAD - 3, CALLER(msg.sender) - 2
lpReceipts = IChromaticMarket(market).addLiquidityBatch(
recipient,
feeRates,
amounts,
abi.encode(AddLiquidityBatchCallbackData({provider: msg.sender, amount: totalAmount}))
);
for (uint i; i < feeRates.length; ) {
uint256 receiptId = lpReceipts[i].id;
//slither-disable-next-line unused-return
receiptIds[market][msg.sender].add(receiptId);
//slither-disable-next-line reentrancy-benign
providerMap[market][receiptId] = msg.sender;
unchecked {
++i;
}
}
}
/**
* @inheritdoc IChromaticRouter
*/
function claimLiquidityBatch(address market, uint256[] calldata _receiptIds) external override {
IChromaticMarket(market).claimLiquidityBatch(_receiptIds, bytes(""));
}
/**
* @inheritdoc IChromaticRouter
*/
function removeLiquidityBatch(
address market,
address recipient,
int16[] calldata feeRates,
uint256[] calldata clbTokenAmounts
) external override returns (LpReceipt[] memory lpReceipts) {
require(feeRates.length == clbTokenAmounts.length, "TradeRouter: invalid arguments");
// address provider = msg.sender; // save gas : MSTORE,MLOAD - 3, CALLER(msg.sender) - 2
lpReceipts = IChromaticMarket(market).removeLiquidityBatch(
recipient,
feeRates,
clbTokenAmounts,
abi.encode(
RemoveLiquidityBatchCallbackData({
provider: msg.sender,
clbTokenAmounts: clbTokenAmounts
})
)
);
for (uint i; i < feeRates.length; ) {
uint256 receiptId = lpReceipts[i].id;
//slither-disable-next-line unused-return
receiptIds[market][msg.sender].add(receiptId);
//slither-disable-next-line reentrancy-benign
providerMap[market][receiptId] = msg.sender;
unchecked {
++i;
}
}
}
/**
* @inheritdoc IChromaticRouter
*/
function withdrawLiquidityBatch(
address market,
uint256[] calldata _receiptIds
) external override {
IChromaticMarket(market).withdrawLiquidityBatch(_receiptIds, bytes(""));
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/Clones.sol)
pragma solidity ^0.8.0;
/**
* @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
* deploying minimal proxy contracts, also known as "clones".
*
* > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
* > a minimal bytecode implementation that delegates all calls to a known, fixed address.
*
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
* deterministic method.
*
* _Available since v3.4._
*/
library Clones {
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create opcode, which should never revert.
*/
function clone(address implementation) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create(0, 0x09, 0x37)
}
require(instance != address(0), "ERC1167: create failed");
}
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `implementation` and `salt` multiple time will revert, since
* the clones cannot be deployed twice at the same address.
*/
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create2(0, 0x09, 0x37, salt)
}
require(instance != address(0), "ERC1167: create2 failed");
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(add(ptr, 0x38), deployer)
mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
mstore(add(ptr, 0x14), implementation)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
mstore(add(ptr, 0x58), salt)
mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
predicted := keccak256(add(ptr, 0x43), 0x55)
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt
) internal view returns (address predicted) {
return predictDeterministicAddress(implementation, salt, address(this));
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;
uint256 constant BPS = 10000;
uint256 constant FEE_RATES_LENGTH = 36;
uint256 constant PRICE_PRECISION = 1e18;
// 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: BUSL-1.1
pragma solidity 0.8.19;
/**
* @title Errors
* @dev This library provides a set of error codes as string constants for handling exceptions and revert messages in the library.
*/
library Errors {
/**
* @dev Error code indicating that there is not enough free liquidity available in liquidity pool when open a new poisition.
*/
string constant NOT_ENOUGH_FREE_LIQUIDITY = "NEFL";
/**
* @dev Error code indicating that the specified amount is too small when add liquidity to each bin.
*/
string constant TOO_SMALL_AMOUNT = "TSA";
/**
* @dev Error code indicating that the provided oracle version is invalid or unsupported.
*/
string constant INVALID_ORACLE_VERSION = "IOV";
/**
* @dev Error code indicating that the specified value exceeds the allowed margin range when claim a position.
*/
string constant EXCEED_MARGIN_RANGE = "IOV";
/**
* @dev Error code indicating that the provided trading fee rate is not supported.
*/
string constant UNSUPPORTED_TRADING_FEE_RATE = "UTFR";
/**
* @dev Error code indicating that the oracle provider is already registered.
*/
string constant ALREADY_REGISTERED_ORACLE_PROVIDER = "ARO";
/**
* @dev Error code indicating that the settlement token is already registered.
*/
string constant ALREADY_REGISTERED_TOKEN = "ART";
/**
* @dev Error code indicating that the settlement token is not registered.
*/
string constant UNREGISTERED_TOKEN = "URT";
/**
* @dev Error code indicating that the interest rate has not been initialized.
*/
string constant INTEREST_RATE_NOT_INITIALIZED = "IRNI";
/**
* @dev Error code indicating that the provided interest rate exceeds the maximum allowed rate.
*/
string constant INTEREST_RATE_OVERFLOW = "IROF";
/**
* @dev Error code indicating that the provided timestamp for an interest rate is in the past.
*/
string constant INTEREST_RATE_PAST_TIMESTAMP = "IRPT";
/**
* @dev Error code indicating that the provided interest rate record cannot be appended to the existing array.
*/
string constant INTEREST_RATE_NOT_APPENDABLE = "IRNA";
/**
* @dev Error code indicating that an interest rate has already been applied and cannot be modified further.
*/
string constant INTEREST_RATE_ALREADY_APPLIED = "IRAA";
/**
* @dev Error code indicating that the position is unsettled.
*/
string constant UNSETTLED_POSITION = "USP";
/**
* @dev Error code indicating that the position quantity is invalid.
*/
string constant INVALID_POSITION_QTY = "IPQ";
/**
* @dev Error code indicating that the oracle price is not positive.
*/
string constant NOT_POSITIVE_PRICE = "NPP";
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {IERC1155} from "@openzeppelin/contracts/interfaces/IERC1155.sol";
import {IERC1155MetadataURI} from "@openzeppelin/contracts/interfaces/IERC1155MetadataURI.sol";
/**
* @title ICLBToken
* @dev Interface for CLBToken contract, which represents Liquidity Bin tokens.
*/
interface ICLBToken is IERC1155, IERC1155MetadataURI {
/**
* @dev Total amount of tokens in with a given id.
* @param id The token ID for which to retrieve the total supply.
* @return The total supply of tokens for the given token ID.
*/
function totalSupply(uint256 id) external view returns (uint256);
/**
* @dev Total amounts of tokens in with the given ids.
* @param ids The token IDs for which to retrieve the total supply.
* @return The total supples of tokens for the given token IDs.
*/
function totalSupplyBatch(uint256[] memory ids) external view returns (uint256[] memory);
/**
* @dev Mints new tokens and assigns them to the specified address.
* @param to The address to which the minted tokens will be assigned.
* @param id The token ID to mint.
* @param amount The amount of tokens to mint.
* @param data Additional data to pass during the minting process.
*/
function mint(address to, uint256 id, uint256 amount, bytes calldata data) external;
/**
* @dev Burns tokens from a specified address.
* @param from The address from which to burn tokens.
* @param id The token ID to burn.
* @param amount The amount of tokens to burn.
*/
function burn(address from, uint256 id, uint256 amount) external;
/**
* @dev Retrieves the number of decimals used for token amounts.
* @return The number of decimals used for token amounts.
*/
function decimals() external view returns (uint8);
/**
* @dev Retrieves the name of a token.
* @param id The token ID for which to retrieve the name.
* @return The name of the token.
*/
function name(uint256 id) external view returns (string memory);
/**
* @dev Retrieves the description of a token.
* @param id The token ID for which to retrieve the description.
* @return The description of the token.
*/
function description(uint256 id) external view returns (string memory);
/**
* @dev Retrieves the image URI of a token.
* @param id The token ID for which to retrieve the image URI.
* @return The image URI of the token.
*/
function image(uint256 id) external view returns (string memory);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {IChromaticTradeCallback} from "@chromatic-protocol/contracts/core/interfaces/callback/IChromaticTradeCallback.sol";
import {Position} from "@chromatic-protocol/contracts/core/libraries/Position.sol";
import {OpenPositionInfo, ClosePositionInfo, ClaimPositionInfo} from "@chromatic-protocol/contracts/core/interfaces/market/Types.sol";
/**
* @title IChromaticAccount
* @dev Interface for the ChromaticAccount contract, which manages user accounts and positions.
*/
interface IChromaticAccount is IChromaticTradeCallback {
/**
* @dev Emitted when a position is opened.
* @param marketAddress The address of the market.
* @param positionId The position identifier
* @param openVersion The version of the oracle when the position was opened
* @param qty The quantity of the position
* @param openTimestamp The timestamp when the position was opened
* @param takerMargin The amount of collateral that a trader must provide
* @param makerMargin The margin amount provided by the maker.
* @param tradingFee The trading fee associated with the position.
*/
event OpenPosition(
address indexed marketAddress,
uint256 indexed positionId,
uint256 openVersion,
int256 qty,
uint256 openTimestamp,
uint256 takerMargin,
uint256 makerMargin,
uint256 tradingFee
);
/**
* @dev Emitted when a position is closed.
* @param marketAddress The address of the market.
* @param positionId The position identifier
* @param closeVersion The version of the oracle when the position was closed
* @param closeTimestamp The timestamp when the position was closed
*/
event ClosePosition(
address indexed marketAddress,
uint256 indexed positionId,
uint256 closeVersion,
uint256 closeTimestamp
);
/**
* @dev Emitted when a position is claimed.
* @param marketAddress The address of the market.
* @param positionId The position identifier
* @param entryPrice The entry price of the position
* @param exitPrice The exit price of the position
* @param realizedPnl The profit or loss of the claimed position.
* @param interest The interest paid for the claimed position.
* @param cause The description of being claimed.
*/
event ClaimPosition(
address indexed marketAddress,
uint256 indexed positionId,
uint256 entryPrice,
uint256 exitPrice,
int256 realizedPnl,
uint256 interest,
bytes4 cause
);
/**
* @notice Returns the balance of the specified token for the account.
* @param token The address of the token.
* @return The balance of the token.
*/
function balance(address token) external view returns (uint256);
/**
* @notice Withdraws the specified amount of tokens from the account.
* @param token The address of the token to withdraw.
* @param amount The amount of tokens to withdraw.
*/
function withdraw(address token, uint256 amount) external;
/**
* @notice Checks if the specified market has the specified position ID.
* @param marketAddress The address of the market.
* @param positionId The ID of the position.
* @return A boolean indicating whether the market has the position ID.
*/
function hasPositionId(address marketAddress, uint256 positionId) external view returns (bool);
/**
* @notice Retrieves an array of position IDs owned by this account for the specified market.
* @param marketAddress The address of the market.
* @return An array of position IDs.
*/
function getPositionIds(address marketAddress) external view returns (uint256[] memory);
/**
* @notice Opens a new position in the specified market.
* @param marketAddress The address of the market.
* @param qty The quantity of the position.
* @param takerMargin The margin required for the taker.
* @param makerMargin The margin required for the maker.
* @param maxAllowableTradingFee The maximum allowable trading fee.
* @return openPositionInfo The opened position information.
*/
function openPosition(
address marketAddress,
int256 qty,
uint256 takerMargin,
uint256 makerMargin,
uint256 maxAllowableTradingFee
) external returns (OpenPositionInfo memory);
/**
* @notice Closes the specified position in the specified market.
* @param marketAddress The address of the market.
* @param positionId The ID of the position to close.
*/
function closePosition(address marketAddress, uint256 positionId) external;
/**
* @notice Claims the specified position in the specified market.
* @param marketAddress The address of the market.
* @param positionId The ID of the position to claim.
*/
function claimPosition(address marketAddress, uint256 positionId) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
/**
* @title IChromaticLiquidityCallback
* @dev Interface for a contract that handles liquidity callbacks in the Chromatic protocol.
* Liquidity callbacks are used to handle various operations related to liquidity management.
* This interface defines the function signatures for different types of liquidity callbacks.
*/
interface IChromaticLiquidityCallback {
/**
* @notice Handles the callback after adding liquidity to the Chromatic protocol.
* @param settlementToken The address of the settlement token used for adding liquidity.
* @param vault The address of the vault where the liquidity is added.
* @param data Additional data associated with the liquidity addition.
*/
function addLiquidityCallback(
address settlementToken,
address vault,
bytes calldata data
) external;
/**
* @notice Handles the callback after adding liquidity to the Chromatic protocol.
* @param settlementToken The address of the settlement token used for adding liquidity.
* @param vault The address of the vault where the liquidity is added.
* @param data Additional data associated with the liquidity addition.
*/
function addLiquidityBatchCallback(
address settlementToken,
address vault,
bytes calldata data
) external;
/**
* @notice Handles the callback after claiming liquidity from the Chromatic protocol.
* @param receiptId The ID of the liquidity claim receipt.
* @param feeRate The trading fee rate associated with the liquidity claim.
* @param depositedAmount The amount of liquidity deposited.
* @param mintedCLBTokenAmount The amount of CLB tokens minted as liquidity.
* @param data Additional data associated with the liquidity claim.
*/
function claimLiquidityCallback(
uint256 receiptId,
int16 feeRate,
uint256 depositedAmount,
uint256 mintedCLBTokenAmount,
bytes calldata data
) external;
/**
* @notice Handles the callback after claiming liquidity from the Chromatic protocol.
* @param receiptIds The array of the liquidity receipt IDs.
* @param feeRates The array of trading fee rates associated with each claim in the batch.
* @param depositedAmounts The array of deposited liquidity amounts for each receipt in the batch.
* @param mintedCLBTokenAmounts The array of CLB token amounts minted for each receipt in the batch.
* @param data Additional data associated with the liquidity claim.
*/
function claimLiquidityBatchCallback(
uint256[] calldata receiptIds,
int16[] calldata feeRates,
uint256[] calldata depositedAmounts,
uint256[] calldata mintedCLBTokenAmounts,
bytes calldata data
) external;
/**
* @notice Handles the callback after removing liquidity from the Chromatic protocol.
* @param clbToken The address of the Chromatic liquidity token.
* @param clbTokenId The ID of the Chromatic liquidity token to be removed.
* @param data Additional data associated with the liquidity removal.
*/
function removeLiquidityCallback(
address clbToken,
uint256 clbTokenId,
bytes calldata data
) external;
/**
* @notice Handles the callback after removing liquidity from the Chromatic protocol.
* @param clbToken The address of the Chromatic liquidity token.
* @param clbTokenIds The array of the Chromatic liquidity token IDs to be removed.
* @param data Additional data associated with the liquidity removal.
*/
function removeLiquidityBatchCallback(
address clbToken,
uint256[] calldata clbTokenIds,
bytes calldata data
) external;
/**
* @notice Handles the callback after withdrawing liquidity from the Chromatic protocol.
* @param receiptId The ID of the liquidity withdrawal receipt.
* @param feeRate The trading fee rate associated with the liquidity withdrawal.
* @param withdrawnAmount The amount of liquidity that has been withdrawn.
* @param burnedCLBTokenAmount The amount of CLB tokens burned during the withdrawal.
* @param data Additional data associated with the liquidity withdrawal.
*/
function withdrawLiquidityCallback(
uint256 receiptId,
int16 feeRate,
uint256 withdrawnAmount,
uint256 burnedCLBTokenAmount,
bytes calldata data
) external;
/**
* @notice Handles the callback after withdrawing liquidity from the Chromatic protocol.
* @param receiptIds The array of the liquidity receipt IDs.
* @param feeRates The array of trading fee rates associated with each withdrawal in the batch.
* @param withdrawnAmounts The array of withdrawn liquidity amounts for each receipt in the batch.
* @param burnedCLBTokenAmounts The array of CLB token amounts burned for each receipt in the batch.
* @param data Additional data associated with the liquidity withdrawal.
*/
function withdrawLiquidityBatchCallback(
uint256[] calldata receiptIds,
int16[] calldata feeRates,
uint256[] calldata withdrawnAmounts,
uint256[] calldata burnedCLBTokenAmounts,
bytes calldata data
) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {IMarketTradeOpenPosition} from "@chromatic-protocol/contracts/core/interfaces/market/IMarketTradeOpenPosition.sol";
import {IMarketTradeClosePosition} from "@chromatic-protocol/contracts/core/interfaces/market/IMarketTradeClosePosition.sol";
import {IMarketAddLiquidity} from "@chromatic-protocol/contracts/core/interfaces/market/IMarketAddLiquidity.sol";
import {IMarketRemoveLiquidity} from "@chromatic-protocol/contracts/core/interfaces/market/IMarketRemoveLiquidity.sol";
import {IMarketLens} from "@chromatic-protocol/contracts/core/interfaces/market/IMarketLens.sol";
import {IMarketState} from "@chromatic-protocol/contracts/core/interfaces/market/IMarketState.sol";
import {IMarketLiquidate} from "@chromatic-protocol/contracts/core/interfaces/market/IMarketLiquidate.sol";
import {IMarketSettle} from "@chromatic-protocol/contracts/core/interfaces/market/IMarketSettle.sol";
import {IMarketEvents} from "@chromatic-protocol/contracts/core/interfaces/market/IMarketEvents.sol";
import {IMarketErrors} from "@chromatic-protocol/contracts/core/interfaces/market/IMarketErrors.sol";
/**
* @title IChromaticMarket
* @dev Interface for the Chromatic Market contract, which combines trade and liquidity functionalities.
*/
interface IChromaticMarket is
IMarketEvents,
IMarketErrors,
IMarketTradeOpenPosition,
IMarketTradeClosePosition,
IMarketAddLiquidity,
IMarketRemoveLiquidity,
IMarketLens,
IMarketState,
IMarketLiquidate,
IMarketSettle
{
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {IInterestCalculator} from "@chromatic-protocol/contracts/core/interfaces/IInterestCalculator.sol";
import {IMarketDeployer} from "@chromatic-protocol/contracts/core/interfaces/factory/IMarketDeployer.sol";
import {ISettlementTokenRegistry} from "@chromatic-protocol/contracts/core/interfaces/factory/ISettlementTokenRegistry.sol";
import {IOracleProviderRegistry} from "@chromatic-protocol/contracts/core/interfaces/factory/IOracleProviderRegistry.sol";
/**
* @title IChromaticMarketFactory
* @dev Interface for the Chromatic Market Factory contract.
*/
interface IChromaticMarketFactory is
IMarketDeployer,
IOracleProviderRegistry,
ISettlementTokenRegistry,
IInterestCalculator
{
/**
* @notice Emitted when the DAO address is updated.
* @param daoOld The old DAO address.
* @param daoNew The new DAO address.
*/
event DaoUpdated(address indexed daoOld, address indexed daoNew);
/**
* @notice Emitted when the DAO treasury address is updated.
* @param treasuryOld The old DAO treasury address.
* @param treasuryNew The new DAO treasury address.
*/
event TreasuryUpdated(address indexed treasuryOld, address indexed treasuryNew);
/**
* @notice Emitted when the liquidator address is updated.
* @param liquidatorOld The old liquidator address.
* @param liquidatorNew The new liquidator address.
*/
event LiquidatorUpdated(address indexed liquidatorOld, address indexed liquidatorNew);
/**
* @notice Emitted when the keeper fee payer address is updated.
* @param keeperFeePayerOld The old keeper fee payer address.
* @param keeperFeePayerNew The new keeper fee payer address.
*/
event KeeperFeePayerUpdated(
address indexed keeperFeePayerOld,
address indexed keeperFeePayerNew
);
/**
* @notice Emitted when the default protocol fee rate is updated.
* @param defaultProtocolFeeRateOld The old default protocol fee rate.
* @param defaultProtocolFeeRateNew The new default protocol fee rate.
*/
event DefaultProtocolFeeRateUpdated(
uint16 indexed defaultProtocolFeeRateOld,
uint16 indexed defaultProtocolFeeRateNew
);
/**
* @notice Emitted when the vault address is set.
* @param vault The vault address.
*/
event VaultSet(address indexed vault);
/**
* @notice Emitted when the market settlement task address is updated.
* @param marketSettlementOld The old market settlement task address.
* @param marketSettlementNew The new market settlement task address.
*/
event MarketSettlementUpdated(
address indexed marketSettlementOld,
address indexed marketSettlementNew
);
/**
* @notice Emitted when a market is created.
* @param oracleProvider The address of the oracle provider.
* @param settlementToken The address of the settlement token.
* @param market The address of the created market.
*/
event MarketCreated(
address indexed oracleProvider,
address indexed settlementToken,
address indexed market
);
/**
* @notice Returns the address of the DAO.
* @return The address of the DAO.
*/
function dao() external view returns (address);
/**
* @notice Returns the address of the DAO treasury.
* @return The address of the DAO treasury.
*/
function treasury() external view returns (address);
/**
* @notice Returns the address of the liquidator.
* @return The address of the liquidator.
*/
function liquidator() external view returns (address);
/**
* @notice Returns the address of the vault.
* @return The address of the vault.
*/
function vault() external view returns (address);
/**
* @notice Returns the address of the keeper fee payer.
* @return The address of the keeper fee payer.
*/
function keeperFeePayer() external view returns (address);
/**
* @notice Returns the address of the market settlement task.
* @return The address of the market settlement task.
*/
function marketSettlement() external view returns (address);
/**
* @notice Returns the default protocol fee rate.
* @return The default protocol fee rate.
*/
function defaultProtocolFeeRate() external view returns (uint16);
/**
* @notice Updates the DAO address.
* @param _dao The new DAO address.
*/
function updateDao(address _dao) external;
/**
* @notice Updates the DAO treasury address.
* @param _treasury The new DAO treasury address.
*/
function updateTreasury(address _treasury) external;
/**
* @notice Updates the liquidator address.
* @param _liquidator The new liquidator address.
*/
function updateLiquidator(address _liquidator) external;
/**
* @notice Updates the keeper fee payer address.
* @param _keeperFeePayer The new keeper fee payer address.
*/
function updateKeeperFeePayer(address _keeperFeePayer) external;
/**
* @notice Updates the default protocl fee rate.
* @param _defaultProtocolFeeRate The new default protocol fee rate.
*/
function updateDefaultProtocolFeeRate(uint16 _defaultProtocolFeeRate) external;
/**
* @notice Sets the vault address.
* @param _vault The vault address.
*/
function setVault(address _vault) external;
/**
* @notice Updates the market settlement task address.
* @param _marketSettlement The new market settlement task address.
*/
function updateMarketSettlement(address _marketSettlement) external;
/**
* @notice Returns an array of all market addresses.
* @return markets An array of all market addresses.
*/
function getMarkets() external view returns (address[] memory markets);
/**
* @notice Returns an array of market addresses associated with a settlement token.
* @param settlementToken The address of the settlement token.
* @return An array of market addresses.
*/
function getMarketsBySettlmentToken(
address settlementToken
) external view returns (address[] memory);
/**
* @notice Returns the address of a market associated with an oracle provider and settlement token.
* @param oracleProvider The address of the oracle provider.
* @param settlementToken The address of the settlement token.
* @return The address of the market.
*/
function getMarket(
address oracleProvider,
address settlementToken
) external view returns (address);
/**
* @notice Creates a new market associated with an oracle provider and settlement token.
* @param oracleProvider The address of the oracle provider.
* @param settlementToken The address of the settlement token.
*/
function createMarket(address oracleProvider, address settlementToken) external;
/**
* @notice Checks if a market is registered.
* @param market The address of the market.
* @return True if the market is registered, false otherwise.
*/
function isRegisteredMarket(address market) external view returns (bool);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {IChromaticLiquidityCallback} from "@chromatic-protocol/contracts/core/interfaces/callback/IChromaticLiquidityCallback.sol";
import {Position} from "@chromatic-protocol/contracts/core/libraries/Position.sol";
import {LpReceipt} from "@chromatic-protocol/contracts/core/libraries/LpReceipt.sol";
import {OpenPositionInfo} from "@chromatic-protocol/contracts/core/interfaces/market/IMarketTradeOpenPosition.sol";
/**
* @title IChromaticRouter
* @dev Interface for the ChromaticRouter contract.
*/
interface IChromaticRouter is IChromaticLiquidityCallback {
/**
* @dev Emitted when a position is opened.
* @param marketAddress The address of the market.
* @param trader The owner of The account
* @param account The account The address of the account opening the position.
* @param tradingFee The trading fee associated with the position.
* @param tradingFeeUSD The trading fee in USD
*/
event OpenPosition(
address indexed marketAddress,
address indexed trader,
address indexed account,
uint256 tradingFee,
uint256 tradingFeeUSD
);
/**
* @dev Emitted when a new account is created.
* @param account The address of the created account.
* @param owner The address of the owner of the created account.
*/
event AccountCreated(address indexed account, address indexed owner);
/**
* @dev Opens a new position in a ChromaticMarket contract.
* @param market The address of the ChromaticMarket contract.
* @param qty The quantity of the position.
* @param takerMargin The margin amount for the taker.
* @param makerMargin The margin amount for the maker.
* @param maxAllowableTradingFee The maximum allowable trading fee.
* @return position The new position.
*/
function openPosition(
address market,
int256 qty,
uint256 takerMargin,
uint256 makerMargin,
uint256 maxAllowableTradingFee
) external returns (OpenPositionInfo memory);
/**
* @notice Closes a position in a ChromaticMarket contract.
* @param market The address of the ChromaticMarket contract.
* @param positionId The ID of the position to close.
*/
function closePosition(address market, uint256 positionId) external;
/**
* @notice Claims a position from a ChromaticMarket contract.
* @param market The address of the ChromaticMarket contract.
* @param positionId The ID of the position to claim.
*/
function claimPosition(address market, uint256 positionId) external;
/**
* @notice Adds liquidity to a ChromaticMarket contract.
* @param market The address of the ChromaticMarket contract.
* @param feeRate The fee rate of the liquidity bin.
* @param amount The amount to add as liquidity.
* @param recipient The recipient address.
* @return receipt The LP receipt.
*/
function addLiquidity(
address market,
int16 feeRate,
uint256 amount,
address recipient
) external returns (LpReceipt memory);
/**
* @notice Claims liquidity from a ChromaticMarket contract.
* @param market The address of the ChromaticMarket contract.
* @param receiptId The ID of the LP receipt.
*/
function claimLiquidity(address market, uint256 receiptId) external;
/**
* @notice Removes liquidity from a ChromaticMarket contract.
* @param market The address of the ChromaticMarket contract.
* @param feeRate The fee rate of the liquidity bin.
* @param clbTokenAmount The amount of CLB tokens to remove as liquidity.
* @param recipient The recipient address.
* @return receipt The LP receipt.
*/
function removeLiquidity(
address market,
int16 feeRate,
uint256 clbTokenAmount,
address recipient
) external returns (LpReceipt memory);
/**
* @notice Withdraws liquidity from a ChromaticMarket contract.
* @param market The address of the ChromaticMarket contract.
* @param receiptId The ID of the LP receipt.
*/
function withdrawLiquidity(address market, uint256 receiptId) external;
/**
* @notice Creates a new user account.
* @dev Only one account can be created per user.
* Emits an `AccountCreated` event upon successful creation.
*/
function createAccount() external;
/**
* @notice Retrieves the account of the caller.
* @return The account address.
*/
function getAccount() external view returns (address);
/**
* @notice Retrieves the LP receipt IDs of the caller for the specified market.
* @param market The address of the ChromaticMarket contract.
* @return An array of LP receipt IDs.
*/
function getLpReceiptIds(address market) external view returns (uint256[] memory);
/**
* @notice Get the LP receipt IDs associated with a specific market and owner.
* @param market The address of the ChromaticMarket contract.
* @param owner The address of the owner.
* @return An array of LP receipt IDs.
*/
function getLpReceiptIds(
address market,
address owner
) external view returns (uint256[] memory);
/**
* @notice Adds liquidity to multiple liquidity bins of ChromaticMarket contract in a batch.
* @param market The address of the ChromaticMarket contract.
* @param recipient The address of the recipient for each liquidity bin.
* @param feeRates An array of fee rates for each liquidity bin.
* @param amounts An array of amounts to add as liquidity for each bin.
* @return lpReceipts An array of LP receipts.
*/
function addLiquidityBatch(
address market,
address recipient,
int16[] calldata feeRates,
uint256[] calldata amounts
) external returns (LpReceipt[] memory lpReceipts);
/**
* @notice Claims liquidity from multiple ChromaticMarket contracts in a batch.
* @param market The address of the ChromaticMarket contract.
* @param receiptIds An array of LP receipt IDs to claim liquidity from.
*/
function claimLiquidityBatch(address market, uint256[] calldata receiptIds) external;
/**
* @notice Removes liquidity from multiple ChromaticMarket contracts in a batch.
* @param market The address of the ChromaticMarket contract.
* @param recipient The address of the recipient for each liquidity bin.
* @param feeRates An array of fee rates for each liquidity bin.
* @param clbTokenAmounts An array of CLB token amounts to remove as liquidity for each bin.
* @return lpReceipts An array of LP receipts.
*/
function removeLiquidityBatch(
address market,
address recipient,
int16[] calldata feeRates,
uint256[] calldata clbTokenAmounts
) external returns (LpReceipt[] memory lpReceipts);
/**
* @notice Withdraws liquidity from multiple ChromaticMarket contracts in a batch.
* @param market The address of the ChromaticMarket contract.
* @param receiptIds An array of LP receipt IDs to withdraw liquidity from.
*/
function withdrawLiquidityBatch(address market, uint256[] calldata receiptIds) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {Position} from "@chromatic-protocol/contracts/core/libraries/Position.sol";
import {ClaimPositionInfo} from "@chromatic-protocol/contracts/core/interfaces/market/Types.sol";
/**
* @title IChromaticTradeCallback
* @dev The interface for handling callbacks related to Chromatic trading operations.
*/
interface IChromaticTradeCallback {
/**
* @notice Callback function called after opening a position.
* @param settlementToken The address of the settlement token used in the position.
* @param vault The address of the vault contract.
* @param marginRequired The amount of margin required for the position.
* @param data Additional data related to the callback.
*/
function openPositionCallback(
address settlementToken,
address vault,
uint256 marginRequired,
bytes calldata data
) external;
/**
* @notice Callback function called after claiming a position.
* @param position The claimed position.
* @param claimInfo The pnl related information of the claim
* @param data Additional data related to the callback.
*/
function claimPositionCallback(
Position memory position,
ClaimPositionInfo memory claimInfo,
bytes calldata data
) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {ILendingPool} from "@chromatic-protocol/contracts/core/interfaces/vault/ILendingPool.sol";
import {IVault} from "@chromatic-protocol/contracts/core/interfaces/vault/IVault.sol";
/**
* @title IChromaticVault
* @notice Interface for the Chromatic Vault contract.
*/
interface IChromaticVault is IVault, ILendingPool {
/**
* @dev Emitted when market earning is accumulated.
* @param market The address of the market.
* @param earning The amount of earning accumulated.
*/
event MarketEarningAccumulated(address indexed market, uint256 earning);
/**
* @dev Emitted when maker earning is distributed.
* @param token The address of the settlement token.
* @param earning The amount of earning distributed.
* @param usedKeeperFee The amount of keeper fee used.
*/
event MakerEarningDistributed(
address indexed token,
uint256 indexed earning,
uint256 indexed usedKeeperFee
);
/**
* @dev Emitted when market earning is distributed.
* @param market The address of the market.
* @param earning The amount of earning distributed.
* @param usedKeeperFee The amount of keeper fee used.
* @param marketBalance The balance of the market.
*/
event MarketEarningDistributed(
address indexed market,
uint256 indexed earning,
uint256 indexed usedKeeperFee,
uint256 marketBalance
);
/**
* @notice Emitted when the vault earning distributor address is set.
* @param vaultEarningDistributor The vault earning distributor address.
* @param oldVaultEarningDistributor The old vault earning distributor address.
*/
event VaultEarningDistributorSet(
address indexed vaultEarningDistributor,
address indexed oldVaultEarningDistributor
);
function setVaultEarningDistributor(address _earningDistributor) external;
function pendingMakerEarnings(address token) external view returns (uint256);
function pendingMarketEarnings(address market) external view returns (uint256);
/**
* @notice Creates a maker earning distribution task for a token.
* @param token The address of the settlement token.
*/
function createMakerEarningDistributionTask(address token) external;
/**
* @notice Cancels a maker earning distribution task for a token.
* @param token The address of the settlement token.
*/
function cancelMakerEarningDistributionTask(address token) external;
/**
* @notice Distributes the maker earning for a token to the each markets.
* @param token The address of the settlement token.
* @param fee The keeper fee amount.
* @param keeper The keeper address to receive fee.
*/
function distributeMakerEarning(address token, uint256 fee, address keeper) external;
/**
* @notice Creates a market earning distribution task for a market.
* @param market The address of the market.
*/
function createMarketEarningDistributionTask(address market) external;
/**
* @notice Cancels a market earning distribution task for a market.
* @param market The address of the market.
*/
function cancelMarketEarningDistributionTask(address market) external;
/**
* @notice Distributes the market earning for a market to the each bins.
* @param market The address of the market.
* @param fee The fee amount.
* @param keeper The keeper address to receive fee.
*/
function distributeMarketEarning(address market, uint256 fee, address keeper) external;
function acquireTradingLock() external;
function releaseTradingLock() external;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/IERC1155.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
*/
interface IERC1155 is IERC165 {
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/**
* @dev Returns the amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) external view returns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(
address[] calldata accounts,
uint256[] calldata ids
) external view returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1155MetadataURI.sol)
pragma solidity ^0.8.0;
import "../token/ERC1155/extensions/IERC1155MetadataURI.sol";
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol)
pragma solidity ^0.8.0;
import "../utils/introspection/IERC165.sol";
// 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 v4.4.1 (interfaces/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../token/ERC20/extensions/IERC20Metadata.sol";
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (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.
*/
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].
*/
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
pragma solidity 0.8.19;
/**
* @title IInterestCalculator
* @dev Interface for an interest calculator contract.
*/
interface IInterestCalculator {
/**
* @notice Calculates the interest accrued for a given token and amount within a specified time range.
* @param token The address of the token.
* @param amount The amount of the token.
* @param from The starting timestamp (inclusive) of the time range.
* @param to The ending timestamp (exclusive) of the time range.
* @return The accrued interest for the specified token and amount within the given time range.
*/
function calculateInterest(
address token,
uint256 amount,
uint256 from, // timestamp (inclusive)
uint256 to // timestamp (exclusive)
) external view returns (uint256);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
/**
* @title ILendingPool
* @dev Interface for a lending pool contract.
*/
interface ILendingPool {
/**
* @notice Emitted when a flash loan is executed.
* @param sender The address initiating the flash loan.
* @param recipient The address receiving the flash loan.
* @param amount The amount of the flash loan.
* @param paid The amount paid back after the flash loan.
* @param paidToTakerPool The amount paid to the taker pool after the flash loan.
* @param paidToMakerPool The amount paid to the maker pool after the flash loan.
*/
event FlashLoan(
address indexed sender,
address indexed recipient,
uint256 indexed amount,
uint256 paid,
uint256 paidToTakerPool,
uint256 paidToMakerPool
);
/**
* @notice Executes a flash loan.
* @param token The address of the token for the flash loan.
* @param amount The amount of the flash loan.
* @param recipient The address to receive the flash loan.
* @param data Additional data for the flash loan.
*/
function flashLoan(
address token,
uint256 amount,
address recipient,
bytes calldata data
) external;
/**
* @notice Retrieves the pending share of earnings for a specific bin (subset) of funds in a market.
* @param market The address of the market.
* @param settlementToken The settlement token address.
* @param binBalance The balance of funds in the bin.
* @return The pending share of earnings for the specified bin.
*/
function getPendingBinShare(
address market,
address settlementToken,
uint256 binBalance
) external view returns (uint256);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {LpReceipt} from "@chromatic-protocol/contracts/core/libraries/LpReceipt.sol";
/**
* @title IMarketAddLiquidity
* @dev The interface for adding and claiming liquidity in a market.
*/
interface IMarketAddLiquidity {
/**
* @dev Adds liquidity to the market.
* @param recipient The address to receive the liquidity tokens.
* @param tradingFeeRate The trading fee rate for the liquidity.
* @param data Additional data for the liquidity callback.
* @return The liquidity receipt.
*/
function addLiquidity(
address recipient,
int16 tradingFeeRate,
bytes calldata data
) external returns (LpReceipt memory);
/**
* @notice Adds liquidity to multiple liquidity bins of the market in a batch.
* @param recipient The address of the recipient for each liquidity bin.
* @param tradingFeeRates An array of fee rates for each liquidity bin.
* @param amounts An array of amounts to add as liquidity for each bin.
* @param data Additional data for the liquidity callback.
* @return An array of LP receipts.
*/
function addLiquidityBatch(
address recipient,
int16[] calldata tradingFeeRates,
uint256[] calldata amounts,
bytes calldata data
) external returns (LpReceipt[] memory);
/**
* @dev Claims liquidity from a liquidity receipt.
* @param receiptId The ID of the liquidity receipt.
* @param data Additional data for the liquidity callback.
*/
function claimLiquidity(uint256 receiptId, bytes calldata data) external;
/**
* @dev Claims liquidity from a liquidity receipt.
* @param receiptIds The array of the liquidity receipt IDs.
* @param data Additional data for the liquidity callback.
*/
function claimLiquidityBatch(uint256[] calldata receiptIds, bytes calldata data) external;
/**
* @dev Distributes earning to the liquidity bins.
* @param earning The amount of earning to distribute.
* @param marketBalance The balance of the market.
*/
function distributeEarningToBins(uint256 earning, uint256 marketBalance) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
/**
* @title An interface for a contract that is capable of deploying Chromatic markets
* @notice A contract that constructs a market must implement this to pass arguments to the market
* @dev This is used to avoid having constructor arguments in the market contract, which results in the init code hash
* of the market being constant allowing the CREATE2 address of the market to be cheaply computed on-chain
*/
interface IMarketDeployer {
/**
* @notice Get the parameters to be used in constructing the market, set transiently during market creation.
* @dev Called by the market constructor to fetch the parameters of the market
* Returns underlyingAsset The underlying asset of the market
* Returns settlementToken The settlement token of the market
* Returns protocolFeeRate The protocol fee rate of the market
* Returns vPoolCapacity Capacity of virtual future pool
* Returns vPoolA Amplification coefficient of virtual future pool, precise value
*/
function parameters()
external
view
returns (address oracleProvider, address settlementToken, uint16 protocolFeeRate);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
/**
* @title IMarketErrors
*/
interface IMarketErrors {
/**
* @dev Throws an error indicating that the caller is not the DAO.
*/
error OnlyAccessableByDao();
/**
* @dev Throws an error indicating that the caller is nether the chormatic factory contract nor the DAO.
*/
error OnlyAccessableByFactoryOrDao();
/**
* @dev Throws an error indicating that the caller is not the chromatic liquidator contract.
*/
error OnlyAccessableByLiquidator();
/**
* @dev Throws an error indicating that the caller is not the chromatch vault contract.
*/
error OnlyAccessableByVault();
/**
* @dev Throws an error indicating that the amount of liquidity is too small.
* This error is thrown when attempting to remove liquidity with an amount of zero.
*/
error TooSmallAmount();
/**
* @dev Throws an error indicating that the specified liquidity receipt does not exist.
*/
error NotExistLpReceipt();
/**
* @dev Throws an error indicating that the liquidity receipt is not claimable.
*/
error NotClaimableLpReceipt();
/**
* @dev Throws an error indicating that the liquidity receipt is not withdrawable.
*/
error NotWithdrawableLpReceipt();
/**
* @dev Throws an error indicating that the liquidity receipt action is invalid.
*/
error InvalidLpReceiptAction();
/**
* @dev Throws an error indicating that the transferred token amount is invalid.
* This error is thrown when the transferred token amount does not match the expected amount.
*/
error InvalidTransferredTokenAmount();
error DuplicatedTradingFeeRate();
error AddLiquidityDisabled();
error RemoveLiquidityDisabled();
/**
* @dev Throws an error indicating that the taker margin provided is smaller than the minimum required margin for the specific settlement token.
* The minimum required margin is determined by the DAO and represents the minimum amount required for operations such as liquidation and payment of keeper fees.
*/
error TooSmallTakerMargin();
/**
* @dev Throws an error indicating that the margin settlement token balance does not increase by the required margin amount after the callback.
*/
error NotEnoughMarginTransferred();
/**
* @dev Throws an error indicating that the caller is not permitted to perform the action as they are not the owner of the position.
*/
error NotPermitted();
/**
* @dev Throws an error indicating that the total trading fee (including protocol fee) exceeds the maximum allowable trading fee.
*/
error ExceedMaxAllowableTradingFee();
/**
* @dev Throws an error indicating thatwhen the specified leverage exceeds the maximum allowable leverage level set by the Oracle Provider.
* Each Oracle Provider has a specific maximum allowable leverage level, which is determined by the DAO.
* The default maximum allowable leverage level is 0, which corresponds to a leverage of up to 10x.
*/
error ExceedMaxAllowableLeverage();
/**
* @dev Throws an error indicating that the maker margin value is not within the allowable range based on the absolute quantity and the specified minimum/maximum take-profit basis points (BPS).
* The maker margin must fall within the range calculated based on the absolute quantity of the position and the specified minimum/maximum take-profit basis points (BPS) set by the Oracle Provider.
* The default range for the minimum/maximum take-profit basis points is 10% to 1000%.
*/
error NotAllowableMakerMargin();
/**
* @dev Throws an error indicating that the requested position does not exist.
*/
error NotExistPosition();
/**
* @dev Throws an error indicating that an error occurred during the claim position callback.
*/
error ClaimPositionCallbackError();
/**
* @dev Throws an error indicating that the position has already been closed.
*/
error AlreadyClosedPosition();
/**
*@dev Throws an error indicating that the position is not claimable.
*/
error NotClaimablePosition();
error OpenPositionDisabled();
error ClosePositionDisabled();
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {Position} from "@chromatic-protocol/contracts/core/libraries/Position.sol";
import {LpReceipt} from "@chromatic-protocol/contracts/core/libraries/LpReceipt.sol";
import {PositionMode, LiquidityMode, DisplayMode} from "@chromatic-protocol/contracts/core/interfaces/market/Types.sol";
/**
* @title IMarketEvents
*/
interface IMarketEvents {
/**
* @notice Emitted when the protocol fee rate of the market is changed
* @param protocolFeeRateOld The previous value of the protocol fee rate
* @param protocolFeeRateNew The updated value of the protocol fee rate
*/
event ProtocolFeeRateUpdated(uint16 protocolFeeRateOld, uint16 protocolFeeRateNew);
/**
* @notice Emitted when the position mode of the market is changed
* @param positionModeOld The previous value of the position mode
* @param positionModeNew The updated value of the position mode
*/
event PositionModeUpdated(PositionMode positionModeOld, PositionMode positionModeNew);
/**
* @notice Emitted when the liquidity mode of the market is changed
* @param liquidityModeOld The previous value of the liquidity mode
* @param liquidityModeNew The updated value of the liquidity mode
*/
event LiquidityModeUpdated(LiquidityMode liquidityModeOld, LiquidityMode liquidityModeNew);
/**
* @notice Emitted when the display mode of the market is changed
* @param displayModeOld The previous value of the display mode
* @param displayModeNew The updated value of the display mode
*/
event DisplayModeUpdated(DisplayMode displayModeOld, DisplayMode displayModeNew);
/**
* @dev Emitted when liquidity is added to the market.
* @param receipt The liquidity receipt.
*/
event AddLiquidity(LpReceipt receipt);
/**
* @dev Emitted when liquidity is added to the market.
* @param receipts An array of LP receipts.
*/
event AddLiquidityBatch(LpReceipt[] receipts);
/**
* @dev Emitted when liquidity is claimed from the market.
* @param clbTokenAmount The amount of CLB tokens claimed.
* @param receipt The liquidity receipt.
*/
event ClaimLiquidity(LpReceipt receipt, uint256 indexed clbTokenAmount);
/**
* @dev Emitted when liquidity is claimed from the market.
* @param receipts An array of LP receipts.
* @param clbTokenAmounts The amount list of CLB tokens claimed.
*/
event ClaimLiquidityBatch(LpReceipt[] receipts, uint256[] clbTokenAmounts);
/**
* @dev Emitted when liquidity is removed from the market.
* @param receipt The liquidity receipt.
*/
event RemoveLiquidity(LpReceipt receipt);
/**
* @dev Emitted when liquidity is removed from the market.
* @param receipts An array of LP receipts.
*/
event RemoveLiquidityBatch(LpReceipt[] receipts);
/**
* @dev Emitted when liquidity is withdrawn from the market.
* @param receipt The liquidity receipt.
* @param amount The amount of liquidity withdrawn.
* @param burnedCLBTokenAmount The amount of burned CLB tokens.
*/
event WithdrawLiquidity(
LpReceipt receipt,
uint256 indexed amount,
uint256 indexed burnedCLBTokenAmount
);
/**
* @dev Emitted when liquidity is withdrawn from the market.
* @param receipts An array of LP receipts.
* @param amounts The amount list of liquidity withdrawn.
* @param burnedCLBTokenAmounts The amount list of burned CLB tokens.
*/
event WithdrawLiquidityBatch(
LpReceipt[] receipts,
uint256[] amounts,
uint256[] burnedCLBTokenAmounts
);
/**
* @dev Emitted when a position is opened.
* @param account The address of the account opening the position.
* @param position The opened position.
*/
event OpenPosition(address indexed account, Position position);
/**
* @dev Emitted when a position is closed.
* @param account The address of the account closing the position.
* @param position The closed position.
*/
event ClosePosition(address indexed account, Position position);
/**
* @dev Emitted when a position is claimed.
* @param account The address of the account claiming the position.
* @param pnl The profit or loss of the claimed position.
* @param interest The interest paid for the claimed position.
* @param position The claimed position.
*/
event ClaimPosition(
address indexed account,
int256 indexed pnl,
uint256 indexed interest,
Position position
);
/**
* @dev Emitted when a position is claimed by keeper.
* @param account The address of the account claiming the position.
* @param pnl The profit or loss of the claimed position.
* @param interest The interest paid for the claimed position.
* @param usedKeeperFee The amount of keeper fee used for the liquidation.
* @param position The claimed position.
*/
event ClaimPositionByKeeper(
address indexed account,
int256 indexed pnl,
uint256 indexed interest,
uint256 usedKeeperFee,
Position position
);
/**
* @dev Emitted when a position is liquidated.
* @param account The address of the account being liquidated.
* @param pnl The profit or loss of the claimed position.
* @param interest The interest paid for the claimed position.
* @param usedKeeperFee The amount of keeper fee used for the liquidation.
* @param position The liquidated position.
*/
event Liquidate(
address indexed account,
int256 indexed pnl,
uint256 indexed interest,
uint256 usedKeeperFee,
Position position
);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {PendingPosition, ClosingPosition, PendingLiquidity, ClaimableLiquidity, LiquidityBinStatus} from "@chromatic-protocol/contracts/core/interfaces/market/Types.sol";
import {LpReceipt} from "@chromatic-protocol/contracts/core/libraries/LpReceipt.sol";
import {Position} from "@chromatic-protocol/contracts/core/libraries/Position.sol";
/**
* @title IMarketLens
* @dev The interface for liquidity information retrieval in a market.
*/
interface IMarketLens {
/**
* @dev Retrieves the total liquidity amount for a specific trading fee rate in the liquidity pool.
* @param tradingFeeRate The trading fee rate for which to retrieve the liquidity amount.
* @return amount The total liquidity amount for the specified trading fee rate.
*/
function getBinLiquidity(int16 tradingFeeRate) external view returns (uint256 amount);
/**
* @dev Retrieves the available (free) liquidity amount for a specific trading fee rate in the liquidity pool.
* @param tradingFeeRate The trading fee rate for which to retrieve the available liquidity amount.
* @return amount The available (free) liquidity amount for the specified trading fee rate.
*/
function getBinFreeLiquidity(int16 tradingFeeRate) external view returns (uint256 amount);
/**
* @dev Retrieves the values of a specific trading fee rate's bins in the liquidity pool.
* The value of a bin represents the total valuation of the liquidity in the bin.
* @param tradingFeeRates The list of trading fee rate for which to retrieve the bin value.
* @return values The value list of the bins for the specified trading fee rates.
*/
function getBinValues(
int16[] calldata tradingFeeRates
) external view returns (uint256[] memory values);
/**
* @dev Retrieves the liquidity receipt with the given receipt ID.
* It throws NotExistLpReceipt if the specified receipt ID does not exist.
* @param receiptId The ID of the liquidity receipt to retrieve.
* @return receipt The liquidity receipt with the specified ID.
*/
function getLpReceipt(uint256 receiptId) external view returns (LpReceipt memory);
/**
* @dev Retrieves the liquidity receipts with the given receipt IDs.
* It throws NotExistLpReceipt if the specified receipt ID does not exist.
* @param receiptIds The ID list of the liquidity receipt to retrieve.
* @return receipts The liquidity receipt list with the specified IDs.
*/
function getLpReceipts(
uint256[] calldata receiptIds
) external view returns (LpReceipt[] memory);
/**
* @dev Retrieves the pending liquidity information for a specific trading fee rate from the associated LiquidityPool.
* @param tradingFeeRate The trading fee rate for which to retrieve the pending liquidity.
* @return pendingLiquidity An instance of PendingLiquidity representing the pending liquidity information.
*/
function pendingLiquidity(int16 tradingFeeRate) external view returns (PendingLiquidity memory);
/**
* @dev Retrieves the pending liquidity information for multiple trading fee rates from the associated LiquidityPool.
* @param tradingFeeRates The list of trading fee rates for which to retrieve the pending liquidity.
* @return pendingLiquidityBatch An array of PendingLiquidity instances representing the pending liquidity information for each trading fee rate.
*/
function pendingLiquidityBatch(
int16[] calldata tradingFeeRates
) external view returns (PendingLiquidity[] memory);
/**
* @dev Retrieves the claimable liquidity information for a specific trading fee rate and oracle version from the associated LiquidityPool.
* @param tradingFeeRate The trading fee rate for which to retrieve the claimable liquidity.
* @param oracleVersion The oracle version for which to retrieve the claimable liquidity.
* @return claimableLiquidity An instance of ClaimableLiquidity representing the claimable liquidity information.
*/
function claimableLiquidity(
int16 tradingFeeRate,
uint256 oracleVersion
) external view returns (ClaimableLiquidity memory);
/**
* @dev Retrieves the claimable liquidity information for multiple trading fee rates and a specific oracle version from the associated LiquidityPool.
* @param tradingFeeRates The list of trading fee rates for which to retrieve the claimable liquidity.
* @param oracleVersion The oracle version for which to retrieve the claimable liquidity.
* @return claimableLiquidityBatch An array of ClaimableLiquidity instances representing the claimable liquidity information for each trading fee rate.
*/
function claimableLiquidityBatch(
int16[] calldata tradingFeeRates,
uint256 oracleVersion
) external view returns (ClaimableLiquidity[] memory);
/**
* @dev Retrieves the liquidity bin statuses for the caller's liquidity pool.
* @return statuses An array of LiquidityBinStatus representing the liquidity bin statuses.
*/
function liquidityBinStatuses() external view returns (LiquidityBinStatus[] memory);
/**
* @dev Retrieves the position with the given position ID.
* It throws NotExistPosition if the specified position ID does not exist.
* @param positionId The ID of the position to retrieve.
* @return position The position with the specified ID.
*/
function getPosition(uint256 positionId) external view returns (Position memory);
/**
* @dev Retrieves multiple positions by their IDs.
* @param positionIds The IDs of the positions to retrieve.
* @return positions An array of retrieved positions.
*/
function getPositions(
uint256[] calldata positionIds
) external view returns (Position[] memory positions);
/**
* @dev Retrieves the pending position information for a specific trading fee rate from the associated LiquidityPool.
* @param tradingFeeRate The trading fee rate for which to retrieve the pending position.
* @return pendingPosition An instance of PendingPosition representing the pending position information.
*/
function pendingPosition(int16 tradingFeeRate) external view returns (PendingPosition memory);
/**
* @dev Retrieves the pending position information for multiple trading fee rates from the associated LiquidityPool.
* @param tradingFeeRates The list of trading fee rates for which to retrieve the pending position.
* @return pendingPositionBatch An array of PendingPosition instances representing the pending position information for each trading fee rate.
*/
function pendingPositionBatch(
int16[] calldata tradingFeeRates
) external view returns (PendingPosition[] memory);
/**
* @dev Retrieves the closing position information for a specific trading fee rate from the associated LiquidityPool.
* @param tradingFeeRate The trading fee rate for which to retrieve the closing position.
* @return closingPosition An instance of PendingPosition representing the closing position information.
*/
function closingPosition(int16 tradingFeeRate) external view returns (ClosingPosition memory);
/**
* @dev Retrieves the closing position information for multiple trading fee rates from the associated LiquidityPool.
* @param tradingFeeRates The list of trading fee rates for which to retrieve the closing position.
* @return pendingPositionBatch An array of PendingPosition instances representing the closing position information for each trading fee rate.
*/
function closingPositionBatch(
int16[] calldata tradingFeeRates
) external view returns (ClosingPosition[] memory);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {IOracleProvider} from "@chromatic-protocol/contracts/oracle/interfaces/IOracleProvider.sol";
/**
* @title IMarketLiquidate
* @dev Interface for liquidating and claiming positions in a market.
*/
interface IMarketLiquidate {
/**
* @dev Checks if a position is eligible for liquidation.
* @param positionId The ID of the position to check.
* @return A boolean indicating if the position is eligible for liquidation.
*/
function checkLiquidation(uint256 positionId) external view returns (bool);
/**
* @dev Checks if a position is eligible for liquidation.
* @param positionId The ID of the position to check.
* @param oracleVersion The oracle version data for liquidation check.
* @return A boolean indicating if the position is eligible for liquidation.
*/
function checkLiquidationWithOracleVersion(
uint256 positionId,
IOracleProvider.OracleVersion memory oracleVersion
) external view returns (bool);
/**
* @dev Liquidates a position.
* @param positionId The ID of the position to liquidate.
* @param keeper The address of the keeper performing the liquidation.
* @param keeperFee The native token amount of the keeper's fee.
*/
function liquidate(uint256 positionId, address keeper, uint256 keeperFee) external;
/**
* @dev Checks if a position is eligible for claim.
* @param positionId The ID of the position to check.
* @return A boolean indicating if the position is eligible for claim.
*/
function checkClaimPosition(uint256 positionId) external view returns (bool);
/**
* @dev Claims a closed position on behalf of a keeper.
* @param positionId The ID of the position to claim.
* @param keeper The address of the keeper claiming the position.
* @param keeperFee The native token amount of the keeper's fee.
*/
function claimPosition(uint256 positionId, address keeper, uint256 keeperFee) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {LpReceipt} from "@chromatic-protocol/contracts/core/libraries/LpReceipt.sol";
/**
* @title IMarketRemoveLiquidity
* @dev The interface for removing and withdrawing liquidity in a market.
*/
interface IMarketRemoveLiquidity {
/**
* @dev Removes liquidity from the market.
* @param recipient The address to receive the removed liquidity.
* @param tradingFeeRate The trading fee rate for the liquidity.
* @param data Additional data for the liquidity callback.
* @return The liquidity receipt.
*/
function removeLiquidity(
address recipient,
int16 tradingFeeRate,
bytes calldata data
) external returns (LpReceipt memory);
/**
* @dev Removes liquidity from the market.
* @param recipient The address to receive the removed liquidity.
* @param tradingFeeRates An array of fee rates for each liquidity bin.
* @param clbTokenAmounts An array of clb token amounts to remove as liquidity for each bin.
* @param data Additional data for the liquidity callback.
* @return The liquidity receipt.
*/
function removeLiquidityBatch(
address recipient,
int16[] calldata tradingFeeRates,
uint256[] calldata clbTokenAmounts,
bytes calldata data
) external returns (LpReceipt[] memory);
/**
* @dev Withdraws liquidity from a liquidity receipt.
* @param receiptId The ID of the liquidity receipt.
* @param data Additional data for the liquidity callback.
*/
function withdrawLiquidity(uint256 receiptId, bytes calldata data) external;
/**
* @dev Withdraws liquidity from a liquidity receipt.
* @param receiptIds The array of the liquidity receipt IDs.
* @param data Additional data for the liquidity callback.
*/
function withdrawLiquidityBatch(uint256[] calldata receiptIds, bytes calldata data) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
/**
* @title IMarketSettle
* @dev Interface for market settlement.
*/
interface IMarketSettle {
/**
* @notice Executes the settlement process for the Chromatic market.
* @dev This function is called to settle the market.
* @param feeRates The feeRate list of liquidity bin to settle.
*/
function settle(int16[] calldata feeRates) external;
/**
* @notice Executes the settlement process for the Chromatic market.
* @dev This function is called to settle the market.
*/
function settleAll() external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {IERC20Metadata} from "@openzeppelin/contracts/interfaces/IERC20Metadata.sol";
import {PositionMode, LiquidityMode, DisplayMode} from "@chromatic-protocol/contracts/core/interfaces/market/Types.sol";
import {IOracleProvider} from "@chromatic-protocol/contracts/oracle/interfaces/IOracleProvider.sol";
import {IChromaticMarketFactory} from "@chromatic-protocol/contracts/core/interfaces/IChromaticMarketFactory.sol";
import {IChromaticVault} from "@chromatic-protocol/contracts/core/interfaces/IChromaticVault.sol";
import {ICLBToken} from "@chromatic-protocol/contracts/core/interfaces/ICLBToken.sol";
/**
* @title IMarketState
* @dev Interface for accessing the state of a market contract.
*/
interface IMarketState {
/**
* @dev Returns the factory contract for the market.
* @return The factory contract.
*/
function factory() external view returns (IChromaticMarketFactory);
/**
* @dev Returns the settlement token of the market.
* @return The settlement token.
*/
function settlementToken() external view returns (IERC20Metadata);
/**
* @dev Returns the oracle provider contract for the market.
* @return The oracle provider contract.
*/
function oracleProvider() external view returns (IOracleProvider);
/**
* @dev Returns the CLB token contract for the market.
* @return The CLB token contract.
*/
function clbToken() external view returns (ICLBToken);
/**
* @dev Returns the vault contract for the market.
* @return The vault contract.
*/
function vault() external view returns (IChromaticVault);
/**
* @notice Returns the protocol fee rate
* @return The protocol fee rate for the market
*/
function protocolFeeRate() external view returns (uint16);
/**
* @notice Update the new protocol fee rate
* @param _protocolFeeRate new protocol fee rate for the market
*/
function updateProtocolFeeRate(uint16 _protocolFeeRate) external;
/**
* @notice Returns the position mode
* @return The position mode for the market
*/
function positionMode() external view returns (PositionMode);
/**
* @notice Update the new position mode
* @param _positionMode new position mode for the market
*/
function updatePositionMode(PositionMode _positionMode) external;
/**
* @notice Returns the liquidity mode
* @return The liquidity mode for the market
*/
function liquidityMode() external view returns (LiquidityMode);
/**
* @notice Update the new liquidity mode
* @param _liquidityMode new liquidity mode for the market
*/
function updateLiquidityMode(LiquidityMode _liquidityMode) external;
/**
* @notice Returns the display mode
* @return The display mode for the market
*/
function displayMode() external view returns (DisplayMode);
/**
* @notice Update the new display mode
* @param _displayMode new display mode for the market
*/
function updateDisplayMode(DisplayMode _displayMode) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {ClosePositionInfo} from "@chromatic-protocol/contracts/core/interfaces/market/Types.sol";
/**
* @title IMarketTradeClosePosition
* @dev Interface for closing and claiming positions in a market.
*/
interface IMarketTradeClosePosition {
/**
* @dev Closes a position in the market.
* @param positionId The ID of the position to close.
* @return The closed position.
*/
function closePosition(uint256 positionId) external returns (ClosePositionInfo memory);
/**
* @dev Claims a closed position in the market.
* @param positionId The ID of the position to claim.
* @param recipient The address of the recipient of the claimed position.
* @param data Additional data for the claim callback.
*/
function claimPosition(
uint256 positionId,
address recipient, // EOA or account contract
bytes calldata data
) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {OpenPositionInfo} from "@chromatic-protocol/contracts/core/interfaces/market/Types.sol";
/**
* @title IMarketTradeOpenPosition
* @dev Interface for open positions in a market.
*/
interface IMarketTradeOpenPosition {
/**
* @dev Opens a new position in the market.
* @param qty The quantity of the position.
* @param takerMargin The margin amount provided by the taker.
* @param makerMargin The margin amount provided by the maker.
* @param maxAllowableTradingFee The maximum allowable trading fee for the position.
* @param data Additional data for the position callback.
* @return The opened position.
*/
function openPosition(
int256 qty,
uint256 takerMargin,
uint256 makerMargin,
uint256 maxAllowableTradingFee,
bytes calldata data
) external returns (OpenPositionInfo memory);
}
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.19;
import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";
interface IOracleProvider is IERC165 {
/// @dev Error for invalid oracle round
error InvalidOracleRound();
/**
* @dev A singular oracle version with its corresponding data
* @param version The iterative version
* @param timestamp the timestamp of the oracle update
* @param price The oracle price of the corresponding version
*/
struct OracleVersion {
uint256 version;
uint256 timestamp;
int256 price;
}
/**
* @notice Checks for a new price and updates the internal phase annotation state accordingly
* @dev `sync` is expected to be called soon after a phase update occurs in the underlying proxy.
* Phase updates should be detected using off-chain mechanism and should trigger a `sync` call
* This is feasible in the short term due to how infrequent phase updates are, but phase update
* and roundCount detection should eventually be implemented at the contract level.
* Reverts if there is more than 1 phase to update in a single sync because we currently cannot
* determine the startingRoundId for the intermediary phase.
* @return The current oracle version after sync
*/
function sync() external returns (OracleVersion memory);
/**
* @notice Returns the current oracle version
* @return oracleVersion Current oracle version
*/
function currentVersion() external view returns (OracleVersion memory);
/**
* @notice Returns the current oracle version
* @param version The version of which to lookup
* @return oracleVersion Oracle version at version `version`
*/
function atVersion(uint256 version) external view returns (OracleVersion memory);
/**
* @notice Retrieves the description of the Oracle Provider.
* @return A string representing the description of the Oracle Provider.
*/
function description() external view returns (string memory);
/**
* @notice Retrieves the name of the Oracle Provider.
* @return A string representing the name of the Oracle Provider.
*/
function oracleProviderName() external view returns (string memory);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {OracleProviderProperties} from "@chromatic-protocol/contracts/core/libraries/registry/OracleProviderProperties.sol";
/**
* @title IOracleProviderRegistry
* @dev Interface for the Oracle Provider Registry contract.
*/
interface IOracleProviderRegistry {
/**
* @dev Emitted when a new oracle provider is registered.
* @param oracleProvider The address of the registered oracle provider.
* @param properties The properties of the registered oracle provider.
*/
event OracleProviderRegistered(
address indexed oracleProvider,
OracleProviderProperties properties
);
/**
* @dev Emitted when an oracle provider is unregistered.
* @param oracleProvider The address of the unregistered oracle provider.
*/
event OracleProviderUnregistered(address indexed oracleProvider);
/**
* @dev Emitted when the take-profit basis points range of an oracle provider is updated.
* @param oracleProvider The address of the oracle provider.
* @param minTakeProfitBPS The new minimum take-profit basis points.
* @param maxTakeProfitBPS The new maximum take-profit basis points.
*/
event UpdateTakeProfitBPSRange(
address indexed oracleProvider,
uint32 indexed minTakeProfitBPS,
uint32 indexed maxTakeProfitBPS
);
/**
* @dev Emitted when the level of an oracle provider is set.
* @param oracleProvider The address of the oracle provider.
* @param level The new level set for the oracle provider.
*/
event UpdateLeverageLevel(address indexed oracleProvider, uint8 indexed level);
/**
* @notice Registers an oracle provider.
* @param oracleProvider The address of the oracle provider to register.
* @param properties The properties of the oracle provider.
*/
function registerOracleProvider(
address oracleProvider,
OracleProviderProperties memory properties
) external;
/**
* @notice Unregisters an oracle provider.
* @param oracleProvider The address of the oracle provider to unregister.
*/
function unregisterOracleProvider(address oracleProvider) external;
/**
* @notice Gets the registered oracle providers.
* @return An array of registered oracle provider addresses.
*/
function registeredOracleProviders() external view returns (address[] memory);
/**
* @notice Checks if an oracle provider is registered.
* @param oracleProvider The address of the oracle provider to check.
* @return A boolean indicating if the oracle provider is registered.
*/
function isRegisteredOracleProvider(address oracleProvider) external view returns (bool);
/**
* @notice Retrieves the properties of an oracle provider.
* @param oracleProvider The address of the oracle provider.
* @return The properties of the oracle provider.
*/
function getOracleProviderProperties(
address oracleProvider
) external view returns (OracleProviderProperties memory);
/**
* @notice Updates the take-profit basis points range of an oracle provider.
* @param oracleProvider The address of the oracle provider.
* @param minTakeProfitBPS The new minimum take-profit basis points.
* @param maxTakeProfitBPS The new maximum take-profit basis points.
*/
function updateTakeProfitBPSRange(
address oracleProvider,
uint32 minTakeProfitBPS,
uint32 maxTakeProfitBPS
) external;
/**
* @notice Updates the leverage level of an oracle provider in the registry.
* @dev The level must be either 0 or 1, and the max leverage must be x10 for level 0 or x20 for level 1.
* @param oracleProvider The address of the oracle provider.
* @param level The new leverage level to be set for the oracle provider.
*/
function updateLeverageLevel(address oracleProvider, uint8 level) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {InterestRate} from "@chromatic-protocol/contracts/core/libraries/InterestRate.sol";
/**
* @title ISettlementTokenRegistry
* @dev Interface for the Settlement Token Registry contract.
*/
interface ISettlementTokenRegistry {
/**
* @dev Emitted when a new settlement token is registered.
* @param token The address of the registered settlement token.
* @param oracleProvider The oracle provider address for the settlement token.
* @param minimumMargin The minimum margin for the markets using this settlement token.
* @param interestRate The interest rate for the settlement token.
* @param flashLoanFeeRate The flash loan fee rate for the settlement token.
* @param earningDistributionThreshold The earning distribution threshold for the settlement token.
* @param uniswapFeeTier The Uniswap fee tier for the settlement token.
*/
event SettlementTokenRegistered(
address indexed token,
address indexed oracleProvider,
uint256 minimumMargin,
uint256 interestRate,
uint256 flashLoanFeeRate,
uint256 earningDistributionThreshold,
uint24 uniswapFeeTier
);
/**
* @dev Emitted when the oracle provider address for a settlement token is set.
* @param token The address of the settlement token.
* @param oracleProvider The oracle provider address for the settlement token.
*/
event SetSettlementTokenOracleProvider(address indexed token, address indexed oracleProvider);
/**
* @dev Emitted when the minimum margin for a settlement token is set.
* @param token The address of the settlement token.
* @param minimumMargin The new minimum margin for the settlement token.
*/
event SetMinimumMargin(address indexed token, uint256 indexed minimumMargin);
/**
* @dev Emitted when the flash loan fee rate for a settlement token is set.
* @param token The address of the settlement token.
* @param flashLoanFeeRate The new flash loan fee rate for the settlement token.
*/
event SetFlashLoanFeeRate(address indexed token, uint256 indexed flashLoanFeeRate);
/**
* @dev Emitted when the earning distribution threshold for a settlement token is set.
* @param token The address of the settlement token.
* @param earningDistributionThreshold The new earning distribution threshold for the settlement token.
*/
event SetEarningDistributionThreshold(
address indexed token,
uint256 indexed earningDistributionThreshold
);
/**
* @dev Emitted when the Uniswap fee tier for a settlement token is set.
* @param token The address of the settlement token.
* @param uniswapFeeTier The new Uniswap fee tier for the settlement token.
*/
event SetUniswapFeeTier(address indexed token, uint24 indexed uniswapFeeTier);
/**
* @dev Emitted when an interest rate record is appended for a settlement token.
* @param token The address of the settlement token.
* @param annualRateBPS The annual interest rate in basis points (BPS).
* @param beginTimestamp The timestamp when the interest rate record begins.
*/
event InterestRateRecordAppended(
address indexed token,
uint256 indexed annualRateBPS,
uint256 indexed beginTimestamp
);
/**
* @dev Emitted when the last interest rate record is removed for a settlement token.
* @param token The address of the settlement token.
* @param annualRateBPS The annual interest rate in basis points (BPS).
* @param beginTimestamp The timestamp when the interest rate record begins.
*/
event LastInterestRateRecordRemoved(
address indexed token,
uint256 indexed annualRateBPS,
uint256 indexed beginTimestamp
);
/**
* @notice Registers a new settlement token.
* @param token The address of the settlement token to register.
* @param oracleProvider The oracle provider address for the settlement token.
* @param minimumMargin The minimum margin for the settlement token.
* @param interestRate The interest rate for the settlement token.
* @param flashLoanFeeRate The flash loan fee rate for the settlement token.
* @param earningDistributionThreshold The earning distribution threshold for the settlement token.
* @param uniswapFeeTier The Uniswap fee tier for the settlement token.
*/
function registerSettlementToken(
address token,
address oracleProvider,
uint256 minimumMargin,
uint256 interestRate,
uint256 flashLoanFeeRate,
uint256 earningDistributionThreshold,
uint24 uniswapFeeTier
) external;
/**
* @notice Gets the list of registered settlement tokens.
* @return An array of addresses representing the registered settlement tokens.
*/
function registeredSettlementTokens() external view returns (address[] memory);
/**
* @notice Checks if a settlement token is registered.
* @param token The address of the settlement token to check.
* @return True if the settlement token is registered, false otherwise.
*/
function isRegisteredSettlementToken(address token) external view returns (bool);
/**
* @notice Gets the oracle provider address for a settlement token.
* @param token The address of the settlement token.
* @return The oracle provider address for the settlement token.
*/
function getSettlementTokenOracleProvider(address token) external view returns (address);
/**
* @notice Sets the oracle provider address for a settlement token.
* @param token The address of the settlement token.
* @param oracleProvider The new oracle provider address for the settlement token.
*/
function setSettlementTokenOracleProvider(address token, address oracleProvider) external;
/**
* @notice Gets the minimum margin for a settlement token.
* @dev The minimumMargin is used as the minimum value for the taker margin of a position
* or as the minimum value for the maker margin of each bin.
* @param token The address of the settlement token.
* @return The minimum margin for the settlement token.
*/
function getMinimumMargin(address token) external view returns (uint256);
/**
* @notice Sets the minimum margin for a settlement token.
* @param token The address of the settlement token.
* @param minimumMargin The new minimum margin for the settlement token.
*/
function setMinimumMargin(address token, uint256 minimumMargin) external;
/**
* @notice Gets the flash loan fee rate for a settlement token.
* @param token The address of the settlement token.
* @return The flash loan fee rate for the settlement token.
*/
function getFlashLoanFeeRate(address token) external view returns (uint256);
/**
* @notice Sets the flash loan fee rate for a settlement token.
* @param token The address of the settlement token.
* @param flashLoanFeeRate The new flash loan fee rate for the settlement token.
*/
function setFlashLoanFeeRate(address token, uint256 flashLoanFeeRate) external;
/**
* @notice Gets the earning distribution threshold for a settlement token.
* @param token The address of the settlement token.
* @return The earning distribution threshold for the settlement token.
*/
function getEarningDistributionThreshold(address token) external view returns (uint256);
/**
* @notice Sets the earning distribution threshold for a settlement token.
* @param token The address of the settlement token.
* @param earningDistributionThreshold The new earning distribution threshold for the settlement token.
*/
function setEarningDistributionThreshold(
address token,
uint256 earningDistributionThreshold
) external;
/**
* @notice Gets the Uniswap fee tier for a settlement token.
* @param token The address of the settlement token.
* @return The Uniswap fee tier for the settlement token.
*/
function getUniswapFeeTier(address token) external view returns (uint24);
/**
* @notice Sets the Uniswap fee tier for a settlement token.
* @param token The address of the settlement token.
* @param uniswapFeeTier The new Uniswap fee tier for the settlement token.
*/
function setUniswapFeeTier(address token, uint24 uniswapFeeTier) external;
/**
* @notice Appends an interest rate record for a settlement token.
* @param token The address of the settlement token.
* @param annualRateBPS The annual interest rate in basis points (BPS).
* @param beginTimestamp The timestamp when the interest rate record begins.
*/
function appendInterestRateRecord(
address token,
uint256 annualRateBPS,
uint256 beginTimestamp
) external;
/**
* @notice Removes the last interest rate record for a settlement token.
* @param token The address of the settlement token.
*/
function removeLastInterestRateRecord(address token) external;
/**
* @notice Gets the current interest rate for a settlement token.
* @param token The address of the settlement token.
* @return The current interest rate for the settlement token.
*/
function currentInterestRate(address token) external view returns (uint256);
/**
* @notice Gets all the interest rate records for a settlement token.
* @param token The address of the settlement token.
* @return An array of interest rate records for the settlement token.
*/
function getInterestRateRecords(
address token
) external view returns (InterestRate.Record[] memory);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
/**
* @title IVault
* @dev Interface for the Vault contract, responsible for managing positions and liquidity.
*/
interface IVault {
/**
* @notice Emitted when a position is opened.
* @param market The address of the market.
* @param positionId The ID of the opened position.
* @param takerMargin The margin amount provided by the taker for the position.
* @param tradingFee The trading fee associated with the position.
* @param protocolFee The protocol fee associated with the position.
*/
event OnOpenPosition(
address indexed market,
uint256 indexed positionId,
uint256 indexed takerMargin,
uint256 tradingFee,
uint256 protocolFee
);
/**
* @notice Emitted when a position is claimed.
* @param market The address of the market.
* @param positionId The ID of the claimed position.
* @param recipient The address of the recipient of the settlement amount.
* @param takerMargin The margin amount provided by the taker for the position.
* @param settlementAmount The settlement amount received by the recipient.
*/
event OnClaimPosition(
address indexed market,
uint256 indexed positionId,
address indexed recipient,
uint256 takerMargin,
uint256 settlementAmount
);
/**
* @notice Emitted when liquidity is added to the vault.
* @param market The address of the market.
* @param amount The amount of liquidity added.
*/
event OnAddLiquidity(address indexed market, uint256 indexed amount);
/**
* @notice Emitted when pending liquidity is settled.
* @param market The address of the market.
* @param pendingDeposit The amount of pending deposit being settled.
* @param pendingWithdrawal The amount of pending withdrawal being settled.
*/
event OnSettlePendingLiquidity(
address indexed market,
uint256 indexed pendingDeposit,
uint256 indexed pendingWithdrawal
);
/**
* @notice Emitted when liquidity is withdrawn from the vault.
* @param market The address of the market.
* @param amount The amount of liquidity withdrawn.
* @param recipient The address of the recipient of the withdrawn liquidity.
*/
event OnWithdrawLiquidity(
address indexed market,
uint256 indexed amount,
address indexed recipient
);
/**
* @notice Emitted when the keeper fee is transferred.
* @param fee The amount of the transferred keeper fee as native token.
* @param amount The amount of settlement token to be used for paying keeper fee.
*/
event TransferKeeperFee(uint256 indexed fee, uint256 indexed amount);
/**
* @notice Emitted when the keeper fee is transferred for a specific market.
* @param market The address of the market.
* @param fee The amount of the transferred keeper fee as native token.
* @param amount The amount of settlement token to be used for paying keeper fee.
*/
event TransferKeeperFee(address indexed market, uint256 indexed fee, uint256 indexed amount);
/**
* @notice Emitted when the protocol fee is transferred for a specific position.
* @param market The address of the market.
* @param positionId The ID of the position.
* @param amount The amount of the transferred fee.
*/
event TransferProtocolFee(
address indexed market,
uint256 indexed positionId,
uint256 indexed amount
);
/**
* @notice Called when a position is opened by a market contract.
* @param settlementToken The settlement token address.
* @param positionId The ID of the opened position.
* @param takerMargin The margin amount provided by the taker for the position.
* @param tradingFee The trading fee associated with the position.
* @param protocolFee The protocol fee associated with the position.
*/
function onOpenPosition(
address settlementToken,
uint256 positionId,
uint256 takerMargin,
uint256 tradingFee,
uint256 protocolFee
) external;
/**
* @notice Called when a position is claimed by a market contract.
* @param settlementToken The settlement token address.
* @param positionId The ID of the claimed position.
* @param recipient The address that will receive the settlement amount.
* @param takerMargin The margin amount provided by the taker for the position.
* @param settlementAmount The amount to be settled for the position.
*/
function onClaimPosition(
address settlementToken,
uint256 positionId,
address recipient,
uint256 takerMargin,
uint256 settlementAmount
) external;
/**
* @notice Called when liquidity is added to the vault by a market contract.
* @param settlementToken The settlement token address.
* @param amount The amount of liquidity being added.
*/
function onAddLiquidity(address settlementToken, uint256 amount) external;
/**
* @notice Called when pending liquidity is settled in the vault by a market contract.
* @param settlementToken The settlement token address.
* @param pendingDeposit The amount of pending deposits being settled.
* @param pendingWithdrawal The amount of pending withdrawals being settled.
*/
function onSettlePendingLiquidity(
address settlementToken,
uint256 pendingDeposit,
uint256 pendingWithdrawal
) external;
/**
* @notice Called when liquidity is withdrawn from the vault by a market contract.
* @param settlementToken The settlement token address.
* @param recipient The address that will receive the withdrawn liquidity.
* @param amount The amount of liquidity to be withdrawn.
*/
function onWithdrawLiquidity(
address settlementToken,
address recipient,
uint256 amount
) external;
/**
* @notice Transfers the keeper fee from the market to the specified keeper.
* @param settlementToken The settlement token address.
* @param keeper The address of the keeper to receive the fee.
* @param fee The amount of the fee to transfer as native token.
* @param margin The margin amount used for the fee payment.
* @return usedFee The actual settlement token amount of fee used for the transfer.
*/
function transferKeeperFee(
address settlementToken,
address keeper,
uint256 fee,
uint256 margin
) external returns (uint256 usedFee);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {BPS} from "@chromatic-protocol/contracts/core/libraries/Constants.sol";
import {Errors} from "@chromatic-protocol/contracts/core/libraries/Errors.sol";
/**
* @title InterestRate
* @notice Provides functions for managing interest rates.
* @dev The library allows for the initialization, appending, and removal of interest rate records,
* as well as calculating interest based on these records.
*/
library InterestRate {
using Math for uint256;
/**
* @dev Record type
* @param annualRateBPS Annual interest rate in BPS
* @param beginTimestamp Timestamp when the interest rate becomes effective
*/
struct Record {
uint256 annualRateBPS;
uint256 beginTimestamp;
}
uint256 private constant MAX_RATE_BPS = BPS; // max interest rate is 100%
uint256 private constant YEAR = 365 * 24 * 3600;
/**
* @dev Ensure that the interest rate records have been initialized before certain functions can be called.
* It checks whether the length of the Record array is greater than 0.
* Throws an error with the code `Errors.INTEREST_RATE_NOT_INITIALIZED` if the array is empty (it indicates that the interest rate has not been initialized).
*/
modifier initialized(Record[] storage self) {
require(self.length != 0, Errors.INTEREST_RATE_NOT_INITIALIZED);
_;
}
/**
* @notice Initialize the interest rate records.
* @param self The stored record array
* @param initialInterestRate The initial interest rate
*/
function initialize(Record[] storage self, uint256 initialInterestRate) internal {
self.push(Record({annualRateBPS: initialInterestRate, beginTimestamp: 0}));
}
/**
* @notice Add a new interest rate record to the array.
* @dev Annual rate is not greater than the maximum rate and that the begin timestamp is in the future,
* and the new record's begin timestamp is greater than the previous record's timestamp.
* Throws an error with the code `Errors.INTEREST_RATE_NOT_INITIALIZED` if the array is empty.
* Throws an error with the code `Errors.INTEREST_RATE_OVERFLOW` if the rate exceed the maximum allowed rate (100%).
* Throws an error with the code `Errors.INTEREST_RATE_PAST_TIMESTAMP` if the timestamp is in the past, ensuring that the interest rate period has not already started.
* Throws an error with the code `Errors.INTEREST_RATE_NOT_APPENDABLE` if the timestamp is greater than the last recorded timestamp, ensuring that the new record is appended in chronological order.
* @param self The stored record array
* @param annualRateBPS The annual interest rate in BPS
* @param beginTimestamp Begin timestamp of this record
*/
function appendRecord(
Record[] storage self,
uint256 annualRateBPS,
uint256 beginTimestamp
) internal initialized(self) {
require(annualRateBPS <= MAX_RATE_BPS, Errors.INTEREST_RATE_OVERFLOW);
//slither-disable-next-line timestamp
require(beginTimestamp > block.timestamp, Errors.INTEREST_RATE_PAST_TIMESTAMP);
Record memory lastRecord = self[self.length - 1];
require(beginTimestamp > lastRecord.beginTimestamp, Errors.INTEREST_RATE_NOT_APPENDABLE);
self.push(Record({annualRateBPS: annualRateBPS, beginTimestamp: beginTimestamp}));
}
/**
* @notice Remove the last interest rate record from the array.
* @dev The current time must be less than the begin timestamp of the last record.
* If the array has only one record, it returns false along with an empty record.
* Otherwise, it removes the last record from the array and returns true along with the removed record.
* Throws an error with the code `Errors.INTEREST_RATE_NOT_INITIALIZED` if the array is empty.
* Throws an error with the code `Errors.INTEREST_RATE_ALREADY_APPLIED` if the `beginTimestamp` of the last record is not in the future.
* @param self The stored record array
* @return removed Whether the last record is removed
* @return record The removed record
*/
function removeLastRecord(
Record[] storage self
) internal initialized(self) returns (bool removed, Record memory record) {
if (self.length <= 1) {
// empty
return (false, Record(0, 0));
}
Record memory lastRecord = self[self.length - 1];
//slither-disable-next-line timestamp
require(block.timestamp < lastRecord.beginTimestamp, Errors.INTEREST_RATE_ALREADY_APPLIED);
self.pop();
return (true, lastRecord);
}
/**
* @notice Find the interest rate record that applies to a given timestamp.
* @dev It iterates through the array from the end to the beginning
* and returns the first record with a begin timestamp less than or equal to the provided timestamp.
* Throws an error with the code `Errors.INTEREST_RATE_NOT_INITIALIZED` if the array is empty.
* @param self The stored record array
* @param timestamp Given timestamp
* @return interestRate The record which is found
* @return index The index of record
*/
function findRecordAt(
Record[] storage self,
uint256 timestamp
) internal view initialized(self) returns (Record memory interestRate, uint256 index) {
for (uint256 i = self.length; i != 0; ) {
unchecked {
index = i - 1;
}
interestRate = self[index];
if (interestRate.beginTimestamp <= timestamp) {
return (interestRate, index);
}
unchecked {
i--;
}
}
return (self[0], 0); // empty result (this line is not reachable)
}
/**
* @notice Calculate the interest
* @dev Throws an error with the code `Errors.INTEREST_RATE_NOT_INITIALIZED` if the array is empty.
* @param self The stored record array
* @param amount Token amount
* @param from Begin timestamp (inclusive)
* @param to End timestamp (exclusive)
*/
function calculateInterest(
Record[] storage self,
uint256 amount,
uint256 from, // timestamp (inclusive)
uint256 to // timestamp (exclusive)
) internal view initialized(self) returns (uint256) {
if (from >= to) {
return 0;
}
uint256 interest = 0;
uint256 endTimestamp = type(uint256).max;
for (uint256 idx = self.length; idx != 0; ) {
Record memory record = self[idx - 1];
if (endTimestamp <= from) {
break;
}
interest += _interest(
amount,
record.annualRateBPS,
Math.min(to, endTimestamp) - Math.max(from, record.beginTimestamp)
);
endTimestamp = record.beginTimestamp;
unchecked {
idx--;
}
}
return interest;
}
function _interest(
uint256 amount,
uint256 rateBPS, // annual rate
uint256 period // in seconds
) private pure returns (uint256) {
return amount.mulDiv(rateBPS * period, BPS * YEAR, Math.Rounding.Up);
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;
import {IOracleProvider} from "@chromatic-protocol/contracts/oracle/interfaces/IOracleProvider.sol";
import {IInterestCalculator} from "@chromatic-protocol/contracts/core/interfaces/IInterestCalculator.sol";
import {IChromaticVault} from "@chromatic-protocol/contracts/core/interfaces/IChromaticVault.sol";
import {ICLBToken} from "@chromatic-protocol/contracts/core/interfaces/ICLBToken.sol";
/**
* @dev Represents the context information required for LP bin operations.
* @param oracleProvider The Oracle Provider contract used for price feed
* @param interestCalculator The Interest Calculator contract used for interest calculations
* @param vault The Chromatic Vault contract responsible for managing liquidity and margin
* @param clbToken The CLB token contract that represents LP ownership in the pool
* @param market The address of market contract
* @param settlementToken The address of the settlement token used in the market
* @param tokenPrecision The precision of the settlement token used in the market
* @param _currentVersionCache Cached instance of the current oracle version
*/
struct LpContext {
IOracleProvider oracleProvider;
IInterestCalculator interestCalculator;
IChromaticVault vault;
ICLBToken clbToken;
address market;
address settlementToken;
uint256 tokenPrecision;
IOracleProvider.OracleVersion _currentVersionCache;
}
using LpContextLib for LpContext global;
/**
* @title LpContextLib
* @notice Provides functions that operate on the `LpContext` struct
*/
library LpContextLib {
/**
* @notice Syncs the oracle version used by the market.
* @param self The memory instance of `LpContext` struct
*/
function syncOracleVersion(LpContext memory self) internal {
self._currentVersionCache = self.oracleProvider.sync();
}
/**
* @notice Retrieves the current oracle version used by the market
* @dev If the `_currentVersionCache` has been initialized, then returns it.
* If not, it calls the `currentVersion` function on the `oracleProvider of the market
* to fetch the current version and stores it in the cache,
* and then returns the current version.
* @param self The memory instance of `LpContext` struct
* @return OracleVersion The current oracle version
*/
function currentOracleVersion(
LpContext memory self
) internal view returns (IOracleProvider.OracleVersion memory) {
if (self._currentVersionCache.version == 0) {
//slither-disable-next-line calls-loop
self._currentVersionCache = self.oracleProvider.currentVersion();
}
return self._currentVersionCache;
}
/**
* @notice Retrieves the oracle version at a specific version number
* @dev If the `_currentVersionCache` matches the requested version, then returns it.
* Otherwise, it calls the `atVersion` function on the `oracleProvider` of the market
* to fetch the desired version.
* @param self The memory instance of `LpContext` struct
* @param version The requested version number
* @return OracleVersion The oracle version at the requested version number
*/
function oracleVersionAt(
LpContext memory self,
uint256 version
) internal view returns (IOracleProvider.OracleVersion memory) {
if (self._currentVersionCache.version == version) {
return self._currentVersionCache;
}
return self.oracleProvider.atVersion(version);
}
/**
* @notice Calculates the interest accrued for a given amount of settlement tokens
within a specified time range.
* @dev This function internally calls the `calculateInterest` function on the `interestCalculator` contract.
* @param self The memory instance of the `LpContext` struct.
* @param amount The amount of settlement tokens for which the interest needs to be calculated.
* @param from The starting timestamp of the time range (inclusive).
* @param to The ending timestamp of the time range (exclusive).
* @return The accrued interest as a `uint256` value.
*/
function calculateInterest(
LpContext memory self,
uint256 amount,
uint256 from,
uint256 to
) internal view returns (uint256) {
//slither-disable-next-line calls-loop
return
amount == 0 || from >= to
? 0
: self.interestCalculator.calculateInterest(self.settlementToken, amount, from, to);
}
/**
* @notice Checks if an oracle version is in the past.
* @param self The memory instance of the `LpContext` struct.
* @param oracleVersion The oracle version to check.
* @return A boolean value indicating whether the oracle version is in the past.
*/
function isPastVersion(
LpContext memory self,
uint256 oracleVersion
) internal view returns (bool) {
return oracleVersion != 0 && oracleVersion < self.currentOracleVersion().version;
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;
import {CLBTokenLib} from "@chromatic-protocol/contracts/core/libraries/CLBTokenLib.sol";
/**
* @dev The LpAction enum represents the types of LP actions that can be performed.
*/
enum LpAction {
ADD_LIQUIDITY,
REMOVE_LIQUIDITY
}
/**
* @dev The LpReceipt struct represents a receipt of an LP action performed.
* @param id An identifier for the receipt
* @param oracleVersion The oracle version associated with the action
* @param amount The amount involved in the action,
* when the action is `ADD_LIQUIDITY`, this value represents the amount of settlement tokens
* when the action is `REMOVE_LIQUIDITY`, this value represents the amount of CLB tokens
* @param recipient The address of the recipient of the action
* @param action An enumeration representing the type of LP action performed (ADD_LIQUIDITY or REMOVE_LIQUIDITY)
* @param tradingFeeRate The trading fee rate associated with the LP action
*/
struct LpReceipt {
uint256 id;
uint256 oracleVersion;
uint256 amount;
address recipient;
LpAction action;
int16 tradingFeeRate;
}
using LpReceiptLib for LpReceipt global;
/**
* @title LpReceiptLib
* @notice Provides functions that operate on the `LpReceipt` struct
*/
library LpReceiptLib {
/**
* @notice Computes the ID of the CLBToken contract based on the trading fee rate.
* @param self The LpReceipt struct.
* @return The ID of the CLBToken contract.
*/
function clbTokenId(LpReceipt memory self) internal pure returns (uint256) {
return CLBTokenLib.encodeId(self.tradingFeeRate);
}
}
// 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: BUSL-1.1
pragma solidity 0.8.19;
/**
* @dev The OracleProviderProperties struct represents properties of the oracle provider.
* @param minTakeProfitBPS The minimum take-profit basis points.
* @param maxTakeProfitBPS The maximum take-profit basis points.
* @param leverageLevel The leverage level of the oracle provider.
*/
struct OracleProviderProperties {
uint32 minTakeProfitBPS;
uint32 maxTakeProfitBPS;
uint8 leverageLevel;
}
using OracleProviderPropertiesLib for OracleProviderProperties global;
library OracleProviderPropertiesLib {
function checkValidLeverageLevel(uint8 leverageLevel) internal pure returns (bool) {
return leverageLevel <= 3;
}
function maxAllowableLeverage(
OracleProviderProperties memory self
) internal pure returns (uint256 leverage) {
uint8 level = self.leverageLevel;
assembly {
switch level
case 0 {
leverage := 10
}
case 1 {
leverage := 20
}
case 2 {
leverage := 50
}
case 3 {
leverage := 100
}
default {
leverage := 0
}
}
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;
import {IOracleProvider} from "@chromatic-protocol/contracts/oracle/interfaces/IOracleProvider.sol";
import {PositionUtil} from "@chromatic-protocol/contracts/core/libraries/PositionUtil.sol";
import {LpContext} from "@chromatic-protocol/contracts/core/libraries/LpContext.sol";
import {BinMargin} from "@chromatic-protocol/contracts/core/libraries/BinMargin.sol";
/**
* @dev The Position struct represents a trading position.
* @param id The position identifier
* @param openVersion The version of the oracle when the position was opened
* @param closeVersion The version of the oracle when the position was closed
* @param qty The quantity of the position
* @param openTimestamp The timestamp when the position was opened
* @param closeTimestamp The timestamp when the position was closed
* @param takerMargin The amount of collateral that a trader must provide
* @param owner The owner of the position, usually it is the account address of trader
* @param liquidator The liquidator contract address
* @param _binMargins The bin margins for the position, it represents the amount of collateral for each bin
* @param _protocolFeeRate The protocol fee rate for the market
*/
struct Position {
uint256 id;
uint256 openVersion;
uint256 closeVersion;
int256 qty;
uint256 openTimestamp;
uint256 closeTimestamp;
uint256 takerMargin;
address owner;
address liquidator;
uint16 _protocolFeeRate;
BinMargin[] _binMargins;
}
using PositionLib for Position global;
/**
* @title PositionLib
* @notice Provides functions that operate on the `Position` struct
*/
library PositionLib {
// using Math for uint256;
// using SafeCast for uint256;
// using SignedMath for int256;
/**
* @notice Calculates the entry price of the position based on the position's open oracle version
* @dev It fetches oracle price from `IOracleProvider`
* at the settle version calculated based on the position's open oracle version
* @param self The memory instance of the `Position` struct
* @param ctx The context object for this transaction
* @return uint256 The entry price
*/
function entryPrice(
Position memory self,
LpContext memory ctx
) internal view returns (uint256) {
return PositionUtil.settlePrice(ctx.oracleProvider, self.openVersion);
}
/**
* @notice Calculates the exit price of the position based on the position's close oracle version
* @dev It fetches oracle price from `IOracleProvider`
* at the settle version calculated based on the position's close oracle version
* @param self The memory instance of the `Position` struct
* @param ctx The context object for this transaction
* @return uint256 The exit price
*/
function exitPrice(Position memory self, LpContext memory ctx) internal view returns (uint256) {
return PositionUtil.settlePrice(ctx.oracleProvider, self.closeVersion);
}
/**
* @notice Calculates the profit or loss of the position based on the close oracle version and the qty
* @param self The memory instance of the `Position` struct
* @param ctx The context object for this transaction
* @return int256 The profit or loss
*/
function pnl(Position memory self, LpContext memory ctx) internal view returns (int256) {
return
self.closeVersion > self.openVersion
? PositionUtil.pnl(self.qty, self.entryPrice(ctx), self.exitPrice(ctx))
: int256(0);
}
/**
* @notice Calculates the total margin required for the makers of the position
* @dev The maker margin is calculated by summing up the amounts of all bin margins
* in the `_binMargins` array
* @param self The memory instance of the `Position` struct
* @return margin The maker margin
*/
function makerMargin(Position memory self) internal pure returns (uint256 margin) {
for (uint256 i; i < self._binMargins.length; ) {
margin += self._binMargins[i].amount;
unchecked {
++i;
}
}
}
/**
* @notice Calculates the total trading fee for the position
* @dev The trading fee is calculated by summing up the trading fees of all bin margins
* in the `_binMargins` array
* @param self The memory instance of the `Position` struct
* @return fee The trading fee
*/
function tradingFee(Position memory self) internal pure returns (uint256 fee) {
for (uint256 i; i < self._binMargins.length; ) {
fee += self._binMargins[i].tradingFee(self._protocolFeeRate);
unchecked {
++i;
}
}
}
/**
* @notice Calculates the total protocol fee for a position.
* @param self The Position struct representing the position.
* @return fee The total protocol fee amount.
*/
function protocolFee(Position memory self) internal pure returns (uint256 fee) {
for (uint256 i; i < self._binMargins.length; ) {
fee += self._binMargins[i].protocolFee(self._protocolFeeRate);
unchecked {
++i;
}
}
}
/**
* @notice Returns an array of BinMargin instances
* representing the bin margins for the position
* @param self The memory instance of the `Position` struct
* @return margins The bin margins for the position
*/
function binMargins(Position memory self) internal pure returns (BinMargin[] memory margins) {
margins = self._binMargins;
}
/**
* @notice Sets the `_binMargins` array for the position
* @param self The memory instance of the `Position` struct
* @param margins The bin margins for the position
*/
function setBinMargins(Position memory self, BinMargin[] memory margins) internal pure {
self._binMargins = margins;
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {SignedMath} from "@openzeppelin/contracts/utils/math/SignedMath.sol";
import {IOracleProvider} from "@chromatic-protocol/contracts/oracle/interfaces/IOracleProvider.sol";
import {PRICE_PRECISION} from "@chromatic-protocol/contracts/core/libraries/Constants.sol";
import {Errors} from "@chromatic-protocol/contracts/core/libraries/Errors.sol";
/**
* @title PositionUtil
* @notice Provides utility functions for managing positions
*/
library PositionUtil {
using Math for uint256;
using SafeCast for uint256;
using SignedMath for int256;
/**
* @notice Returns next oracle version to settle
* @dev It adds 1 to the `oracleVersion`
* and ensures that the `oracleVersion` is greater than 0 using a require statement.
* Throws an error with the code `Errors.INVALID_ORACLE_VERSION` if the `oracleVersion` is not valid.
* @param oracleVersion Input oracle version
* @return uint256 Next oracle version to settle
*/
function settleVersion(uint256 oracleVersion) internal pure returns (uint256) {
require(oracleVersion != 0, Errors.INVALID_ORACLE_VERSION);
return oracleVersion + 1;
}
/**
* @notice Calculates the price of the position based on the `oracleVersion` to settle
* @dev It calls another overloaded `settlePrice` function
* with an additional `OracleVersion` parameter,
* passing the `currentVersion` obtained from the `provider`
* @param provider The oracle provider
* @param oracleVersion The oracle version of position
* @return uint256 The calculated price to settle
*/
function settlePrice(
IOracleProvider provider,
uint256 oracleVersion
) internal view returns (uint256) {
return settlePrice(provider, oracleVersion, provider.currentVersion());
}
/**
* @notice Calculates the price of the position based on the `oracleVersion` to settle
* @dev It calculates the price by considering the `settleVersion`
* and the `currentVersion` obtained from the `IOracleProvider`.
* It ensures that the settle version is not greater than the current version;
* otherwise, it triggers an error with the message `Errors.UNSETTLED_POSITION`.
* It retrieves the corresponding `OracleVersion` using `atVersion` from the `IOracleProvider`,
* and then calls `oraclePrice` to obtain the price.
* @param provider The oracle provider
* @param oracleVersion The oracle version of position
* @param currentVersion The current oracle version
* @return uint256 The calculated entry price to settle
*/
function settlePrice(
IOracleProvider provider,
uint256 oracleVersion,
IOracleProvider.OracleVersion memory currentVersion
) internal view returns (uint256) {
uint256 _settleVersion = settleVersion(oracleVersion);
require(_settleVersion <= currentVersion.version, Errors.UNSETTLED_POSITION);
//slither-disable-next-line calls-loop
IOracleProvider.OracleVersion memory _oracleVersion = _settleVersion ==
currentVersion.version
? currentVersion
: provider.atVersion(_settleVersion);
return oraclePrice(_oracleVersion);
}
/**
* @notice Extracts the price value from an `OracleVersion` struct
* @dev If the price is not positive value, it triggers an error with the message `Errors.NOT_POSITIVE_PRICE`.
* @param oracleVersion The memory instance of `OracleVersion` struct
* @return uint256 The price value of `oracleVersion`
*/
function oraclePrice(
IOracleProvider.OracleVersion memory oracleVersion
) internal pure returns (uint256) {
require(oracleVersion.price > 0, Errors.NOT_POSITIVE_PRICE);
return oracleVersion.price.abs();
}
/**
* @notice Calculates the profit or loss (PnL) for a position based on the quantity, entry price, and exit price
* @dev It first calculates the price difference (`delta`) between the exit price and the entry price.
* If the quantity is negative, indicating short position, it adjusts the `delta` to reflect a negative change.
* The function then calculates the absolute PnL by multiplying the absolute value of the quantity
* with the absolute value of the `delta`, divided by the entry price.
* Finally, if `delta` is negative, indicating a loss, the absolute PnL is negated to represent a negative value.
* @param qty The quantity of the position
* @param _entryPrice The entry price of the position
* @param _exitPrice The exit price of the position
* @return int256 The profit or loss
*/
function pnl(
int256 qty, // as token precision
uint256 _entryPrice,
uint256 _exitPrice
) internal pure returns (int256) {
if (qty == 0 || _entryPrice == _exitPrice) return 0;
int256 delta = _exitPrice > _entryPrice
? (_exitPrice - _entryPrice).toInt256()
: -(_entryPrice - _exitPrice).toInt256();
if (qty < 0) delta *= -1;
int256 absPnl = qty.abs().mulDiv(delta.abs(), _entryPrice).toInt256();
return delta < 0 ? -absPnl : absPnl;
}
/**
* @notice Verifies the validity of a position quantity added to the bin
* @dev It ensures that the sign of the current quantity of the bin's position
* and the added quantity are same or zero.
* If the condition is not met, it triggers an error with the message `Errors.INVALID_POSITION_QTY`.
* @param currentQty The current quantity of the bin's pending position
* @param addedQty The position quantity added
*/
function checkAddPositionQty(int256 currentQty, int256 addedQty) internal pure {
require(
!((currentQty > 0 && addedQty <= 0) || (currentQty < 0 && addedQty >= 0)),
Errors.INVALID_POSITION_QTY
);
}
/**
* @notice Verifies the validity of a position quantity removed from the bin
* @dev It ensures that the sign of the current quantity of the bin's position
* and the removed quantity are same or zero,
* and the absolute removed quantity is not greater than the absolute current quantity.
* If the condition is not met, it triggers an error with the message `Errors.INVALID_POSITION_QTY`.
* @param currentQty The current quantity of the bin's position
* @param removeQty The position quantity removed
*/
function checkRemovePositionQty(int256 currentQty, int256 removeQty) internal pure {
require(
!((currentQty == 0) ||
(removeQty == 0) ||
(currentQty > 0 && removeQty > currentQty) ||
(currentQty < 0 && removeQty < currentQty)),
Errors.INVALID_POSITION_QTY
);
}
/**
* @notice Calculates the transaction amount based on the quantity and price
* @param qty The quantity of the position
* @param price The price of the position
* @return uint256 The transaction amount
*/
function transactionAmount(int256 qty, uint256 price) internal pure returns (uint256) {
return qty.abs().mulDiv(price, PRICE_PRECISION);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}
// 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.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
pragma solidity 0.8.19;
bytes4 constant CLAIM_USER = "UC";
bytes4 constant CLAIM_KEEPER = "KC";
bytes4 constant CLAIM_TP = "TP";
bytes4 constant CLAIM_SL = "SL";
enum PositionMode {
Normal,
OpenDisabled,
CloseDisabled,
Suspended
}
enum LiquidityMode {
Normal,
AddDisabled,
RemoveDisabled,
Suspended
}
enum DisplayMode {
Normal,
Suspended,
Deprecating,
Deprecated
}
/**
* @dev The OpenPositionInfo struct represents a opened trading position.
* @param id The position identifier
* @param openVersion The version of the oracle when the position was opened
* @param qty The quantity of the position
* @param openTimestamp The timestamp when the position was opened
* @param takerMargin The amount of collateral that a trader must provide
* @param makerMargin The margin amount provided by the maker.
* @param tradingFee The trading fee associated with the position.
*/
struct OpenPositionInfo {
uint256 id;
uint256 openVersion;
int256 qty;
uint256 openTimestamp;
uint256 takerMargin;
uint256 makerMargin;
uint256 tradingFee;
}
/**
* @dev The ClosePositionInfo struct represents a closed trading position.
* @param id The position identifier
* @param closeVersion The version of the oracle when the position was closed
* @param closeTimestamp The timestamp when the position was closed
*/
struct ClosePositionInfo {
uint256 id;
uint256 closeVersion;
uint256 closeTimestamp;
}
/**
* @dev The ClaimPositionInfo struct represents a claimed position information.
* @param id The position identifier
* @param entryPrice The entry price of the position
* @param exitPrice The exit price of the position
* @param realizedPnl The profit or loss of the claimed position.
* @param interest The interest paid for the claimed position.
* @param cause The description of being claimed.
*/
struct ClaimPositionInfo {
uint256 id;
uint256 entryPrice;
uint256 exitPrice;
int256 realizedPnl;
uint256 interest;
bytes4 cause;
}
/**
* @dev Represents a pending position within the LiquidityBin
* @param openVersion The oracle version when the position was opened.
* @param totalQty The total quantity of the pending position.
* @param totalMakerMargin The total maker margin of the pending position.
* @param totalTakerMargin The total taker margin of the pending position.
*/
struct PendingPosition {
uint256 openVersion;
int256 totalQty;
uint256 totalMakerMargin;
uint256 totalTakerMargin;
}
/**
* @dev Represents the closing position within an LiquidityBin.
* @param closeVersion The oracle version when the position was closed.
* @param totalQty The total quantity of the closing position.
* @param totalEntryAmount The total entry amount of the closing position.
* @param totalMakerMargin The total maker margin of the closing position.
* @param totalTakerMargin The total taker margin of the closing position.
*/
struct ClosingPosition {
uint256 closeVersion;
int256 totalQty;
uint256 totalEntryAmount;
uint256 totalMakerMargin;
uint256 totalTakerMargin;
}
/**
* @dev A struct representing pending liquidity information.
* @param oracleVersion The oracle version of pending liqudity.
* @param mintingTokenAmountRequested The amount of settlement tokens requested for minting.
* @param burningCLBTokenAmountRequested The amount of CLB tokens requested for burning.
*/
struct PendingLiquidity {
uint256 oracleVersion;
uint256 mintingTokenAmountRequested;
uint256 burningCLBTokenAmountRequested;
}
/**
* @dev A struct representing claimable liquidity information.
* @param mintingTokenAmountRequested The amount of settlement tokens requested for minting.
* @param mintingCLBTokenAmount The actual amount of CLB tokens minted.
* @param burningCLBTokenAmountRequested The amount of CLB tokens requested for burning.
* @param burningCLBTokenAmount The actual amount of CLB tokens burned.
* @param burningTokenAmount The amount of settlement tokens equal in value to the burned CLB tokens.
*/
struct ClaimableLiquidity {
uint256 mintingTokenAmountRequested;
uint256 mintingCLBTokenAmount;
uint256 burningCLBTokenAmountRequested;
uint256 burningCLBTokenAmount;
uint256 burningTokenAmount;
}
/**
* @dev A struct representing status of the liquidity bin.
* @param liquidity The total liquidity amount in the bin
* @param freeLiquidity The amount of free liquidity available in the bin.
* @param binValue The current value of the bin.
* @param tradingFeeRate The trading fee rate for the liquidity.
*/
struct LiquidityBinStatus {
uint256 liquidity;
uint256 freeLiquidity;
uint256 binValue;
int16 tradingFeeRate;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {IChromaticMarketFactory} from "@chromatic-protocol/contracts/core/interfaces/IChromaticMarketFactory.sol";
/**
* @title VerifyCallback
* @dev Abstract contract for verifying callback functions from registered markets.
*/
abstract contract VerifyCallback {
//slither-disable-next-line immutable-states
address marketFactory;
/**
* @dev Throws an error indicating that the caller is not a registered market.
*/
error NotMarket();
/**
* @dev Modifier to verify the callback function is called by a registered market.
* Throws a `NotMarket` error if the caller is not a registered market.
*/
modifier verifyCallback() {
if (!IChromaticMarketFactory(marketFactory).isRegisteredMarket(msg.sender))
revert NotMarket();
_;
}
}
{
"compilationTarget": {
"contracts/periphery/ChromaticRouter.sol": "ChromaticRouter"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 30000
},
"remappings": [
":@chromatic-protocol/contracts/=contracts/",
":ds-test/=lib/forge-std/lib/ds-test/src/",
":forge-std/=lib/forge-std/src/"
]
}
[{"inputs":[{"internalType":"address","name":"_marketFactory","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"NotMarket","type":"error"},{"inputs":[],"name":"OnlyAccessableByDao","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"AccountCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"marketAddress","type":"address"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"tradingFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tradingFeeUSD","type":"uint256"}],"name":"OpenPosition","type":"event"},{"inputs":[],"name":"accountBase","outputs":[{"internalType":"contract ChromaticAccount","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"int16","name":"feeRate","type":"int16"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"addLiquidity","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"oracleVersion","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"enum LpAction","name":"action","type":"uint8"},{"internalType":"int16","name":"tradingFeeRate","type":"int16"}],"internalType":"struct LpReceipt","name":"receipt","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"int16[]","name":"feeRates","type":"int16[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"addLiquidityBatch","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"oracleVersion","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"enum LpAction","name":"action","type":"uint8"},{"internalType":"int16","name":"tradingFeeRate","type":"int16"}],"internalType":"struct LpReceipt[]","name":"lpReceipts","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"settlementToken","type":"address"},{"internalType":"address","name":"vault","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"addLiquidityBatchCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"settlementToken","type":"address"},{"internalType":"address","name":"vault","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"addLiquidityCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"uint256","name":"receiptId","type":"uint256"}],"name":"claimLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"uint256[]","name":"_receiptIds","type":"uint256[]"}],"name":"claimLiquidityBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_receiptIds","type":"uint256[]"},{"internalType":"int16[]","name":"","type":"int16[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"claimLiquidityBatchCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"receiptId","type":"uint256"},{"internalType":"int16","name":"","type":"int16"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"claimLiquidityCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"uint256","name":"positionId","type":"uint256"}],"name":"claimPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"uint256","name":"positionId","type":"uint256"}],"name":"closePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"createAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAccount","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"getLpReceiptIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"}],"name":"getLpReceiptIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"int256","name":"qty","type":"int256"},{"internalType":"uint256","name":"takerMargin","type":"uint256"},{"internalType":"uint256","name":"makerMargin","type":"uint256"},{"internalType":"uint256","name":"maxAllowableTradingFee","type":"uint256"}],"name":"openPosition","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"openVersion","type":"uint256"},{"internalType":"int256","name":"qty","type":"int256"},{"internalType":"uint256","name":"openTimestamp","type":"uint256"},{"internalType":"uint256","name":"takerMargin","type":"uint256"},{"internalType":"uint256","name":"makerMargin","type":"uint256"},{"internalType":"uint256","name":"tradingFee","type":"uint256"}],"internalType":"struct OpenPositionInfo","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"int16","name":"feeRate","type":"int16"},{"internalType":"uint256","name":"clbTokenAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"removeLiquidity","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"oracleVersion","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"enum LpAction","name":"action","type":"uint8"},{"internalType":"int16","name":"tradingFeeRate","type":"int16"}],"internalType":"struct LpReceipt","name":"receipt","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"int16[]","name":"feeRates","type":"int16[]"},{"internalType":"uint256[]","name":"clbTokenAmounts","type":"uint256[]"}],"name":"removeLiquidityBatch","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"oracleVersion","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"enum LpAction","name":"action","type":"uint8"},{"internalType":"int16","name":"tradingFeeRate","type":"int16"}],"internalType":"struct LpReceipt[]","name":"lpReceipts","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"clbToken","type":"address"},{"internalType":"uint256[]","name":"clbTokenIds","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"removeLiquidityBatchCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"clbToken","type":"address"},{"internalType":"uint256","name":"clbTokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"removeLiquidityCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"uint256","name":"receiptId","type":"uint256"}],"name":"withdrawLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"uint256[]","name":"_receiptIds","type":"uint256[]"}],"name":"withdrawLiquidityBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_receiptIds","type":"uint256[]"},{"internalType":"int16[]","name":"","type":"int16[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"withdrawLiquidityBatchCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"receiptId","type":"uint256"},{"internalType":"int16","name":"","type":"int16"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"withdrawLiquidityCallback","outputs":[],"stateMutability":"nonpayable","type":"function"}]