deleted docs that i already imported

This commit is contained in:
xianny
2021-05-20 12:47:22 -07:00
parent 7886d913fa
commit 7f7d587974
34 changed files with 0 additions and 4357 deletions

View File

@@ -1,235 +0,0 @@
---
title: ERC20 Transformations
---
The 0x Protocol is able to perform a variety of atomic transformations
on ERC20 tokens, in addition to simply executing trades. This is made
possible through composable smart contracts, called
[Transformers](../architecture/transformers.html). These trustless
modules extend the core Exchange logic, enabling workflows like
converting between ETH\<\>WETH or aggregating liquidity across DEX\'s.
These operations can be combined with trade exeuction to create a
seamlesss trading experience.
Anyone can run transformations using the `transformERC20` Exchange
function.
``` {.solidity}
/// @dev Executes a series of transformations to convert an ERC20 `inputToken`
/// to an ERC20 `outputToken`.
/// @param inputToken The token being provided by the sender.
/// If `0xeee...`, ETH is implied and should be provided with the call.`
/// @param outputToken The token to be acquired by the sender.
/// `0xeee...` implies ETH.
/// @param inputTokenAmount The amount of `inputToken` to take from the sender.
/// If set to `uint256(-1)`, the entire spendable balance of the taker
/// will be solt.
/// @param minOutputTokenAmount The minimum amount of `outputToken` the sender
/// must receive for the entire transformation to succeed. If set to zero,
/// the minimum output token transfer will not be asserted.
/// @param transformations The transformations to execute on the token balance(s)
/// in sequence.
/// @return outputTokenAmount The amount of `outputToken` received by the sender.
function transformERC20(
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
uint256 inputTokenAmount,
uint256 minOutputTokenAmount,
Transformation[] memory transformations
)
public
override
payable
returns (uint256 outputTokenAmount);
```
A Transformation is defined by a `deploymentNonce` (which identifies the
contract that implements the transformation) and `data` for that
contract.
``` {.solidity}
/// @dev Defines a transformation to run in `transformERC20()`.
struct Transformation {
// The deployment nonce for the transformer.
// The address of the transformer contract will be derived from this
// value.
uint32 deploymentNonce;
// Arbitrary data to pass to the transformer.
bytes data;
}
```
The transaction will revert if a transformation fails; the
[inputTokenAmount]{.title-ref} cannot be transferred from the sender; or
the `minOutputTokenAmount` is not transferred to the sender. A single
[TransformedERC20](../basics/events.html#transformederc20) event is be
emitted upon successful execution of all transformations.
# Liquidity Aggregation
Liquidity can be pulled from other Decentralized Exchanges (DEX) to
supplement native liquidity (0x orders). This is currently used by 0x
API to provide the aggregate the best prices across the entire DEX
Ecosystem. Check out <https://matcha.xyz> to see this in action!
Supported DEX\'s:
- Balancer
- Curve
- DoDo
- Kyber
- MStable
- Mooniswap
- Oasis
- Shell
- Sushiswap
- Uniswap v1/v2
This transformation is implemented by the
[FillQuoteTransformer](../architecture/transformers.html). Abi-Encode
the following struct to get the `data`:
::: {.warning}
::: {.title}
Warning
:::
An upgrade is pending to this transformation. This currently uses
Exchange V3 Orders, but will soon be updated to use [V4
Orders](../basics/orders.html). - 11/26/2020
:::
``` {.solidity}
/// @dev Transform data to ABI-encode and pass into `transform()`.
struct TransformData {
// Whether we are performing a market sell or buy.
Side side;
// The token being sold.
// This should be an actual token, not the ETH pseudo-token.
IERC20TokenV06 sellToken;
// The token being bought.
// This should be an actual token, not the ETH pseudo-token.
IERC20TokenV06 buyToken;
// The orders to fill.
IExchange.Order[] orders;
// Signatures for each respective order in `orders`.
bytes[] signatures;
// Maximum fill amount for each order. This may be shorter than the
// number of orders, where missing entries will be treated as `uint256(-1)`.
// For sells, this will be the maximum sell amount (taker asset).
// For buys, this will be the maximum buy amount (maker asset).
uint256[] maxOrderFillAmounts;
// Amount of `sellToken` to sell or `buyToken` to buy.
// For sells, this may be `uint256(-1)` to sell the entire balance of
// `sellToken`.
uint256 fillAmount;
// Who to transfer unused protocol fees to.
// May be a valid address or one of:
// `address(0)`: Stay in flash wallet.
// `address(1)`: Send to the taker.
// `address(2)`: Send to the sender (caller of `transformERC20()`).
address payable refundReceiver;
// Required taker address for RFQT orders.
// Null means any taker can fill it.
address rfqtTakerAddress;
}
```
This transformation currently executes a Market Sell or Market Buy on a
series of [0x V3
Orders](https://github.com/0xProject/0x-protocol-specification/blob/master/v3/v3-specification.md#orders).
The transaction will revert if the `fillAmount` is not reached; an
individual order can fail without the entire transaction reverting. A
[ProtocolFeeUnfunded](../basics/events.html#protocolfeeunfunded) event
will be emitted if an order failed to fill because the Taker did not
send a sufficient protocol fee.
# WETH Wrapping
This transformation is implemented by the
[WethTransformer](../architecture/transformers.html). Abi-Encode the
following struct to get the `data`:
``` {.solidity}
/// @dev Transform data to ABI-encode and pass into `transform()`.
struct TransformData {
// The token to wrap/unwrap. Must be either ETH or WETH.
IERC20TokenV06 token;
// Amount of `token` to wrap or unwrap.
// `uint(-1)` will unwrap the entire balance.
uint256 amount;
}
```
If the supplied token address is [WETH
(etherToken)](../basics/addresses.html) then the supplied WETH will be
unwrapped to `ETH`. If any other address is supplied the any ETH passed
in will be wrapped into `WETH`. No events are emitted by 0x during this
transformation, although token contracts may have events. This will
revert if `allowances <../basics/allowances.html>_` are not set or the
available balance is less than `amount`.
# Affiliate Fees
This transformation is implemented by the
[AffiliateFeeTransformer](../architecture/transformers.html). Abi-Encode
the following struct to get the `data`:
``` {.solidity}
/// @dev Information for a single fee.
struct TokenFee {
// The token to transfer to `recipient`.
IERC20TokenV06 token;
// Amount of each `token` to transfer to `recipient`.
// If `amount == uint256(-1)`, the entire balance of `token` will be
// transferred.
uint256 amount;
// Recipient of `token`.
address payable recipient;
}
```
This pays the `recipient` in the `amount` of `token` specified. This can
be used by integrators who wish to add an additional fee on top of 0x
Orders. No events are emitted by 0x during this transformation, although
token contracts may have events. This will revert if
[allowances](../basics/allowances.html) are not set or the available
balance is less than `amount`.
# Pay Taker
This transformation is implemented by the
[PayTakerTransformer](../architecture/transformers.html). Abi-Encode the
following struct to get the `data`:
``` {.solidity}
/// @dev Transform data to ABI-encode and pass into `transform()`.
struct TransformData {
// The tokens to transfer to the taker.
IERC20TokenV06[] tokens;
// Amount of each token in `tokens` to transfer to the taker.
// `uint(-1)` will transfer the entire balance.
uint256[] amounts;
}
```
This pays the `taker` in the `amounts` of each `tokens` specified. This
is generally run at the end of all other transformations. For example,
if you\'ve swapped the taker\'s ETH for WETH then executed a trade
through [Liquidity Aggregation](#liquidity-aggregation), this
transformation will can transfer the final output token back to the
Taker.
No events are emitted by 0x during this transformation, although token
contracts may have events. This will revert if
[allowances](../basics/allowances.html) are not set or the available
balance is less than `amount`.
# Adding Custom Transformations
Transformations are trustless, but at this time they are permissioned so
only 0x Labs can deploy new Transformers. If you are interested in
deploying your own transformation logic, please reach out to us on
[Discord](https://discord.com/invite/d3FTX3M). Learn more about why this
is permissioned in the [Transformer
Deployer](../architecture/transformer_deployer.html) section.

View File

@@ -1,178 +0,0 @@
###############################
ERC20 Transformations
###############################
The 0x Protocol is able to perform a variety of atomic transformations on ERC20 tokens, in addition to simply executing trades. This is made possible through composable smart contracts, called `Transformers <../architecture/transformers.html>`_. These trustless modules extend the core Exchange logic, enabling workflows like converting between ETH<>WETH or aggregating liquidity across DEX's. These operations can be combined with trade exeuction to create a seamlesss trading experience.
Anyone can run transformations using the ``transformERC20`` Exchange function.
.. code-block:: solidity
/// @dev Executes a series of transformations to convert an ERC20 `inputToken`
/// to an ERC20 `outputToken`.
/// @param inputToken The token being provided by the sender.
/// If `0xeee...`, ETH is implied and should be provided with the call.`
/// @param outputToken The token to be acquired by the sender.
/// `0xeee...` implies ETH.
/// @param inputTokenAmount The amount of `inputToken` to take from the sender.
/// If set to `uint256(-1)`, the entire spendable balance of the taker
/// will be solt.
/// @param minOutputTokenAmount The minimum amount of `outputToken` the sender
/// must receive for the entire transformation to succeed. If set to zero,
/// the minimum output token transfer will not be asserted.
/// @param transformations The transformations to execute on the token balance(s)
/// in sequence.
/// @return outputTokenAmount The amount of `outputToken` received by the sender.
function transformERC20(
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
uint256 inputTokenAmount,
uint256 minOutputTokenAmount,
Transformation[] memory transformations
)
public
override
payable
returns (uint256 outputTokenAmount);
A Transformation is defined by a ``deploymentNonce`` (which identifies the contract that implements the transformation) and ``data`` for that contract.
.. code-block:: solidity
/// @dev Defines a transformation to run in `transformERC20()`.
struct Transformation {
// The deployment nonce for the transformer.
// The address of the transformer contract will be derived from this
// value.
uint32 deploymentNonce;
// Arbitrary data to pass to the transformer.
bytes data;
}
The transaction will revert if a transformation fails; the `inputTokenAmount` cannot be transferred from the sender; or the ``minOutputTokenAmount`` is not transferred to the sender. A single `TransformedERC20 <../basics/events.html#transformederc20>`_ event is be emitted upon successful execution of all transformations.
Liquidity Aggregation
---------------------
Liquidity can be pulled from other Decentralized Exchanges (DEX) to supplement native liquidity (0x orders). This is currently used by 0x API to provide the aggregate the best prices across the entire DEX Ecosystem. Check out `https://matcha.xyz <https://matcha.xyz>`_ to see this in action!
Supported DEX's:
* Balancer
* Curve
* DoDo
* Kyber
* MStable
* Mooniswap
* Oasis
* Shell
* Sushiswap
* Uniswap v1/v2
This transformation is implemented by the `FillQuoteTransformer <../architecture/transformers.html>`_. Abi-Encode the following struct to get the ``data``:
.. warning::
An upgrade is pending to this transformation. This currently uses Exchange V3 Orders, but will soon be updated to use `V4 Orders <../basics/orders.html>`_. - 11/26/2020
.. code-block:: solidity
/// @dev Transform data to ABI-encode and pass into `transform()`.
struct TransformData {
// Whether we are performing a market sell or buy.
Side side;
// The token being sold.
// This should be an actual token, not the ETH pseudo-token.
IERC20TokenV06 sellToken;
// The token being bought.
// This should be an actual token, not the ETH pseudo-token.
IERC20TokenV06 buyToken;
// The orders to fill.
IExchange.Order[] orders;
// Signatures for each respective order in `orders`.
bytes[] signatures;
// Maximum fill amount for each order. This may be shorter than the
// number of orders, where missing entries will be treated as `uint256(-1)`.
// For sells, this will be the maximum sell amount (taker asset).
// For buys, this will be the maximum buy amount (maker asset).
uint256[] maxOrderFillAmounts;
// Amount of `sellToken` to sell or `buyToken` to buy.
// For sells, this may be `uint256(-1)` to sell the entire balance of
// `sellToken`.
uint256 fillAmount;
// Who to transfer unused protocol fees to.
// May be a valid address or one of:
// `address(0)`: Stay in flash wallet.
// `address(1)`: Send to the taker.
// `address(2)`: Send to the sender (caller of `transformERC20()`).
address payable refundReceiver;
// Required taker address for RFQT orders.
// Null means any taker can fill it.
address rfqtTakerAddress;
}
This transformation currently executes a Market Sell or Market Buy on a series of `0x V3 Orders <https://github.com/0xProject/0x-protocol-specification/blob/master/v3/v3-specification.md#orders>`_. The transaction will revert if the ``fillAmount`` is not reached; an individual order can fail without the entire transaction reverting. A `ProtocolFeeUnfunded <../basics/events.html#protocolfeeunfunded>`_ event will be emitted if an order failed to fill because the Taker did not send a sufficient protocol fee.
WETH Wrapping
-------------
This transformation is implemented by the `WethTransformer <../architecture/transformers.html>`_. Abi-Encode the following struct to get the ``data``:
.. code-block:: solidity
/// @dev Transform data to ABI-encode and pass into `transform()`.
struct TransformData {
// The token to wrap/unwrap. Must be either ETH or WETH.
IERC20TokenV06 token;
// Amount of `token` to wrap or unwrap.
// `uint(-1)` will unwrap the entire balance.
uint256 amount;
}
If the supplied token address is `WETH (etherToken) <../basics/addresses.html>`_ then the supplied WETH will be unwrapped to ``ETH``. If any other address is supplied the any ETH passed in will be wrapped into ``WETH``. No events are emitted by 0x during this transformation, although token contracts may have events. This will revert if ``allowances <../basics/allowances.html>_`` are not set or the available balance is less than ``amount``.
Affiliate Fees
--------------
This transformation is implemented by the `AffiliateFeeTransformer <../architecture/transformers.html>`_. Abi-Encode the following struct to get the ``data``:
.. code-block:: solidity
/// @dev Information for a single fee.
struct TokenFee {
// The token to transfer to `recipient`.
IERC20TokenV06 token;
// Amount of each `token` to transfer to `recipient`.
// If `amount == uint256(-1)`, the entire balance of `token` will be
// transferred.
uint256 amount;
// Recipient of `token`.
address payable recipient;
}
This pays the ``recipient`` in the ``amount`` of ``token`` specified. This can be used by integrators who wish to add an additional fee on top of 0x Orders. No events are emitted by 0x during this transformation, although token contracts may have events. This will revert if `allowances <../basics/allowances.html>`_ are not set or the available balance is less than ``amount``.
Pay Taker
---------
This transformation is implemented by the `PayTakerTransformer <../architecture/transformers.html>`_. Abi-Encode the following struct to get the ``data``:
.. code-block:: solidity
/// @dev Transform data to ABI-encode and pass into `transform()`.
struct TransformData {
// The tokens to transfer to the taker.
IERC20TokenV06[] tokens;
// Amount of each token in `tokens` to transfer to the taker.
// `uint(-1)` will transfer the entire balance.
uint256[] amounts;
}
This pays the ``taker`` in the ``amounts`` of each ``tokens`` specified. This is generally run at the end of all other transformations. For example, if you've swapped the taker's ETH for WETH then executed a trade through `Liquidity Aggregation`_, this transformation will can transfer the final output token back to the Taker.
No events are emitted by 0x during this transformation, although token contracts may have events. This will revert if `allowances <../basics/allowances.html>`_ are not set or the available balance is less than ``amount``.
Adding Custom Transformations
-----------------------------
Transformations are trustless, but at this time they are permissioned so only 0x Labs can deploy new Transformers. If you are interested in deploying your own transformation logic, please reach out to us on `Discord <https://discord.com/invite/d3FTX3M>`_. Learn more about why this is permissioned in the `Transformer Deployer <../architecture/transformer_deployer.html>`_ section.

