From 8ad082ed246900c2362014fef079b5d135563718 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Wed, 7 Dec 2022 17:02:05 -0500 Subject: [PATCH 1/2] Update existing protocol docs to point to protocol-specific resources Remove documentation of outdated/irrelevant portions of the protocol --- docs/_static/img/logo.png | Bin 0 -> 36569 bytes docs/_static/img/logo.svg | 15 - docs/_static/img/smart_nonce_diagram.webp | Bin 0 -> 5182 bytes docs/architecture/governor.rst | 14 +- docs/architecture/overview.rst | 10 +- docs/architecture/proxy.rst | 50 +- docs/basics/orders.rst | 4 +- docs/basics/signatures.rst | 75 + docs/guides/nft_guide.rst | 454 ++++++ docs/guides/smart_nonce.rst | 17 + docs/index.rst | 61 +- docs/tokenomics/governance.rst | 5 - docs/tokenomics/research.rst | 9 - docs/tokenomics/staking.md | 1486 -------------------- docs/tokenomics/staking_reward_formula.rst | 9 - 15 files changed, 618 insertions(+), 1591 deletions(-) create mode 100644 docs/_static/img/logo.png delete mode 100644 docs/_static/img/logo.svg create mode 100644 docs/_static/img/smart_nonce_diagram.webp create mode 100644 docs/basics/signatures.rst create mode 100644 docs/guides/nft_guide.rst create mode 100644 docs/guides/smart_nonce.rst delete mode 100644 docs/tokenomics/governance.rst delete mode 100644 docs/tokenomics/research.rst delete mode 100644 docs/tokenomics/staking.md delete mode 100644 docs/tokenomics/staking_reward_formula.rst diff --git a/docs/_static/img/logo.png b/docs/_static/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f395ed4e4c3f8ed664b2232cc4ce4fa2da7cf934 GIT binary patch literal 36569 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 literal 0 HcmV?d00001 diff --git a/docs/_static/img/logo.svg b/docs/_static/img/logo.svg deleted file mode 100644 index d288659ba2..0000000000 --- a/docs/_static/img/logo.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/docs/_static/img/smart_nonce_diagram.webp b/docs/_static/img/smart_nonce_diagram.webp new file mode 100644 index 0000000000000000000000000000000000000000..56b2b11aa9efdc53f17f395615e723bb0a9dcbc0 GIT binary patch literal 5182 zcmV-E6v69KNk&FC6aWBMMM6+kP&iB~6aWA(dqP40g$Mrs-z(|=?6@mb&v?!ieAhal$E6~bQ|msp0)KeFMf0%h$lVaO zr0k$Q62_pNyxYsb^5}_WYKinJ&O&U$WVb>c0qj&DIdw+5H_P) zZmx>K8i`wOpe@1e`xbY&?P7oq#|xB?)#=Omq#sl$?u(VXCl?}rL)em2`SK1D=|1A! zjRVR#?cnR{+hALP^07L7Im^cYb+W`b^MZTy4ap5*YobU|@ZKbtpKz?^jg1_ROFxy4}FJ6FJ|>Q+(L>ewr&0D*t4N z@%Zg=I(?Hv^+p10YwaI(UBWQa=h?77k-Z`8dZWgFHU9hGH45uxSjViE+n~mOHU6{W zWvCtpI)$>fd(2f%tI&NR>zcYwt6#--2fB8^gk@7UsTaBe&h(PiZHabgGp*o` z+pmTNJ%KBMCau3F!?olQ^f~&Jx?28iFnY?`{#;H;^jpAK-(+&!ud_B>zMjB~0Q7iY z`*EB#=zN%e&>sE>9u>iI@8G2-O9P*qTt&U*?xk=xctH>U0~i(r1dJ-ieSM5-8Eg-1 z8du5Qpuj%44-W?eOq0gDZd6rVbKjBWz`yJ2Amq5n4mi^c==rTDMu!6M$b2MGsmL`= zLRg15yaPD>3#^KR)QHK+{L~sQG(xr>uWZ5frUvV9!_e|8F1i++clm})_dMe$6}wyA z*AHIHGp`$g3l97FI*hN|ml{X@3y=BSaVpDccvIg$DbM`^D~3EgC8J&!Hn#O*TeQ(I z`y_BO2pF*u$#{1pY#CGF2~i(&;#ut@N%uiVObV1p!aF3R??$THUNR~6%3$e8Wb3It zv{9SA?CLquCnD1dbgixty6nE-Y#@0c98fX-9oQRzM;ZcGIOjv$`*5Hg9%rEbjV%MA zta58_D0y1{khr=zw7ep5qUqiW01kBo#;uY#&^(92=L!VpJQ~#A#UrSWo6>!cggCrI zA~DK9;$lqr%+aG+mTWzSaeK6T>i(5d`B!pNFq+vrs&) ziZm7NfBsWQZ;D42cx1gd2H<@cUteGMyoWaF4>ZaVV_SsV%VoeXfxwWBYdt*H!k2+r zFm5X*6@CY})Hv&roQ#(P_K1nYJ4B3AdzW&hU8Ufx-%Y;r*T3lD@w>Pl03yHG)gBB^ z1=iqXfKGcZG=+}`!4E3pR|DXYB`fY-*cT$Pr4QWu>+?Ym_nScQHVG(tekD*)ryK%L zl;-7?vO6db@bL6(RLe89F%a|Fqq&>ulf}g09U`-aYhh)5PtQ88^H#kCIQ?}mFHbA3 zr}S5#$F_4mpm)4){V}%sl8k5W3C`Bf)yJy%K2*bo6v6$?Qs1^KGYnfKamVdX{jj9` zhF3|S`tTTzx?DEd-Nm?evC%l;eSqk+dBxOx5nhL%Uy5S*Oi+nB@61E$Hv#_d z)%fqfjy;hQC2WOUk0BRAfE@!={!Ez{ais-9FLP@v8t` z3ulp+$Cq)zb3X&q9!M(2t@`Oy&gv}3=qYl<_hxbTkIZCT6g_iDJNpGmMHVDr*xrik zT!Wh~8l5ukJNR+9gGjfpfZJv7D4XvPCt!$DG15buw>kz%-k}?OrD++!kpQ6LrinOH zL%JA?SCe2*#BbguEPX+eaq(?0xbIvku1G>I0mJsj$hTl=96E>HgJARyg~)2JwU+=| zr%4hpM5!1dTlp%G%xChd`pTqb02=S%`!rx8$#y^3ZPV(c00*7R+?iA(}U8kFnFb!7bz_*y0{1K{s@ zL5{sLOeC2a5@A2WEmunXW7bPEF6Pex{LY9g5|K~9u)!yT_o>r91`{T3+&&HoF#H_w zj)_bH##Q*bTjx**mc_#_GHDqg-m%c5Y<0XOQ$r%=YdF^g<~x^2GcJ}T0QIkmE0Q6t z$_B^$>9ZFiIM!?UL9wzgj6l)|($Gl8lR^{w{qBB^5Dz36~te^Mp77!#?tO ziUCqPK9Y~8*hTzZ?;_);+3g-j-r(mwsL;Om9EKYI)wJ(Pv|Qqcpg55?|ubA$sf}9@VGlQ?oc{8lXgsOFJVf~)& zbuA{mZL+w+;#R&ZfY*XeV-W!8r!2MGi2RK^eu7zvq$+O8IMzwW@QrlNsBq)s8C0&3 zRG4gTf;FyvtL!z5&f($Vs=Gk+QD`71X)dgvBzCp=_-`vE6{skIlXHorfT&dP zl(XC<`4urL4<>{d#TAN84K#=fBClfne zt_K;$C=)wft_L8ntL1uFz^<0-VF9~Zu7?Hebh#c9_PSh;5M?b#<#+$zEZ3vPfB$<& zefpo!xrpS46`GNd^3N=I|G}J{&c)1IM9th_w-EcI+)J*^GW>If2V(zpw5@L2=!`F{ zWqCx;30f9)4oN06LLHs2pBUC*@?mg!wB;>jIYph&s&D`7k;q%`H4!9mCUFk&~pn zg3g_^p)W?OSrF@0j7(utso-@-tk)qxd`i87!^2zuD5!L+##pmMJ?6Pnyfa(;7EXfN z6~LxGdb%FgJvG<=9`jc5tI4J3h&sU%laVQ>LIF@Bl19p8bZ#_FexP+%pU5f{G08groR`I=Yp~K`fEY3J1nMu zu0S`u)6kbTv#)c{i0gvIv*o75keDOB>lVDviIycYg)NyO=rSiZcpJAn#mx!2t$87= z<4K+9luF~ebxsn!MbyVLt!SxQtlF@m_8OBlwO2fO?pL&C9Ez+qXdInA6dulw z8e4jrw~%UM%ym*I6i#z(>fO(#S06M=6Q#!LqghdnS~U==lM5^GQZv`FcJ*nm^F^pm zF08&w&0M9E^P1}Oy7OMBRxTXpT7B0P3XkgX{=}R^^PU}8ty~8*u^OxHe#KZvMYTDU z%_0}3Tf-liD^ZbXg-lgX{1-AlR`)AfBfFpYo@j^J?|^27JrDd3pwz@vJDx;E;(zH) z!2hRaeo^TEpn|H`pXz5}edeWg)~eeZpvVo7Z!PW{Pb-zmb5u=mZMIe0In6dbY=!2* zvS3l@mRF!wIrg)(K6CVe7f}0bkdSXJZo-EEyct`T9$bFjUvHD%uUOl0uI53qU{UB6 zSHOZ&mwuMkXUWeZI0ur!}>mlyfx?js=TCx3~g8U|Ch> z4BKpSa`H^U1UF%1N?MECyO+1`GK!RITLkTf4KLWHyFC;N;mU(z!J^PDt3b-q`poe; zXL91M=OtmcnU>=&TT_1Br?!(r}D@P%Ky!x@8qeSy-Rh$vIcR zy54eRTZ{Yl#3Ds8L~SF-*$yySuqbrPDv+|YKC^$#71Oo)MrK3YT3k+4z?+k)e*+?S z+p5+$Kdjx7kF-_1$N4?ob{>ZSlfq57KNTw%hC!I!bq^Js!I+qdB7--JF+d>STHI@q?tW|G{$Mx% z-LNs%zHq-H05I+WR$$@SGJpp(`h9Mb-meG`S>?_LSAnIpEiOJ7=lylI)KrcBt?ZXB z+6O_~`B(eia~S>)ff|cm7yPx0$~3;~wi_s~pOer?2SlnxmW6a_vlPC305YSyb_l2wIv3ejlr<=XUOP#c zHXK$=6WQIN0wAv581Z`ejGhUTa-+jTx1t}@Id1Pq$2(Qsw?{g_wx*k5KBmDLqck8pKr}6KGDdG=!1#qN^`ptBKq(ILi zJIP^R*9$a_B2IPSz1fhkYtH7(ewW0%$xeB(;l)eA()I8?ttDrC?C@H;rHf!#iueOw z0iZqpX7dCSae@DUm7MEQ9Z$5$Z2PC+eB{Ef#45^w+4C<2OV`7vgi%S9JLr}yhT$pi z%tkT_fg;CB^=WZ|0;^*@R#UZX)yS?0=nzsS_WD>Im3=tuwJ-je;*Rs(-^yH?*TdJI~{Pi$-celFJsqvae>MKIcQ`Cw=6$hqreMUv!-^C^pqhu##*wAX8#I2Uf6#$H!2b8#E9rlg}&NNZ;5ZXBMWxHGodb}aW=qa+W zU&&?93lc-u30v!in*Cp=W8*vIYlJP`IQ+a{9?Th~#%vo$?!M?B_!hEl9H|)T8@YHa zn$iBPk^xva3HZCv#9SLkTBgCQL~$EOmep$(S+7}~SN%RRid0Um^KEhr!h(I$jRqZ)tGJLNVC&0cZO^mM@FoLgm|7k1+OOp za6aC<-gsd$)5a04q71eS6t{82ayI_NRrkvG<1oSh>Xa=eX4^R8bOYWSCELc4n9pHZ zJT6UreZ8h58J7n3HZj-65yw1OJ5tof5xWJ#c7+}hd2^Xxv5DC>jx_rX{xwUsjU&T8 zgjeEGWgr=Qa)C52(`2rVBW+S4VTq`XBlZg$BYh1bmzxg7#B3W!UY*1})lu0tj=UFb zxYHz_nF&Vi%-;p02jo&Tc9@B|HjXUqQ+mF^WpNuvA7o4tIOL7$sz<4Dyw*Ctz$v~fgAE- s^~etcES~d-Jf32Q@x6apNzhJv9sR4#d|x-(_nyO0``, 2 days - ExchangeProxy, ``setTransformerDeployer``, ``87c96419``, 2 days - ExchangeProxy, ``transferOwnership``, ``f2fde38b``, 2 days + ExchangeProxy, ``setQuoteSigner``, ````, 2 day + ExchangeProxy, ``setTransformerDeployer``, ``87c96419``, 2 day + ExchangeProxy, ``transferOwnership``, ``f2fde38b``, 2 day StakingProxy, ``addExchangeAddress``, ``8a2e271a``, 14 days StakingProxy, ``removeExchangeAddress``, ``01e28d84``, 14 days StakingProxy, ``attachStakingContract``, ``66615d56``, 14 days diff --git a/docs/architecture/overview.rst b/docs/architecture/overview.rst index 29a7e8446a..601f4c111d 100644 --- a/docs/architecture/overview.rst +++ b/docs/architecture/overview.rst @@ -2,7 +2,7 @@ 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 `ZeroEx` (Exchange Proxy) contract implements a delegate-call proxy pattern to create a system of composable smart contracts. This architecture enables 0x Protocol to innovate with minimal friction alongside the growing DeFi ecosystem. The diagram below illustrates our system (click to enlarge). @@ -24,13 +24,7 @@ The table below defines our smart contract nomenclature. +-------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | `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. | +| `Governor <./governor.html>`_ | A smart contract that governs trusted contracts in the system: Proxy, Features, Flash Wallet. | +-------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | `PLP Sandbox <./plp_sandbox.html>`_ | `PLP <../advanced/plp.html>`_ liquidity providers are called from this sandbox. | +-------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ \ No newline at end of file diff --git a/docs/architecture/proxy.rst b/docs/architecture/proxy.rst index 0a17dd0490..5169f1079c 100644 --- a/docs/architecture/proxy.rst +++ b/docs/architecture/proxy.rst @@ -2,37 +2,22 @@ Proxy ############################### -The `ZeroEx `_ 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. +The `ZeroEx `_ contract (also called Exchange Proxy or EP) is the main contract that manages the process and performs the exchange of assets. It implements a per-function proxy pattern where each function can have a distinct implementation contract, also known as "features". The `ZeroEx` contract's sole responsibility is to maintain a mapping of "features" to implementation contracts and route (delegate) calls to per-function implementation contracts through its fallback mechanism. .. image:: ../_static/img/proxy.png :align: center :scale: 100% -View the code for the Proxy `here `_. There is also a `gas-optimized implementation `_ that may be put into production in the future (there is a lot of overhead for our integrators when redeploying this contract). +View the code for the Proxy `here `_. The deployed contract address for each network can be found in `here `_. -Bootstrapping -============= -The ZeroEx contract comes pre-loaded with only one Feature: `Bootstrap `_. 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% +Deployment +========== +At deployment, the ``ZeroEx`` contract goes through an ``InitialMigration`` that bootstraps two core features to the proxy pattern: Function Registry and Ownership. 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()``. +``SimpleFunctionRegistry`` is one of the initial and core features of the `ZeroEx` contract boostrapped in during the ``InitialMigration``. 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. @@ -54,7 +39,7 @@ Call ``rollback()`` to revert a function implementation to a prior version in it Ownership ========= -Another Feature, ``InitialMigration``, bootstraps into the proxy is the Ownable feature. This exposes ownership management functions: ``transferOwnership()`` and ``owner()``. This feature also enables ubiquitous modifiers such as onlyOwner, so it is an implicit dependency of nearly every other feature. +``Ownable`` is another initial and core feature of the `ZeroEx` contract that is bootstrapped into the proxy during the ``InitialMigration``. 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 @@ -256,3 +241,24 @@ Functions can be re-entered by default; those secured by the ``nonReentrant`` mo **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. + +Initial Bootstrapping +===================== + +The way that the initial bootstrapping is accomplished is through the ``bootstrap()`` function that can only be called by the deployer. Check `here `_ to see the full boostrapping feature. + +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% diff --git a/docs/basics/orders.rst b/docs/basics/orders.rst index 71023931c7..038c2202ee 100644 --- a/docs/basics/orders.rst +++ b/docs/basics/orders.rst @@ -295,9 +295,9 @@ In both cases, the ``@0x/protocol-utils`` package simplifies generating these si The Orderbook ======================= -Orders are shared through a decentralized and permissionless network, called `0x Mesh `_. The simplest way to post and discover orders is through `0x API `_. See `this guide `_ tailored for Market Makers. +Orders can be hosted by any server and are usually represented as a JSON object off-chain. For example, one off-chain way to post and discover orders is through `0x API `_. -Orders are usually represented as a JSON object off-chain. Below is a table represention and example of how orders should be formatted off-chain. +Below is a table represention and example of how orders should be formatted off-chain. JSON representation of RFQ Orders ********************************* diff --git a/docs/basics/signatures.rst b/docs/basics/signatures.rst new file mode 100644 index 0000000000..d6faf2be92 --- /dev/null +++ b/docs/basics/signatures.rst @@ -0,0 +1,75 @@ +Signatures +========== + +Signatures are used in several places in 0x Protocol to prove an actor +has agreed to the behavior in some off-chain message. + +Signatures are represented by the following struct: + +.. code:: solidity + + struct Signature { + // How to validate the signature. + SignatureType signatureType; + // EC Signature data. + uint8 v; + // EC Signature data. + bytes32 r; + // EC Signature data. + bytes32 s; + } + +Where ``SignatureType`` is: + +.. code:: solidity + + enum SignatureType { + ILLEGAL, + INVALID, + EIP712, + ETHSIGN, + PRESIGNED + } + +Descriptions of the valid signature types follow. + +**EIP712 (``2``)** + +This is the signature type typically used when an order is signed +through a UI, such as Metamask. This is commonly achieved by calling +some variant of the ``eth_signTypedData`` (which fully utilizes EIP712) +JSONRPC command on the Ethereum provider. + +It can also be generated in a headless manner using a standard +``ecsign()`` implementation +(`example `__) +by re-hashing the `canonical order +hash `__ with a prefix as follows and +signing the result: + +.. code:: solidity + + eip712HashToSign = keccak256(abi.encodePacked( + "\x19Ethereum Signed Message:\n32", + orderHash + )); + +ETHSIGN (``3``) +^^^^^^^^^^^^^^^ + +This is the signature type typically used when an order is signed in a +headless environment (e.g., script or backend). This commonly achieved +by calling the ``eth_sign`` JSONRPC command on the Ethereum provider or, +perhaps more straight-forwardly, using a standard ``ecsign()`` +implementation +(`example `__). +Unlike the ``EIP712`` signature type, the hash to sign is simply the +`canonical order hash `__ (no prefix). + +PRESIGNED (``4``) +^^^^^^^^^^^^^^^^^ + +This signature type is used exclusively with NFT orders (721 and 1155) +for now. This value indicates that the order maker has previously marked +the order as fillable on-chain. The remaining fields in the +``Signature`` struct will be ignored. \ No newline at end of file diff --git a/docs/guides/nft_guide.rst b/docs/guides/nft_guide.rst new file mode 100644 index 0000000000..d6299bafe8 --- /dev/null +++ b/docs/guides/nft_guide.rst @@ -0,0 +1,454 @@ +############################### +NFT Guides - Creating Orders +############################### + +The easiest way of creating a 0x NFT order is to use the npm packages `@0x/protocol-utils` and `@0x/utils` + +>>> yarn add @0x/protocol-utils @0x/utils +or +npm install @0x/protocol-utils @0x/utils + + +Create an ERC721Order +===================== + +The following code snippet shows how to construct a basic ERC721 sell order in JavaScript. In the following example, the seller indicates that they would like to receive ether by providing the sentinel value `0xeee...`` as the `erc20Token`. + +.. code-block:: javascript + const { ERC721Order, NFTOrder } = require("@0x/protocol-utils"); + const utils = require("@0x/utils"); + + // Construct sell order + const sellOrder = new ERC721Order({ + // The EVM blockchain that this order is for, in this case Ethereum mainnet. + chainId: 1, + // The address of the 0x v4 ExchangeProxy contract on Ethereum. + verifyingContract: '0xdef1c0ded9bec7f1a1670819833240f027b25eff', + // Whether to sell or buy the given NFT + direction: NFTOrder.TradeDirection.SellNFT, + // This indicates that the seller would like to receive ETH. + erc20Token: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + // The price, in this case 1 ETH. + erc20TokenAmount: utils.BigNumber('1e18'), + // Address of the ERC721 contract. + erc721Token: '0x5180db8f5c931aae63c74266b211f580155ecac8', + // Token ID of the NFT to sell. + erc721TokenId: 123, + // Address of the seller. This is also the address that will be + // signing this order. + maker: '0x6cc5f688a315f3dc28a7781717a9a798a59fda7b', + // A null taker address allows anyone to fill this order + taker: '0x0000000000000000000000000000000000000000', + // A unique order nonce + nonce: 420, + // Order expires in one hour + expiry: new utils.BigNumber(Math.floor(Date.now() / 1000 + 3600)), + }); + +An ERC721 sell order can be created similarly. Note that buy orders must use WETH instead of ether, because the ERC20 `transferFrom` functionality is needed to execute a buy order. + +.. code-block:: javascript + const { ERC721Order, NFTOrder } = require("@0x/protocol-utils"); + const utils = require("@0x/utils"); + + // Construct buy order + const buyOrder = new ERC721Order({ + // The EVM blockchain that this order is for, in this case Ethereum mainnet. + chainId: 1, + // The address of the 0x v4 ExchangeProxy contract on Ethereum. + verifyingContract: '0xdef1c0ded9bec7f1a1670819833240f027b25eff', + // Whether to sell or buy the given NFT + direction: NFTOrder.TradeDirection.BuyNFT, + // Address of the ERC20 token to buy with, in this case WETH. + erc20Token: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + // The price, in this case 1 WETH. + erc20TokenAmount: utils.BigNumber('1e18'), + // Address of the ERC721 contract. + erc721Token: '0x5180db8f5c931aae63c74266b211f580155ecac8', + // Token ID of the NFT to buy. + erc721TokenId: 234, + // Address of the buyer. This is also the address that will be + // signing this order. + maker: '0x6cc5f688a315f3dc28a7781717a9a798a59fda7b', + // A null taker address allows anyone to fill this order + taker: '0x0000000000000000000000000000000000000000', + // A unique order nonce + nonce: 421, + // Order expires in one hour + expiry: new utils.BigNumber(Math.floor(Date.now() / 1000 + 3600)), + }); + +**Choosing a nonce** + +If two orders signed by the same maker have the same nonce, filling or cancelling one can result in the other becoming unfillable. + +:: + + Two ERC721 orders with the same nonce cannot both be filled, but two ERC1155 orders with the same nonce can both be filled (as long as the orders are not identical). + +You can use a pseudorandom value or the current timestamp as the order nonce, but nonces can be chosen in a specific way to enable more gas-efficient fills and cancellations. See `Smart Nonces <./smart_nonce.rst>`_ for explanation. + +We recommend using the most significant 128 bits of the nonce as an application/marketplace identifier. The least significant 128 bits of the nonce can be incremented from 0 for each order created by a particular maker. + +**Royalties and Fees** + +0x V4 has flexible support for creator royalties and platform fees. Marketplaces can pay out royalties to creators in real-time, and even have the option to send fees to their own custom fee disbursement contract. +Fees are paid by the **buyer**, denominated in the asset paid by the buyer, and are paid **in addition** to the `erc20TokenAmount` specified in the order. +The following code snippet shows how to create an ERC721 order with a single fee. Multiple fees can be specified by providing multiple fee objects in the order fees field. + +.. code-block:: javascript + const { ERC721Order, NFTOrder } = require("@0x/protocol-utils"); + const utils = require("@0x/utils"); + + const fee = { + // Address to receive the fee. Can be a smart contract. + recipient: '0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c', + amount: utils.BigNumber('1e17'), // 0.1 ETH + // If the fee recipient is a contract, this field can be used + // to invoke a callback. In this case, there is no callback. + feeData: '0x', + }; + + // Construct sell order + const order = new ERC721Order({ + chainId: 1, + verifyingContract: '0xdef1c0ded9bec7f1a1670819833240f027b25eff', + direction: NFTOrder.TradeDirection.SellNFT, + erc20Token: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + erc20TokenAmount: utils.BigNumber('1e18'), + erc721Token: '0x5180db8f5c931aae63c74266b211f580155ecac8', + erc721TokenId: 123, + maker: '0x6cc5f688a315f3dc28a7781717a9a798a59fda7b', + taker: '0x0000000000000000000000000000000000000000', + fees: [fee], + nonce: 420, + expiry: new utils.BigNumber(Math.floor(Date.now() / 1000 + 3600)), + }); + +**Collection Offers** + +In 0x V4, it is possible to create a bid for any NFT in a particular collection. The following code snippet shows how to create an order to buy any CryptoCoven $WITCH. + +.. code-block:: javascript + const { ERC721Order, NFTOrder } = require("@0x/protocol-utils"); + const utils = require("@0x/utils"); + + const property = { + // Providing `address(0)` and `0x` serves as the sentinel + // values for a "null property", i.e. any token ID from the + // given collection can be used to fill the order. + propertyValidator: '0x0000000000000000000000000000000000000000', + propertyData: '0x', + }; + + // Construct sell order + const order = new ERC721Order({ + chainId: 1, + verifyingContract: '0xdef1c0ded9bec7f1a1670819833240f027b25eff', + direction: NFTOrder.TradeDirection.SellNFT, + erc20Token: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + erc20TokenAmount: utils.BigNumber('1e18'), + erc721Token: '0x5180db8f5c931aae63c74266b211f580155ecac8', + // If one or more properties are specified in the order, the + // `erc721TokenId` must be 0. + erc721TokenId: 0, + maker: '0x6cc5f688a315f3dc28a7781717a9a798a59fda7b', + taker: '0x0000000000000000000000000000000000000000', + erc721TokenProperties: [property], + nonce: 420, + expiry: new utils.BigNumber(Math.floor(Date.now() / 1000 + 3600)), + } + +Sign an ERC721 Order +==================== + +Off-chain orders must be signed by the order maker to be filled. For on-chain orders, refer to the next section. + +**Signing with a private key** + +Signing an order with a private key is easy: the `ERC721Order` and `ERC1155Order` classes from `@0x/protocol-utils` expose a `getSignatureWithKey` function that take a 0x-prefixed private key string. + +.. code-block:: javascript + const { ERC721Order, NFTOrder, SignatureType } = require("@0x/protocol-utils"); + const utils = require("@0x/utils"); + + // Construct order + const order = new ERC721Order({ + chainId: 1, + verifyingContract: '0xdef1c0ded9bec7f1a1670819833240f027b25eff', + direction: NFTOrder.TradeDirection.SellNFT, + erc20Token: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + erc20TokenAmount: utils.BigNumber('1e18'), + erc721Token: '0x5180db8f5c931aae63c74266b211f580155ecac8', + erc721TokenId: 123, + maker: '0x6cc5f688a315f3dc28a7781717a9a798a59fda7b', + taker: '0x0000000000000000000000000000000000000000', + nonce: 420, + expiry: new utils.BigNumber(Math.floor(Date.now() / 1000 + 3600)), + }); + + // Sign order with private key + const signature = await order.getSignatureWithKey( + PRIVATE_KEY, // '0x123456789...' + SignatureType.EIP712 + ); + +**Signing with ethers** + +.. code-block:: javascript + const { ERC721Order, NFTOrder, SignatureType } = require("@0x/protocol-utils"); + const utils = require("@0x/utils"); + const { ethers } = require("ethers"); + + // Construct order + const order = new ERC721Order({ + chainId: 1, + verifyingContract: '0xdef1c0ded9bec7f1a1670819833240f027b25eff', + direction: NFTOrder.TradeDirection.SellNFT, + erc20Token: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + erc20TokenAmount: utils.BigNumber('1e18'), + erc721Token: '0x5180db8f5c931aae63c74266b211f580155ecac8', + erc721TokenId: 123, + maker: '0x6cc5f688a315f3dc28a7781717a9a798a59fda7b', + taker: '0x0000000000000000000000000000000000000000', + nonce: 420, + expiry: new utils.BigNumber(Math.floor(Date.now() / 1000 + 3600)), + }); + + // Get ethers Signer + const provider = new ethers.providers.JsonRpcProvider(/* constructor params */); + const signer = provider.getSigner(/* address */); + + const { domain, message } = order.getEIP712TypedData(); + const types = { + [ERC721Order.STRUCT_NAME]: ERC721Order.STRUCT_ABI, + ['Fee']: NFTOrder.FEE_ABI, + ['Property']: NFTOrder.PROPERTY_ABI, + }; + const rawSignature = await signer._signTypedData( + domain, + types, + message + ); + const { v, r, s } = ethers.utils.splitSignature(rawSignature); + const signature = { + v, + r, + s, + signatureType: 2 + }; + +**On-chain Orders** + +Orders can be simultaneously "signed" and listed on-chain using the `preSignERC721Order` or `preSignERC1155Order` functions. Orders can only be signed by the maker address specified in the order. + +.. code-block:: solidity + /// @dev Approves an ERC721 order on-chain. After pre-signing + /// the order, the `PRESIGNED` signature type will become + /// valid for that order and signer. + /// @param order An ERC721 order. + function preSignERC721Order(LibNFTOrder.ERC721Order calldata order) + external; + + /// @dev Approves an ERC1155 order on-chain. After pre-signing + /// the order, the `PRESIGNED` signature type will become + /// valid for that order and signer. + /// @param order An ERC1155 order. + function preSignERC1155Order(LibNFTOrder.ERC1155Order calldata order) + external; + +If an order has been pre-signed, it can be filled by providing a “null” signature with the PRESIGNED signature type (see `LibSignature.sol `_): + +.. code-block:: solidity + LibSignature.Signature({ + signatureType: LibSignature.SignatureType.PRESIGNED, + v: uint8(0), + r: bytes32(0), + s: bytes32(0) + }); + +The pre-sign functions emit the entire order as an event, so that the order is easily indexable by subgraphs and thus easily indexable by subgraphs and thus easily discoverable without the need for an off-chain database. + +.. code-block:: solidity + /// @dev Emitted when an `ERC721Order` is pre-signed. + /// Contains all the fields of the order. + event ERC721OrderPreSigned( + LibNFTOrder.TradeDirection direction, + address maker, + address taker, + uint256 expiry, + uint256 nonce, + IERC20TokenV06 erc20Token, + uint256 erc20TokenAmount, + LibNFTOrder.Fee[] fees, + IERC721Token erc721Token, + uint256 erc721TokenId, + LibNFTOrder.Property[] erc721TokenProperties + ); + + /// @dev Emitted when an `ERC1155Order` is pre-signed. + /// Contains all the fields of the order. + event ERC1155OrderPreSigned( + LibNFTOrder.TradeDirection direction, + address maker, + address taker, + uint256 expiry, + uint256 nonce, + IERC20TokenV06 erc20Token, + uint256 erc20TokenAmount, + LibNFTOrder.Fee[] fees, + IERC1155Token erc1155Token, + uint256 erc1155TokenId, + LibNFTOrder.Property[] erc1155TokenProperties, + uint128 erc1155TokenAmount + ); + +The pre-sign functions also enable smart contracts to create and "sign" NFT orders, opening the door for potential integrations with e.g. multisig wallets. + +Filling an ERC721 Order +======================= + +The basic functions used for filling NFT orders are the following: + +.. code-block:: solidity + /// @dev Sells an ERC721 asset to fill the given order. + /// @param buyOrder The ERC721 buy order. + /// @param signature The order signature from the maker. + /// @param erc721TokenId The ID of the ERC721 asset being + /// sold. If the given order specifies properties, + /// the asset must satisfy those properties. Otherwise, + /// it must equal the tokenId in the order. + /// @param unwrapNativeToken If this parameter is true and the + /// ERC20 token of the order is e.g. WETH, unwraps the + /// token before transferring it to the taker. + /// @param callbackData If this parameter is non-zero, invokes + /// `zeroExERC721OrderCallback` on `msg.sender` after + /// the ERC20 tokens have been transferred to `msg.sender` + /// but before transferring the ERC721 asset to the buyer. + function sellERC721( + LibNFTOrder.ERC721Order calldata buyOrder, + LibSignature.Signature calldata signature, + uint256 erc721TokenId, + bool unwrapNativeToken, + bytes calldata callbackData + ) + external; + + /// @dev Buys an ERC721 asset by filling the given order. + /// @param sellOrder The ERC721 sell order. + /// @param signature The order signature. + /// @param callbackData If this parameter is non-zero, invokes + /// `zeroExERC721OrderCallback` on `msg.sender` after + /// the ERC721 asset has been transferred to `msg.sender` + /// but before transferring the ERC20 tokens to the seller. + /// Native tokens acquired during the callback can be used + /// to fill the order. + function buyERC721( + LibNFTOrder.ERC721Order calldata sellOrder, + LibSignature.Signature calldata signature, + bytes calldata callbackData + ) + external + payable; + + /// @dev Sells an ERC1155 asset to fill the given order. + /// @param buyOrder The ERC1155 buy order. + /// @param signature The order signature from the maker. + /// @param erc1155TokenId The ID of the ERC1155 asset being + /// sold. If the given order specifies properties, + /// the asset must satisfy those properties. Otherwise, + /// it must equal the tokenId in the order. + /// @param erc1155SellAmount The amount of the ERC1155 asset + /// to sell. + /// @param unwrapNativeToken If this parameter is true and the + /// ERC20 token of the order is e.g. WETH, unwraps the + /// token before transferring it to the taker. + /// @param callbackData If this parameter is non-zero, invokes + /// `zeroExERC1155OrderCallback` on `msg.sender` after + /// the ERC20 tokens have been transferred to `msg.sender` + /// but before transferring the ERC1155 asset to the buyer. + function sellERC1155( + LibNFTOrder.ERC1155Order calldata buyOrder, + LibSignature.Signature calldata signature, + uint256 erc1155TokenId, + uint128 erc1155SellAmount, + bool unwrapNativeToken, + bytes calldata callbackData + ) + external; + + /// @dev Buys an ERC1155 asset by filling the given order. + /// @param sellOrder The ERC1155 sell order. + /// @param signature The order signature. + /// @param erc1155BuyAmount The amount of the ERC1155 asset + /// to buy. + /// @param callbackData If this parameter is non-zero, invokes + /// `zeroExERC1155OrderCallback` on `msg.sender` after + /// the ERC1155 asset has been transferred to `msg.sender` + /// but before transferring the ERC20 tokens to the seller. + /// Native tokens acquired during the callback can be used + /// to fill the order. + function buyERC1155( + LibNFTOrder.ERC1155Order calldata sellOrder, + LibSignature.Signature calldata signature, + uint128 erc1155BuyAmount, + bytes calldata callbackData + ) + external + payable; + +`sellERC721` and `sellERC1155` are used when the caller is **selling** an NFT, so the order being filled is a **buy** order. +`buyERC721` and `buyERC1155` are used when the caller is **buying** an NFT, so the order being filled is a **sell** order. +Note that the only difference in parameters between the ERC721 and ERC1155 functions is `erc1155BuyAmount`. This value specifies the amount of the ERC1155 asset to sell/buy from the given order, which may be greater than one in the case of semi-fungible ERC1155 assets. + +Cancelling an ERC721 Order +========================== + +All orders, whether off-chain or on-chain, can only be cancelled on-chain. The following contract functions are used to cancel individual ERC721 and ERC1155 orders. + +.. code-block:: solidity + /// @dev Cancel a single ERC721 order by its nonce. The caller + /// should be the maker of the order. Silently succeeds if + /// an order with the same nonce has already been filled or + /// cancelled. + /// @param orderNonce The order nonce. + function cancelERC721Order(uint256 orderNonce) + external; + + /// @dev Cancel a single ERC1155 order by its nonce. The caller + /// should be the maker of the order. Silently succeeds if + /// an order with the same nonce has already been filled or + /// cancelled. + /// @param orderNonce The order nonce. + function cancelERC1155Order(uint256 orderNonce) + external; + +Note that if there are multiple outstanding orders with the same nonce, calling `cancelERC721Order` or `cancelERC1155Order` would cancel all those orders. +The following functions can be used to cancel multiple orders. + +.. code-block:: solidity + /// @dev Cancel multiple ERC721 orders by their nonces. The caller + /// should be the maker of the orders. Silently succeeds if + /// an order with the same nonce has already been filled or + /// cancelled. + /// @param orderNonces The order nonces. + function batchCancelERC721Orders(uint256[] calldata orderNonces) + external; + + /// @dev Cancel multiple ERC1155 orders by their nonces. The caller + /// should be the maker of the orders. Silently succeeds if + /// an order with the same nonce has already been filled or + /// cancelled. + /// @param orderNonces The order nonces. + function batchCancelERC1155Orders(uint256[] calldata orderNonces) + external; + +Fetching NFT Order Data +======================= + +To fetch collection-level NFT stats from 0x orders (e.g. floor price, total volume), checkout the following tools: + +- `https://module.readme.io/reference/retrieve-collection-floor `_ +- `https://api.reservoir.tools/#/2.%20Aggregator/getEventsCollectionsFlooraskV1 `_ + +These tools are not 0x specific but NFT data is somewhat universal so these tools should do the trick. \ No newline at end of file diff --git a/docs/guides/smart_nonce.rst b/docs/guides/smart_nonce.rst new file mode 100644 index 0000000000..a3415a7447 --- /dev/null +++ b/docs/guides/smart_nonce.rst @@ -0,0 +1,17 @@ +############ +Smart Nonces +############ + +The `nonce` field in the order is a number the maker chooses to ensure uniqueness of the order, but it also has some other functions: +- To identify the order (in addition to the caller/maker) in cancellation functions. +- To identify the order when checking/updating its filled state. +- To potentially reuse EVM storage slots that mark an order as filled, which can provide significant gas savings (~15k) when filling or cancelling the order. + +**Gas Optimized Nonces** + +The protocol marks ERC721 orders as filled when they either get cancelled or filled. Instead of always using a completely new storage slot for each order from a maker, the upper 248 bits of the nonce will identify the storage slot/bucket/status vector to be used and the lower 8 bits of the nonce will identify the bit offset in that slot (each slot is also 256 bits) which will be flipped from 0 to 1 when the order is cancelled or filled. + +.. image:: ./_static/img/smart_nonce_diagram.webp + :width: 600 + +To take advantage of this gas optimization, makers should reuse the upper 248 bits of their nonce across up to 256 different orders, varying the value of the lower 8 bits between them. \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index 60042444f7..f887d19676 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,17 +1,39 @@ 0x Protocol =========== -0x is an open protocol that facilitates trustless, low friction exchange of Ethereum-based assets. -Learn more about 0x Labs at `0x.org `_. Check out our code on `GitHub `_. -Connect with the community on our `Forum `_ and `Reddit `_. -Chat with our team privately on `Discord `_ or publicly on `Twitter `_. +0x Protocol is the trusted open source settlement layer for the permiossionless global exchange of value. +This documentation is aimed to serve as the canonical technical documentation for 0x Protocol and the system of smart contracts that make up its full functionality. The structure of this documentation is as follows: +- Architectural Overview of the whole system of smart contracts that 0x Protocol is comprised of. + - Subsections will provide a deep dive into each contracts +- Tutorial and tools to get started building with/on top of 0x Protocol -.. image:: ./_static/img/logo.svg +To learn more about why 0x Protocol was created, read the whitepaper `here `_ and at `0xProtocol.org `_. + +All code is open sourced on `GitHub `_. + +Connect with the community on our `Forum `_, `Discord `_, `Reddit `_, and `Twitter `_. + + +.. image:: ./_static/img/logo.png :width: 20% :alt: 0x Protocol logo :align: center +.. toctree:: + :maxdepth: 2 + :caption: Architecture + + architecture/overview.rst + architecture/proxy.rst + architecture/features.rst + architecture/transformers.rst + architecture/flash_wallet.rst + architecture/governor.rst + architecture/transformer_deployer.rst + architecture/fee_collectors.rst + architecture/plp_sandbox.rst + .. toctree:: :maxdepth: 2 :caption: Basics @@ -34,27 +56,10 @@ Chat with our team privately on `Discord `_ .. toctree:: :maxdepth: 2 - :caption: Architecture - - architecture/overview.rst - architecture/proxy.rst - architecture/features.rst - architecture/transformers.rst - architecture/flash_wallet.rst - architecture/governor.rst - architecture/transformer_deployer.rst - architecture/fee_collectors.rst - architecture/plp_sandbox.rst - - -.. toctree:: - :maxdepth: 2 - :caption: ZRX Tokenomics + :caption: Guide - tokenomics/research.rst - tokenomics/staking.md - tokenomics/staking_reward_formula.rst - tokenomics/governance.rst + guides/nft_guide.rst + guides/smart_nonce.rst .. toctree:: :maxdepth: 2 @@ -71,9 +76,9 @@ Chat with our team privately on `Discord `_ :maxdepth: 1 :caption: Connect - 0x Labs + 0x Protocol GitHub - Forum + Forum Reddit - Discord + Discord Twitter \ No newline at end of file diff --git a/docs/tokenomics/governance.rst b/docs/tokenomics/governance.rst deleted file mode 100644 index 0ac6c79fbc..0000000000 --- a/docs/tokenomics/governance.rst +++ /dev/null @@ -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 `_. Anyone can propose a change to the system by creating a ZEIP. Visit `https://0x.org/zrx/vote `_ to participate! \ No newline at end of file diff --git a/docs/tokenomics/research.rst b/docs/tokenomics/research.rst deleted file mode 100644 index db11b2a9f7..0000000000 --- a/docs/tokenomics/research.rst +++ /dev/null @@ -1,9 +0,0 @@ -############################### -Research -############################### - -.. raw:: html - - -