protocol/docs/basics/functions.rst

584 lines
24 KiB
ReStructuredText

###############################
Basic Functionality
###############################
Below is a catalog of basic Exchange functionality. For more advanced usage, like meta-transactions and dex aggregation, see the Advanced section.
+---------------------------------+--------------------------------------------------------------------------+
| **Limit Orders** | **Overview** |
+---------------------------------+--------------------------------------------------------------------------+
| `fillLimitOrder`_ | Fills a Limit Order up to the amount requested. |
+---------------------------------+--------------------------------------------------------------------------+
| `fillOrKillLimitOrder`_ | Fills exactly the amount requested or reverts. |
+---------------------------------+--------------------------------------------------------------------------+
| `cancelLimitOrder`_ | Cancels an order so that it can no longer be filled. |
+---------------------------------+--------------------------------------------------------------------------+
| `batchCancelLimitOrders`_ | A batch call to `cancelLimitOrder`. |
+---------------------------------+--------------------------------------------------------------------------+
| `cancelPairLimitOrders`_ | Cancels Limit orders in a specific market pair. |
| | Ex: Cancel all Limit Orders selling WETH for USDC. |
+---------------------------------+--------------------------------------------------------------------------+
| `batchCancelLimitPairOrders`_ | A batch call to `cancelLimitPairOrders`. |
+---------------------------------+--------------------------------------------------------------------------+
| `getLimitOrderInfo`_ | Returns the state of a given order. |
+---------------------------------+--------------------------------------------------------------------------+
| `getLimitOrderHash`_ | Returns the EIP-712 hash for an order. |
+---------------------------------+--------------------------------------------------------------------------+
| **RFQ Orders** | **Overview** |
+---------------------------------+--------------------------------------------------------------------------+
| `fillRfqOrder`_ | These are analogous to the above LimitOrder functions. |
+---------------------------------+ |
| `fillOrKillRfqOrder`_ | |
+---------------------------------+ |
| `cancelRfqOrder`_ | |
+---------------------------------+ |
| `batchCancelRfqOrders`_ | |
+---------------------------------+ |
| `cancelPairRfqOrders`_ | |
+---------------------------------+ |
| `batchCancelPairRfqOrders`_ | |
+---------------------------------+ |
| `getRfqOrderInfo`_ | |
+---------------------------------+ |
| `getRfqOrderHash`_ | |
+---------------------------------+--------------------------------------------------------------------------+
| `registerAllowedRfqOrigins`_ | Register tx.origin addresses that are allowed to fill an RFQ order. |
+---------------------------------+--------------------------------------------------------------------------+
| **Protocol Fees** | **Overview** |
+---------------------------------+--------------------------------------------------------------------------+
| `getProtocolFeeMultiplier`_ | Takers of limit orders pay a protocol fee of `Multiplier * tx.gasprice`. |
| | This returns the `Multiplier`. |
+---------------------------------+--------------------------------------------------------------------------+
| `transferProtocolFeesForPools`_ | Transfers protocol fees from escrow to the 0x Staking System. |
| | This should be called near the end of each epoch. |
+---------------------------------+--------------------------------------------------------------------------+
Limit Orders
============
These are the basic functions for using a `Limit Order <../basics/orders.html#limit-orders>`_.
fillLimitOrder
--------------
Limit orders can be filled with the ``fillLimitOrder()`` or ``fillOrKillLimitOrder()`` functions on the Exchange Proxy. The address calling these function will be considered the "taker" of the order.
``fillLimitOrder()`` fills a single limit order for **up to** ``takerTokenFillAmount``:
.. code-block:: solidity
function fillLimitOrder(
// The order
LimitOrder calldata order,
// The signature
Signature calldata signature,
// How much taker token to fill the order with
uint128 takerTokenFillAmount
)
external
payable
// How much maker token from the order the taker received.
returns (uint128 takerTokenFillAmount, uint128 makerTokenFillAmount);
If the trade is successful a `LimitOrderFilled <../basics/events.html#limitorderfilled>`_ will be emitted. This function reverts under any of the following conditions:
- The order is fully filled: taker amount sold greater or equal to ``order.takerAmount``.
- The order has expired.
- The order was cancelled.
- The market pair (Ex, ``WETH/USDT``) was cancelled (``order.salt`` is less than the value passed to ``cancelPairLimitOrders``.
- Either the maker or taker has an insufficient allowance/balance.
- The order's ``taker`` field is non-zero and does not match the actual taker. This is ``msg.sender``, unless used with `meta-transactions <../advanced/mtx.rst>`_ in which case it is the signer.
- The order's ``sender`` field is non-zero and does not match ``msg.sender``.
- The maker's signature is invalid.
- The order's ``takerTokenFeeAmount`` is non-zero but the fee cannot be paid due to insufficient allowance/balance.
- Not enough ETH was sent with the transaction to cover the `Protocol Fee <../basics/protocol_fees.html>`_.
fillOrKillLimitOrder
--------------------
``fillOrKillLimitOrder()`` fills a single limit order for **exactly** ``takerTokenFillAmount``:
.. code-block:: solidity
function fillOrKillLimitOrder(
// The order
LimitOrder calldata order,
// The signature
Signature calldata signature,
// How much taker token to fill the order with
uint128 takerTokenFillAmount
)
external
payable
// How much maker token from the order the taker received.
returns (uint128 makerTokenFillAmount);
If the trade is successful a `LimitOrderFilled <../basics/events.html#limitorderfilled>`_ will be emitted. This function reverts under any of the conditions outlined above for ``fillLimitOrder``. Additionally, it will revert if the amount filled is less than ``takerTokenFillAmount``.
cancelLimitOrder
----------------
This function cancels a single limit order created by the caller:
.. code-block:: solidity
function cancelLimitOrder(
// The order
LimitOrder calldata order
)
external;
This function emits an `OrderCancelled <../basics/events.html#ordercancelled>`_ event if the cancellation is successful. The call will revert if ``msg.sender != order.maker``.
batchCancelLimitOrders
----------------------
This function cancels multiple limit orders created by the caller:
.. code-block:: solidity
function batchCancelLimitOrders(
// The orders
LimitOrder[] calldata orders
)
external;
This function emits an `OrderCancelled <../basics/events.html#ordercancelled>`_ event for each order it cancels. The call will revert if ``msg.sender != order.maker`` for any of the orders.
cancelPairLimitOrders
---------------------
This function cancels all limit orders created by the caller with with a maker and taker token pair and a ``salt`` field < the ``salt`` provided. Subsequent calls to this function with the same tokens must provide a ``salt`` >= the last call to succeed.
.. code-block:: solidity
function cancelPairRfqOrders(
address makerToken,
address takerToken,
uint256 salt;
)
external;
This function emits a `PairCancelledLimitOrders <../basics/events.html#paircancelledlimitorders>`_ event, or reverts in one of the following scenarios:
- ``msg.sender != order.maker``
- The ``salt`` parameter is ≤ to a previous ``salt``.
batchCancelLimitPairOrders
--------------------------
This function performs multiple ``cancelLimitPairOrders()`` at once. Each respective index across arrays is equivalent to a single call.
.. code-block:: solidity
function batchCancelLimitPairOrders(
address[] makerTokens,
address[] takerTokens,
uint256[] salts;
)
external;
This function emits a `PairCancelledLimitOrders <../basics/events.html#paircancelledlimitorders>`_ event for each market pair it cancels. It reverts if any of the individual cancellations revert.
getLimitOrderInfo
-----------------
The Exchange Proxy exposes a function ``getLimitOrderInfo()`` to query information about a limit order, such as its fillable state and how much it has been filled by.
.. code-block:: solidity
enum OrderStatus {
INVALID,
FILLABLE,
FILLED,
CANCELLED,
EXPIRED
}
struct OrderInfo {
// The order hash.
bytes32 orderHash;
// Current state of the order.
OrderStatus status;
// How much taker token has been filled in the order.
uint128 takerTokenFilledAmount;
}
function getLimitOrderInfo(
// The order
LimitOrder calldata order
)
external
view
returns (OrderInfo memory orderInfo);
getLimitOrderHash
-----------------
The hash of the order is used to uniquely identify an order inside the protocol. It is computed following the `EIP712 spec <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md>`_ standard. In solidity, the hash is computed as:
.. code-block:: solidity
/// @dev Get the canonical hash of a limit order.
/// @param order The limit order.
/// @return orderHash The order hash.
function getLimitOrderHash(LibNativeOrder.LimitOrder calldata order)
external
view
returns (bytes32 orderHash);
The simplest way to generate an order hash is by calling this function, ex:
.. code-block:: solidity
bytes32 orderHash = IZeroEx(0xDef1C0ded9bec7F1a1670819833240f027b25EfF).getLimitOrderHash(order);
The hash can be manually generated using the following code:
.. code-block:: solidity
bytes32 orderHash = keccak256(abi.encodePacked(
'\x19\x01',
// The domain separator.
keccak256(abi.encode(
// The EIP712 domain separator type hash.
keccak256(abi.encodePacked(
'EIP712Domain(',
'string name,',
'string version,',
'uint256 chainId,',
'address verifyingContract)'
)),
// The EIP712 domain separator values.
'ZeroEx',
'1.0.0',
1, // For mainnet
0xDef1C0ded9bec7F1a1670819833240f027b25EfF, // Address of the Exchange Proxy
)),
// The struct hash.
keccak256(abi.encode(
// The EIP712 type hash.
keccak256(abi.encodePacked(
'LimitOrder(',
'address makerToken,',
'address takerToken,',
'uint128 makerAmount,',
'uint128 takerAmount,',
'uint128 takerTokenFeeAmount,',
'address taker,',
'address maker,',
'address sender,',
'address feeRecipient,',
'bytes32 pool,',
'uint64 expiry,',
'uint256 salt)'
)),
// The struct values.
order.makerToken,
order.takerToken,
order.makerAmount,
order.takerAmount,
order.takerTokenFeeAmount,
order.maker,
order.taker,
order.sender,
order.feeRecipient,
order.pool,
order.expiry,
order.salt
))
));
RFQ Orders
==========
These are the basic functions for using an `RFQ Order <../basics/orders.html#rfq-orders>`_.
fillRfqOrder
------------
RFQ orders can be filled with the ``fillRfqOrder()`` or ``fillOrKillRfqOrder()`` functions on the Exchange Proxy. The address calling this function will be considered the "taker" of the order.
``fillRfqOrder()`` fills a single RFQ order for **up to** ``takerTokenFillAmount``:
.. code-block:: solidity
function fillRfqOrder(
// The order
RfqOrder calldata order,
// The signature
Signature calldata signature,
// How much taker token to fill the order with
uint128 takerTokenFillAmount
)
external
payable
// How much maker token from the order the taker received.
returns (uint128 takerTokenFillAmount, uint128 makerTokenFillAmount);
If the trade is successful a `RfqOrderFilled <../basics/events.html#rfqorderfilled>`_ will be emitted. This function reverts under any of the following conditions:
- The order is fully filled: taker amount sold greater or equal to ``order.takerAmount``.
- The order has expired.
- The order was cancelled.
- The market pair (Ex, ``WETH/USDT``) was cancelled (``order.salt`` is less than the value passed to ``cancelPairLimitOrders``.
- Either the maker or taker has an insufficient allowance/balance.
- The order's ``taker`` field is non-zero and does not match the actual taker. This is ``msg.sender``, unless used with `meta-transactions <../advanced/mtx.rst>`_ in which case it is the signer.
- The order's ``origin`` field is non-zero and does not match ``tx.origin`` or a valid origin (see `registerAllowedRfqOrigins <../basics/functions.html#id11>`_).
- The maker's signature is invalid.
fillOrKillRfqOrder
------------------
``fillOrKillRfqOrder()`` fills a single RFQ order for **exactly** ``takerTokenFillAmount``:
.. code-block:: solidity
function fillOrKillRfqOrder(
// The order
RfqOrder calldata order,
// The signature
Signature calldata signature,
// How much taker token to fill the order with
uint128 takerTokenFillAmount
)
external
payable
// How much maker token from the order the taker received.
returns (uint128 makerTokenFillAmount);
If the trade is successful a `RfqOrderFilled <../basics/events.html#rfqorderfilled>`_ will be emitted. This function reverts under any of the conditions outlined above for ``fillRfqOrder``. Additionally, it will revert if the amount filled is less than ``takerTokenFillAmount``.
cancelRfqOrder
--------------
Similar to limit orders, RFQ orders can be cancelled on-chain through a variety of functions, which can only be called by the order's maker.
``cancelRfqOrder()`` cancels a single RFQ order created by the caller:
.. code-block:: solidity
function cancelRfqOrder(
// The order
RfqOrder calldata order
)
external;
This function emits an `OrderCancelled <../basics/events.html#ordercancelled>`_ event if the cancellation is successful. The call will revert if ``msg.sender != order.maker``.
batchCancelRfqOrders
--------------------
This function cancels multiple RFQ orders created by the caller:
.. code-block:: solidity
function batchCancelRfqOrders(
// The orders
RfqOrder[] calldata orders
)
external;
This function emits an `OrderCancelled <../basics/events.html#ordercancelled>`_ event for each order it cancels. The call will revert if ``msg.sender != order.maker`` for any of the orders.
cancelPairRfqOrders
-------------------
This function cancels all RFQ orders created by the caller with with a maker and taker token pair and a ``salt`` field < the ``salt`` provided. Subsequent calls to this function with the same tokens must provide a ``salt`` >= the last call to succeed.
.. code-block:: solidity
function cancelPairRfqOrders(
address makerToken,
address takerToken,
uint256 salt;
)
external;
This function emits a `PairCancelledRfqOrders <../basics/events.html#paircancelledrfqorders>`_ event, or reverts in one of the following scenarios:
- ``msg.sender != order.maker``
- The ``salt`` parameter is ≤ to a previous ``salt``.
batchCancelPairRfqOrders
------------------------
``batchCancelPairRfqOrders()`` performs multiple ``cancelPairRfqOrders()`` at once. Each respective index across arrays is equivalent to a single call.
.. code-block:: solidity
function batchCancelPairRfqOrders(
address[] makerTokens,
address[] takerTokens,
uint256[] salts;
)
external;
This function emits a `PairCancelledRfqOrders <../basics/events.html#paircancelledrfqorders>`_ event for each market pair it cancels. It reverts if any of the individual cancellations revert.
getRfqOrderInfo
---------------
The Exchange Proxy exposes a function ``getRfqOrderInfo()`` to query information about an RFQ order, such as its fillable state and how much it has been filled by.
.. code-block:: solidity
enum OrderStatus {
INVALID,
FILLABLE,
FILLED,
CANCELLED,
EXPIRED
}
struct OrderInfo {
// The order hash.
bytes32 orderHash;
// Current state of the order.
OrderStatus status;
// How much taker token has been filled in the order.
uint128 takerTokenFilledAmount;
}
function getRfqOrderInfo(
// The order
RfqOrder calldata order
)
external
view
returns (OrderInfo memory orderInfo);
getRfqOrderHash
---------------
The hash of the order is used to uniquely identify an order inside the protocol. It is computed following the `EIP712 spec <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md>`_ standard. In solidity, the hash is computed using:
.. code-block:: solidity
/// @dev Get the canonical hash of an RFQ order.
/// @param order The RFQ order.
/// @return orderHash The order hash.
function getRfqOrderHash(LibNativeOrder.RfqOrder calldata order)
external
view
returns (bytes32 orderHash);
The simplest way to generate an order hash is by calling this function, ex:
.. code-block:: solidity
bytes32 orderHash = IZeroEx(0xDef1C0ded9bec7F1a1670819833240f027b25EfF).getRfqOrderHash(order);
The hash can be manually generated using the following code:
.. code-block:: solidity
bytes32 orderHash = keccak256(abi.encodePacked(
'\x19\x01',
// The domain separator.
keccak256(abi.encode(
// The EIP712 domain separator type hash.
keccak256(abi.encodePacked(
'EIP712Domain(',
'string name,',
'string version,',
'uint256 chainId,',
'address verifyingContract)'
)),
// The EIP712 domain separator values.
'ZeroEx',
'1.0.0',
1, // For mainnet
0xDef1C0ded9bec7F1a1670819833240f027b25EfF, // Address of the Exchange Proxy
)),
// The struct hash.
keccak256(abi.encode(
// The EIP712 type hash.
keccak256(abi.encodePacked(
'RfqOrder(',
'address makerToken,',
'address takerToken,',
'uint128 makerAmount,',
'uint128 takerAmount,',
'address maker,'
'address taker,'
'address txOrigin,'
'bytes32 pool,',
'uint64 expiry,',
'uint256 salt)'
)),
// The struct values.
order.makerToken,
order.takerToken,
order.makerAmount,
order.takerAmount,
order.maker,
order.taker,
order.txOrigin,
order.pool,
order.expiry,
order.salt
))
));
registerAllowedRfqOrigins
-------------------------
The RFQ order includes a ``txOrigin`` field, which a maker can use to restrict which EOA's can submit the Ethereum transaction that fills their order. There are two ways a maker can use this field.
1. Set to the EOA that will submit the transaction (ex, the Taker or a Meta-Transaction relayer).
2. Set to an EOA owned by the maker, which acts as a registry key to lookup valid tx origins.
Looking at the 2nd use case, a maker can register valid tx origins using this function. They would then set ``order.origin`` to be the address they used to call ``registerAllowedRfqOrigins``.
.. code-block:: solidity
/// @dev Mark what tx.origin addresses are allowed to fill an order that
/// specifies the message sender as its txOrigin.
/// @param origins An array of origin addresses to update.
/// @param allowed True to register, false to unregister.
function registerAllowedRfqOrigins(address[] memory origins, bool allowed)
external;
This function emits a `RfqOrderOriginsAllowed <../basics/events.html#rfqorderoriginsallowed>`_ event.
Protocol Fees
=============
There is a fixed protocol fee paid by the Taker each time they fill a `Limit Order <orders.html#limit-orders>`_. Learn more in the `Protocol Fees Section <./protocol_fees.html>`_. Also check out our research in the `Tokenomics Section <../tokenomics/research.html>`_.
getProtocolFeeMultiplier
------------------------
Takers of limit orders pay a protocol fee of Multiplier * tx.gasprice. This returns the Multiplier.
.. code-block:: solidity
/// @dev Get the protocol fee multiplier. This should be multiplied by the
/// gas price to arrive at the required protocol fee to fill a native order.
/// @return multiplier The protocol fee multiplier.
function getProtocolFeeMultiplier()
external
view
returns (uint32 multiplier);
transferProtocolFeesForPools
----------------------------
This function transfers protocol fees from `Fee Collectors <../architecture/fee_collectors.html>`_ to the `Staking System <../tokenomics/staking.html>`_.
.. code-block:: solidity
/// @dev Transfers protocol fees from the `FeeCollector` pools into
/// the staking contract.
/// @param poolIds Staking pool IDs
function transferProtocolFeesForPools(bytes32[] calldata poolIds)
external;