View File

@@ -1,251 +0,0 @@
---
title: Meta-Transactions
---
Meta-Transactions are signed messages that instruct the 0x Protocol to
run function(s) in the context of the signer. This signed mtx can then
be shared off-chain, allowing anyone to execute on-chain. This is useful
for integrators who would like to subsidize the Ethereum Gas Fee, or add
custom smart contract logic to run atomically a fill. A signed
meta-transaction can only be executed once.
A common use case for this is in Request For Quote (RFQ) systems. The
Maker creates an order; the Taker signs a mtx permitting 0x Protocol to
fill the order on their behalf; the mtx is returned to the Maker who
submits it on-chain.
![Meta-Transaction Example](../_static/img/rfqm.png){.align-center}
# Constructing
To construct a Meta-Transaction, abi-encode the following struct and
sign it.
``` {.solidity}
/// @dev Describes an exchange proxy meta transaction.
struct MetaTransactionData {
// Signer of meta-transaction. On whose behalf to execute the MTX.
address payable signer;
// Required sender, or NULL for anyone.
address sender;
// Minimum gas price.
uint256 minGasPrice;
// Maximum gas price.
uint256 maxGasPrice;
// MTX is invalid after this time.
uint256 expirationTimeSeconds;
// Nonce to make this MTX unique.
uint256 salt;
// Encoded call data to a function on the exchange proxy.
bytes callData;
// Amount of ETH to attach to the call.
uint256 value;
// ERC20 fee `signer` pays `sender`.
IERC20TokenV06 feeToken;
// ERC20 fee amount.
uint256 feeAmount;
}
```
The `calldata` field is specific to the function you wish to execute. At
this time, the following functions are supported:
- [fillLimitOrder](../basics/functions.html#filllimitorder)
- [fillRfqOrder](../basics/functions.html#fillrfqorder)
- [transformERC20](../advanced/erc20_transformations.html)
# Signing
Meta-Transactions use the same signing technique as 0x Orders; see the
[How to Sign](../basics/orders.html#how-to-sign) section of the Orders
documentation. See [getMetaTransactionHash](#getmetatransactionhash) for
generating a unique hash for your mtx.
# Functionality
----------------------------------------------------------------------------- -------------------------------------------------
Function Overview
[executeMetaTransaction](#executemetatransaction) Executes a single meta-transaction
[batchExecuteMetaTransactions](#batchexecutemetatransactions) Executes a batch of meta-transactions.
[getMetaTransactionExecutedBlock](#getmetatransactionexecutedblock) Returns the block that a meta-transaction was
executed at.
[getMetaTransactionHashExecutedBlock](#getmetatransactionhashexecutedblock) Same as `getMetaTransactionExecutedBlock`, only
this function takes a meta-transaction hash.
[getMetaTransactionHash](#getmetatransactionhash) Returns the hash of a meta-transaction.
----------------------------------------------------------------------------- -------------------------------------------------
## executeMetaTransaction
A single Meta-Transaction is executed by calling
`executeMetaTransaction`. A batch of mtx\'s can be executed by calling
`batchExecuteMetaTransactions`.
``` {.solidity}
/// @dev Execute a single meta-transaction.
/// @param mtx The meta-transaction.
/// @param signature The signature by `mtx.signer`.
/// @return returnResult The ABI-encoded result of the underlying call.
function executeMetaTransaction(
MetaTransactionData calldata mtx,
LibSignature.Signature calldata signature
)
external
payable
returns (bytes memory returnResult);
```
A
[MetaTransactionExecuted](../basics/events.html#metatransactionexecuted)
event is emitted on succes. The `returnResult` contains the raw return
data for the executed function. For example, if the function returns a
`uint256` then the `returnResult` could be abi-decoded into a `uint256`.
This call will revert in the following scenarios:
- The address in the `mtx.sender` field does not match `msg.sender`.
- The mtx has expired.
- The Ethereum transaction\'s gas price (`tx.gasprice`) is outside of
the range `[mtx.minGasPrice..mtx.maxGasPrice]`
- The ETH sent with the mtx is less than `mtx.value`
- The allowance/balance of `signer` is insufficient to pay `feeAmount`
of `feeToken` to the `sender` (if specified)
- The signature is invalid.
- The mtx was already executed
- The underlying function is not supported by meta-transactions (see
list above).
- The underlying function call reverts.
## batchExecuteMetaTransactions
``` {.solidity}
/// @dev Execute multiple meta-transactions.
/// @param mtxs The meta-transactions.
/// @param signatures The signature by each respective `mtx.signer`.
/// @return returnResults The ABI-encoded results of the underlying calls.
function batchExecuteMetaTransactions(
MetaTransactionData[] calldata mtxs,
LibSignature.Signature[] calldata signatures
)
external
payable
returns (bytes[] memory returnResults);
```
A
[MetaTransactionExecuted](../basics/events.html#metatransactionexecuted)
event is emitted for each mtx on succes. The `returnResult` contains the
raw return data for the executed function This call will revert if the
one of the `mtxs` reverts. Any exceess Ether will be refunded to the
`msg.sender`.
## getMetaTransactionExecutedBlock
The `block.number` is stored on-chain when a mtx is executed. This value
can be retrieved using the following function.
``` {.solidity}
/// @dev Get the block at which a meta-transaction has been executed.
/// @param mtx The meta-transaction.
/// @return blockNumber The block height when the meta-transactioin was executed.
function getMetaTransactionExecutedBlock(MetaTransactionData calldata mtx)
external
view
returns (uint256 blockNumber);
```
## getMetaTransactionHashExecutedBlock
This is a more gas-efficient implementation of
`getMetaTransactionExecutedBlock`.
``` {.solidity}
/// @dev Get the block at which a meta-transaction hash has been executed.
/// @param mtxHash The meta-transaction hash.
/// @return blockNumber The block height when the meta-transactioin was executed.
function getMetaTransactionHashExecutedBlock(bytes32 mtxHash)
external
view
returns (uint256 blockNumber);
```
## getMetaTransactionHash
The hash of the mtx is used to uniquely identify it 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:
``` {.solidity}
/// @dev Get the EIP712 hash of a meta-transaction.
/// @param mtx The meta-transaction.
/// @return mtxHash The EIP712 hash of `mtx`.
function getMetaTransactionHash(MetaTransactionData calldata mtx)
external
view
returns (bytes32 mtxHash);
```
The simplest way to generate an order hash is by calling this function,
ex:
``` {.solidity}
bytes32 orderHash = IZeroEx(0xDef1C0ded9bec7F1a1670819833240f027b25EfF).getMetaTransactionHash(mtx);
```
The hash can be manually generated using the following code:
``` {.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(
"MetaTransactionData("
"address signer,"
"address sender,"
"uint256 minGasPrice,"
"uint256 maxGasPrice,"
"uint256 expirationTimeSeconds,"
"uint256 salt,"
"bytes callData,"
"uint256 value,"
"address feeToken,"
"uint256 feeAmount"
")"
)),
// The struct values.
mtx.signer,
mtx.sender,
mtx.minGasPrice,
mtx.maxGasPrice,
mtx.expirationTimeSeconds,
mtx.salt,
keccak256(mtx.callData),
mtx.value,
mtx.feeToken,
mtx.feeAmount
))
));
```

View File

@@ -1,233 +0,0 @@
###############################
Meta-Transactions
###############################
Meta-Transactions are signed messages that instruct the 0x Protocol to run function(s) in the context of the signer. This signed mtx can then be shared off-chain, allowing anyone to execute on-chain. This is useful for integrators who would like to subsidize the Ethereum Gas Fee, or add custom smart contract logic to run atomically a fill. A signed meta-transaction can only be executed once.
A common use case for this is in Request For Quote (RFQ) systems. The Maker creates an order; the Taker signs a mtx permitting 0x Protocol to fill the order on their behalf; the mtx is returned to the Maker who submits it on-chain.
.. image:: ../_static/img/rfqm.png
:alt: Meta-Transaction Example
:align: center
Constructing
============
To construct a Meta-Transaction, abi-encode the following struct and sign it.
.. code-block:: solidity
/// @dev Describes an exchange proxy meta transaction.
struct MetaTransactionData {
// Signer of meta-transaction. On whose behalf to execute the MTX.
address payable signer;
// Required sender, or NULL for anyone.
address sender;
// Minimum gas price.
uint256 minGasPrice;
// Maximum gas price.
uint256 maxGasPrice;
// MTX is invalid after this time.
uint256 expirationTimeSeconds;
// Nonce to make this MTX unique.
uint256 salt;
// Encoded call data to a function on the exchange proxy.
bytes callData;
// Amount of ETH to attach to the call.
uint256 value;
// ERC20 fee `signer` pays `sender`.
IERC20TokenV06 feeToken;
// ERC20 fee amount.
uint256 feeAmount;
}
The ``calldata`` field is specific to the function you wish to execute. At this time, the following functions are supported:
- `fillLimitOrder <../basics/functions.html#filllimitorder>`_
- `fillRfqOrder <../basics/functions.html#fillrfqorder>`_
- `transformERC20 <../advanced/erc20_transformations.html>`_
Signing
=======
Meta-Transactions use the same signing technique as 0x Orders; see the `How to Sign <../basics/orders.html#how-to-sign>`_ section of the Orders documentation. See `getMetaTransactionHash`_ for generating a unique hash for your mtx.
Functionality
=============
+----------------------------------------+------------------------------------------------------------------------------------------------+
| Function | Overview |
+----------------------------------------+------------------------------------------------------------------------------------------------+
| `executeMetaTransaction`_ | Executes a single meta-transaction |
+----------------------------------------+------------------------------------------------------------------------------------------------+
| `batchExecuteMetaTransactions`_ | Executes a batch of meta-transactions. |
+----------------------------------------+------------------------------------------------------------------------------------------------+
| `getMetaTransactionExecutedBlock`_ | Returns the block that a meta-transaction was executed at. |
+----------------------------------------+------------------------------------------------------------------------------------------------+
| `getMetaTransactionHashExecutedBlock`_ | Same as ``getMetaTransactionExecutedBlock``, only this function takes a meta-transaction hash. |
+----------------------------------------+------------------------------------------------------------------------------------------------+
| `getMetaTransactionHash`_ | Returns the hash of a meta-transaction. |
+----------------------------------------+------------------------------------------------------------------------------------------------+
executeMetaTransaction
----------------------
A single Meta-Transaction is executed by calling ``executeMetaTransaction``. A batch of mtx's can be executed by calling ``batchExecuteMetaTransactions``.
.. code-block:: solidity
/// @dev Execute a single meta-transaction.
/// @param mtx The meta-transaction.
/// @param signature The signature by `mtx.signer`.
/// @return returnResult The ABI-encoded result of the underlying call.
function executeMetaTransaction(
MetaTransactionData calldata mtx,
LibSignature.Signature calldata signature
)
external
payable
returns (bytes memory returnResult);
A `MetaTransactionExecuted <../basics/events.html#metatransactionexecuted>`_ event is emitted on succes. The ``returnResult`` contains the raw return data for the executed function. For example, if the function returns a ``uint256`` then the ``returnResult`` could be abi-decoded into a ``uint256``.
This call will revert in the following scenarios:
- The address in the ``mtx.sender`` field does not match ``msg.sender``.
- The mtx has expired.
- The Ethereum transaction's gas price (``tx.gasprice``) is outside of the range ``[mtx.minGasPrice..mtx.maxGasPrice]``
- The ETH sent with the mtx is less than ``mtx.value``
- The allowance/balance of ``signer`` is insufficient to pay ``feeAmount`` of ``feeToken`` to the ``sender`` (if specified)
- The signature is invalid.
- The mtx was already executed
- The underlying function is not supported by meta-transactions (see list above).
- The underlying function call reverts.
batchExecuteMetaTransactions
----------------------------
.. code-block:: solidity
/// @dev Execute multiple meta-transactions.
/// @param mtxs The meta-transactions.
/// @param signatures The signature by each respective `mtx.signer`.
/// @return returnResults The ABI-encoded results of the underlying calls.
function batchExecuteMetaTransactions(
MetaTransactionData[] calldata mtxs,
LibSignature.Signature[] calldata signatures
)
external
payable
returns (bytes[] memory returnResults);
A `MetaTransactionExecuted <../basics/events.html#metatransactionexecuted>`_ event is emitted for each mtx on succes. The ``returnResult`` contains the raw return data for the executed function This call will revert if the one of the ``mtxs`` reverts. Any exceess Ether will be refunded to the ``msg.sender``.
getMetaTransactionExecutedBlock
-------------------------------
The ``block.number`` is stored on-chain when a mtx is executed. This value can be retrieved using the following function.
.. code-block:: solidity
/// @dev Get the block at which a meta-transaction has been executed.
/// @param mtx The meta-transaction.
/// @return blockNumber The block height when the meta-transactioin was executed.
function getMetaTransactionExecutedBlock(MetaTransactionData calldata mtx)
external
view
returns (uint256 blockNumber);
getMetaTransactionHashExecutedBlock
-----------------------------------
This is a more gas-efficient implementation of ``getMetaTransactionExecutedBlock``.
.. code-block:: solidity
/// @dev Get the block at which a meta-transaction hash has been executed.
/// @param mtxHash The meta-transaction hash.
/// @return blockNumber The block height when the meta-transactioin was executed.
function getMetaTransactionHashExecutedBlock(bytes32 mtxHash)
external
view
returns (uint256 blockNumber);
getMetaTransactionHash
----------------------
The hash of the mtx is used to uniquely identify it 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 EIP712 hash of a meta-transaction.
/// @param mtx The meta-transaction.
/// @return mtxHash The EIP712 hash of `mtx`.
function getMetaTransactionHash(MetaTransactionData calldata mtx)
external
view
returns (bytes32 mtxHash);
The simplest way to generate an order hash is by calling this function, ex:
.. code-block:: solidity
bytes32 orderHash = IZeroEx(0xDef1C0ded9bec7F1a1670819833240f027b25EfF).getMetaTransactionHash(mtx);
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(
"MetaTransactionData("
"address signer,"
"address sender,"
"uint256 minGasPrice,"
"uint256 maxGasPrice,"
"uint256 expirationTimeSeconds,"
"uint256 salt,"
"bytes callData,"
"uint256 value,"
"address feeToken,"
"uint256 feeAmount"
")"
)),
// The struct values.
mtx.signer,
mtx.sender,
mtx.minGasPrice,
mtx.maxGasPrice,
mtx.expirationTimeSeconds,
mtx.salt,
keccak256(mtx.callData),
mtx.value,
mtx.feeToken,
mtx.feeAmount
))
));

View File

@@ -1,134 +0,0 @@
---
title: Pluggable Liquidity (PLP)
---
PLP (Pluggable Liquidity PLP) enables anyone to extend the 0x Protocol
with their own on-chain liquidity provider, like an AMM (Automated
Market Maker). Liquidity providers are sandboxed so their code can be
totally closed-source; they are executed via the
[LiquidityProviderFeature](../architecture/features.html)
# Implementing a Liquidity Provider
The only requirement is that the provider implements the interface in
[ILiquidityProvider](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/vendor/ILiquidityProvider.sol).
Note that `sellEthForToken` and `sellTokenForEth` do not need to be
implemented if the liquidity provider does not trade ETH/WETH.
``` {.solidity}
/// @dev Trades `inputToken` for `outputToken`. The amount of `inputToken`
/// to sell must be transferred to the contract prior to calling this
/// function to trigger the trade.
/// @param inputToken The token being sold.
/// @param outputToken The token being bought.
/// @param recipient The recipient of the bought tokens.
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
/// @return boughtAmount The amount of `outputToken` bought.
function sellTokenForToken(
address inputToken,
address outputToken,
address recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
)
external
returns (uint256 boughtAmount);
/// @dev Trades ETH for token. ETH must either be attached to this function
/// call or sent to the contract prior to calling this function to
/// trigger the trade.
/// @param outputToken The token being bought.
/// @param recipient The recipient of the bought tokens.
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
/// @return boughtAmount The amount of `outputToken` bought.
function sellEthForToken(
address outputToken,
address recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
)
external
payable
returns (uint256 boughtAmount);
/// @dev Trades token for ETH. The token must be sent to the contract prior
/// to calling this function to trigger the trade.
/// @param inputToken The token being sold.
/// @param recipient The recipient of the bought tokens.
/// @param minBuyAmount The minimum acceptable amount of ETH to buy.
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
/// @return boughtAmount The amount of ETH bought.
function sellTokenForEth(
address inputToken,
address payable recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
)
external
returns (uint256 boughtAmount);
/// @dev Quotes the amount of `outputToken` that would be obtained by
/// selling `sellAmount` of `inputToken`.
/// @param inputToken Address of the taker token (what to sell). Use
/// the wETH address if selling ETH.
/// @param outputToken Address of the maker token (what to buy). Use
/// the wETH address if buying ETH.
/// @param sellAmount Amount of `inputToken` to sell.
/// @return outputTokenAmount Amount of `outputToken` that would be obtained.
function getSellQuote(
address inputToken,
address outputToken,
uint256 sellAmount
)
external
view
returns (uint256 outputTokenAmount);
```
# Trading with a Liquidity Provider
To trade with a liquidity provider use the `sellToLiquidityProvider`
function.
``` {.solidity}
/// @dev Sells `sellAmount` of `inputToken` to the liquidity provider
/// at the given `provider` address.
/// @param inputToken The token being sold.
/// @param outputToken The token being bought.
/// @param provider The address of the on-chain liquidity provider
/// to trade with.
/// @param recipient The recipient of the bought tokens. If equal to
/// address(0), `msg.sender` is assumed to be the recipient.
/// @param sellAmount The amount of `inputToken` to sell.
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to
/// buy. Reverts if this amount is not satisfied.
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
/// @return boughtAmount The amount of `outputToken` bought.
function sellToLiquidityProvider(
address inputToken,
address outputToken,
address payable provider,
address recipient,
uint256 sellAmount,
uint256 minBuyAmount,
bytes calldata auxiliaryData
)
external
override
payable
returns (uint256 boughtAmount);
```
This function transfers tokens from `msg.sender` to the liquidity
provider then executes the trade through a sandboxed contract external
to the Exchange Proxy. The sandbox then executes the trade through the
provider. This function then transfers the output tokens to the
`recipient`.
This function will emit a
[LiquidityProviderSwap](../basics/events.html#liquidityproviderswap)
event if the trade succeeds. It will revert if the amount of
`outputToken` returned by the Liquidity Provider is less than
`minBuyAmount`.

View File

@@ -1,122 +0,0 @@
###############################
Pluggable Liquidity (PLP)
###############################
PLP (Pluggable Liquidity PLP) enables anyone to extend the 0x Protocol with their own on-chain liquidity provider, like an AMM (Automated Market Maker). Liquidity providers are sandboxed so their code can be totally closed-source; they are executed via the `LiquidityProviderFeature <../architecture/features.html>`_
Implementing a Liquidity Provider
=================================
The only requirement is that the provider implements the interface in `ILiquidityProvider <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/vendor/ILiquidityProvider.sol>`_.
Note that ``sellEthForToken`` and ``sellTokenForEth`` do not need to be implemented if the liquidity provider does not trade ETH/WETH.
.. code-block:: solidity
/// @dev Trades `inputToken` for `outputToken`. The amount of `inputToken`
/// to sell must be transferred to the contract prior to calling this
/// function to trigger the trade.
/// @param inputToken The token being sold.
/// @param outputToken The token being bought.
/// @param recipient The recipient of the bought tokens.
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
/// @return boughtAmount The amount of `outputToken` bought.
function sellTokenForToken(
address inputToken,
address outputToken,
address recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
)
external
returns (uint256 boughtAmount);
/// @dev Trades ETH for token. ETH must either be attached to this function
/// call or sent to the contract prior to calling this function to
/// trigger the trade.
/// @param outputToken The token being bought.
/// @param recipient The recipient of the bought tokens.
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to buy.
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
/// @return boughtAmount The amount of `outputToken` bought.
function sellEthForToken(
address outputToken,
address recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
)
external
payable
returns (uint256 boughtAmount);
/// @dev Trades token for ETH. The token must be sent to the contract prior
/// to calling this function to trigger the trade.
/// @param inputToken The token being sold.
/// @param recipient The recipient of the bought tokens.
/// @param minBuyAmount The minimum acceptable amount of ETH to buy.
/// @param auxiliaryData Arbitrary auxiliary data supplied to the contract.
/// @return boughtAmount The amount of ETH bought.
function sellTokenForEth(
address inputToken,
address payable recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
)
external
returns (uint256 boughtAmount);
/// @dev Quotes the amount of `outputToken` that would be obtained by
/// selling `sellAmount` of `inputToken`.
/// @param inputToken Address of the taker token (what to sell). Use
/// the wETH address if selling ETH.
/// @param outputToken Address of the maker token (what to buy). Use
/// the wETH address if buying ETH.
/// @param sellAmount Amount of `inputToken` to sell.
/// @return outputTokenAmount Amount of `outputToken` that would be obtained.
function getSellQuote(
address inputToken,
address outputToken,
uint256 sellAmount
)
external
view
returns (uint256 outputTokenAmount);
Trading with a Liquidity Provider
=================================
To trade with a liquidity provider use the ``sellToLiquidityProvider`` function.
.. code-block:: solidity
/// @dev Sells `sellAmount` of `inputToken` to the liquidity provider
/// at the given `provider` address.
/// @param inputToken The token being sold.
/// @param outputToken The token being bought.
/// @param provider The address of the on-chain liquidity provider
/// to trade with.
/// @param recipient The recipient of the bought tokens. If equal to
/// address(0), `msg.sender` is assumed to be the recipient.
/// @param sellAmount The amount of `inputToken` to sell.
/// @param minBuyAmount The minimum acceptable amount of `outputToken` to
/// buy. Reverts if this amount is not satisfied.
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
/// @return boughtAmount The amount of `outputToken` bought.
function sellToLiquidityProvider(
address inputToken,
address outputToken,
address payable provider,
address recipient,
uint256 sellAmount,
uint256 minBuyAmount,
bytes calldata auxiliaryData
)
external
override
payable
returns (uint256 boughtAmount);
This function transfers tokens from ``msg.sender`` to the liquidity provider then executes the trade through a sandboxed contract external to the Exchange Proxy. The sandbox then executes the trade through the provider. This function then transfers the output tokens to the ``recipient``.
This function will emit a `LiquidityProviderSwap <../basics/events.html#liquidityproviderswap>`_ event if the trade succeeds. It will revert if the amount of ``outputToken`` returned by the Liquidity Provider is less than ``minBuyAmount``.

View File

@@ -1,50 +0,0 @@
---
title: Optimized Uniswap Router
---
The 0x Protocol is equipped with a highly optimized [UniswapV2
Router](https://uniswap.org/docs/v2/smart-contracts/router02/), which
can reduce the transaction cost of trading with Uniswap. Call the
`sellToUniswap` function to execute a trade on Uniswap through the 0x
Protocol.
``` {.solidity}
/// @dev Efficiently sell directly to uniswap/sushiswap.
/// @param tokens Sell path.
/// @param sellAmount of `tokens[0]` Amount to sell.
/// @param minBuyAmount Minimum amount of `tokens[-1]` to buy.
/// @param isSushi Use sushiswap if true.
/// @return buyAmount Amount of `tokens[-1]` bought.
function sellToUniswap(
IERC20TokenV06[] calldata tokens,
uint256 sellAmount,
uint256 minBuyAmount,
bool isSushi
)
external
payable
returns (uint256 buyAmount);
```
This function sells `sellAmount` of `tokens[0]` for at least
`minBuyAmount` of `tokens[-1]`. The `tokens` array defines how to route
the trade between Uniswap pools. This function does not emit any events,
although Uniswap pools will emit their own events. This function reverts
if amount bought from Uniswap is less than `minBuyAmount`, or if Uniswap
reverts.
See the source code for our router
[here](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/UniswapFeature.sol).
See the official [Uniswap V2
Documentation](https://uniswap.org/docs/v2/) for information on
events/reverts/allowances.
::: {.note}
::: {.title}
Note
:::
This function does not use allowances set on 0x. The `msg.sender` must
have allowances set on Uniswap (or SushiSwap).
:::

View File

@@ -1,32 +0,0 @@
###############################
Optimized Uniswap Router
###############################
The 0x Protocol is equipped with a highly optimized `UniswapV2 Router <https://uniswap.org/docs/v2/smart-contracts/router02/>`_, which can reduce the transaction cost of trading with Uniswap. Call the ``sellToUniswap`` function to execute a trade on Uniswap through the 0x Protocol.
.. code-block:: solidity
/// @dev Efficiently sell directly to uniswap/sushiswap.
/// @param tokens Sell path.
/// @param sellAmount of `tokens[0]` Amount to sell.
/// @param minBuyAmount Minimum amount of `tokens[-1]` to buy.
/// @param isSushi Use sushiswap if true.
/// @return buyAmount Amount of `tokens[-1]` bought.
function sellToUniswap(
IERC20TokenV06[] calldata tokens,
uint256 sellAmount,
uint256 minBuyAmount,
bool isSushi
)
external
payable
returns (uint256 buyAmount);
This function sells ``sellAmount`` of ``tokens[0]`` for at least ``minBuyAmount`` of ``tokens[-1]``. The ``tokens`` array defines how to route the trade between Uniswap pools. This function does not emit any events, although Uniswap pools will emit their own events. This function reverts if amount bought from Uniswap is less than ``minBuyAmount``, or if Uniswap reverts.
See the source code for our router `here <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/UniswapFeature.sol>`_.
See the official `Uniswap V2 Documentation <https://uniswap.org/docs/v2/>`_ for information on events/reverts/allowances.
.. note::
This function does not use allowances set on 0x. The ``msg.sender`` must have allowances set on Uniswap (or SushiSwap).

View File

@@ -1,87 +0,0 @@
---
title: Features
---
Features implement the core feature set of the 0x Protocol. They are
trusted with user allowances and permissioned by the [0x
Governor](./governor.html). Features are run in the context of the
[Proxy](../proxy.html), via a `delegatecall`.
Below is a catalog of Features.
---------------------------- ----------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------
**Feature** **Description** **Resources**
BootstrapFeature Bootstraps the entire system. [Code](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/BootstrapFeature.sol);
[Usage](./proxy.html#bootstrapping)
LiquidityProviderFeature Connects the system to Pluggable Liquidity (PLP). [Code](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/LiquidityProviderFeature.sol);
[Usage](../advanced/plp.html#trading-with-a-liquidity-provider)
MetaTransactionsFeature Executes Meta-Transactions. [Code](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/MetaTransactionsFeature.sol);
[Usage](../advanced/mtx.html)
NativeLiquidityFeature Functions for native 0x liquidity (see [Code](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/NativeOrdersFeature.sol);
[Orders](../basics/orders.html)). [Usage](../basics/functions.html)
OwnableFeature An implementation of Ownable that is compatible with the [Code](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/OwnableFeature.sol);
delegate-call proxy pattern. [Usage](./architecture/proxy.html#ownership)
SignatureValidationFeature *This feature is deprecated. Its code will be removed after [Code](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/SignatureValidatorFeature.sol)
the contract is decommissioned.*
SimpleFunctionRegistry Implements the registry of functions/features available in [Code](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/SimpleFunctionRegistryFeature.sol);
the system. [Usage](./proxy.html#function-registry)
TokenSpenderFeature *This feature is deprecated. Its code will be removed after [Code](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/TokenSpenderFeature.sol)
the contract is decommissioned.*
TransformERC20Feature Executes [Transformers](./transformers.html) to aggregate [Code](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/TransformERC20Feature.sol);
liquidity and operate on ERC20 tokens. [Usage](../advanced/erc20_transformations.html)
UniswapFeature A highly-optimized UniswapV2 router; used to source [Code](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/UniswapFeature.sol);
liquidity from Uniswap. [Usage](../advanced/uniswap.html)
---------------------------- ----------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------
# Implementing a Feature
The only requirement is that the Feature implements the interface in
[IFeature](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/IFeature.sol).
Review the [Proxy Section](./proxy.html) for details on how to write a
smart contract that is compatible with our architecture (ex, how to
properly manage state).
``` {.solidity}
/// @dev Basic interface for a feature contract.
interface IFeature {
// solhint-disable func-name-mixedcase
/// @dev The name of this feature set.
function FEATURE_NAME() external view returns (string memory name);
/// @dev The version of this feature set.
function FEATURE_VERSION() external view returns (uint256 version);
}
```
# Best Practices
We use this checklist to review the safety of new Features.
- [ ] Feature has updated version information.
- [ ] implements IFeature interface.
- [ ] Feature contracts are stateless (including inherited contracts).
- [ ] onlySelf feature functions are prefixed with _.
- [ ] Feature functions are added to full_migration_tests.
- [ ] No delegatecalls from inside a feature. Call other features through the router.
- [ ] No self-destruct in features (except BootstrapFeature).
- [ ] No intentionally persistent (non-atomic) balances on the Exchange Proxy.
- [ ] No direct access to another features storage bucket without strong justification.
- [ ] No executing arbitrary calldata from the context of the Exchange Proxy.
- [ ] No external calls to arbitrary contracts from within the Exchange Proxy.
- [ ] Features use unique StorageIds.
- [ ] Document functions with execution contexts outside of the Exchange Proxy.
- [ ] Document feature dependencies in checklist doc.
- [ ] Document reentrant functions in checklist doc.
- [ ] Document temporary balances.

View File

@@ -1,77 +0,0 @@
###############################
Features
###############################
Features implement the core feature set of the 0x Protocol. They are trusted with user allowances and permissioned by the `0x Governor <./governor.html>`_. Features are run in the context of the `Proxy <../proxy.html>`_, via a ``delegatecall``.
Below is a catalog of Features.
.. table::
:widths: 20 60 20
+----------------------------+----------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| **Feature** | **Description** | **Resources** |
+----------------------------+----------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| BootstrapFeature | Bootstraps the entire system. | `Code <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/BootstrapFeature.sol>`__; `Usage <./proxy.html#bootstrapping>`__ |
+----------------------------+----------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| LiquidityProviderFeature | Connects the system to Pluggable Liquidity (PLP). | `Code <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/LiquidityProviderFeature.sol>`__; `Usage <../advanced/plp.html#trading-with-a-liquidity-provider>`__ |
+----------------------------+----------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| MetaTransactionsFeature | Executes Meta-Transactions. | `Code <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/MetaTransactionsFeature.sol>`__; `Usage <../advanced/mtx.html>`__ |
+----------------------------+----------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| NativeLiquidityFeature | Functions for native 0x liquidity (see `Orders <../basics/orders.html>`_). | `Code <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/NativeOrdersFeature.sol>`__; `Usage <../basics/functions.html>`__ |
+----------------------------+----------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| OwnableFeature | An implementation of Ownable that is compatible with the delegate-call proxy pattern. | `Code <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/OwnableFeature.sol>`__; `Usage <./architecture/proxy.html#ownership>`__ |
+----------------------------+----------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| SignatureValidationFeature | *This feature is deprecated. Its code will be removed after the contract is decommissioned.* | `Code <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/SignatureValidatorFeature.sol>`__ |
+----------------------------+----------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| SimpleFunctionRegistry | Implements the registry of functions/features available in the system. | `Code <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/SimpleFunctionRegistryFeature.sol>`__; `Usage <./proxy.html#function-registry>`__ |
+----------------------------+----------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| TokenSpenderFeature | *This feature is deprecated. Its code will be removed after the contract is decommissioned.* | `Code <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/TokenSpenderFeature.sol>`__ |
+----------------------------+----------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| TransformERC20Feature | Executes `Transformers <./transformers.html>`_ to aggregate liquidity and operate on ERC20 tokens. | `Code <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/TransformERC20Feature.sol>`__; `Usage <../advanced/erc20_transformations.html>`__ |
+----------------------------+----------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| UniswapFeature | A highly-optimized UniswapV2 router; used to source liquidity from Uniswap. | `Code <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/UniswapFeature.sol>`__; `Usage <../advanced/uniswap.html>`__ |
+----------------------------+----------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
Implementing a Feature
======================
The only requirement is that the Feature implements the interface in `IFeature <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/IFeature.sol>`_. Review the `Proxy Section <./proxy.html>`_ for details on how to write a smart contract that is compatible with our architecture (ex, how to properly manage state).
.. code-block:: solidity
/// @dev Basic interface for a feature contract.
interface IFeature {
// solhint-disable func-name-mixedcase
/// @dev The name of this feature set.
function FEATURE_NAME() external view returns (string memory name);
/// @dev The version of this feature set.
function FEATURE_VERSION() external view returns (uint256 version);
}
Best Practices
================
We use this checklist to review the safety of new Features.
::
- [ ] Feature has updated version information.
- [ ] implements IFeature interface.
- [ ] Feature contracts are stateless (including inherited contracts).
- [ ] onlySelf feature functions are prefixed with _.
- [ ] Feature functions are added to full_migration_tests.
- [ ] No delegatecalls from inside a feature. Call other features through the router.
- [ ] No self-destruct in features (except BootstrapFeature).
- [ ] No intentionally persistent (non-atomic) balances on the Exchange Proxy.
- [ ] No direct access to another features storage bucket without strong justification.
- [ ] No executing arbitrary calldata from the context of the Exchange Proxy.
- [ ] No external calls to arbitrary contracts from within the Exchange Proxy.
- [ ] Features use unique StorageIds.
- [ ] Document functions with execution contexts outside of the Exchange Proxy.
- [ ] Document feature dependencies in checklist doc.
- [ ] Document reentrant functions in checklist doc.
- [ ] Document temporary balances.

View File

@@ -1,29 +0,0 @@
---
title: Fee Collectors
---
The [Protocol Fees](../basics/protocol_fees.html) are paid into special
Fee Collector contracts at time-of-fill. There is one collector for each
Staking Pool. The fees are paid in aggregate from the collector to the
[Staking System](../tokenomics/staking.md); this can happen at anytime,
but is most optimal to run during finalization. This increases the cost
of finalizing an epoch, but substantially reduces the transaction cost
for takers executing trades.
# Architecture
1. There is one Fee Collector per staking pool. The fee collector
serves as a repository for protocol fees attributed to a given pool.
It automatically `approve()s` the staking contract so fees can be
aggregated during finalization. It also contains functionality to
convert ETH to WETH. Fee collectors are created using `CREATE2`.
This gives us predictable addresses.
2. When a [Limit Order](../basics/orders.html#limitorders) is filled,
the protocol fee is paid to the Fee Collector that corresponds to
`order.pool`.
3. The [transferProtocolFeesForPools()
\<../basics/functions.html\#transferprotocolfeesforpools\>]{.title-ref}
function can be called to transfer the fees for a set of pools from
their respective Fee Collectors into the Staking system.
![image](../_static/img/fee_collectors.png){.align-center}

View File

@@ -1,17 +0,0 @@
###############################
Fee Collectors
###############################
The `Protocol Fees <../basics/protocol_fees.html>`_ are paid into special Fee Collector contracts at time-of-fill. There is one collector for each Staking Pool. The fees are paid in aggregate from the collector to the `Staking System <../tokenomics/staking.md>`_; this can happen at anytime, but is most optimal to run during finalization. This increases the cost of finalizing an epoch, but substantially reduces the transaction cost for takers executing trades.
Architecture
============
1. There is one Fee Collector per staking pool. The fee collector serves as a repository for protocol fees attributed to a given pool. It automatically ``approve()s`` the staking contract so fees can be aggregated during finalization. It also contains functionality to convert ETH to WETH. Fee collectors are created using ``CREATE2``. This gives us predictable addresses.
2. When a `Limit Order <../basics/orders.html#limitorders>`_ is filled, the protocol fee is paid to the Fee Collector that corresponds to ``order.pool``.
3. The `transferProtocolFeesForPools() <../basics/functions.html#transferprotocolfeesforpools>` function can be called to transfer the fees for a set of pools from their respective Fee Collectors into the Staking system.
.. image:: ../_static/img/fee_collectors.png
:align: center

View File

@@ -1,68 +0,0 @@
---
title: Flash Wallet
---
The Flash Wallet is a sandboxed escrow contract that holds funds for
[Transformers](./transformers.html) to operate on. A
[Feature](./features.html) contract transfers tokens to the Flash
Wallet, which then delegate call\'s into a Transformer to run operations
on the escrowed funds. Transformers are trustless and therefore only
have access to the funds deposted into the Flash Wallet; they do not
have access to user allowances.
The wallet is currently only used by the `TransformERC20` feature. It is
deployed using the `createTransformWallet()` function on the feature,
which is only callable by the owner/governor. This allows us to deploy a
fresh wallet in case we somehow break the old one, like if we
accidentally selfdestruct it or clobber its state.
::: {.note}
::: {.title}
Note
:::
The wallet is currently only used for ERC20 tokens, but can be extended
to work with other standards, like ERC1155 and ERC223, by implementing
the required fallbacks for those standards.
:::
The Flash Wallet exposes two functions of interest: `executeCall()` and
`executeDelegateCall()`. The former executes a `call` and reverts if the
callee reverts. The latter executes a `delegatecall` and reverts if the
callee reverts.
``` {.solidity}
/// @dev Execute an arbitrary call. Only an authority can call this.
/// @param target The call target.
/// @param callData The call data.
/// @param value Ether to attach to the call.
/// @return resultData The data returned by the call.
function executeCall(
address payable target,
bytes calldata callData,
uint256 value
)
external
payable
override
onlyOwner
returns (bytes memory resultData);
/// @dev Execute an arbitrary delegatecall, in the context of this puppet.
/// Only an authority can call this.
/// @param target The call target.
/// @param callData The call data.
/// @return resultData The data returned by the call.
function executeDelegateCall(
address payable target,
bytes calldata callData
)
external
payable
override
onlyOwner
returns (bytes memory resultData);
```
View the code for the Flash Wallet
[here](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/external/FlashWallet.sol).

View File

@@ -1,47 +0,0 @@
###############################
Flash Wallet
###############################
The Flash Wallet is a sandboxed escrow contract that holds funds for `Transformers <./transformers.html>`_ to operate on. A `Feature <./features.html>`_ contract transfers tokens to the Flash Wallet, which then delegate call's into a Transformer to run operations on the escrowed funds. Transformers are trustless and therefore only have access to the funds deposted into the Flash Wallet; they do not have access to user allowances.
The wallet is currently only used by the ``TransformERC20`` feature. It is deployed using the ``createTransformWallet()`` function on the feature, which is only callable by the owner/governor. This allows us to deploy a fresh wallet in case we somehow break the old one, like if we accidentally selfdestruct it or clobber its state.
.. note::
The wallet is currently only used for ERC20 tokens, but can be extended to work with other standards, like ERC1155 and ERC223, by implementing the required fallbacks for those standards.
The Flash Wallet exposes two functions of interest: ``executeCall()`` and ``executeDelegateCall()``. The former executes a ``call`` and reverts if the callee reverts. The latter executes a ``delegatecall`` and reverts if the callee reverts.
.. code-block:: solidity
/// @dev Execute an arbitrary call. Only an authority can call this.
/// @param target The call target.
/// @param callData The call data.
/// @param value Ether to attach to the call.
/// @return resultData The data returned by the call.
function executeCall(
address payable target,
bytes calldata callData,
uint256 value
)
external
payable
override
onlyOwner
returns (bytes memory resultData);
/// @dev Execute an arbitrary delegatecall, in the context of this puppet.
/// Only an authority can call this.
/// @param target The call target.
/// @param callData The call data.
/// @return resultData The data returned by the call.
function executeDelegateCall(
address payable target,
bytes calldata callData
)
external
payable
override
onlyOwner
returns (bytes memory resultData);
View the code for the Flash Wallet `here <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/external/FlashWallet.sol>`_.

View File

@@ -1,104 +0,0 @@
---
title: Governor
---
::: {.note}
::: {.title}
Note
:::
This page is tailored for Exchange V4. For information on governance
over past exhcange versions, see [this
specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v3/zero-ex-governor.md).
:::
The `ZeroExGovernor` is a time-locked multi-signature wallet that has
permission to perform administrative functions within the protocol.
Functions are timelocked (see below). Many functions that can be used to
mitigate damage in case of emergencies (for example, if a vulnerability
is discovered that puts user funds at risk) do not have a timelock.
The `ZeroExGovernor` is able to perform the following functions within
the protocol:
# Managing Ownership
The `ZeroExGovernor` can transfer ownership of any contract for which it
is the `owner` by calling the following function:
``` {.solidity}
/// @dev Transfers ownership to a new address.
/// @param newOwner Address of the new owner.
function transferOwnership(address newOwner)
public;
```
# Managing Authorizations
The `ZeroExGovernor` can also manage authorizations all permissioned
contracts in the Exchange and Staking systems. While the
`ZeroExGovernor` itself is currently the only authorized address in
these contracts, this feature can be used to allow new contracts to
perform admin functions under different conditions in the future (such
as with an on-chain token vote).
``` {.solidity}
/// @dev Authorizes an address.
/// @param target Address to authorize.
function addAuthorizedAddress(address target)
external;
/// @dev Removes authorizion of an address.
/// @param target Address to remove authorization from.
function removeAuthorizedAddress(address target)
external;
/// @dev Removes authorizion of an address.
/// @param target Address to remove authorization from.
/// @param index Index of target in authorities array.
function removeAuthorizedAddressAtIndex(
address target,
uint256 index
)
external;
```
# Administering Systems
The governor owns all permissioned, trusted contracts under the 0x
Protocol. Any `onlyOwner` function can be executed by the governor. The
governor requires 2/3 signatures and is timelocked.
# Timelocks
Function timelocks are represented in days, where one day is equivalent
to 86,400 seconds.
Contract Function Selector Timelock
----------------- ---------------------------------- ----------------------------- ----------
AllowanceTarget `addAuthorizedAddress` `42f1181e` 1 day
AllowanceTarget `removeAuthorizedAddress` `70712939` 0 days
AllowanceTarget `removeAuthorizedAddressAtIndex` `9ad26744` 0 days
Governor `registerFunctionCall` `751ad560` 1 day
ExchangeProxy `extend` `6eb224cb` 1 day
ExchangeProxy `migrate` `261fe679` 1 day
ExchangeProxy `rollback` `9db64a40` 0 days
ExchangeProxy `setQuoteSigner` `<deprecation in progress>` 1 day
ExchangeProxy `setTransformerDeployer` `87c96419` 1 day
ExchangeProxy `transferOwnership` `f2fde38b` 1 day
StakingProxy `addExchangeAddress` `8a2e271a` 14 days
StakingProxy `removeExchangeAddress` `01e28d84` 14 days
StakingProxy `attachStakingContract` `66615d56` 14 days
StakingProxy `detachStakingContract` `37b006a6` 14 days
StakingProxy `setParams` `9c3ccc82` 7 days
StakingProxy `addAuthorizedAddress` `42f1181e` 14 days
StakingProxy `removeAuthorizedAddress` `70712939` 14 days
StakingProxy `removeAuthorizedAddressAtIndex` `9ad26744` 14 days
StakingProxy `transferOwnership` `f2fde38b` 14 days
ZrxVault `setStakingProxy` `6bf3f9e5` 14 days
ZrxVault `enterCatastrophicFailure` `c02e5a7f` 0 days
ZrxVault `setZrxProxy` `ca5b0218` 14 days
ZrxVault `addAuthorizedAddress` `42f1181e` 14 days
ZrxVault `removeAuthorizedAddress` `70712939` 14 days
ZrxVault `removeAuthorizedAddressAtIndex` `9ad26744` 14 days
ZrxVault `transferOwnership` `f2fde38b` 14 days

View File

@@ -1,90 +0,0 @@
###############################
Governor
###############################
.. note::
This page is tailored for Exchange V4. For information on governance over past exhcange versions, see `this specification <https://github.com/0xProject/0x-protocol-specification/blob/master/v3/zero-ex-governor.md>`_.
The ``ZeroExGovernor`` is a time-locked multi-signature wallet that has permission to perform administrative functions within the protocol. Functions are timelocked (see below). Many functions that can be used to mitigate damage in case of emergencies (for example, if a vulnerability is discovered that puts user funds at risk) do not have a timelock.
The ``ZeroExGovernor`` is able to perform the following functions within the protocol:
Managing Ownership
==================
The ``ZeroExGovernor`` can transfer ownership of any contract for which it is the ``owner`` by calling the following function:
.. code-block:: solidity
/// @dev Transfers ownership to a new address.
/// @param newOwner Address of the new owner.
function transferOwnership(address newOwner)
public;
Managing Authorizations
=======================
The ``ZeroExGovernor`` can also manage authorizations all permissioned contracts in the Exchange and Staking systems. While the ``ZeroExGovernor`` itself is currently the only authorized address in these contracts, this feature can be used to allow new contracts to perform admin functions under different conditions in the future (such as with an on-chain token vote).
.. code-block:: solidity
/// @dev Authorizes an address.
/// @param target Address to authorize.
function addAuthorizedAddress(address target)
external;
/// @dev Removes authorizion of an address.
/// @param target Address to remove authorization from.
function removeAuthorizedAddress(address target)
external;
/// @dev Removes authorizion of an address.
/// @param target Address to remove authorization from.
/// @param index Index of target in authorities array.
function removeAuthorizedAddressAtIndex(
address target,
uint256 index
)
external;
Administering Systems
=======================
The governor owns all permissioned, trusted contracts under the 0x Protocol. Any ``onlyOwner`` function can be executed by the governor. The governor requires 2/3 signatures and is timelocked.
Timelocks
============
Function timelocks are represented in days, where one day is equivalent to 86,400 seconds.
.. csv-table::
:header: "Contract", "Function", "Selector", "Timelock"
AllowanceTarget, ``addAuthorizedAddress``, ``42f1181e``, 1 day
AllowanceTarget, ``removeAuthorizedAddress``, ``70712939``, 0 days
AllowanceTarget, ``removeAuthorizedAddressAtIndex``, ``9ad26744``, 0 days
Governor, ``registerFunctionCall``, ``751ad560``, 1 day
ExchangeProxy, ``extend``, ``6eb224cb``, 1 day
ExchangeProxy, ``migrate``, ``261fe679``, 1 day
ExchangeProxy, ``rollback``, ``9db64a40``, 0 days
ExchangeProxy, ``setQuoteSigner``, ``<deprecation in progress>``, 1 day
ExchangeProxy, ``setTransformerDeployer``, ``87c96419``, 1 day
ExchangeProxy, ``transferOwnership``, ``f2fde38b``, 1 day
StakingProxy, ``addExchangeAddress``, ``8a2e271a``, 14 days
StakingProxy, ``removeExchangeAddress``, ``01e28d84``, 14 days
StakingProxy, ``attachStakingContract``, ``66615d56``, 14 days
StakingProxy, ``detachStakingContract``, ``37b006a6``, 14 days
StakingProxy, ``setParams``, ``9c3ccc82``, 7 days
StakingProxy, ``addAuthorizedAddress``, ``42f1181e``, 14 days
StakingProxy, ``removeAuthorizedAddress``, ``70712939``, 14 days
StakingProxy, ``removeAuthorizedAddressAtIndex``, ``9ad26744``, 14 days
StakingProxy, ``transferOwnership``, ``f2fde38b``, 14 days
ZrxVault, ``setStakingProxy``, ``6bf3f9e5``, 14 days
ZrxVault, ``enterCatastrophicFailure``, ``c02e5a7f``, 0 days
ZrxVault, ``setZrxProxy``, ``ca5b0218``, 14 days
ZrxVault, ``addAuthorizedAddress``, ``42f1181e``, 14 days
ZrxVault, ``removeAuthorizedAddress``, ``70712939``, 14 days
ZrxVault, ``removeAuthorizedAddressAtIndex``, ``9ad26744``, 14 days
ZrxVault, ``transferOwnership``, ``f2fde38b``, 14 days

View File

@@ -1,52 +0,0 @@
---
title: Overview
---
The 0x Exchange implements a delegate-call proxy pattern to create a
system of composable smart contracts. This architecture enables 0x to
innovate with minimal friction alongside the growing DeFi ecosystem.
The diagram below illustrates our system (click to enlarge).
![image](../_static/img/architecture.png)
------------------------------------------------------------------------
The table below defines our smart contract nomenclature.
---------------------------------------- ------------------------------------------------------
**Term** **Definition**
[Proxy](./proxy.html) The point of entry into the system. This contract
delegate-calls into Features.
[Features](./features.html) These contracts implement the core feature set of the
0x Protocol. They are trusted with user allowances and
permissioned by the 0x Governor.
[Transformers](./transformers.html) These contracts extend the core protocol. They are
trustless and permissioned by the Transformer
Deployer.
[Flash Wallet](./flash_wallet.html) The Flash Wallet is a sandboxed escrow contract that
holds funds for Transformers to operate on. For
example, the `WETHtransformer` wraps any Ether in the
Flash Wallet.
[Allowance Users set their allowances on this contract. It is
Target](../basics/allowances.html) scheduled to be deprecated after the official V4
release in January, 2021. After which point allowances
will be set directly on the Proxy.
[Governor](./governor.html) A MultiSig that governs trusted contracts in the
system: Proxy, Features, Flash Wallet.
[Transformer Deploys Transformers. A transformer is authenticated
Deployer](./transformer_deployer.html) using a nonce of the Transformer Deployer.
[Fee Collectors](./fee_collectors.html) [Protocol fees](../basics/protocol_fees.html) are paid
into these contracts at time-of-fill.
[PLP Sandbox](./plp_sandbox.html) [PLP](../advanced/plp.html) liquidity providers are
called from this sandbox.
---------------------------------------- ------------------------------------------------------

View File

@@ -1,36 +0,0 @@
###############################
Overview
###############################
The 0x Exchange implements a delegate-call proxy pattern to create a system of composable smart contracts. This architecture enables 0x to innovate with minimal friction alongside the growing DeFi ecosystem.
The diagram below illustrates our system (click to enlarge).
.. image:: ../_static/img/architecture.png
:scale: 70%
------------
The table below defines our smart contract nomenclature.
+-------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| **Term** | **Definition** |
+-------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| `Proxy <./proxy.html>`_ | The point of entry into the system. This contract delegate-calls into Features. |
+-------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| `Features <./features.html>`_ | These contracts implement the core feature set of the 0x Protocol. They are trusted with user allowances and permissioned by the 0x Governor. |
+-------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| `Transformers <./transformers.html>`_ | These contracts extend the core protocol. They are trustless and permissioned by the Transformer Deployer. |
+-------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| `Flash Wallet <./flash_wallet.html>`_ | The Flash Wallet is a sandboxed escrow contract that holds funds for Transformers to operate on. For example, the ``WETHtransformer`` wraps any Ether in the Flash Wallet. |
+-------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| `Allowance Target <../basics/allowances.html>`_ | Users set their allowances on this contract. It is scheduled to be deprecated after the official V4 release in January, 2021. After which point allowances will be set directly on the Proxy. |
+-------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| `Governor <./governor.html>`_ | A MultiSig that governs trusted contracts in the system: Proxy, Features, Flash Wallet. |
+-------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| `Transformer Deployer <./transformer_deployer.html>`_ | Deploys Transformers. A transformer is authenticated using a nonce of the Transformer Deployer. |
+-------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| `Fee Collectors <./fee_collectors.html>`_ | `Protocol fees <../basics/protocol_fees.html>`_ are paid into these contracts at time-of-fill. |
+-------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| `PLP Sandbox <./plp_sandbox.html>`_ | `PLP <../advanced/plp.html>`_ liquidity providers are called from this sandbox. |
+-------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

View File

@@ -1,19 +0,0 @@
---
title: PLP Sandbox
---
[PLP](../advanced/plp.html) are external, closed-source contracts that
provide liquidity to the 0x Protocol. We want to limit the contracts
called from the context of the [Proxy](./proxy.html) contract because
this contract has access to user funds. We must mitigate the attack
vector where an ERC20 Token (or some other trusted contract) is passed
in place of a legitimate PLP liquidity provider. We do this by routing
trades through the PLP Sandbox.
The diagram below illustrates this workflow.
![image](../_static/img/plp_sandbox.png){.align-center}
See the [PLP Section](../advanced/plp.html) for usage. View the code for
the PLP Sandbox is
[here](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/external/LiquidityProviderSandbox.sol).

View File

@@ -1,14 +0,0 @@
###############################
PLP Sandbox
###############################
`PLP <../advanced/plp.html>`_ are external, closed-source contracts that provide liquidity to the 0x Protocol. We want to limit the contracts called from the context of the `Proxy <./proxy.html>`_ contract because this contract has access to user funds. We must mitigate the attack vector where an ERC20 Token (or some other trusted contract) is passed in place of a legitimate PLP liquidity provider. We do this by routing trades through the PLP Sandbox.
The diagram below illustrates this workflow.
.. image:: ../_static/img/plp_sandbox.png
:align: center
See the `PLP Section <../advanced/plp.html>`_ for usage. View the code for the PLP Sandbox is `here <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/external/LiquidityProviderSandbox.sol>`_.

View File

@@ -1,383 +0,0 @@
---
title: Proxy
---
The
[ZeroEx](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/ZeroEx.sol)
contract implements a per-function proxy pattern. Every function
registered to the proxy contract can have a distinct implementation
contract. Implementation contracts are called "features" and can expose
multiple, related functions. Since features can be upgraded
independently, there will no longer be a collective "version" of the
API, defaulting to a rolling release model. The ZeroEx contract's only
responsibility is to route (delegate) calls to per-function
implementation contracts through its fallback.
![image](../_static/img/proxy.png){.align-center}
View the code for the Proxy
[here](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/ZeroEx.sol).
There is also a [gas-optimized
implementation](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/ZeroExOptimized.sol)
that may be put into production in the future (there is a lot of
overhead for our integrators when redeploying this contract).
# Bootstrapping
The ZeroEx contract comes pre-loaded with only one Feature:
[Bootstrap](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/BootstrapFeature.sol).
This exposes a `bootstrap()` function that can only be called by the
deployer. This function does a few things:
1. De-register the bootstrap() function, which prevents it being called
again.
2. Self-destruct.
3. Delegatecall the bootstrapper target contract and call data.
``` {.solidity}
// Execute a bootstrapper in the context of the proxy.
function bootstrap(address target, bytes callData) external
```
Below is the bootstrap workflow (click to enlarge).
![image](../_static/img/bootstrap.png){.align-center}
# Function Registry
One of the initial features InitialMigration bootstraps into the ZeroEx
contract is the function registry feature, SimpleFunctionRegistry. This
feature exposes the following function registry management features:
`extend()` and `rollback()`.
Call `extend()` to register a new function (selector) and implementation
(address). This also maintains a history of past implementations so we
can roll back to one, if needed.
``` {.solidity}
// Register or replace a function.
function extend(bytes4 selector, address impl)
external
onlyOwner;
```
Call `rollback()` to revert a function implementation to a prior version
in its history.
``` {.solidity}
// Roll back to a previousimplementation of a function.
function rollback(bytes4 selector, address targetImpl)
external
onlyOwner;
```
# Ownership
Another Feature, `InitialMigration`, bootstraps into the proxy is the
Ownable feature. This exposes ownership management functions:
`transferOwnership()` and `getOwner()`. This feature also enables
ubiquitous modifiers such as onlyOwner, so it is an implicit dependency
of nearly every other feature.
``` {.solidity}
// Change the owner of this contract.
function transferOwnership(address newOwner)
external
onlyOwner;
// Get the owner of this contract.
function getOwner()
external
view
returns (address owner_);
```
# Migrations
Migrations are upgrade logic that run in the context of the proxy
contract. To do this, the owner calls the `migrate()` function, provided
by the `Ownable` Feature. This follows a similar sequence as the
bootstrap process. Notably, it temporarily sets the owner of the
contract to itself for the duration of the migration call, which allows
the migrator to perform admin-level operations through other features,
such as registering or rolling back new functions. Before exiting, the
owner is set to the newOwner, which is passed in to the call.
One motivation for the existence of this function, as opposed to just
having the make individual admin calls, is a shortcoming of the
ZeroExGoverner contract, which is designed to perform one operation at a
time, with no strict ordering of those operations.
This is a stripped down `migrate()` feature implementation:
``` {.solidity}
contract Ownable {
// Execute a migration function in the context of the proxy contract.
function migrate(address target, bytes calldata data, address newOwner)
external
onlyOwner
{
// If the owner is already set to ourselves then we've reentered.
require(OwnableStorage.owner != address(this));
// Temporarily set the owner to ourselves.
OwnableStorage.owner = address(this);
// Perform the migration.
target.delegatecall(data);
// Set the new owner.
OwnableStorage.owner = newOWner;
}
}
```
This is an example sequence of a migration (click to enlarge):
![image](../_static/img/zero_ex_migrate.png){.align-center}
# Storage Buckets
Because feature functions get delegatecalled into, they all share the
same execution context and, thus, state space. It's critical that
storage for each feature be compartmentalized from other features to
avoid accidentally writing to the same slot. We solve this by strictly
adhering to a storage bucket pattern for our feature contracts. This
rule also extends to all inherited contracts/mixins.
Storage buckets are enabled by new language features in solidity 0.6,
which allow us to rewrite a storage variable's slot reference to a
globally unique ID. These IDs are stored in an append-only enum defined
in LibStorage, to enforce uniqueness. The true storage slot for a bucket
is the feature's storage ID multiplied by a large constant to prevent
overlap between buckets.
Example:
``` {.solidity}
LibStorage {
enum StorageId {
MyFeature
}
function getStorageSlot(StorageId id) internal pure returns (uint256) {
return uint256(id) * 1e18;
}
}
LibMyFeatureStorage {
// Storage layout for this feature.
struct Storage {
mapping(bytes32 => bytes) myData;
}
// Get the storage bucket for this feature.
function getStorage() internal view returns (Storage storage st) {
uint256 slot = LibStorage.getStorageSlot(
LibStorage.StorageId.MyFeature
);
assembly { st_slot := slot }
}
}
```
With the above pattern, writing to storage is simply:
``` {.solidity}
LibMyFeatureStorage.getStorage().myData[...] = ...
```
# Version Management
**Inspection**
This is a rolling release model, where every feature/function has its
own version. All feature contracts (except Bootstrap because it's
ephemeral), implement the IFeature interface:
``` {.solidity}
interface IFeature {
// The name of this feature set.
function FEATURE_NAME() external view returns (string memory name);
// The version of this feature set.
function FEATURE_VERSION() external view returns (uint256 version);
}
```
So, to get the version of a function one could do
`IFeature(getFunctionImplementation(foo.selector)).FEATURE_VERSION`.
**Best Practices**
The registry is intentionally not prescriptive on how features should be
migrated. But there are some general best practices we can follow to
avoid harming users, and ourselves.
**Deprecation**
In general, unless a function has a vulnerability, we should keep it
intact for the duration of the deprecation schedule. Afterwards, we can
ultimately disable the function by either calling extend() with a null
implementation or by calling rollback() to a null implementation.
**Patches**
These include bug-fixes, optimizations, or any other changes that
preserve the intended behavior of the function. For these cases, we
should upgrade the function in-place, i.e., using the same selector but
changing the implementation contract, through extend().
**Vulnerabilities**
If a vulnerability is found in a live function, we should call
rollback() immediately to reset it to a non-vulnerable implementation.
Because rollback() is a separate function from extend(), it can be
exempted from timelocks to allow a swift response.
**Upgrades**
These involve meaningful behavioral changes, such as new settlement
logic, changes to the order format (or its interpretation), etc. These
should always be registered under a new selector, which comes free if
the arguments also change, to allow users the opportunity to opt-in to
new behavior. If the upgrade is intended to replace an existing feature,
the old version should follow a deprecation schedule, unless we're
confident no one is using it.
**Features used by Features**
Not all features are designed to be exclusively consumed by the public.
We can have internal features by applying an onlySelf modifier to the
function. We need to be mindful of another class of user: the contract
itself. Avoiding missteps on this will require a combination of
diligence and good regression test suites.
# Known Risks
The extreme flexibility of this model means we have few built-in
guardrails that more conventional architectures enjoy. To avoid
pitfalls, we've established a few new patterns to follow during
development, but the following areas will always need careful scrutiny
during code reviews.
**Extended Attack Surface for Features**
Because features all run in the same execution context, they inherit
potential vulnerabilities from other features. Some vulnerabilities may
also arise from the interactions of separate features, which may not be
obvious without examining the system as a whole. Reviewers will always
need to be mindful of these scenarios and features should try to create
as much isolation of responsibilities as possible.
**Storage Layout Risks**
All features registered to the proxy will run in the same storage
context as the proxy itself. We employ a pattern of per-feature storage
buckets (structs) with globally unique bucket slots to mitigate issues.
**Slot Overlap**
Every time we develop a new feature, an entry is appended to the
`LibStorage.StorageId` enum, which is the bucket ID for the feature's
storage. This applies to the storage used by the proxy contract itself.
When calculating the true slot for the storage bucket, this enum value
is offset by `1` and bit shifted by `128`:
``` {.solidity}
function getStorageSlot(StorageId id) internal pure returns (uint256) {
return (uint256(id) + 1) << 128;
}
```
Given Solidity's [storage layout
rules](https://solidity.readthedocs.io/en/v0.6.6/miscellaneous.html)),
subsequent storage buckets should always be 2\^128 slots apart, which
means buckets can have 2\^128 flattened inline fields before
overlapping. While it's not impossible for buckets to overlap with this
pattern, it should be extremely unlikely if we follow it closely. Maps
and arrays are not stored sequentially but should also be affected by
their base slot value to make collisions unlikely.
**Inherited Storage**
A more insidious way to corrupt storage buckets is to have a feature
unintentionally inherit from a mixin that has plain (non-bucketed) state
variables, because the mixin can potentially read/write to slots shared
by other buckets through them. To avoid this:
1. We prefix all feature-compatible mixins with "Fixin" ("Feature" +
"Mixin") and only allow contract inheritance from these.
2\. Storage IDs are offset by 1 before computing the slot value. This
means the first real storage bucket will actually start at slot 2\^128,
which gives us a safety buffer for these scenarios, since it's unlikely
a mixin would unintentionally access slots beyond 2\^128. Shared Access
to Storage
There is nothing stopping a feature from reaching into another feature's
storage bucket and reading/modifying it. Generally this pattern is
discouraged but may be necessary in some cases, or may be preferable to
save gas. This can create an implicit tight coupling between features
and we need to take those interactions into account when upgrading the
features that own those storage buckets.
**Restricted Functions and Privilege Escalation**
We will also be registering functions that have caller restrictions.
Functions designed for internal use only will have an onlySelf modifier
that asserts that `msg.sender == address(this)`. The other class of
restricted functions are owner-only functions, which have an `onlyOwner`
modifier that asserts that the
`msg.sender == LibOwnableStorage.Storage.owner`.
The check on owner-only functions can be easily circumvented in a
feature by directly overwriting `LibOwnableStorage.Storage.owner` with
another address. If best practices and patterns are adhered to, doing so
would involve deliberate and obvious effort and should be caught in
reviews.
**Self-Destructing Features**
A feature contract with self-destruct logic must safeguard this code
path to only be executed after the feature is deregistered, otherwise
its registered functions will fail. In most cases this would just cause
the feature to temporarily go dark until we could redeploy it. But it
may leave the proxy in an unusable state if this occurs in the contract
of a mission-critical feature, e.g., Ownable or SimpleFunctionRegistry
(neither of which can self-destruct).
Features should also be careful that `selfdestruct` is never executed in
the context of the proxy to avoid destroying the proxy itself.
**Allowances**
Although the proxy will not have access to the V3 asset proxies
initially, early features will require taker allowances to be accessible
to the proxy somehow. Instead of having the proxy contract itself be the
allowance target, we intend on using a separate "Puppet" contract,
callable only by the proxy contract. This creates a layer of separation
between the proxy contract and allowances, so moving user funds is a
much more deliberate action. In the event of a major vulnerability, the
owner can simply detach the puppet contract from the proxy. This also
avoids the situation where the proxy has lingering allowances if we
decide grant it asset proxy authorization.
**Balances**
Inevitably, there will be features that will cause the Exchange Proxy to
hold temporary balances (e.g., payable functions). Thus, it's a good
idea that no feature should cause the Exchange Proxy to hold a permanent
balance of tokens or ether, since these balances can easily get mixed up
with temporary balances.
**Reentrancy**
Functions can be re-entered by default; those secured by the
`nonReentrant` modifier cannot be re-entered.
**Colliding Function Selectors**
We manually ensure that function selectors do not collide during PR\'s.
See the [Feature Checklist](./features.html#best-practices) for a
complete list of our best practices on Feature Development.

View File

@@ -1,257 +0,0 @@
###############################
Proxy
###############################
The `ZeroEx <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/ZeroEx.sol>`_ contract implements a per-function proxy pattern. Every function registered to the proxy contract can have a distinct implementation contract. Implementation contracts are called “features” and can expose multiple, related functions. Since features can be upgraded independently, there will no longer be a collective “version” of the API, defaulting to a rolling release model. The ZeroEx contracts only responsibility is to route (delegate) calls to per-function implementation contracts through its fallback.
.. image:: ../_static/img/proxy.png
:align: center
:scale: 100%
View the code for the Proxy `here <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/ZeroEx.sol>`_. There is also a `gas-optimized implementation <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/ZeroExOptimized.sol>`_ that may be put into production in the future (there is a lot of overhead for our integrators when redeploying this contract).
Bootstrapping
=============
The ZeroEx contract comes pre-loaded with only one Feature: `Bootstrap <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/features/BootstrapFeature.sol>`_. This exposes a ``bootstrap()`` function that can only be called by the deployer. This function does a few things:
1. De-register the bootstrap() function, which prevents it being called again.
2. Self-destruct.
3. Delegatecall the bootstrapper target contract and call data.
.. code-block:: solidity
// Execute a bootstrapper in the context of the proxy.
function bootstrap(address target, bytes callData) external
Below is the bootstrap workflow (click to enlarge).
.. image:: ../_static/img/bootstrap.png
:align: center
:scale: 70%
Function Registry
=================
One of the initial features InitialMigration bootstraps into the ZeroEx contract is the function registry feature, SimpleFunctionRegistry. This feature exposes the following function registry management features: ``extend()`` and ``rollback()``.
Call ``extend()`` to register a new function (selector) and implementation (address). This also maintains a history of past implementations so we can roll back to one, if needed.
.. code-block:: solidity
// Register or replace a function.
function extend(bytes4 selector, address impl)
external
onlyOwner;
Call ``rollback()`` to revert a function implementation to a prior version in its history.
.. code-block:: solidity
// Roll back to a previousimplementation of a function.
function rollback(bytes4 selector, address targetImpl)
external
onlyOwner;
Ownership
=========
Another Feature, ``InitialMigration``, bootstraps into the proxy is the Ownable feature. This exposes ownership management functions: ``transferOwnership()`` and ``getOwner()``. This feature also enables ubiquitous modifiers such as onlyOwner, so it is an implicit dependency of nearly every other feature.
.. code-block:: solidity
// Change the owner of this contract.
function transferOwnership(address newOwner)
external
onlyOwner;
// Get the owner of this contract.
function getOwner()
external
view
returns (address owner_);
Migrations
==========
Migrations are upgrade logic that run in the context of the proxy contract. To do this, the owner calls the ``migrate()`` function, provided by the ``Ownable`` Feature. This follows a similar sequence as the bootstrap process. Notably, it temporarily sets the owner of the contract to itself for the duration of the migration call, which allows the migrator to perform admin-level operations through other features, such as registering or rolling back new functions. Before exiting, the owner is set to the newOwner, which is passed in to the call.
One motivation for the existence of this function, as opposed to just having the make individual admin calls, is a shortcoming of the ZeroExGoverner contract, which is designed to perform one operation at a time, with no strict ordering of those operations.
This is a stripped down ``migrate()`` feature implementation:
.. code-block:: solidity
contract Ownable {
// Execute a migration function in the context of the proxy contract.
function migrate(address target, bytes calldata data, address newOwner)
external
onlyOwner
{
// If the owner is already set to ourselves then we've reentered.
require(OwnableStorage.owner != address(this));
// Temporarily set the owner to ourselves.
OwnableStorage.owner = address(this);
// Perform the migration.
target.delegatecall(data);
// Set the new owner.
OwnableStorage.owner = newOWner;
}
}
This is an example sequence of a migration (click to enlarge):
.. image:: ../_static/img/zero_ex_migrate.png
:align: center
:scale: 70%
Storage Buckets
===============
Because feature functions get delegatecalled into, they all share the same execution context and, thus, state space. Its critical that storage for each feature be compartmentalized from other features to avoid accidentally writing to the same slot. We solve this by strictly adhering to a storage bucket pattern for our feature contracts. This rule also extends to all inherited contracts/mixins.
Storage buckets are enabled by new language features in solidity 0.6, which allow us to rewrite a storage variables slot reference to a globally unique ID. These IDs are stored in an append-only enum defined in LibStorage, to enforce uniqueness. The true storage slot for a bucket is the features storage ID multiplied by a large constant to prevent overlap between buckets.
Example:
.. code-block:: solidity
LibStorage {
enum StorageId {
MyFeature
}
function getStorageSlot(StorageId id) internal pure returns (uint256) {
return uint256(id) * 1e18;
}
}
LibMyFeatureStorage {
// Storage layout for this feature.
struct Storage {
mapping(bytes32 => bytes) myData;
}
// Get the storage bucket for this feature.
function getStorage() internal view returns (Storage storage st) {
uint256 slot = LibStorage.getStorageSlot(
LibStorage.StorageId.MyFeature
);
assembly { st_slot := slot }
}
}
With the above pattern, writing to storage is simply:
.. code-block:: solidity
LibMyFeatureStorage.getStorage().myData[...] = ...
Version Management
==================
**Inspection**
This is a rolling release model, where every feature/function has its own version. All feature contracts (except Bootstrap because its ephemeral), implement the IFeature interface:
.. code-block:: solidity
interface IFeature {
// The name of this feature set.
function FEATURE_NAME() external view returns (string memory name);
// The version of this feature set.
function FEATURE_VERSION() external view returns (uint256 version);
}
So, to get the version of a function one could do ``IFeature(getFunctionImplementation(foo.selector)).FEATURE_VERSION``.
**Best Practices**
The registry is intentionally not prescriptive on how features should be migrated. But there are some general best practices we can follow to avoid harming users, and ourselves.
**Deprecation**
In general, unless a function has a vulnerability, we should keep it intact for the duration of the deprecation schedule. Afterwards, we can ultimately disable the function by either calling extend() with a null implementation or by calling rollback() to a null implementation.
**Patches**
These include bug-fixes, optimizations, or any other changes that preserve the intended behavior of the function. For these cases, we should upgrade the function in-place, i.e., using the same selector but changing the implementation contract, through extend().
**Vulnerabilities**
If a vulnerability is found in a live function, we should call rollback() immediately to reset it to a non-vulnerable implementation. Because rollback() is a separate function from extend(), it can be exempted from timelocks to allow a swift response.
**Upgrades**
These involve meaningful behavioral changes, such as new settlement logic, changes to the order format (or its interpretation), etc. These should always be registered under a new selector, which comes free if the arguments also change, to allow users the opportunity to opt-in to new behavior. If the upgrade is intended to replace an existing feature, the old version should follow a deprecation schedule, unless were confident no one is using it.
**Features used by Features**
Not all features are designed to be exclusively consumed by the public. We can have internal features by applying an onlySelf modifier to the function. We need to be mindful of another class of user: the contract itself. Avoiding missteps on this will require a combination of diligence and good regression test suites.
Known Risks
===========
The extreme flexibility of this model means we have few built-in guardrails that more conventional architectures enjoy. To avoid pitfalls, weve established a few new patterns to follow during development, but the following areas will always need careful scrutiny during code reviews.
**Extended Attack Surface for Features**
Because features all run in the same execution context, they inherit potential vulnerabilities from other features. Some vulnerabilities may also arise from the interactions of separate features, which may not be obvious without examining the system as a whole. Reviewers will always need to be mindful of these scenarios and features should try to create as much isolation of responsibilities as possible.
**Storage Layout Risks**
All features registered to the proxy will run in the same storage context as the proxy itself. We employ a pattern of per-feature storage buckets (structs) with globally unique bucket slots to mitigate issues.
**Slot Overlap**
Every time we develop a new feature, an entry is appended to the ``LibStorage.StorageId`` enum, which is the bucket ID for the features storage. This applies to the storage used by the proxy contract itself. When calculating the true slot for the storage bucket, this enum value is offset by ``1`` and bit shifted by ``128``:
.. code-block:: solidity
function getStorageSlot(StorageId id) internal pure returns (uint256) {
return (uint256(id) + 1) << 128;
}
Given Soliditys `storage layout rules <https://solidity.readthedocs.io/en/v0.6.6/miscellaneous.html)>`_, subsequent storage buckets should always be 2^128 slots apart, which means buckets can have 2^128 flattened inline fields before overlapping. While its not impossible for buckets to overlap with this pattern, it should be extremely unlikely if we follow it closely. Maps and arrays are not stored sequentially but should also be affected by their base slot value to make collisions unlikely.
**Inherited Storage**
A more insidious way to corrupt storage buckets is to have a feature unintentionally inherit from a mixin that has plain (non-bucketed) state variables, because the mixin can potentially read/write to slots shared by other buckets through them. To avoid this:
1. We prefix all feature-compatible mixins with “Fixin” (“Feature” + “Mixin”) and only allow contract inheritance from these.
2. Storage IDs are offset by 1 before computing the slot value. This means the first real storage bucket will actually start at slot 2^128, which gives us a safety buffer for these scenarios, since its unlikely a mixin would unintentionally access slots beyond 2^128.
Shared Access to Storage
There is nothing stopping a feature from reaching into another features storage bucket and reading/modifying it. Generally this pattern is discouraged but may be necessary in some cases, or may be preferable to save gas. This can create an implicit tight coupling between features and we need to take those interactions into account when upgrading the features that own those storage buckets.
**Restricted Functions and Privilege Escalation**
We will also be registering functions that have caller restrictions. Functions designed for internal use only will have an onlySelf modifier that asserts that ``msg.sender == address(this)``. The other class of restricted functions are owner-only functions, which have an ``onlyOwner`` modifier that asserts that the ``msg.sender == LibOwnableStorage.Storage.owner``.
The check on owner-only functions can be easily circumvented in a feature by directly overwriting ``LibOwnableStorage.Storage.owner`` with another address. If best practices and patterns are adhered to, doing so would involve deliberate and obvious effort and should be caught in reviews.
**Self-Destructing Features**
A feature contract with self-destruct logic must safeguard this code path to only be executed after the feature is deregistered, otherwise its registered functions will fail. In most cases this would just cause the feature to temporarily go dark until we could redeploy it. But it may leave the proxy in an unusable state if this occurs in the contract of a mission-critical feature, e.g., Ownable or SimpleFunctionRegistry (neither of which can self-destruct).
Features should also be careful that ``selfdestruct`` is never executed in the context of the proxy to avoid destroying the proxy itself.
**Allowances**
Although the proxy will not have access to the V3 asset proxies initially, early features will require taker allowances to be accessible to the proxy somehow. Instead of having the proxy contract itself be the allowance target, we intend on using a separate “Puppet” contract, callable only by the proxy contract. This creates a layer of separation between the proxy contract and allowances, so moving user funds is a much more deliberate action. In the event of a major vulnerability, the owner can simply detach the puppet contract from the proxy. This also avoids the situation where the proxy has lingering allowances if we decide grant it asset proxy authorization.
**Balances**
Inevitably, there will be features that will cause the Exchange Proxy to hold temporary balances (e.g., payable functions). Thus, its a good idea that no feature should cause the Exchange Proxy to hold a permanent balance of tokens or ether, since these balances can easily get mixed up with temporary balances.
**Reentrancy**
Functions can be re-entered by default; those secured by the ``nonReentrant`` modifier cannot be re-entered.
**Colliding Function Selectors**
We manually ensure that function selectors do not collide during PR's. See the `Feature Checklist <./features.html#best-practices>`_ for a complete list of our best practices on Feature Development.

View File

@@ -1,92 +0,0 @@
---
title: Transformer Deployer
---
[Transformers](./transformers.html) need to be permissioned because they
are executed in the context of the [Flash Wallet](./flash_wallet.html).
This means that a malicious Transformer could grief the protocol by
destroying the Flash Wallet via `selfdestruct`, so we need some way to
authenticate that the Transformer is safe to use at runtime.
The Transformer Deployer `create`\'s all Transformers, and its
deployment nonce is used to validate a Transformer at runtime. The
deployer is owned by 0x Labs, so only we are able to deploy
Transformers.
The deployer implements two functions: `deploy()` and `kill()`. The
former is used to deploy new Transformers; it will emit a
[Deployed](../basics/events.html#deployed) event (that includes the
nonce) or reverts if it fails to `create` the Transformer. The `kill()`
function is used to destroy deprecated Transformers; this emits a
[Killed](../basics/events.html#killed) event or reverts if the
Transformer\'s `die()` function reverts. Note that we cannot verify a
Transformer called `selfdestruct` in the `kill` function because this
information is not available until after the transaction executes.
``` {.solidity}
/// @dev Deploy a new contract. Only callable by an authority.
/// Any attached ETH will also be forwarded.
function deploy(bytes memory bytecode)
public
payable
onlyAuthorized
returns (address deployedAddress);
/// @dev Call `die()` on a contract. Only callable by an authority.
/// @param target The target contract to call `die()` on.
/// @param ethRecipient The Recipient of any ETH locked in `target`.
function kill(IKillable target, address payable ethRecipient)
public
onlyAuthorized;
```
View the code for the Transformer Deployer
[here](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/external/TransformerDeployer.sol).
# Permissionless Transfomer Deployer
A permissionless deployer has been developed and can be seen
[here](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/external/PermissionlessTransformerDeployer.sol).
This serves a similar function to the current delployer, only it is
capable of validating the Transformer\'s bytecode before deploying. It
does this by tracing the bytecode in search of reachable opcodes that
could post a threat to the Flash Wallet.
The `isDelegateCallSafe` function performs this check. It will return
`false` if any of the following opcodes are reachable: `callcode`,
`delegatecall`, `selfdestruct`, `create`, `create2`, `sload`, `sstore`.
``` {.solidity}
/// @dev Checks whether a given address is safe to be called via
/// delegatecall. A contract is considered unsafe if it includes any
/// of the following opcodes: CALLCODE, DELEGATECALL, SELFDESTRUCT,
/// CREATE, CREATE2, SLOAD, and STORE. This code is adapted from
/// https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/helpers/IndestructibleRegistry.sol
/// @param target The address to check.
/// @return True if the contract is considered safe for delegatecall.
function isDelegateCallSafe(address target) public view returns (bool);
```
THe `deploy` function is similar to the existing Transformer Deployer,
only it uses a user-provided nonce to deploy the Transformer.
``` {.solidity}
/// @dev Deploy a new contract. Any attached ETH will be forwarded.
function deploy(bytes memory bytecode, bytes32 salt)
public
payable
returns (address deployedAddress);
```
Note that there is no `kill` function in this deployer.
View the code for the Permissionless Transformer Deployer
[here](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/external/PermissionlessTransformerDeployer.sol).
There is some overhead to switching over to this deployer, as the [Flash
Wallet](./flash_wallet.html) would need to be redeployed and some
integrators would need to update their code. Therefore, this will be put
into production once there is community-demand for permissionless
transformers. Reach out to us on
[Discord](https://discord.com/invite/d3FTX3M) if you\'d like to deploy a
Transformer!

View File

@@ -1,64 +0,0 @@
###############################
Transformer Deployer
###############################
`Transformers <./transformers.html>`_ need to be permissioned because they are executed in the context of the `Flash Wallet <./flash_wallet.html>`_. This means that a malicious Transformer could grief the protocol by destroying the Flash Wallet via ``selfdestruct``, so we need some way to authenticate that the Transformer is safe to use at runtime.
The Transformer Deployer ``create``'s all Transformers, and its deployment nonce is used to validate a Transformer at runtime. The deployer is owned by 0x Labs, so only we are able to deploy Transformers.
The deployer implements two functions: ``deploy()`` and ``kill()``. The former is used to deploy new Transformers; it will emit a `Deployed <../basics/events.html#deployed>`_ event (that includes the nonce) or reverts if it fails to ``create`` the Transformer. The ``kill()`` function is used to destroy deprecated Transformers; this emits a `Killed <../basics/events.html#killed>`_ event or reverts if the Transformer's ``die()`` function reverts. Note that we cannot verify a Transformer called ``selfdestruct`` in the ``kill`` function because this information is not available until after the transaction executes.
.. code-block:: solidity
/// @dev Deploy a new contract. Only callable by an authority.
/// Any attached ETH will also be forwarded.
function deploy(bytes memory bytecode)
public
payable
onlyAuthorized
returns (address deployedAddress);
/// @dev Call `die()` on a contract. Only callable by an authority.
/// @param target The target contract to call `die()` on.
/// @param ethRecipient The Recipient of any ETH locked in `target`.
function kill(IKillable target, address payable ethRecipient)
public
onlyAuthorized;
View the code for the Transformer Deployer `here <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/external/TransformerDeployer.sol>`__.
Permissionless Transfomer Deployer
===================================
A permissionless deployer has been developed and can be seen `here <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/external/PermissionlessTransformerDeployer.sol>`__. This serves a similar function to the current delployer, only it is capable of validating the Transformer's bytecode before deploying. It does this by tracing the bytecode in search of reachable opcodes that could post a threat to the Flash Wallet.
The ``isDelegateCallSafe`` function performs this check. It will return ``false`` if any of the following opcodes are reachable: ``callcode``, ``delegatecall``, ``selfdestruct``, ``create``, ``create2``, ``sload``, ``sstore``.
.. code-block:: solidity
/// @dev Checks whether a given address is safe to be called via
/// delegatecall. A contract is considered unsafe if it includes any
/// of the following opcodes: CALLCODE, DELEGATECALL, SELFDESTRUCT,
/// CREATE, CREATE2, SLOAD, and STORE. This code is adapted from
/// https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/helpers/IndestructibleRegistry.sol
/// @param target The address to check.
/// @return True if the contract is considered safe for delegatecall.
function isDelegateCallSafe(address target) public view returns (bool);
THe ``deploy`` function is similar to the existing Transformer Deployer, only it uses a user-provided nonce to deploy the Transformer.
.. code-block:: solidity
/// @dev Deploy a new contract. Any attached ETH will be forwarded.
function deploy(bytes memory bytecode, bytes32 salt)
public
payable
returns (address deployedAddress);
Note that there is no ``kill`` function in this deployer.
View the code for the Permissionless Transformer Deployer `here <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/external/PermissionlessTransformerDeployer.sol>`_.
There is some overhead to switching over to this deployer, as the `Flash Wallet <./flash_wallet.html>`_ would need to be redeployed and some integrators would need to update their code. Therefore, this will be put into production once there is community-demand for permissionless transformers. Reach out to us on `Discord <https://discord.com/invite/d3FTX3M>`_ if you'd like to deploy a Transformer!

View File

@@ -1,62 +0,0 @@
---
title: Transformers
---
Transformers extend the core protocol. They are trustless and
permissioned by the [Transformer Deployer](./transformer_deployer.html).
A Transformer is identified by the nonce of the Transformer Deployer
that corresponds to its address. These contracts are executed in the
context of the [Flash Wallet](./flash_wallet.html) (via `delegatecall`).
Below is a catalog of Transformers.
-------------------------- ----------------------------------------------------------- ----------- ------------------------------------------------------------------------------------------------------------------------------------------
**Transformer** **Description** **Nonce** **Resources**
FillQuoteTransformer Aggregates Liquidity across DEXs and Native 0x Orders. 9 [Code](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/transformers/FillQuoteTransformer.sol);
[Usage](../advanced/erc20_transformations.html#liquidity-aggregation)
AffiliateFeesTransformer Allows integrators to charge an affiliate fee when an order 8 [Code](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/transformers/AffiliateFeeTransformer.sol);
is filled by their platform. [Usage](../advanced/erc20_transformations.html#affiliate-fees)
PayTakerTransformer Forwards funds in the Flash Wallet to the Taker. 7 [Code](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/transformers/PayTakerTransformer.sol);
[Usage](../advanced/erc20_transformations.html#pay-taker)
WethTransformer Wraps ETH into WETH (and unwraps) 6 [Code](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/transformers/WethTransformer.sol);
[Usage](../advanced/erc20_transformations.html#weth-wrapping)
-------------------------- ----------------------------------------------------------- ----------- ------------------------------------------------------------------------------------------------------------------------------------------
# Implementing a Transformer
Transformers are currently used by the
[TransformERC20Feature](./features.html) to aggregate liquidity and
perform operations on ERC20 tokens (ex, wrapping ETH). Your transformer
should inherit from [Transformer
Contract](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/transformers/Transformer.sol)
and implement the interface in
[IERC20Transformer](https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/transformers/IERC20Transformer.sol).
``` {.solidity}
// @dev A transformation callback used in `TransformERC20.transformERC20()`.
interface IERC20Transformer {
/// @dev Context information to pass into `transform()` by `TransformERC20.transformERC20()`.
struct TransformContext {
// The caller of `TransformERC20.transformERC20()`.
address payable sender;
// taker The taker address, which may be distinct from `sender` in the case
// meta-transactions.
address payable taker;
// Arbitrary data to pass to the transformer.
bytes data;
}
/// @dev Called from `TransformERC20.transformERC20()`. This will be
/// delegatecalled in the context of the FlashWallet instance being used.
/// @param context Context information.
/// @return success The success bytes (`LibERC20Transformer.TRANSFORMER_SUCCESS`).
function transform(TransformContext calldata context)
external
returns (bytes4 success);
}
```

View File

@@ -1,53 +0,0 @@
###############################
Transformers
###############################
Transformers extend the core protocol. They are trustless and permissioned by the `Transformer Deployer <./transformer_deployer.html>`_. A Transformer is identified by the nonce of the Transformer Deployer that corresponds to its address. These contracts are executed in the context of the `Flash Wallet <./flash_wallet.html>`_ (via ``delegatecall``).
Below is a catalog of Transformers.
.. table::
:widths: 20 60 10 10
+--------------------------+------------------------------------------------------------------------------------------+-----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| **Transformer** | **Description** | **Nonce** | **Resources** |
+--------------------------+------------------------------------------------------------------------------------------+-----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| FillQuoteTransformer | Aggregates Liquidity across DEXs and Native 0x Orders. | 9 | `Code <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/transformers/FillQuoteTransformer.sol>`__; `Usage <../advanced/erc20_transformations.html#liquidity-aggregation>`__ |
+--------------------------+------------------------------------------------------------------------------------------+-----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| AffiliateFeesTransformer | Allows integrators to charge an affiliate fee when an order is filled by their platform. | 8 | `Code <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/transformers/AffiliateFeeTransformer.sol>`__; `Usage <../advanced/erc20_transformations.html#affiliate-fees>`__ |
+--------------------------+------------------------------------------------------------------------------------------+-----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| PayTakerTransformer | Forwards funds in the Flash Wallet to the Taker. | 7 | `Code <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/transformers/PayTakerTransformer.sol>`__; `Usage <../advanced/erc20_transformations.html#pay-taker>`__ |
+--------------------------+------------------------------------------------------------------------------------------+-----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| WethTransformer | Wraps ETH into WETH (and unwraps) | 6 | `Code <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/transformers/WethTransformer.sol>`__; `Usage <../advanced/erc20_transformations.html#weth-wrapping>`__ |
+--------------------------+------------------------------------------------------------------------------------------+-----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
Implementing a Transformer
==========================
Transformers are currently used by the `TransformERC20Feature <./features.html>`_ to aggregate liquidity and perform operations on ERC20 tokens (ex, wrapping ETH). Your transformer should inherit from `Transformer Contract <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/transformers/Transformer.sol>`_ and implement the interface in `IERC20Transformer <https://github.com/0xProject/protocol/blob/development/contracts/zero-ex/contracts/src/transformers/IERC20Transformer.sol>`_.
.. code-block:: solidity
// @dev A transformation callback used in `TransformERC20.transformERC20()`.
interface IERC20Transformer {
/// @dev Context information to pass into `transform()` by `TransformERC20.transformERC20()`.
struct TransformContext {
// The caller of `TransformERC20.transformERC20()`.
address payable sender;
// taker The taker address, which may be distinct from `sender` in the case
// meta-transactions.
address payable taker;
// Arbitrary data to pass to the transformer.
bytes data;
}
/// @dev Called from `TransformERC20.transformERC20()`. This will be
/// delegatecalled in the context of the FlashWallet instance being used.
/// @param context Context information.
/// @return success The success bytes (`LibERC20Transformer.TRANSFORMER_SUCCESS`).
function transform(TransformContext calldata context)
external
returns (bytes4 success);
}

View File

@@ -1,37 +0,0 @@
---
title: Protocol Fees
---
An ETH protocol fee is paid by the Taker each time a [Limit
Order](./orders.html#limit-orders) is [filled](./functions.html). The
fee is proportional to the gas cost of filling an order and scales
linearly with gas price. The cost is currently `70k * tx.gasprice`. At
the end of every Staking Epoch, these fees are aggregated and
distributed to the makers as a liquidity reward: the reward is
proportional to the maker\'s collected fees and staked ZRX relative to
other makers. To learn more about protocol fees and liquidity
incentives, see the [Official
Spec](https://github.com/0xProject/0x-protocol-specification/blob/master/staking/staking-specification.md).
::: {.note}
::: {.title}
Note
:::
[RFQ Orders](./orders.html#rfq-orders) are introduced in Exchange V4,
and there is currently no protocol fee for filling this type of order.
The existing fee mechanics work well for limit orders, where arb bots
pay to compete for liquidity; however, it does not translate well to RFQ
where makers are matched with a specific taker. We are researching fee
models that could be used for RFQ and will keep the community up-to-date
on our [Forum](https://forum.0x.org/).
:::
::: {.warning}
::: {.title}
Warning
:::
In Exchange V3, protocol fees could be paid in ETH or WETH. As of V4,
they can only be paid in ETH.
:::

View File

@@ -1,9 +0,0 @@
---
title: Governance
---
The 0x Community uses their ZRX (and staked ZRX) tokens to govern the
protocol, by voting on proposals called
[ZEIPs](https://github.com/0xProject/ZEIPs). Anyone can propose a change
to the system by creating a ZEIP. Visit <https://0x.org/zrx/vote> to
participate!

View File

@@ -1,5 +0,0 @@
###############################
Governance
###############################
The 0x Community uses their ZRX (and staked ZRX) tokens to govern the protocol, by voting on proposals called `ZEIPs <https://github.com/0xProject/ZEIPs>`_. Anyone can propose a change to the system by creating a ZEIP. Visit `https://0x.org/zrx/vote <https://0x.org/zrx/vote>`_ to participate!

View File

@@ -1,9 +0,0 @@
---
title: Research
---
```{=html}
<embed>
<iframe class="researchPdf" src="../_static/protocol-fees.pdf" width="100%" />
</embed>
```

View File

@@ -1,9 +0,0 @@
###############################
Research
###############################
.. raw:: html
<embed>
<iframe class="researchPdf" src="../_static/protocol-fees.pdf" width="100%" />
</embed>

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +0,0 @@
---
title: Staking Reward Formula
---
```{=html}
<embed>
<iframe class="researchPdf" src="../_static/adjusted-staking-percentage-formula.pdf" width="100%" />
</embed>
```

View File

@@ -1,9 +0,0 @@
###############################
Staking Reward Formula
###############################
.. raw:: html
<embed>
<iframe class="researchPdf" src="../_static/adjusted-staking-percentage-formula.pdf" width="100%" />
</embed>