# 0x Mesh Docs ## DEPRECATED: Mesh Docs have [moved to Github](https://github.com/0xProject/0x-mesh/blob/master/DOCUMENTATION.md) Welcome to the [0x Mesh](https://github.com/0xProject/0x-mesh) documentation! 0x Mesh is a peer-to-peer network for sharing orders that adhere to the [0x order message format](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format). Some resources: - [Announcement blog post](https://blog.0xproject.com/0x-roadmap-2019-part-3-networked-liquidity-0x-mesh-9a24026202b3) - [MVP architecture doc](https://drive.google.com/file/d/1dAVTEND7e1sISO9VZSOou0DN-igoUi9z/view) - [Github repo](https://github.com/0xProject/0x-mesh/) ### Supported networks - Mainnet - Kovan - Ropsten - Rinkeby - [Ganache snapshot](https://cloud.docker.com/u/0xorg/repository/docker/0xorg/mesh-ganache-cli) ## Running Mesh Make sure you have Docker installed. Then run: ```bash docker run \ -it \ --rm \ -p 60557:60557 \ -p 60558:60558 \ -e ETHEREUM_NETWORK_ID="1" \ -e ETHEREUM_RPC_URL="https://mainnet.infura.io/v3/a9a23d2566e542629179d6372ace13c9" \ -e VERBOSITY=5 \ -e PRIVATE_KEY_PATH="" \ -e USE_BOOTSTRAP_LIST=false -e BLOCK_POLLING_INTERVAL="5s" 0xorg/mesh:latest ``` **Notes:** - `60557` is the `RPC_PORT` and `60558` is the `P2P_LISTEN_PORT` - In order to enable P2P order discovery and sharing, set `USE_BOOTSTRAP_LIST` to `true`. - Running a VPN may interfere with Mesh. If you are having difficulty connecting to peers, disable your VPN. - If you are running against a POA testnet (e.g., Kovan), you might want to shorten the `BLOCK_POLLING_INTERVAL` since blocks are mined more frequently then on mainnet. ### Persisting State If you want the Mesh state to persist across Docker container re-starts, mount a local `0x_mesh` directory to your container. Add the following to the `docker run` command above: ``` -v {abs_local_path}/0x_mesh:/usr/mesh/0x_mesh ``` **Note:** Replace `{abs_local_path}` with the absolute path to the desired `0x_mesh` directory on the host machine. The Mesh database will now be stored within `0x_mesh/db`. ## Possible environment variables All possible env vars are detailed in the [Config](https://godoc.org/github.com/0xProject/0x-mesh/core#Config) struct. They are copied here for convenience, although the source code is authoritative. ```go type Config struct { // Verbosity is the logging verbosity: 0=panic, 1=fatal, 2=error, 3=warn, 4=info, 5=debug 6=trace Verbosity int `envvar:"VERBOSITY" default:"2"` // DatabaseDir is the directory to use for persisting the database. DatabaseDir string `envvar:"DATABASE_DIR" default:"./0x_mesh/db"` // P2PListenPort is the port on which to listen for new peer connections. By // default, 0x Mesh will let the OS select a randomly available port. P2PListenPort int `envvar:"P2P_LISTEN_PORT" default:"0"` // EthereumRPCURL is the URL of an Etheruem node which supports the JSON RPC // API. EthereumRPCURL string `envvar:"ETHEREUM_RPC_URL"` // EthereumNetworkID is the network ID to use when communicating with // Ethereum. EthereumNetworkID int `envvar:"ETHEREUM_NETWORK_ID"` // UseBootstrapList is whether to use the predetermined list of peers to // bootstrap the DHT and peer discovery. UseBootstrapList bool `envvar:"USE_BOOTSTRAP_LIST" default:"false"` // PrivateKeyPath is the path to a Secp256k1 private key which will be // used for signing messages and generating a peer ID. If empty, a randomly // generated key will be used. PrivateKeyPath string `envvar:"PRIVATE_KEY_PATH" default:"./0x_mesh/key/privkey"` // OrderExpirationBuffer is the amount of time before the order's stipulated expiration time // that you'd want it pruned from the Mesh node. OrderExpirationBuffer time.Duration `envvar:"ORDER_EXPIRATION_BUFFER" default:"10s"` // BlockPollingInterval is the polling interval to wait before checking for a new Ethereum block // that might contain transactions that impact the fillability of orders stored by Mesh. Different // networks have different block producing intervals: POW networks are typically slower (e.g., Mainnet) // and POA networks faster (e.g., Kovan) so one should adjust the polling interval accordingly. BlockPollingInterval time.Duration `envvar:"BLOCK_POLLING_INTERVAL" default:"5s"` } ``` ## JSON-RPC API Our JSON-RPC API is very similar to the [Ethereum JSON-RPC API](https://github.com/ethereum/wiki/wiki/JSON-RPC), we even use a bunch of `go-ethereum`'s code to generate it. #### Some differences: - It is **only accessible via a WebSocket connection** - uint256 amounts should not be hex encoded, but rather sent as numerical strings Since the API adheres to the [JSON-RPC 2.0 spec](https://www.jsonrpc.org/specification), you can use any JSON-RPC 2.0 compliant client in the language of your choice. The clients made for Ethereum work even better since they extend the standard to include [subscriptions](https://github.com/ethereum/go-ethereum/wiki/RPC-PUB-SUB). #### Recommended clients: - Javascript/Typescript: [Web3-providers](https://www.npmjs.com/package/web3-providers) - See our [example Mesh WS client](https://github.com/0xProject/0x-mesh-demo-client-javascript) built with it - Python: [Web3.py](https://github.com/ethereum/web3.py) has a [WebSocketProvider](https://web3py.readthedocs.io/en/stable/providers.html#web3.providers.websocket.WebsocketProvider) you can use - Go: Mesh ships with a [Mesh RPC client](https://godoc.org/github.com/0xProject/0x-mesh/rpc#Client) - see the [demos](https://github.com/0xProject/0x-mesh/tree/master/cmd/demo) for example usage ### Methods ### `mesh_addOrders` Adds an array of 0x signed orders to the Mesh node. **Example payload:** ```json { "jsonrpc": "2.0", "method": "mesh_addOrders", "params": [ [ { "makerAddress": "0x6440b8c5f5a3c725eb394c7c40994afaf50a0d39", "takerAddress": "0x0000000000000000000000000000000000000000", "feeRecipientAddress": "0xa258b39954cef5cb142fd567a46cddb31a670124", "senderAddress": "0x0000000000000000000000000000000000000000", "makerAssetAmount": "1233400000000000", "takerAssetAmount": "12334000000000000000000", "makerFee": "0", "takerFee": "0", "exchangeAddress": "0x4f833a24e1f95d70f028921e27040ca56e09ab0b", "expirationTimeSeconds": "1560917245", "signature": "0x1b6a49302774b0b0e14ef59e91fcf950dfb7db5705ae6929e06198518b1105301d4ef94b1b4760e550378bb5b7746b1a29c174290afe9448324cef4112dd03d7a103", "salt": "1545196045897", "makerAssetData": "0xf47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "takerAssetData": "0xf47261b00000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef" } ] ], "id": 1 } ``` **Example response:** ```json { "jsonrpc": "2.0", "id": 2, "result": { "accepted": [ { "orderHash": "0x4e7269386c8f2234305aafb421ba470f39064d79c4826006eaffe723b2066272", "signedOrder": { "makerAddress": "0x8cff49b26d4d13e0601769f8a60fd697b713b9c6", "makerAssetData": "0xf47261b0000000000000000000000000c778417e063141139fce010982780140aa0cd5ab", "makerAssetAmount": "100000000000000000", "makerFee": "0", "takerAddress": "0x0000000000000000000000000000000000000000", "takerAssetData": "0xf47261b0000000000000000000000000ff67881f8d12f372d91baae9752eb3631ff0ed00", "takerAssetAmount": "1000000000000000000", "takerFee": "0", "senderAddress": "0x0000000000000000000000000000000000000000", "exchangeAddress": "0x4530c0483a1633c7a1c97d2c53721caff2caaaaf", "feeRecipientAddress": "0x0000000000000000000000000000000000000000", "expirationTimeSeconds": "1559826927", "salt": "48128453606684653105952683301312821720867493716494911784363103883716429240740", "signature": "0x1cf5839d9a0025e684c3663151b1db14533cc8c9e495fb92543a37a7fffc0677a23f3b6d66a1f56d3fda46eb5277b4a91c7b7faad4fdaaa5aac9a1185dd545a8a002" }, "fillableTakerAssetAmount": 1000000000000000000 } ], "rejected": [] } } ``` Within the context of this endpoint: - _accepted_: means the order was found to be fillable for a non-zero amount and was therefore added to 0x Mesh (unless it already added of course) - _rejected_: means the order was not added to Mesh, however there could be many reasons for this. For example: - The order could have been unfillable - It could have failed some Mesh-specific validation (e.g., max order acceptable size in bytes) - The network request to the Ethereum RPC endpoint used to validate the order failed Some _rejected_ reasons warrant attempting to add the order again. Currently, the only reason we recommend re-trying adding the order is for the `NetworkRequestFailed` status code. Make sure to leave some time between attempts. See the [AcceptedOrderInfo](https://godoc.org/github.com/0xProject/0x-mesh/zeroex#AcceptedOrderInfo) and [RejectedOrderInfo](https://godoc.org/github.com/0xProject/0x-mesh/zeroex#RejectedOrderInfo) type definitions as well as all the possible [RejectedOrderStatus](https://godoc.org/github.com/0xProject/0x-mesh/zeroex#pkg-variables) types that could be returned. **Note:** The `fillableTakerAssetAmount` takes into account the amount of the order that has already been filled AND the maker's balance/allowance. Thus, it represents the amount this order could _actually_ be filled for at this moment in time. ### `mesh_subscribe` to `orders` topic Mesh has implemented subscriptions in the [same manner as Geth](https://github.com/ethereum/go-ethereum/wiki/RPC-PUB-SUB). In order to start a subscription, you must send the following payload: ```json { "jsonrpc":"2.0", "method":"mesh_subscribe", "params":["orders"], "id":1 } ``` **Example response:** ```json { "jsonrpc":"2.0", "result": "0xcd0c3e8af590364c09d0fa6a1210faf5", "id":1 } ``` `result` contains the `subscriptionId` that uniquely identifies this subscription. The subscription is now active. You will now receive event payloads from Mesh of the following form: **Example event:** ```json { "jsonrpc": "2.0", "method": "mesh_subscription", "params": { "subscription": "0xcd0c3e8af590364c09d0fa6a1210faf5", "result": [ { "orderHash": "0x96e6eb6174dbf0458686bdae44c9a330d9a9eb563962512a7be545c4ecc13fd4", "signedOrder": { "makerAddress": "0x50f84bbee6fb250d6f49e854fa280445369d64d9", "makerAssetData": "0xf47261b00000000000000000000000000f5d2fb29fb7d3cfee444a200298f468908cc942", "makerAssetAmount": "4424020538752105500000", "makerFee": "0", "takerAddress": "0x0000000000000000000000000000000000000000", "takerAssetData": "0xf47261b0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "takerAssetAmount": "1000000000000000061", "takerFee": "0", "senderAddress": "0x0000000000000000000000000000000000000000", "exchangeAddress": "0x4f833a24e1f95d70f028921e27040ca56e09ab0b", "feeRecipientAddress": "0xa258b39954cef5cb142fd567a46cddb31a670124", "expirationTimeSeconds": "1559422407", "salt": "1559422141994", "signature": "0x1cf16c2f3a210965b5e17f51b57b869ba4ddda33df92b0017b4d8da9dacd3152b122a73844eaf50ccde29a42950239ba36a525ed7f1698a8a5e1896cf7d651aed203" }, "kind": "CANCELLED", "fillableTakerAssetAmount": 0, "txHash": "0x9e6830a7044b39e107f410e4f765995fd0d3d69d5c3b3582a1701b9d68167560" } ] } } ``` See the [OrderEvent](https://godoc.org/github.com/0xProject/0x-mesh/zeroex#OrderEvent) type declaration as well as the [OrderEventKind](https://godoc.org/github.com/0xProject/0x-mesh/zeroex#pkg-constants) event types for a complete list of the events that could be emitted. To unsubscribe, send a `mesh_unsubscribe` request specifying the `subscriptionId`. **Example unsubscription payload:** ```json { "id": 1, "method": "mesh_unsubscribe", "params": ["0xcd0c3e8af590364c09d0fa6a1210faf5"] } ``` ### `mesh_subscribe` to `heartbeat` topic After a sustained network disruption, it is possible that a WebSocket connection between client and server fails to reconnect. Both sides of the connection are unable to distinguish between network latency and a dropped connection and might continue to wait for new messages on the dropped connection. In order to avoid this, and promptly establish a new connection, clients can subscribe to a heartbeat from the server. The server will emit a heartbeat every 5 seconds. If the client hasn't received the expected heartbeat in a while, it can proactively close the connection and establish a new one. There are affordances for checking this edge-case in the [WebSocket specification](https://tools.ietf.org/html/rfc6455#section-5.5.2) however our research has found that [many WebSocket clients](https://github.com/0xProject/0x-mesh/issues/170#issuecomment-503391627) fail to provide this functionality. We therefore decided to support it at the application-level. ```json { "jsonrpc":"2.0", "method":"mesh_subscribe", "params":["heartbeat"], "id":1 } ``` **Example response:** ```json { "jsonrpc":"2.0", "result": "0xab1a3e8af590364c09d0fa6a12103ada", "id":1 } ``` `result` contains the `subscriptionId` that uniquely identifies this subscription. The subscription is now active. You will now receive event payloads from Mesh of the following form: **Example event:** ```json { "jsonrpc": "2.0", "method": "mesh_subscription", "params": { "subscription": "0xab1a3e8af590364c09d0fa6a12103ada", "result": "tick" } } ``` To unsubscribe, send a `mesh_unsubscribe` request specifying the `subscriptionId`. **Example unsubscription payload:** ```json { "id": 1, "method": "mesh_unsubscribe", "params": ["0xab1a3e8af590364c09d0fa6a12103ada"] } ```