Contract
0xf985cA33B8b787599DE77E4Ccf2d0Ecbf27d87d9
1
Contract Overview
Balance:
4.985254477416483918 ETH
ETH Value:
$5,931.56 (@ $1,189.82/ETH)
My Name Tag:
Not Available
[ Download CSV Export ]
Latest 25 internal transaction
[ Download CSV Export ]
Contract Name:
Broker
Compiler Version
v0.7.4+commit.3f05b770
Optimization Enabled:
Yes with 1000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.7.4; pragma experimental ABIEncoderV2; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/math/SignedSafeMath.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import "@openzeppelin/contracts/utils/SafeCast.sol"; import "../interface/ILiquidityPoolFull.sol"; import "../interface/IPoolCreatorFull.sol"; import "../interface/IAccessControl.sol"; import "../libraries/SafeMathExt.sol"; import "../libraries/OrderData.sol"; import "../libraries/Signature.sol"; import "../libraries/Utils.sol"; import "../Type.sol"; contract Broker is ReentrancyGuard { using Address for address; using SafeMath for uint256; using SafeMathExt for int256; using SignedSafeMath for int256; using SafeCast for int256; using OrderData for Order; using OrderData for bytes; using Signature for bytes32; uint256 internal constant GWEI = 10**9; uint256 internal _chainID; mapping(address => uint32) internal _nonces; mapping(address => uint256) internal _balances; mapping(bytes32 => int256) internal _orderFilled; mapping(bytes32 => bool) internal _orderCanceled; event Deposit(address indexed trader, uint256 amount); event Withdraw(address indexed trader, uint256 amount); event Transfer(address indexed sender, address indexed recipient, uint256 amount); event TradeFailed(bytes32 orderHash, Order order, int256 amount, string reason); event TradeSuccess(bytes32 orderHash, Order order, int256 amount, uint256 gasReward); event CancelOrder(bytes32 orderHash); event FillOrder(bytes32 orderHash, int256 fillAmount); event CallFunction( bytes32 userData1, bytes32 userData2, string functionSignature, bytes callData, bytes signature ); constructor() { _chainID = Utils.chainID(); } /** * @notice Sending eth to this contract is equivalent to depositing eth to the account of sender */ receive() external payable { deposit(); } /** * @notice Get the eth balance of the trader's account * @param trader The address of the trader * @return uint256 The eth balance of the trader's account */ function balanceOf(address trader) public view returns (uint256) { return _balances[trader]; } /** * @notice Deposit eth to the account of sender as gas reward of the broker */ function deposit() public payable nonReentrant { _balances[msg.sender] = _balances[msg.sender].add(msg.value); emit Deposit(msg.sender, msg.value); } /** * @notice Withdraw eth for gas reward. * * @param amount The amount of eth to withdraw. */ function withdraw(uint256 amount) public nonReentrant { _balances[msg.sender] = _balances[msg.sender].sub(amount); Address.sendValue(payable(msg.sender), amount); emit Withdraw(msg.sender, amount); } /** * @notice Return if an order is canceled. * * @param order Order object. */ function isOrderCanceled(Order memory order) public view returns (bool) { bytes32 orderHash = order.getOrderHash(); return _orderCanceled[orderHash]; } /** * @notice Return filled amount of an order. * * @param order Order object. * @return filledAmount The amount of already filled. */ function getOrderFilledAmount(Order memory order) public view returns (int256 filledAmount) { bytes32 orderHash = order.getOrderHash(); filledAmount = _orderFilled[orderHash]; } /** * @notice Cancel an order to prevent any further trade. * Currently, Only trader or relayer and the authorized account (by order.trader) * are able to cancel an order. * * @param order Order object. */ function cancelOrder(Order memory order) public { if (msg.sender != order.trader && msg.sender != order.relayer) { (, , address[7] memory addresses, , ) = ILiquidityPoolFull(order.liquidityPool) .getLiquidityPoolInfo(); IAccessControl accessControl = IAccessControl( IPoolCreatorFull(addresses[0]).getAccessController() ); bool isGranted = accessControl.isGranted( order.trader, msg.sender, Constant.PRIVILEGE_TRADE ); require(isGranted, "sender must be trader or relayer or authorized"); } bytes32 orderHash = order.getOrderHash(); require(!_orderCanceled[orderHash], "order is already canceled"); _orderCanceled[orderHash] = true; emit CancelOrder(orderHash); } /** * @notice Trade multiple orders, each order will be treated separately. * @param compressedOrders The compressed order objects to trade. * @param amounts The trading amounts of position. * @param gasRewards The gas rewards of eth given to their brokers. */ function batchTrade( bytes[] calldata compressedOrders, int256[] calldata amounts, uint256[] calldata gasRewards ) external { uint256 orderCount = compressedOrders.length; for (uint256 i = 0; i < orderCount; i++) { Order memory order = compressedOrders[i].decodeOrderData(); bytes memory signature = compressedOrders[i].decodeSignature(); bytes32 orderHash = order.getOrderHash(); require(orderHash.getSigner(signature) == order.trader, "signer mismatch"); int256 amount = amounts[i]; uint256 gasReward = gasRewards[i]; if (order.chainID != _chainID) { emit TradeFailed(orderHash, order, amount, "chain id mismatch"); return; } if (_orderCanceled[orderHash]) { emit TradeFailed(orderHash, order, amount, "order is canceled"); return; } if (_orderFilled[orderHash].add(amount).abs() > order.amount.abs()) { emit TradeFailed(orderHash, order, amount, "no enough amount to fill"); return; } if (gasReward > balanceOf(order.trader)) { emit TradeFailed(orderHash, order, amount, "insufficient fee"); return; } if (gasReward > order.brokerFeeLimit * GWEI) { emit TradeFailed(orderHash, order, amount, "fee exceeds trade gas limit"); return; } if (amount.abs() < order.minTradeAmount) { emit TradeFailed(orderHash, order, amount, "amount is less than min trade amount"); return; } try ILiquidityPoolFull(order.liquidityPool).brokerTrade(compressedOrders[i], amount) returns (int256 filledAmount) { _fillOrder(orderHash, filledAmount); _transfer(order.trader, order.relayer, gasReward); emit TradeSuccess(orderHash, order, filledAmount, gasReward); } catch Error(string memory reason) { emit TradeFailed(orderHash, order, amount, reason); return; } catch { emit TradeFailed(orderHash, order, amount, "transaction failed"); return; } } } /** * @dev Update the filled position amount of the order. * * @param orderHash The hash of the order. * @param amount The changed amount of filled position. */ function _fillOrder(bytes32 orderHash, int256 amount) internal { _orderFilled[orderHash] = _orderFilled[orderHash].add(amount); emit FillOrder(orderHash, amount); } /** * @dev Transfer eth from sender's account to recipient's account. * * @param sender The address of the sender * @param recipient The address of the recipient * @param amount The amount of eth to transfer */ function _transfer( address sender, address recipient, uint256 amount ) internal { require(recipient != address(0), "the recipient is zero address"); if (amount == 0) { return; } require(_balances[sender] >= amount, "insufficient fee"); _balances[sender] = _balances[sender].sub(amount); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when 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. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @title SignedSafeMath * @dev Signed math operations with safety checks that revert on error. */ library SignedSafeMath { int256 constant private _INT256_MIN = -2**255; /** * @dev Returns the multiplication of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(int256 a, int256 b) internal pure returns (int256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow"); int256 c = a * b; require(c / a == b, "SignedSafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two signed integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(int256 a, int256 b) internal pure returns (int256) { require(b != 0, "SignedSafeMath: division by zero"); require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow"); int256 c = a / b; return c; } /** * @dev Returns the subtraction of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(int256 a, int256 b) internal pure returns (int256) { int256 c = a - b; require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow"); return c; } /** * @dev Returns the addition of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(int256 a, int256 b) internal pure returns (int256) { int256 c = a + b; require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow"); return c; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.2 <0.8.0; /** * @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 * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 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://diligence.consensys.net/posts/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.5.11/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"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (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 functionCall(target, data, "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"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(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) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(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) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // 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 // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor () internal { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <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 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 */ function toUint128(uint256 value) internal pure returns (uint128) { require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits"); return uint128(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 */ function toUint64(uint256 value) internal pure returns (uint64) { require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits"); return uint64(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 */ function toUint32(uint256 value) internal pure returns (uint32) { require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits"); return uint32(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 */ function toUint16(uint256 value) internal pure returns (uint16) { require(value < 2**16, "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. */ function toUint8(uint256 value) internal pure returns (uint8) { require(value < 2**8, "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. */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @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) { require(value >= -2**127 && value < 2**127, "SafeCast: value doesn\'t fit in 128 bits"); return int128(value); } /** * @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) { require(value >= -2**63 && value < 2**63, "SafeCast: value doesn\'t fit in 64 bits"); return int64(value); } /** * @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) { require(value >= -2**31 && value < 2**31, "SafeCast: value doesn\'t fit in 32 bits"); return int32(value); } /** * @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) { require(value >= -2**15 && value < 2**15, "SafeCast: value doesn\'t fit in 16 bits"); return int16(value); } /** * @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) { require(value >= -2**7 && value < 2**7, "SafeCast: value doesn\'t fit in 8 bits"); return int8(value); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { require(value < 2**255, "SafeCast: value doesn't fit in an int256"); return int256(value); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity 0.7.4; pragma experimental ABIEncoderV2; import "./IPerpetual.sol"; import "./ILiquidityPool.sol"; import "./ILiquidityPoolGetter.sol"; import "./ILiquidityPoolGovernance.sol"; interface ILiquidityPoolFull is IPerpetual, ILiquidityPool, ILiquidityPoolGetter, ILiquidityPoolGovernance {}
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity 0.7.4; import "./IAccessControl.sol"; import "./IPoolCreator.sol"; import "./ITracer.sol"; import "./IVersionControl.sol"; import "./IVariables.sol"; import "./IKeeperWhitelist.sol"; interface IPoolCreatorFull is IPoolCreator, IVersionControl, ITracer, IVariables, IAccessControl, IKeeperWhitelist { /** * @notice Owner of version control. */ function owner() external view override(IVersionControl, IVariables) returns (address); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity 0.7.4; interface IAccessControl { function grantPrivilege(address trader, uint256 privilege) external; function revokePrivilege(address trader, uint256 privilege) external; function isGranted( address owner, address trader, uint256 privilege ) external view returns (bool); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.7.4; import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/math/SignedSafeMathUpgradeable.sol"; import "./Constant.sol"; import "./Utils.sol"; enum Round { CEIL, FLOOR } library SafeMathExt { using SafeMathUpgradeable for uint256; using SignedSafeMathUpgradeable for int256; /* * @dev Always half up for uint256 */ function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x.mul(y).add(Constant.UNSIGNED_ONE / 2) / Constant.UNSIGNED_ONE; } /* * @dev Always half up for uint256 */ function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x.mul(Constant.UNSIGNED_ONE).add(y / 2).div(y); } /* * @dev Always half up for uint256 */ function wfrac( uint256 x, uint256 y, uint256 z ) internal pure returns (uint256 r) { r = x.mul(y).add(z / 2).div(z); } /* * @dev Always half up if no rounding parameter */ function wmul(int256 x, int256 y) internal pure returns (int256 z) { z = roundHalfUp(x.mul(y), Constant.SIGNED_ONE) / Constant.SIGNED_ONE; } /* * @dev Always half up if no rounding parameter */ function wdiv(int256 x, int256 y) internal pure returns (int256 z) { if (y < 0) { y = neg(y); x = neg(x); } z = roundHalfUp(x.mul(Constant.SIGNED_ONE), y).div(y); } /* * @dev Always half up if no rounding parameter */ function wfrac( int256 x, int256 y, int256 z ) internal pure returns (int256 r) { int256 t = x.mul(y); if (z < 0) { z = neg(z); t = neg(t); } r = roundHalfUp(t, z).div(z); } function wmul( int256 x, int256 y, Round round ) internal pure returns (int256 z) { z = div(x.mul(y), Constant.SIGNED_ONE, round); } function wdiv( int256 x, int256 y, Round round ) internal pure returns (int256 z) { z = div(x.mul(Constant.SIGNED_ONE), y, round); } function wfrac( int256 x, int256 y, int256 z, Round round ) internal pure returns (int256 r) { int256 t = x.mul(y); r = div(t, z, round); } function abs(int256 x) internal pure returns (int256) { return x >= 0 ? x : neg(x); } function neg(int256 a) internal pure returns (int256) { return SignedSafeMathUpgradeable.sub(int256(0), a); } /* * @dev ROUND_HALF_UP rule helper. * You have to call roundHalfUp(x, y) / y to finish the rounding operation. * 0.5 ≈ 1, 0.4 ≈ 0, -0.5 ≈ -1, -0.4 ≈ 0 */ function roundHalfUp(int256 x, int256 y) internal pure returns (int256) { require(y > 0, "roundHalfUp only supports y > 0"); if (x >= 0) { return x.add(y / 2); } return x.sub(y / 2); } /* * @dev Division, rounding ceil or rounding floor */ function div( int256 x, int256 y, Round round ) internal pure returns (int256 divResult) { require(y != 0, "division by zero"); divResult = x.div(y); if (x % y == 0) { return divResult; } bool isSameSign = Utils.hasTheSameSign(x, y); if (round == Round.CEIL && isSameSign) { divResult = divResult.add(1); } if (round == Round.FLOOR && !isSameSign) { divResult = divResult.sub(1); } } function max(int256 a, int256 b) internal pure returns (int256) { return a >= b ? a : b; } function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.7.4; pragma experimental ABIEncoderV2; import "../libraries/Utils.sol"; import "../Type.sol"; library OrderData { uint32 internal constant MASK_CLOSE_ONLY = 0x80000000; uint32 internal constant MASK_MARKET_ORDER = 0x40000000; uint32 internal constant MASK_STOP_LOSS_ORDER = 0x20000000; uint32 internal constant MASK_TAKE_PROFIT_ORDER = 0x10000000; uint32 internal constant MASK_USE_TARGET_LEVERAGE = 0x08000000; // old domain, will be removed in future string internal constant DOMAIN_NAME = "Mai Protocol v3"; bytes32 internal constant EIP712_DOMAIN_TYPEHASH = keccak256(abi.encodePacked("EIP712Domain(string name)")); bytes32 internal constant DOMAIN_SEPARATOR = keccak256(abi.encodePacked(EIP712_DOMAIN_TYPEHASH, keccak256(bytes(DOMAIN_NAME)))); bytes32 internal constant EIP712_ORDER_TYPE = keccak256( abi.encodePacked( "Order(address trader,address broker,address relayer,address referrer,address liquidityPool,", "int256 minTradeAmount,int256 amount,int256 limitPrice,int256 triggerPrice,uint256 chainID,", "uint64 expiredAt,uint32 perpetualIndex,uint32 brokerFeeLimit,uint32 flags,uint32 salt)" ) ); /* * @dev Check if the order is close-only order. Close-only order means the order can only close position * of the trader * @param order The order object * @return bool True if the order is close-only order */ function isCloseOnly(Order memory order) internal pure returns (bool) { return (order.flags & MASK_CLOSE_ONLY) > 0; } /* * @dev Check if the order is market order. Market order means the order which has no limit price, should be * executed immediately * @param order The order object * @return bool True if the order is market order */ function isMarketOrder(Order memory order) internal pure returns (bool) { return (order.flags & MASK_MARKET_ORDER) > 0; } /* * @dev Check if the order is stop-loss order. Stop-loss order means the order will trigger when the * price is worst than the trigger price * @param order The order object * @return bool True if the order is stop-loss order */ function isStopLossOrder(Order memory order) internal pure returns (bool) { return (order.flags & MASK_STOP_LOSS_ORDER) > 0; } /* * @dev Check if the order is take-profit order. Take-profit order means the order will trigger when * the price is better than the trigger price * @param order The order object * @return bool True if the order is take-profit order */ function isTakeProfitOrder(Order memory order) internal pure returns (bool) { return (order.flags & MASK_TAKE_PROFIT_ORDER) > 0; } /* * @dev Check if the flags contain close-only flag * @param flags The flags * @return bool True if the flags contain close-only flag */ function isCloseOnly(uint32 flags) internal pure returns (bool) { return (flags & MASK_CLOSE_ONLY) > 0; } /* * @dev Check if the flags contain market flag * @param flags The flags * @return bool True if the flags contain market flag */ function isMarketOrder(uint32 flags) internal pure returns (bool) { return (flags & MASK_MARKET_ORDER) > 0; } /* * @dev Check if the flags contain stop-loss flag * @param flags The flags * @return bool True if the flags contain stop-loss flag */ function isStopLossOrder(uint32 flags) internal pure returns (bool) { return (flags & MASK_STOP_LOSS_ORDER) > 0; } /* * @dev Check if the flags contain take-profit flag * @param flags The flags * @return bool True if the flags contain take-profit flag */ function isTakeProfitOrder(uint32 flags) internal pure returns (bool) { return (flags & MASK_TAKE_PROFIT_ORDER) > 0; } function useTargetLeverage(uint32 flags) internal pure returns (bool) { return (flags & MASK_USE_TARGET_LEVERAGE) > 0; } /* * @dev Get the hash of the order * @param order The order object * @return bytes32 The hash of the order */ function getOrderHash(Order memory order) internal pure returns (bytes32) { bytes32 result = keccak256(abi.encode(EIP712_ORDER_TYPE, order)); return keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, result)); } /* * @dev Decode the signature from the data * @param data The data object to decode * @return signature The signature */ function decodeSignature(bytes memory data) internal pure returns (bytes memory signature) { require(data.length >= 350, "broken data"); bytes32 r; bytes32 s; uint8 v; uint8 signType; assembly { r := mload(add(data, 318)) s := mload(add(data, 350)) v := byte(24, mload(add(data, 292))) signType := byte(25, mload(add(data, 292))) } signature = abi.encodePacked(r, s, v, signType); } /* * @dev Decode the order from the data * @param data The data object to decode * @return order The order */ function decodeOrderData(bytes memory data) internal pure returns (Order memory order) { require(data.length >= 256, "broken data"); bytes32 tmp; assembly { // trader / 20 mstore(add(order, 0), mload(add(data, 20))) // broker / 20 mstore(add(order, 32), mload(add(data, 40))) // relayer / 20 mstore(add(order, 64), mload(add(data, 60))) // referrer / 20 mstore(add(order, 96), mload(add(data, 80))) // liquidityPool / 20 mstore(add(order, 128), mload(add(data, 100))) // minTradeAmount / 32 mstore(add(order, 160), mload(add(data, 132))) // amount / 32 mstore(add(order, 192), mload(add(data, 164))) // limitPrice / 32 mstore(add(order, 224), mload(add(data, 196))) // triggerPrice / 32 mstore(add(order, 256), mload(add(data, 228))) // chainID / 32 mstore(add(order, 288), mload(add(data, 260))) // expiredAt + perpetualIndex + brokerFeeLimit + flags + salt + v + signType / 26 tmp := mload(add(data, 292)) } order.expiredAt = uint64(bytes8(tmp)); order.perpetualIndex = uint32(bytes4(tmp << 64)); order.brokerFeeLimit = uint32(bytes4(tmp << 96)); order.flags = uint32(bytes4(tmp << 128)); order.salt = uint32(bytes4(tmp << 160)); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.7.4; pragma experimental ABIEncoderV2; import "@openzeppelin/contracts-upgradeable/cryptography/ECDSAUpgradeable.sol"; import "../Type.sol"; library Signature { uint8 internal constant SIGN_TYPE_ETH = 0x0; uint8 internal constant SIGN_TYPE_EIP712 = 0x1; /* * @dev Get the signer of the transaction * @param signedHash The hash of the transaction * @param signature The signature of the transaction * @return signer The signer of the transaction */ function getSigner(bytes32 digest, bytes memory signature) internal pure returns (address signer) { bytes32 r; bytes32 s; uint8 v; uint8 signType; assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) signType := byte(1, mload(add(signature, 0x60))) } if (signType == SIGN_TYPE_ETH) { digest = ECDSAUpgradeable.toEthSignedMessageHash(digest); } else if (signType != SIGN_TYPE_EIP712) { revert("unsupported sign type"); } signer = ECDSAUpgradeable.recover(digest, v, r, s); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.7.4; import "@openzeppelin/contracts/utils/EnumerableSet.sol"; import "@openzeppelin/contracts-upgradeable/utils/EnumerableSetUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/math/SignedSafeMathUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; import "./SafeMathExt.sol"; library Utils { using SafeMathExt for int256; using SafeMathExt for uint256; using SafeMathUpgradeable for uint256; using SignedSafeMathUpgradeable for int256; using EnumerableSet for EnumerableSet.AddressSet; using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; using EnumerableSetUpgradeable for EnumerableSetUpgradeable.Bytes32Set; /* * @dev Check if two numbers have the same sign. Zero has the same sign with any number */ function hasTheSameSign(int256 x, int256 y) internal pure returns (bool) { if (x == 0 || y == 0) { return true; } return (x ^ y) >> 255 == 0; } /** * @dev Check if the trader has opened position in the trade. * Example: 2, 1 => true; 2, -1 => false; -2, -3 => true * @param amount The position of the trader after the trade * @param delta The update position amount of the trader after the trade * @return True if the trader has opened position in the trade */ function hasOpenedPosition(int256 amount, int256 delta) internal pure returns (bool) { if (amount == 0) { return false; } return Utils.hasTheSameSign(amount, delta); } /* * @dev Split the delta to two numbers. * Use for splitting the trading amount to the amount to close position and the amount to open position. * Examples: 2, 1 => 0, 1; 2, -1 => -1, 0; 2, -3 => -2, -1 */ function splitAmount(int256 amount, int256 delta) internal pure returns (int256, int256) { if (Utils.hasTheSameSign(amount, delta)) { return (0, delta); } else if (amount.abs() >= delta.abs()) { return (delta, 0); } else { return (amount.neg(), amount.add(delta)); } } /* * @dev Check if amount will be away from zero or cross zero if added the delta. * Use for checking if trading amount will make trader open position. * Example: 2, 1 => true; 2, -1 => false; 2, -3 => true */ function isOpen(int256 amount, int256 delta) internal pure returns (bool) { return Utils.hasTheSameSign(amount, delta) || amount.abs() < delta.abs(); } /* * @dev Get the id of the current chain */ function chainID() internal pure returns (uint256 id) { assembly { id := chainid() } } // function toArray( // EnumerableSet.AddressSet storage set, // uint256 begin, // uint256 end // ) internal view returns (address[] memory result) { // require(end > begin, "begin should be lower than end"); // uint256 length = set.length(); // if (begin >= length) { // return result; // } // uint256 safeEnd = end.min(length); // result = new address[](safeEnd.sub(begin)); // for (uint256 i = begin; i < safeEnd; i++) { // result[i.sub(begin)] = set.at(i); // } // return result; // } function toArray( EnumerableSetUpgradeable.AddressSet storage set, uint256 begin, uint256 end ) internal view returns (address[] memory result) { require(end > begin, "begin should be lower than end"); uint256 length = set.length(); if (begin >= length) { return result; } uint256 safeEnd = end.min(length); result = new address[](safeEnd.sub(begin)); for (uint256 i = begin; i < safeEnd; i++) { result[i.sub(begin)] = set.at(i); } return result; } function toArray( EnumerableSetUpgradeable.Bytes32Set storage set, uint256 begin, uint256 end ) internal view returns (bytes32[] memory result) { require(end > begin, "begin should be lower than end"); uint256 length = set.length(); if (begin >= length) { return result; } uint256 safeEnd = end.min(length); result = new bytes32[](safeEnd.sub(begin)); for (uint256 i = begin; i < safeEnd; i++) { result[i.sub(begin)] = set.at(i); } return result; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.7.4; import "@openzeppelin/contracts-upgradeable/utils/EnumerableSetUpgradeable.sol"; /** * @notice Perpetual state: * - INVALID: Uninitialized or not non-existent perpetual; * - INITIALIZING: Only when LiquidityPoolStorage.isRunning == false. Traders cannot perform operations; * - NORMAL: Full functional state. Traders is able to perform all operations; * - EMERGENCY: Perpetual is unsafe and only clear is available; * - CLEARED: All margin account is cleared. Trade could withdraw remaining margin balance. */ enum PerpetualState { INVALID, INITIALIZING, NORMAL, EMERGENCY, CLEARED } enum OrderType { LIMIT, MARKET, STOP } /** * @notice Data structure to store risk parameter value. */ struct Option { int256 value; int256 minValue; int256 maxValue; } /** * @notice Data structure to store oracle price data. */ struct OraclePriceData { int256 price; uint256 time; } /** * @notice Data structure to store user margin information. See MarginAccountModule.sol for details. */ struct MarginAccount { int256 cash; int256 position; int256 targetLeverage; } /** * @notice Data structure of an order object. */ struct Order { address trader; address broker; address relayer; address referrer; address liquidityPool; int256 minTradeAmount; int256 amount; int256 limitPrice; int256 triggerPrice; uint256 chainID; uint64 expiredAt; uint32 perpetualIndex; uint32 brokerFeeLimit; uint32 flags; uint32 salt; } /** * @notice Core data structure, a core . */ struct LiquidityPoolStorage { bool isRunning; bool isFastCreationEnabled; // addresses address creator; address operator; address transferringOperator; address governor; address shareToken; address accessController; bool reserved3; // isWrapped uint256 scaler; uint256 collateralDecimals; address collateralToken; // pool attributes int256 poolCash; uint256 fundingTime; uint256 reserved5; uint256 operatorExpiration; mapping(address => int256) reserved1; bytes32[] reserved2; // perpetuals uint256 perpetualCount; mapping(uint256 => PerpetualStorage) perpetuals; // insurance fund int256 insuranceFundCap; int256 insuranceFund; int256 donatedInsuranceFund; address reserved4; // reserved slot for future upgrade bytes32[16] reserved; } /** * @notice Core data structure, storing perpetual information. */ struct PerpetualStorage { uint256 id; PerpetualState state; address oracle; int256 totalCollateral; int256 openInterest; // prices OraclePriceData indexPriceData; OraclePriceData markPriceData; OraclePriceData settlementPriceData; // funding state int256 fundingRate; int256 unitAccumulativeFunding; // base parameters int256 initialMarginRate; int256 maintenanceMarginRate; int256 operatorFeeRate; int256 lpFeeRate; int256 referralRebateRate; int256 liquidationPenaltyRate; int256 keeperGasReward; int256 insuranceFundRate; int256 reserved1; int256 maxOpenInterestRate; // risk parameters Option halfSpread; Option openSlippageFactor; Option closeSlippageFactor; Option fundingRateLimit; Option fundingRateFactor; Option ammMaxLeverage; Option maxClosePriceDiscount; // users uint256 totalAccount; int256 totalMarginWithoutPosition; int256 totalMarginWithPosition; int256 redemptionRateWithoutPosition; int256 redemptionRateWithPosition; EnumerableSetUpgradeable.AddressSet activeAccounts; // insurance fund int256 reserved2; int256 reserved3; // accounts mapping(address => MarginAccount) marginAccounts; Option defaultTargetLeverage; // keeper address reserved4; EnumerableSetUpgradeable.AddressSet ammKeepers; EnumerableSetUpgradeable.AddressSet reserved5; // reserved slot for future upgrade bytes32[12] reserved; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity 0.7.4; import "../Type.sol"; interface IPerpetual { /** * @notice Deposit collateral to the perpetual. * Can only called when the perpetual's state is "NORMAL". * This method will always increase `cash` amount in trader's margin account. * * @param perpetualIndex The index of the perpetual in the liquidity pool. * @param trader The address of the trader. * @param amount The amount of collateral to deposit. The amount always use decimals 18. */ function deposit( uint256 perpetualIndex, address trader, int256 amount ) external; /** * @notice Withdraw collateral from the trader's account of the perpetual. * After withdrawn, trader shall at least has maintenance margin left in account. * Can only called when the perpetual's state is "NORMAL". * Margin account must at least keep * The trader's cash will decrease in the perpetual. * Need to update the funding state and the oracle price of each perpetual before * and update the funding rate of each perpetual after * * @param perpetualIndex The index of the perpetual in the liquidity pool. * @param trader The address of the trader. * @param amount The amount of collateral to withdraw. The amount always use decimals 18. */ function withdraw( uint256 perpetualIndex, address trader, int256 amount ) external; /** * @notice If the state of the perpetual is "CLEARED", anyone authorized withdraw privilege by trader can settle * trader's account in the perpetual. Which means to calculate how much the collateral should be returned * to the trader, return it to trader's wallet and clear the trader's cash and position in the perpetual. * * @param perpetualIndex The index of the perpetual in the liquidity pool * @param trader The address of the trader. */ function settle(uint256 perpetualIndex, address trader) external; /** * @notice Clear the next active account of the perpetual which state is "EMERGENCY" and send gas reward of collateral * to sender. If all active accounts are cleared, the clear progress is done and the perpetual's state will * change to "CLEARED". Active means the trader's account is not empty in the perpetual. * Empty means cash and position are zero * * @param perpetualIndex The index of the perpetual in the liquidity pool. */ function clear(uint256 perpetualIndex) external; /** * @notice Trade with AMM in the perpetual, require sender is granted the trade privilege by the trader. * The trading price is determined by the AMM based on the index price of the perpetual. * Trader must be initial margin safe if opening position and margin safe if closing position * @param perpetualIndex The index of the perpetual in the liquidity pool * @param trader The address of trader * @param amount The position amount of the trade * @param limitPrice The worst price the trader accepts * @param deadline The deadline of the trade * @param referrer The referrer's address of the trade * @param flags The flags of the trade * @return int256 The update position amount of the trader after the trade */ function trade( uint256 perpetualIndex, address trader, int256 amount, int256 limitPrice, uint256 deadline, address referrer, uint32 flags ) external returns (int256); /** * @notice Trade with AMM by the order, initiated by the broker. * The trading price is determined by the AMM based on the index price of the perpetual. * Trader must be initial margin safe if opening position and margin safe if closing position * @param orderData The order data object * @param amount The position amount of the trade * @return int256 The update position amount of the trader after the trade */ function brokerTrade(bytes memory orderData, int256 amount) external returns (int256); /** * @notice Liquidate the trader if the trader's margin balance is lower than maintenance margin (unsafe). * Liquidate can be considered as a forced trading between AMM and unsafe margin account; * Based on current liquidity of AMM, it may take positions up to an amount equal to all the position * of the unsafe account. Besides the position, trader need to pay an extra penalty to AMM * for taking the unsafe assets. See TradeModule.sol for ehe strategy of penalty. * * The liquidate price will be determined by AMM. * Caller of this method can be anyone, then get a reward to make up for transaction gas fee. * * If a trader's margin balance is lower than 0 (bankrupt), insurance fund will be use to fill the loss * to make the total profit and loss balanced. (first the `insuranceFund` then the `donatedInsuranceFund`) * * If insurance funds are drained, the state of perpetual will turn to enter "EMERGENCY" than shutdown. * Can only liquidate when the perpetual's state is "NORMAL". * * @param perpetualIndex The index of the perpetual in liquidity pool * @param trader The address of trader to be liquidated. * @return liquidationAmount The amount of positions actually liquidated in the transaction. The amount always use decimals 18. */ function liquidateByAMM(uint256 perpetualIndex, address trader) external returns (int256 liquidationAmount); /** * @notice This method is generally consistent with `liquidateByAMM` function, but there some difference: * - The liquidation price is no longer determined by AMM, but the mark price; * - The penalty is taken by trader who takes position but AMM; * * @param perpetualIndex The index of the perpetual in liquidity pool. * @param liquidator The address of liquidator to receive the liquidated position. * @param trader The address of trader to be liquidated. * @param amount The amount of position to be taken from liquidated trader. The amount always use decimals 18. * @param limitPrice The worst price liquidator accepts. * @param deadline The deadline of transaction. * @return liquidationAmount The amount of positions actually liquidated in the transaction. */ function liquidateByTrader( uint256 perpetualIndex, address liquidator, address trader, int256 amount, int256 limitPrice, uint256 deadline ) external returns (int256 liquidationAmount); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity 0.7.4; pragma experimental ABIEncoderV2; import "../Type.sol"; interface ILiquidityPool { /** * @notice Initialize the liquidity pool and set up its configuration. * * @param operator The operator's address of the liquidity pool. * @param collateral The collateral's address of the liquidity pool. * @param collateralDecimals The collateral's decimals of the liquidity pool. * @param governor The governor's address of the liquidity pool. * @param initData A bytes array contains data to initialize new created liquidity pool. */ function initialize( address operator, address collateral, uint256 collateralDecimals, address governor, bytes calldata initData ) external; /** * @notice Set the liquidity pool to running state. Can be call only once by operater.m n */ function runLiquidityPool() external; /** * @notice If you want to get the real-time data, call this function first */ function forceToSyncState() external; /** * @notice Add liquidity to the liquidity pool. * Liquidity provider deposits collaterals then gets share tokens back. * The ratio of added cash to share token is determined by current liquidity. * Can only called when the pool is running. * * @param cashToAdd The amount of cash to add. always use decimals 18. */ function addLiquidity(int256 cashToAdd) external; /** * @notice Remove liquidity from the liquidity pool. * Liquidity providers redeems share token then gets collateral back. * The amount of collateral retrieved may differ from the amount when adding liquidity, * The index price, trading fee and positions holding by amm will affect the profitability of providers. * Can only called when the pool is running. * * @param shareToRemove The amount of share token to remove. The amount always use decimals 18. * @param cashToReturn The amount of cash(collateral) to return. The amount always use decimals 18. */ function removeLiquidity(int256 shareToRemove, int256 cashToReturn) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity 0.7.4; pragma experimental ABIEncoderV2; import "../Type.sol"; interface ILiquidityPoolGetter { /** * @notice Get the info of the liquidity pool * @return isRunning True if the liquidity pool is running * @return isFastCreationEnabled True if the operator of the liquidity pool is allowed to create new perpetual * when the liquidity pool is running * @return addresses The related addresses of the liquidity pool * @return intNums Int type properties, see below for details. * @return uintNums Uint type properties, see below for details. */ function getLiquidityPoolInfo() external view returns ( bool isRunning, bool isFastCreationEnabled, // [0] creator, // [1] operator, // [2] transferringOperator, // [3] governor, // [4] shareToken, // [5] collateralToken, // [6] vault, address[7] memory addresses, // [0] vaultFeeRate, // [1] poolCash, // [2] insuranceFundCap, // [3] insuranceFund, // [4] donatedInsuranceFund, int256[5] memory intNums, // [0] collateralDecimals, // [1] perpetualCount // [2] fundingTime, // [3] operatorExpiration, uint256[4] memory uintNums ); /** * @notice Get the info of the perpetual. Need to update the funding state and the oracle price * of each perpetual before and update the funding rate of each perpetual after * @param perpetualIndex The index of the perpetual in the liquidity pool * @return state The state of the perpetual * @return oracle The oracle's address of the perpetual * @return nums The related numbers of the perpetual */ function getPerpetualInfo(uint256 perpetualIndex) external view returns ( PerpetualState state, address oracle, // [0] totalCollateral // [1] markPrice, (return settlementPrice if it is in EMERGENCY state) // [2] indexPrice, // [3] fundingRate, // [4] unitAccumulativeFunding, // [5] initialMarginRate, // [6] maintenanceMarginRate, // [7] operatorFeeRate, // [8] lpFeeRate, // [9] referralRebateRate, // [10] liquidationPenaltyRate, // [11] keeperGasReward, // [12] insuranceFundRate, // [13-15] halfSpread value, min, max, // [16-18] openSlippageFactor value, min, max, // [19-21] closeSlippageFactor value, min, max, // [22-24] fundingRateLimit value, min, max, // [25-27] ammMaxLeverage value, min, max, // [28-30] maxClosePriceDiscount value, min, max, // [31] openInterest, // [32] maxOpenInterestRate, // [33-35] fundingRateFactor value, min, max, // [36-38] defaultTargetLeverage value, min, max, int256[39] memory nums ); /** * @notice Get the account info of the trader. Need to update the funding state and the oracle price * of each perpetual before and update the funding rate of each perpetual after * @param perpetualIndex The index of the perpetual in the liquidity pool * @param trader The address of the trader * @return cash The cash(collateral) of the account * @return position The position of the account * @return availableMargin The available margin of the account * @return margin The margin of the account * @return settleableMargin The settleable margin of the account * @return isInitialMarginSafe True if the account is initial margin safe * @return isMaintenanceMarginSafe True if the account is maintenance margin safe * @return isMarginSafe True if the total value of margin account is beyond 0 * @return targetLeverage The target leverage for openning position. */ function getMarginAccount(uint256 perpetualIndex, address trader) external view returns ( int256 cash, int256 position, int256 availableMargin, int256 margin, int256 settleableMargin, bool isInitialMarginSafe, bool isMaintenanceMarginSafe, bool isMarginSafe, // bankrupt int256 targetLeverage ); /** * @notice Get the number of active accounts in the perpetual. * Active means the trader's account is not empty in the perpetual. * Empty means cash and position are zero * @param perpetualIndex The index of the perpetual in the liquidity pool * @return activeAccountCount The number of active accounts in the perpetual */ function getActiveAccountCount(uint256 perpetualIndex) external view returns (uint256); /** * @notice Get the active accounts in the perpetual whose index between begin and end. * Active means the trader's account is not empty in the perpetual. * Empty means cash and position are zero * @param perpetualIndex The index of the perpetual in the liquidity pool * @param begin The begin index * @param end The end index * @return result The active accounts in the perpetual whose index between begin and end */ function listActiveAccounts( uint256 perpetualIndex, uint256 begin, uint256 end ) external view returns (address[] memory result); /** * @notice Get the progress of clearing active accounts. * Return the number of total active accounts and the number of active accounts not cleared * @param perpetualIndex The index of the perpetual in the liquidity pool * @return left The left active accounts * @return total The total active accounts */ function getClearProgress(uint256 perpetualIndex) external view returns (uint256 left, uint256 total); /** * @notice Get the pool margin of the liquidity pool. * Pool margin is how much collateral of the pool considering the AMM's positions of perpetuals * @return poolMargin The pool margin of the liquidity pool */ function getPoolMargin() external view returns (int256 poolMargin, bool isSafe); /** * @notice Query the price, fees and cost when trade agaist amm. * The trading price is determined by the AMM based on the index price of the perpetual. * This method should returns the same result as a 'read-only' trade. * WARN: the result of this function is base on current storage of liquidityPool, not the latest. * To get the latest status, call `syncState` first. * * Flags is a 32 bit uint value which indicates: (from highest bit) * - close only only close position during trading; * - market order do not check limit price during trading; * - stop loss only available in brokerTrade mode; * - take profit only available in brokerTrade mode; * For stop loss and take profit, see `validateTriggerPrice` in OrderModule.sol for details. * * @param perpetualIndex The index of the perpetual in liquidity pool. * @param trader The address of trader. * @param amount The amount of position to trader, positive for buying and negative for selling. The amount always use decimals 18. * @param referrer The address of referrer who will get rebate from the deal. * @param flags The flags of the trade. * @return tradePrice The average fill price. * @return totalFee The total fee collected from the trader after the trade. * @return cost Deposit or withdraw to let effective leverage == targetLeverage if flags contain USE_TARGET_LEVERAGE. > 0 if deposit, < 0 if withdraw. */ function queryTrade( uint256 perpetualIndex, address trader, int256 amount, address referrer, uint32 flags ) external returns ( int256 tradePrice, int256 totalFee, int256 cost ); /** * @notice Query cash to add / share to mint when adding liquidity to the liquidity pool. * Only one of cashToAdd or shareToMint may be non-zero. * * @param cashToAdd The amount of cash to add, always use decimals 18. * @param shareToMint The amount of share token to mint, always use decimals 18. * @return cashToAddResult The amount of cash to add, always use decimals 18. Equal to cashToAdd if cashToAdd is non-zero. * @return shareToMintResult The amount of cash to add, always use decimals 18. Equal to shareToMint if shareToMint is non-zero. */ function queryAddLiquidity(int256 cashToAdd, int256 shareToMint) external view returns (int256 cashToAddResult, int256 shareToMintResult); /** * @notice Query cash to return / share to redeem when removing liquidity from the liquidity pool. * Only one of shareToRemove or cashToReturn may be non-zero. * Can only called when the pool is running. * * @param shareToRemove The amount of share token to redeem, always use decimals 18. * @param cashToReturn The amount of cash to return, always use decimals 18. * @return shareToRemoveResult The amount of share token to redeem, always use decimals 18. Equal to shareToRemove if shareToRemove is non-zero. * @return cashToReturnResult The amount of cash to return, always use decimals 18. Equal to cashToReturn if cashToReturn is non-zero. */ function queryRemoveLiquidity(int256 shareToRemove, int256 cashToReturn) external view returns (int256 shareToRemoveResult, int256 cashToReturnResult); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity 0.7.4; interface ILiquidityPoolGovernance { function setEmergencyState(uint256 perpetualIndex) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <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. * * ``` * 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. */ library EnumerableSetUpgradeable { // 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; // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. 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] = toDeleteIndex + 1; // All indexes are 1-based // 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) { require(set._values.length > index, "EnumerableSet: index out of bounds"); return set._values[index]; } // 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); } // 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)))); } // 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 on 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)); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity 0.7.4; import "./IProxyAdmin.sol"; interface IPoolCreator { function upgradeAdmin() external view returns (IProxyAdmin proxyAdmin); /** * @notice Create a liquidity pool with the latest version. * The sender will be the operator of pool. * * @param collateral he collateral address of the liquidity pool. * @param collateralDecimals The collateral's decimals of the liquidity pool. * @param nonce A random nonce to calculate the address of deployed contracts. * @param initData A bytes array contains data to initialize new created liquidity pool. * @return liquidityPool The address of the created liquidity pool. */ function createLiquidityPool( address collateral, uint256 collateralDecimals, int256 nonce, bytes calldata initData ) external returns (address liquidityPool, address governor); /** * @notice Upgrade a liquidity pool and governor pair then call a patch function on the upgraded contract (optional). * This method checks the sender and forwards the request to ProxyAdmin to do upgrading. * * @param targetVersionKey The key of version to be upgrade up. The target version must be compatible with * current version. * @param dataForLiquidityPool The patch calldata for upgraded liquidity pool. * @param dataForGovernor The patch calldata of upgraded governor. */ function upgradeToAndCall( bytes32 targetVersionKey, bytes memory dataForLiquidityPool, bytes memory dataForGovernor ) external; /** * @notice Indicates the universe settle state. * If the flag set to true: * - all the pereptual created by this poolCreator can be settled immediately; * - all the trading method will be unavailable. */ function isUniverseSettled() external view returns (bool); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity 0.7.4; import "./IProxyAdmin.sol"; interface ITracer { /** * @notice Activate the perpetual for the trader. Active means the trader's account is not empty in * the perpetual. Empty means cash and position are zero. Can only called by a liquidity pool. * * @param trader The address of the trader. * @param perpetualIndex The index of the perpetual in the liquidity pool. * @return True if the activation is successful. */ function activatePerpetualFor(address trader, uint256 perpetualIndex) external returns (bool); /** * @notice Deactivate the perpetual for the trader. Active means the trader's account is not empty in * the perpetual. Empty means cash and position are zero. Can only called by a liquidity pool. * * @param trader The address of the trader. * @param perpetualIndex The index of the perpetual in the liquidity pool. * @return True if the deactivation is successful. */ function deactivatePerpetualFor(address trader, uint256 perpetualIndex) external returns (bool); /** * @notice Liquidity pool must call this method when changing its ownership to the new operator. * Can only be called by a liquidity pool. This method does not affect 'ownership' or privileges * of operator but only make a record for further query. * * @param liquidityPool The address of the liquidity pool. * @param operator The address of the new operator, must be different from the old operator. */ function registerOperatorOfLiquidityPool(address liquidityPool, address operator) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity 0.7.4; import "./IProxyAdmin.sol"; interface IVersionControl { function owner() external view returns (address); function getLatestVersion() external view returns (bytes32 latestVersionKey); /** * @notice Get the details of the version. * * @param versionKey The key of the version to get. * @return liquidityPoolTemplate The address of the liquidity pool template. * @return governorTemplate The address of the governor template. * @return compatibility The compatibility of the specified version. */ function getVersion(bytes32 versionKey) external view returns ( address liquidityPoolTemplate, address governorTemplate, uint256 compatibility ); /** * @notice Get the description of the implementation of liquidity pool. * Description contains creator, create time, compatibility and note * * @param liquidityPool The address of the liquidity pool. * @param governor The address of the governor. * @return appliedVersionKey The version key of given liquidity pool and governor. */ function getAppliedVersionKey(address liquidityPool, address governor) external view returns (bytes32 appliedVersionKey); /** * @notice Check if a key is valid (exists). * * @param versionKey The key of the version to test. * @return isValid Return true if the version of given key is valid. */ function isVersionKeyValid(bytes32 versionKey) external view returns (bool isValid); /** * @notice Check if the implementation of liquidity pool target is compatible with the implementation base. * Being compatible means having larger compatibility. * * @param targetVersionKey The key of the version to be upgraded to. * @param baseVersionKey The key of the version to be upgraded from. * @return isCompatible True if the target version is compatible with the base version. */ function isVersionCompatible(bytes32 targetVersionKey, bytes32 baseVersionKey) external view returns (bool isCompatible); /** * @dev Get a certain number of implementations of liquidity pool within range [begin, end). * * @param begin The index of first element to retrieve. * @param end The end index of element, exclusive. * @return versionKeys An array contains current version keys. */ function listAvailableVersions(uint256 begin, uint256 end) external view returns (bytes32[] memory versionKeys); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity 0.7.4; import "./IProxyAdmin.sol"; interface IVariables { function owner() external view returns (address); /** * @notice Get the address of the vault * @return address The address of the vault */ function getVault() external view returns (address); /** * @notice Get the vault fee rate * @return int256 The vault fee rate */ function getVaultFeeRate() external view returns (int256); /** * @notice Get the address of the access controller. It's always its own address. * * @return address The address of the access controller. */ function getAccessController() external view returns (address); /** * @notice Get the address of the symbol service. * * @return Address The address of the symbol service. */ function getSymbolService() external view returns (address); /** * @notice Set the vault address. Can only called by owner. * * @param newVault The new value of the vault fee rate */ function setVault(address newVault) external; /** * @notice Get the address of the mcb token. * @dev [ConfirmBeforeDeployment] * * @return Address The address of the mcb token. */ function getMCBToken() external pure returns (address); /** * @notice Set the vault fee rate. Can only called by owner. * * @param newVaultFeeRate The new value of the vault fee rate */ function setVaultFeeRate(int256 newVaultFeeRate) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity 0.7.4; interface IKeeperWhitelist { /** * @notice Add an address to keeper whitelist. */ function addKeeper(address keeper) external; /** * @notice Remove an address from keeper whitelist. */ function removeKeeper(address keeper) external; /** * @notice Check if an address is in keeper whitelist. */ function isKeeper(address keeper) external view returns (bool); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity 0.7.4; interface IProxyAdmin { function getProxyImplementation(address proxy) external view returns (address); /** * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}. * * Requirements: * * - This contract must be the admin of `proxy`. */ function upgrade(address proxy, address implementation) external; /** * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See * {TransparentUpgradeableProxy-upgradeToAndCall}. * * Requirements: * * - This contract must be the admin of `proxy`. */ function upgradeAndCall( address proxy, address implementation, bytes memory data ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when 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. */ library SafeMathUpgradeable { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @title SignedSafeMath * @dev Signed math operations with safety checks that revert on error. */ library SignedSafeMathUpgradeable { int256 constant private _INT256_MIN = -2**255; /** * @dev Returns the multiplication of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(int256 a, int256 b) internal pure returns (int256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow"); int256 c = a * b; require(c / a == b, "SignedSafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two signed integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(int256 a, int256 b) internal pure returns (int256) { require(b != 0, "SignedSafeMath: division by zero"); require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow"); int256 c = a / b; return c; } /** * @dev Returns the subtraction of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(int256 a, int256 b) internal pure returns (int256) { int256 c = a - b; require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow"); return c; } /** * @dev Returns the addition of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(int256 a, int256 b) internal pure returns (int256) { int256 c = a + b; require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow"); return c; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.7.4; library Constant { address internal constant INVALID_ADDRESS = address(0); int256 internal constant SIGNED_ONE = 10**18; uint256 internal constant UNSIGNED_ONE = 10**18; uint256 internal constant PRIVILEGE_DEPOSIT = 0x1; uint256 internal constant PRIVILEGE_WITHDRAW = 0x2; uint256 internal constant PRIVILEGE_TRADE = 0x4; uint256 internal constant PRIVILEGE_LIQUIDATE = 0x8; uint256 internal constant PRIVILEGE_GUARD = PRIVILEGE_DEPOSIT | PRIVILEGE_WITHDRAW | PRIVILEGE_TRADE | PRIVILEGE_LIQUIDATE; // max number of uint256 uint256 internal constant SET_ALL_PERPETUALS_TO_EMERGENCY_STATE = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <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. * * ``` * 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. */ 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; // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. 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] = toDeleteIndex + 1; // All indexes are 1-based // 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) { require(set._values.length > index, "EnumerableSet: index out of bounds"); return set._values[index]; } // 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); } // 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)))); } // 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 on 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)); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSAUpgradeable { /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { // Check the signature length if (signature.length != 65) { revert("ECDSA: invalid signature length"); } // Divide the signature in r, s and v variables bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. // solhint-disable-next-line no-inline-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return recover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover-bytes32-bytes-} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "ECDSA: invalid signature 's' value"); require(v == 27 || v == 28, "ECDSA: invalid signature 'v' value"); // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); require(signer != address(0), "ECDSA: invalid signature"); return signer; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * replicates the behavior of the * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`] * JSON-RPC method. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } }
{ "optimizer": { "enabled": true, "runs": 1000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "libraries": {} }
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"userData1","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"userData2","type":"bytes32"},{"indexed":false,"internalType":"string","name":"functionSignature","type":"string"},{"indexed":false,"internalType":"bytes","name":"callData","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"signature","type":"bytes"}],"name":"CallFunction","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"CancelOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"indexed":false,"internalType":"int256","name":"fillAmount","type":"int256"}],"name":"FillOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"components":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"broker","type":"address"},{"internalType":"address","name":"relayer","type":"address"},{"internalType":"address","name":"referrer","type":"address"},{"internalType":"address","name":"liquidityPool","type":"address"},{"internalType":"int256","name":"minTradeAmount","type":"int256"},{"internalType":"int256","name":"amount","type":"int256"},{"internalType":"int256","name":"limitPrice","type":"int256"},{"internalType":"int256","name":"triggerPrice","type":"int256"},{"internalType":"uint256","name":"chainID","type":"uint256"},{"internalType":"uint64","name":"expiredAt","type":"uint64"},{"internalType":"uint32","name":"perpetualIndex","type":"uint32"},{"internalType":"uint32","name":"brokerFeeLimit","type":"uint32"},{"internalType":"uint32","name":"flags","type":"uint32"},{"internalType":"uint32","name":"salt","type":"uint32"}],"indexed":false,"internalType":"struct Order","name":"order","type":"tuple"},{"indexed":false,"internalType":"int256","name":"amount","type":"int256"},{"indexed":false,"internalType":"string","name":"reason","type":"string"}],"name":"TradeFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"components":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"broker","type":"address"},{"internalType":"address","name":"relayer","type":"address"},{"internalType":"address","name":"referrer","type":"address"},{"internalType":"address","name":"liquidityPool","type":"address"},{"internalType":"int256","name":"minTradeAmount","type":"int256"},{"internalType":"int256","name":"amount","type":"int256"},{"internalType":"int256","name":"limitPrice","type":"int256"},{"internalType":"int256","name":"triggerPrice","type":"int256"},{"internalType":"uint256","name":"chainID","type":"uint256"},{"internalType":"uint64","name":"expiredAt","type":"uint64"},{"internalType":"uint32","name":"perpetualIndex","type":"uint32"},{"internalType":"uint32","name":"brokerFeeLimit","type":"uint32"},{"internalType":"uint32","name":"flags","type":"uint32"},{"internalType":"uint32","name":"salt","type":"uint32"}],"indexed":false,"internalType":"struct Order","name":"order","type":"tuple"},{"indexed":false,"internalType":"int256","name":"amount","type":"int256"},{"indexed":false,"internalType":"uint256","name":"gasReward","type":"uint256"}],"name":"TradeSuccess","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[{"internalType":"address","name":"trader","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"compressedOrders","type":"bytes[]"},{"internalType":"int256[]","name":"amounts","type":"int256[]"},{"internalType":"uint256[]","name":"gasRewards","type":"uint256[]"}],"name":"batchTrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"broker","type":"address"},{"internalType":"address","name":"relayer","type":"address"},{"internalType":"address","name":"referrer","type":"address"},{"internalType":"address","name":"liquidityPool","type":"address"},{"internalType":"int256","name":"minTradeAmount","type":"int256"},{"internalType":"int256","name":"amount","type":"int256"},{"internalType":"int256","name":"limitPrice","type":"int256"},{"internalType":"int256","name":"triggerPrice","type":"int256"},{"internalType":"uint256","name":"chainID","type":"uint256"},{"internalType":"uint64","name":"expiredAt","type":"uint64"},{"internalType":"uint32","name":"perpetualIndex","type":"uint32"},{"internalType":"uint32","name":"brokerFeeLimit","type":"uint32"},{"internalType":"uint32","name":"flags","type":"uint32"},{"internalType":"uint32","name":"salt","type":"uint32"}],"internalType":"struct Order","name":"order","type":"tuple"}],"name":"cancelOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"broker","type":"address"},{"internalType":"address","name":"relayer","type":"address"},{"internalType":"address","name":"referrer","type":"address"},{"internalType":"address","name":"liquidityPool","type":"address"},{"internalType":"int256","name":"minTradeAmount","type":"int256"},{"internalType":"int256","name":"amount","type":"int256"},{"internalType":"int256","name":"limitPrice","type":"int256"},{"internalType":"int256","name":"triggerPrice","type":"int256"},{"internalType":"uint256","name":"chainID","type":"uint256"},{"internalType":"uint64","name":"expiredAt","type":"uint64"},{"internalType":"uint32","name":"perpetualIndex","type":"uint32"},{"internalType":"uint32","name":"brokerFeeLimit","type":"uint32"},{"internalType":"uint32","name":"flags","type":"uint32"},{"internalType":"uint32","name":"salt","type":"uint32"}],"internalType":"struct Order","name":"order","type":"tuple"}],"name":"getOrderFilledAmount","outputs":[{"internalType":"int256","name":"filledAmount","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"broker","type":"address"},{"internalType":"address","name":"relayer","type":"address"},{"internalType":"address","name":"referrer","type":"address"},{"internalType":"address","name":"liquidityPool","type":"address"},{"internalType":"int256","name":"minTradeAmount","type":"int256"},{"internalType":"int256","name":"amount","type":"int256"},{"internalType":"int256","name":"limitPrice","type":"int256"},{"internalType":"int256","name":"triggerPrice","type":"int256"},{"internalType":"uint256","name":"chainID","type":"uint256"},{"internalType":"uint64","name":"expiredAt","type":"uint64"},{"internalType":"uint32","name":"perpetualIndex","type":"uint32"},{"internalType":"uint32","name":"brokerFeeLimit","type":"uint32"},{"internalType":"uint32","name":"flags","type":"uint32"},{"internalType":"uint32","name":"salt","type":"uint32"}],"internalType":"struct Order","name":"order","type":"tuple"}],"name":"isOrderCanceled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
608060405234801561001057600080fd5b50600160008190555061002b61003360201b610ae01760201c565b600155610037565b4690565b612348806100466000396000f3fe6080604052600436106100745760003560e01c806389d1e3041161004e57806389d1e304146100fe578063abee6e5c1461012b578063ce4d643b1461014b578063d0e30db01461016b57610083565b80632e1a7d4d146100885780634e199146146100a857806370a08231146100de57610083565b366100835761008161016f565b005b600080fd5b34801561009457600080fd5b506100816100a3366004611864565b610238565b3480156100b457600080fd5b506100c86100c3366004611760565b610314565b6040516100d59190611c08565b60405180910390f35b3480156100ea57600080fd5b506100c86100f93660046115a9565b610336565b34801561010a57600080fd5b5061011e610119366004611760565b610355565b6040516100d59190611bfd565b34801561013757600080fd5b506100816101463660046115e1565b61037a565b34801561015757600080fd5b50610081610166366004611760565b61084e565b6100815b600260005414156101c7576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026000908155338152600360205260409020546101e59034610ae4565b33600081815260036020526040908190209290925590517fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c90610229903490611c08565b60405180910390a26001600055565b60026000541415610290576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026000908155338152600360205260409020546102ae9082610b45565b336000818152600360205260409020919091556102cb9082610ba2565b336001600160a01b03167f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364826040516103049190611c08565b60405180910390a2506001600055565b60008061032083610c8c565b6000908152600460205260409020549392505050565b6001600160a01b0381166000908152600360205260409020545b919050565b60008061036183610c8c565b60009081526005602052604090205460ff169392505050565b8460005b818110156108435761038e6113aa565b6103e989898481811061039d57fe5b90506020028101906103af9190612122565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610dab92505050565b905060606104488a8a858181106103fc57fe5b905060200281019061040e9190612122565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e9792505050565b9050600061045583610c8c565b83519091506001600160a01b031661046d8284610f09565b6001600160a01b03161461049c5760405162461bcd60e51b815260040161049390611fa0565b60405180910390fd5b60008989868181106104aa57fe5b90506020020135905060008888878181106104c157fe5b9050602002013590506001548561012001511461051f577f1955905acc03ff235236ed3bc847a2b24e6a1a945754ffad043f7b8e01adaeb783868460405161050b93929190611de7565b60405180910390a150505050505050610846565b60008381526005602052604090205460ff1615610569577f1955905acc03ff235236ed3bc847a2b24e6a1a945754ffad043f7b8e01adaeb783868460405161050b93929190611ca0565b6105768560c00151610f73565b600084815260046020526040902054610598906105939085610f93565b610f73565b13156105d1577f1955905acc03ff235236ed3bc847a2b24e6a1a945754ffad043f7b8e01adaeb783868460405161050b93929190611d00565b84516105dc90610336565b811115610616577f1955905acc03ff235236ed3bc847a2b24e6a1a945754ffad043f7b8e01adaeb783868460405161050b93929190611ea7565b633b9aca0085610180015163ffffffff1602811115610662577f1955905acc03ff235236ed3bc847a2b24e6a1a945754ffad043f7b8e01adaeb783868460405161050b93929190611e47565b8460a0015161067083610f73565b12156106a9577f1955905acc03ff235236ed3bc847a2b24e6a1a945754ffad043f7b8e01adaeb783868460405161050b93929190611d60565b84608001516001600160a01b0316634fababb38e8e898181106106c857fe5b90506020028101906106da9190612122565b856040518463ffffffff1660e01b81526004016106f993929190611f68565b602060405180830381600087803b15801561071357600080fd5b505af1925050508015610743575060408051601f3d908101601f1916820190925261074091810190611748565b60015b6107d75761074f612191565b8061075a57506107a4565b7f1955905acc03ff235236ed3bc847a2b24e6a1a945754ffad043f7b8e01adaeb78487858460405161078f9493929190611c26565b60405180910390a15050505050505050610846565b7f1955905acc03ff235236ed3bc847a2b24e6a1a945754ffad043f7b8e01adaeb783868460405161050b93929190611edf565b6107e18482610ff8565b6107f48660000151876040015184611055565b7fa31c4dcf97bfab49d7f55b0dbc9a7a49d25cdfa4cead657a12315b48bf11f89a848783856040516108299493929190611f3f565b60405180910390a15050506001909301925061037e915050565b50505b505050505050565b80516001600160a01b0316331480159061087e575080604001516001600160a01b0316336001600160a01b031614155b15610a4e5761088b611426565b81608001516001600160a01b0316630cdc105a6040518163ffffffff1660e01b81526004016102406040518083038186803b1580156108c957600080fd5b505afa1580156108dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109019190611691565b50509250505060008160006007811061091657fe5b60200201516001600160a01b03166316d6b5f66040518163ffffffff1660e01b815260040160206040518083038186803b15801561095357600080fd5b505afa158015610967573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098b91906115c5565b83516040517fc2f3da1d0000000000000000000000000000000000000000000000000000000081529192506000916001600160a01b0384169163c2f3da1d916109db919033906004908101611bd9565b60206040518083038186803b1580156109f357600080fd5b505afa158015610a07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2b9190611677565b905080610a4a5760405162461bcd60e51b815260040161049390612045565b5050505b6000610a5982610c8c565b60008181526005602052604090205490915060ff1615610a8b5760405162461bcd60e51b81526004016104939061200e565b60008181526005602052604090819020805460ff19166001179055517f42c76c81a7cba1b9c861353909a184e20747ab960332628dabcbb5852fc5cbb590610ad4908390611c08565b60405180910390a15050565b4690565b600082820183811015610b3e576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b600082821115610b9c576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b80471015610bf7576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015290519081900360640190fd5b6040516000906001600160a01b0384169083908381818185875af1925050503d8060008114610c42576040519150601f19603f3d011682016040523d82523d6000602084013e610c47565b606091505b5050905080610c875760405162461bcd60e51b815260040180806020018281038252603a815260200180612271603a913960400191505060405180910390fd5b505050565b600080604051602001610c9e90611a20565b6040516020818303038152906040528051906020012083604051602001610cc6929190611c11565b604051602081830303815290604052805190602001209050604051602001610ced90611bb0565b60408051601f1981840301815282825280516020918201208383018352600f84527f4d61692050726f746f636f6c2076330000000000000000000000000000000000938201939093529051610d6592917f553f7e2049687f24030220180e64af84dd1272d5c99c4810278beb4f6e74e30991016119cb565b6040516020818303038152906040528051906020012081604051602001610d8d929190611b7a565b60405160208183030381529060405280519060200120915050919050565b610db36113aa565b61010082511015610dd65760405162461bcd60e51b815260040161049390611fd7565b6014820151815260288201516020820152603c82015160408083019190915260508301516060808401919091526064840151608080850191909152608485015160a08086019190915260a486015160c08087019190915260c487015160e087015260e4870151610100870152610104870151610120870152610124909601519586901c61014086015263ffffffff9086901c81166101608601529085901c81166101808501529084901c81166101a084015292901c9091166101c082015290565b606061015e82511015610ebc5760405162461bcd60e51b815260040161049390611fd7565b61013e82015161015e830151610124840151604051601882901a9160191a90610eef9085908590859085906020016119d9565b604051602081830303815290604052945050505050919050565b602081015160408201516060830151600092919080841a9060011a80610f3957610f328761116e565b9650610f5c565b60ff8116600114610f5c5760405162461bcd60e51b8152600401610493906120d9565b610f68878386866111bf565b979650505050505050565b600080821215610f8b57610f868261133d565b610f8d565b815b92915050565b6000828201818312801590610fa85750838112155b80610fbd5750600083128015610fbd57508381125b610b3e5760405162461bcd60e51b81526004018080602001828103825260218152602001806122506021913960400191505060405180910390fd5b6000828152600460205260409020546110119082610f93565b6000838152600460205260409081902091909155517f66bc40b7d864f86356146c435fb0178293d08d80e04a8fba27d0e372ffe2d82b90610ad490849084906119cb565b6001600160a01b03821661107b5760405162461bcd60e51b8152600401610493906120a2565b8061108557610c87565b6001600160a01b0383166000908152600360205260409020548111156110bd5760405162461bcd60e51b815260040161049390612110565b6001600160a01b0383166000908152600360205260409020546110e09082610b45565b6001600160a01b03808516600090815260036020526040808220939093559084168152205461110f9082610ae4565b6001600160a01b0380841660008181526003602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611161908590611c08565b60405180910390a3505050565b604080517f19457468657265756d205369676e6564204d6573736167653a0a333200000000602080830191909152603c8083019490945282518083039094018452605c909101909152815191012090565b60007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08211156112205760405162461bcd60e51b81526004018080602001828103825260228152602001806122ab6022913960400191505060405180910390fd5b8360ff16601b148061123557508360ff16601c145b6112705760405162461bcd60e51b81526004018080602001828103825260228152602001806122cd6022913960400191505060405180910390fd5b600060018686868660405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156112cc573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611334576040805162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015290519081900360640190fd5b95945050505050565b6000610f8d600083600081830381831280159061135a5750838113155b8061136f575060008312801561136f57508381135b610b3e5760405162461bcd60e51b81526004018080602001828103825260248152602001806122ef6024913960400191505060405180910390fd5b604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081019190915290565b6040518060e001604052806007906020820280368337509192915050565b803561035081612237565b60008083601f840112611460578081fd5b50813567ffffffffffffffff811115611477578182fd5b602083019150836020808302850101111561149157600080fd5b9250929050565b600082601f8301126114a8578081fd5b60405160a0810181811067ffffffffffffffff821117156114c557fe5b6040529050808260a081018510156114dc57600080fd5b60005b60058110156114fe5781518352602092830192909101906001016114df565b50505092915050565b600082601f830112611517578081fd5b6040516080810181811067ffffffffffffffff8211171561153457fe5b604052905080826080810185101561154b57600080fd5b60005b60048110156114fe57815183526020928301929091019060010161154e565b8051801515811461035057600080fd5b803563ffffffff8116811461035057600080fd5b803567ffffffffffffffff8116811461035057600080fd5b6000602082840312156115ba578081fd5b8135610b3e81612237565b6000602082840312156115d6578081fd5b8151610b3e81612237565b600080600080600080606087890312156115f9578182fd5b863567ffffffffffffffff80821115611610578384fd5b61161c8a838b0161144f565b90985096506020890135915080821115611634578384fd5b6116408a838b0161144f565b90965094506040890135915080821115611658578384fd5b5061166589828a0161144f565b979a9699509497509295939492505050565b600060208284031215611688578081fd5b610b3e8261156d565b600080600080600061024086880312156116a9578081fd5b6116b28661156d565b945060206116c181880161156d565b945087605f8801126116d1578182fd5b6116db60e0612167565b80604089016101208a018b8111156116f1578586fd5b855b600781101561171957825161170781612237565b855293850193918501916001016116f3565b508297506117278c82611498565b9650505050505061173c876101c08801611507565b90509295509295909350565b600060208284031215611759578081fd5b5051919050565b60006101e0808385031215611773578182fd5b61177c81612167565b905061178783611444565b815261179560208401611444565b60208201526117a660408401611444565b60408201526117b760608401611444565b60608201526117c860808401611444565b608082015260a083013560a082015260c083013560c082015260e083013560e0820152610100808401358183015250610120808401358183015250610140611811818501611591565b9082015261016061182384820161157d565b9082015261018061183584820161157d565b908201526101a061184784820161157d565b908201526101c061185984820161157d565b908201529392505050565b600060208284031215611875578081fd5b5035919050565b6001600160a01b03169052565b601081527f696e73756666696369656e742066656500000000000000000000000000000000602082015260400190565b6118c482825161187c565b60208101516118d6602084018261187c565b5060408101516118e9604084018261187c565b5060608101516118fc606084018261187c565b50608081015161190f608084018261187c565b5060a081015160a083015260c081015160c083015260e081015160e083015261010080820151818401525061012080820151818401525061014080820151611959828501826119bd565b50506101608082015161196e828501826119b3565b505061018080820151611983828501826119b3565b50506101a080820151611998828501826119b3565b50506101c0808201516119ad828501826119b3565b50505050565b63ffffffff169052565b67ffffffffffffffff169052565b918252602082015260400190565b93845260208401929092527fff0000000000000000000000000000000000000000000000000000000000000060f891821b8116604085015291901b16604182015260420190565b7f4f726465722861646472657373207472616465722c616464726573732062726f81527f6b65722c616464726573732072656c617965722c61646472657373207265666560208201527f727265722c61646472657373206c6971756964697479506f6f6c2c000000000060408201527f696e74323536206d696e5472616465416d6f756e742c696e7432353620616d6f605b8201527f756e742c696e74323536206c696d697450726963652c696e7432353620747269607b8201527f6767657250726963652c75696e7432353620636861696e49442c000000000000609b8201527f75696e743634206578706972656441742c75696e74333220706572706574756160b58201527f6c496e6465782c75696e7433322062726f6b65724665654c696d69742c75696e60d58201527f74333220666c6167732c75696e7433322073616c74290000000000000000000060f582015261010b0190565b7f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b7f454950373132446f6d61696e28737472696e67206e616d652900000000000000815260190190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b901515815260200190565b90815260200190565b8281526102008101610b3e60208301846118b9565b60006102408683526020611c3c818501886118b9565b8561020085015281610220850152845180838601528392505b80831015611c7457858301820151858401610260015291810191611c55565b80831115611c86578361026082870101525b601f01601f19169390930161026001979650505050505050565b6000610240858352611cb560208401866118b9565b8361020084015280610220840152601181840152507f6f726465722069732063616e63656c656400000000000000000000000000000061026083015261028082019050949350505050565b6000610240858352611d1560208401866118b9565b8361020084015280610220840152601881840152507f6e6f20656e6f75676820616d6f756e7420746f2066696c6c000000000000000061026083015261028082019050949350505050565b6000610240858352611d7560208401866118b9565b8361020084015280610220840152602481840152507f616d6f756e74206973206c657373207468616e206d696e20747261646520616d6102608301527f6f756e74000000000000000000000000000000000000000000000000000000006102808301526102a082019050949350505050565b6000610240858352611dfc60208401866118b9565b8361020084015280610220840152601181840152507f636861696e206964206d69736d6174636800000000000000000000000000000061026083015261028082019050949350505050565b6000610240858352611e5c60208401866118b9565b8361020084015280610220840152601b81840152507f666565206578636565647320747261646520676173206c696d6974000000000061026083015261028082019050949350505050565b6000610240858352611ebc60208401866118b9565b8361020084015280610220840152611ed5818401611889565b9695505050505050565b6000610240858352611ef460208401866118b9565b8361020084015280610220840152601281840152507f7472616e73616374696f6e206661696c6564000000000000000000000000000061026083015261028082019050949350505050565b8481526102408101611f5460208301866118b9565b610200820193909352610220015292915050565b6000604082528360408301528385606084013780606085840101526060601f19601f8601168301019050826020830152949350505050565b6020808252600f908201527f7369676e6572206d69736d617463680000000000000000000000000000000000604082015260600190565b6020808252600b908201527f62726f6b656e2064617461000000000000000000000000000000000000000000604082015260600190565b60208082526019908201527f6f7264657220697320616c72656164792063616e63656c656400000000000000604082015260600190565b6020808252602e908201527f73656e646572206d75737420626520747261646572206f722072656c6179657260408201527f206f7220617574686f72697a6564000000000000000000000000000000000000606082015260800190565b6020808252601d908201527f74686520726563697069656e74206973207a65726f2061646472657373000000604082015260600190565b60208082526015908201527f756e737570706f72746564207369676e20747970650000000000000000000000604082015260600190565b600060208252610f8d60208301611889565b6000808335601e19843603018112612138578283fd5b83018035915067ffffffffffffffff821115612152578283fd5b60200191503681900382131561149157600080fd5b60405181810167ffffffffffffffff8111828210171561218357fe5b604052919050565b60e01c90565b600060443d10156121a157612234565b600481823e6308c379a06121b5825161218b565b146121bf57612234565b6040513d600319016004823e80513d67ffffffffffffffff81602484011181841117156121ef5750505050612234565b828401925082519150808211156122095750505050612234565b503d8301602082840101111561222157505050612234565b601f01601f191681016020016040529150505b90565b6001600160a01b038116811461224c57600080fd5b5056fe5369676e6564536166654d6174683a206164646974696f6e206f766572666c6f77416464726573733a20756e61626c6520746f2073656e642076616c75652c20726563697069656e74206d6179206861766520726576657274656445434453413a20696e76616c6964207369676e6174757265202773272076616c756545434453413a20696e76616c6964207369676e6174757265202776272076616c75655369676e6564536166654d6174683a207375627472616374696f6e206f766572666c6f77a26469706673582212203a462743d8a83dfce2767b18648b8110993daf64c8f8a9df2b7d080b2611e03564736f6c63430007040033
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.