Improve Docs for Decentralized Exchange (#1357)

* Decentralized Exchange concept article

1st draft

* DEX: example trade diagram, offers rewording

* Offers: more rewriting/updates

* OfferCreate: Add error cases + other updates

* Known Amendments: fix tecEXPIRED, DepositPreauth

- tecEXPIRED was initially attached to the Checks amendment but got
  moved to DepositPreauth before either became released. The docs weren't
  previously updated to reflect this change
- A change to the snippets caused the DepositPreauth amendment reference
  link to get overwritten so the table links to the feature page rather than the
  amendment description. Special cases this one link.

* OfferCreate error cases: switch to table

* DEX/Offers: edits per review
This commit is contained in:
Rome Reginelli
2022-03-21 08:11:13 -07:00
committed by GitHub
parent 2945394335
commit 79b4e54a6a
7 changed files with 1391 additions and 61 deletions

View File

@@ -0,0 +1,685 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<diagram program="umlet" version="14.2">
<zoom_level>10</zoom_level>
<element>
<id>UMLClass</id>
<coordinates>
<x>140</x>
<y>110</y>
<w>220</w>
<h>120</h>
</coordinates>
<panel_attributes>Offer
--
Buy: 100 FOO.WayGate
Spend: 1000 XRP
-..
(Exchange rate:
10.0 XRP/FOO.WayGate)</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>610</x>
<y>120</y>
<w>210</w>
<h>30</h>
</coordinates>
<panel_attributes>1 XRP for 2 FOO</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>610</x>
<y>150</y>
<w>210</w>
<h>30</h>
</coordinates>
<panel_attributes>10 XRP for 15 FOO</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>610</x>
<y>210</y>
<w>210</w>
<h>30</h>
</coordinates>
<panel_attributes>20000 XRP for 1000 FOO</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>580</x>
<y>110</y>
<w>40</w>
<h>120</h>
</coordinates>
<panel_attributes>lt=..
</panel_attributes>
<additional_attributes>20.0;100.0;10.0;100.0;10.0;10.0;20.0;10.0</additional_attributes>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>610</x>
<y>180</y>
<w>210</w>
<h>30</h>
</coordinates>
<panel_attributes>20 XRP for 5 FOO</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>610</x>
<y>240</y>
<w>210</w>
<h>30</h>
</coordinates>
<panel_attributes>...</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>460</x>
<y>120</y>
<w>130</w>
<h>90</h>
</coordinates>
<panel_attributes>These Offers match because their exchange rates are equal or better.
style=wordwrap
halign=right</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>820</x>
<y>90</y>
<w>120</w>
<h>30</h>
</coordinates>
<panel_attributes>Exchange Rate</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>360</x>
<y>150</y>
<w>110</w>
<h>30</h>
</coordinates>
<panel_attributes>lt=-&gt;&gt;&gt;</panel_attributes>
<additional_attributes>10.0;10.0;90.0;10.0</additional_attributes>
</element>
<element>
<id>UMLActor</id>
<coordinates>
<x>40</x>
<y>110</y>
<w>60</w>
<h>110</h>
</coordinates>
<panel_attributes>Tran</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>70</x>
<y>130</y>
<w>80</w>
<h>30</h>
</coordinates>
<panel_attributes>lt=-&gt;&gt;&gt;</panel_attributes>
<additional_attributes>10.0;10.0;60.0;10.0</additional_attributes>
</element>
<element>
<id>UMLActor</id>
<coordinates>
<x>60</x>
<y>340</y>
<w>60</w>
<h>110</h>
</coordinates>
<panel_attributes>Tran</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>110</x>
<y>190</y>
<w>410</w>
<h>210</h>
</coordinates>
<panel_attributes>lt=-&gt;&gt;&gt;</panel_attributes>
<additional_attributes>390.0;10.0;10.0;190.0</additional_attributes>
</element>
<element>
<id>Text</id>
<coordinates>
<x>300</x>
<y>300</y>
<w>150</w>
<h>80</h>
</coordinates>
<panel_attributes>Tran receives a total of 22 FOO.WayGate from the other traders.
style=wordwrap</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>710</x>
<y>270</y>
<w>30</w>
<h>100</h>
</coordinates>
<panel_attributes>lt=-&gt;&gt;&gt;
</panel_attributes>
<additional_attributes>10.0;10.0;10.0;80.0</additional_attributes>
</element>
<element>
<id>Text</id>
<coordinates>
<x>210</x>
<y>500</y>
<w>200</w>
<h>90</h>
</coordinates>
<panel_attributes>The remainder of Tran's Offer is added to the opposite order book at its original exchange rate.
style=wordwrap</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>610</x>
<y>60</y>
<w>490</w>
<h>210</h>
</coordinates>
<panel_attributes>Order Book: XRP:FOO.WayGate
--
</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>680</x>
<y>90</y>
<w>80</w>
<h>30</h>
</coordinates>
<panel_attributes>Amount</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>990</x>
<y>90</y>
<w>70</w>
<h>30</h>
</coordinates>
<panel_attributes>Owner</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLActor</id>
<coordinates>
<x>1290</x>
<y>110</y>
<w>60</w>
<h>110</h>
</coordinates>
<panel_attributes>Brad</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLActor</id>
<coordinates>
<x>1350</x>
<y>60</y>
<w>60</w>
<h>110</h>
</coordinates>
<panel_attributes>Amy</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLActor</id>
<coordinates>
<x>1300</x>
<y>220</y>
<w>60</w>
<h>110</h>
</coordinates>
<panel_attributes>David</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>940</x>
<y>120</y>
<w>160</w>
<h>30</h>
</coordinates>
<panel_attributes>Amy</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>940</x>
<y>150</y>
<w>160</w>
<h>30</h>
</coordinates>
<panel_attributes>Brad</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>940</x>
<y>180</y>
<w>160</w>
<h>30</h>
</coordinates>
<panel_attributes>Omar</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>940</x>
<y>210</y>
<w>160</w>
<h>30</h>
</coordinates>
<panel_attributes>David</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLActor</id>
<coordinates>
<x>1360</x>
<y>170</y>
<w>60</w>
<h>110</h>
</coordinates>
<panel_attributes>Omar</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>940</x>
<y>240</y>
<w>160</w>
<h>30</h>
</coordinates>
<panel_attributes>...</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>820</x>
<y>240</y>
<w>120</w>
<h>30</h>
</coordinates>
<panel_attributes>≥20</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>820</x>
<y>210</y>
<w>120</w>
<h>30</h>
</coordinates>
<panel_attributes>20.0</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>820</x>
<y>180</y>
<w>120</w>
<h>30</h>
</coordinates>
<panel_attributes>4.0</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>820</x>
<y>150</y>
<w>120</w>
<h>30</h>
</coordinates>
<panel_attributes>0.667</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>820</x>
<y>120</y>
<w>120</w>
<h>30</h>
</coordinates>
<panel_attributes>0.5</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>1110</x>
<y>160</y>
<w>180</w>
<h>30</h>
</coordinates>
<panel_attributes>lt=-&gt;&gt;&gt;</panel_attributes>
<additional_attributes>10.0;10.0;160.0;10.0</additional_attributes>
</element>
<element>
<id>Text</id>
<coordinates>
<x>1120</x>
<y>180</y>
<w>180</w>
<h>90</h>
</coordinates>
<panel_attributes>The owners of the matching Offers receive a total of 31 XRP from Tran.
style=wordwrap</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>610</x>
<y>430</y>
<w>210</w>
<h>30</h>
</coordinates>
<panel_attributes>20000 XRP for 1000 FOO</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>610</x>
<y>460</y>
<w>210</w>
<h>30</h>
</coordinates>
<panel_attributes>...</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>820</x>
<y>400</y>
<w>120</w>
<h>30</h>
</coordinates>
<panel_attributes>Exchange Rate</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>610</x>
<y>370</y>
<w>490</w>
<h>120</h>
</coordinates>
<panel_attributes>Order Book: XRP:FOO.WayGate
--
</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>680</x>
<y>400</y>
<w>80</w>
<h>30</h>
</coordinates>
<panel_attributes>Amount</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>990</x>
<y>400</y>
<w>70</w>
<h>30</h>
</coordinates>
<panel_attributes>Owner</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>940</x>
<y>430</y>
<w>160</w>
<h>30</h>
</coordinates>
<panel_attributes>David</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>940</x>
<y>460</y>
<w>160</w>
<h>30</h>
</coordinates>
<panel_attributes>...</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>820</x>
<y>460</y>
<w>120</w>
<h>30</h>
</coordinates>
<panel_attributes>≥20</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>820</x>
<y>430</y>
<w>120</w>
<h>30</h>
</coordinates>
<panel_attributes>20.0</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>610</x>
<y>620</y>
<w>210</w>
<h>30</h>
</coordinates>
<panel_attributes>...</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>820</x>
<y>560</y>
<w>120</w>
<h>30</h>
</coordinates>
<panel_attributes>Exchange Rate</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>610</x>
<y>530</y>
<w>490</w>
<h>120</h>
</coordinates>
<panel_attributes>Order Book: FOO.WayGate:XRP
--
</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>660</x>
<y>560</y>
<w>80</w>
<h>30</h>
</coordinates>
<panel_attributes>Amount</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>940</x>
<y>560</y>
<w>70</w>
<h>30</h>
</coordinates>
<panel_attributes>Owner</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>940</x>
<y>590</y>
<w>160</w>
<h>30</h>
</coordinates>
<panel_attributes>Tran
bg=green
transparency=0</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>940</x>
<y>620</y>
<w>160</w>
<h>30</h>
</coordinates>
<panel_attributes>...</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>820</x>
<y>620</y>
<w>120</w>
<h>30</h>
</coordinates>
<panel_attributes>...</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>820</x>
<y>590</y>
<w>120</w>
<h>30</h>
</coordinates>
<panel_attributes>0.1
bg=green
transparency=0</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>610</x>
<y>590</y>
<w>210</w>
<h>30</h>
</coordinates>
<panel_attributes>78 FOO for 780 XRP
bg=green
transparency=0</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>90</x>
<y>40</y>
<w>270</w>
<h>60</h>
</coordinates>
<panel_attributes>Tran places an Offer to buy 100 FOO issued by WayGate, by spending up to 1000 XRP.
style=wordwrap</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>130</x>
<y>410</y>
<w>470</w>
<h>170</h>
</coordinates>
<panel_attributes>lt=-&gt;&gt;&gt;
</panel_attributes>
<additional_attributes>10.0;10.0;450.0;150.0</additional_attributes>
</element>
<element>
<id>Text</id>
<coordinates>
<x>760</x>
<y>280</y>
<w>140</w>
<h>80</h>
</coordinates>
<panel_attributes>Consumed Offers are removed from the order book.
style=wordwrap</panel_attributes>
<additional_attributes/>
</element>
</diagram>

View File

@@ -36,7 +36,7 @@ The following is a comprehensive list of all known [amendments](amendments.html)
| [MultiSignReserve][] | v1.2.0 | [Enabled: 2019-04-17](https://livenet.xrpl.org/transactions/C421E1D08EFD78E6B8D06B085F52A34A681D0B51AE62A018527E1B8F54C108FB "BADGE_GREEN") |
| [fixTakerDryOfferRemoval][] | v1.2.0 | [Enabled: 2019-04-02](https://livenet.xrpl.org/transactions/C42335E95F1BD2009A2C090EA57BD7FB026AD285B4B85BE15F669BA4F70D11AF "BADGE_GREEN") |
| [fix1578][] | v1.2.0 | [Enabled: 2019-03-23](https://livenet.xrpl.org/transactions/7A80C87F59BCE6973CBDCA91E4DBDB0FC5461D3599A8BC8EAD02FA590A50005D "BADGE_GREEN") |
| [DepositPreauth][] | v1.1.0 | [Enabled: 2018-10-09](https://livenet.xrpl.org/transactions/AD27403CB840AE67CADDB084BC54249D7BD1B403885819B39CCF723DC671F927 "BADGE_GREEN") |
| [DepositPreauth][DepositPreauthAmendment] | v1.1.0 | [Enabled: 2018-10-09](https://livenet.xrpl.org/transactions/AD27403CB840AE67CADDB084BC54249D7BD1B403885819B39CCF723DC671F927 "BADGE_GREEN") |
| [fix1515][] | v1.1.0 | [Enabled: 2018-10-09](https://livenet.xrpl.org/transactions/6DF60D9EC8AF3C39B173840F4D1C57F8A8AB51E7C6571483B4A5F1AA0A9AAEBF "BADGE_GREEN") |
| [fix1543][] | v1.0.0 | [Enabled: 2018-06-21](https://livenet.xrpl.org/transactions/EA6054C9D256657014052F1447216CEA75FFDB1C9342D45EB0F9E372C0F879E6 "BADGE_GREEN") |
| [fix1623][] | v1.0.0 | [Enabled: 2018-06-20](https://livenet.xrpl.org/transactions/4D218D86A2B33E29F17AA9C25D8DFFEE5D2559F75F7C0B1D016D3F2C2220D3EB "BADGE_GREEN") |
@@ -99,8 +99,6 @@ The sender or the receiver can cancel a Check at any time before it is cashed. A
Introduces three new transaction types: CheckCreate, CheckCancel, and CheckCash, and a new ledger object type, Check. Adds a new transaction result code, `tecEXPIRED`, which occurs when trying to create a Check whose expiration time is in the past.
This amendment also changes the OfferCreate transaction to return `tecEXPIRED` when trying to create an Offer whose expiration time is in the past. Without this amendment, an OfferCreate whose expiration time is in the past returns `tesSUCCESS` but does not create or execute an Offer.
## CryptoConditions
[CryptoConditions]: #cryptoconditions
@@ -167,7 +165,7 @@ Also fixes a bug in the EscrowCreate and PaymentChannelCreate transactions where
## DepositPreauth
[DepositPreauth]: #depositpreauth
[DepositPreauthAmendment]: #depositpreauth
| Amendment | DepositPreauth |
|:----------|:-----------|
@@ -180,7 +178,9 @@ Provides users of [deposit authorization](depositauth.html) with a way to preaut
Adds a new transaction type, DepositPreauth for adding or removing preauthorization, and a DepositPreauth ledger object type for tracking preauthorizations from one account to another. Adds a JSON-RPC command, `deposit_authorized`, to query whether an account is authorized to send payments directly to another. <!-- STYLE_OVERRIDE: is authorized to -->
Also changes the behavior of cross-currency Payments from an account to itself when that account requires deposit authorization. Without this amendment, those payments always fail with the code `tecNO_PERMISSION`. With this amendment, those payments succeed as they would with Deposit Authorization disabled.
Changes the behavior of cross-currency Payments from an account to itself when that account requires deposit authorization. Without this amendment, those payments always fail with the code `tecNO_PERMISSION`. With this amendment, those payments succeed as they would with Deposit Authorization disabled.
TAlso changes the OfferCreate transaction to return `tecEXPIRED` when trying to create an Offer whose expiration time is in the past. Without this amendment, an OfferCreate whose expiration time is in the past returns `tesSUCCESS` but does not create or execute an Offer.
## EnforceInvariants

View File

@@ -0,0 +1,74 @@
---
html: decentralized-exchange.html
parent: concepts.html
template: pagetype-category.html.jinja
blurb: The XRP Ledger contains a fully-functional exchange where users can trade tokens for XRP or each other.
targets:
- en
---
# Decentralized Exchange
The XRP Ledger has possibly the world's oldest _decentralized exchange_ (sometimes abbreviated "DEX"), operating continuously since the XRP Ledger's launch in 2012. The exchange allows users to buy and sell [tokens](tokens.html) for XRP or other tokens, with minimal [fees](fees.html) charged to the network itself (not paid out to any party).
**Caution:** Any can [issue a token](issue-a-fungible-token.html) with any currency code or ticker symbol they want and sell it in the decentralized exchange. Always perform due diligence before buying a token, and pay attention to the issuer. Otherwise, you might give up something of value and receive worthless tokens in exchange.
## Structure
The XRP Ledger's decentralized exchange consists of an unlimited number of currency pairs, tracked on-demand when users make trades. A currency pair can consist of XRP and a token or two different tokens; tokens are always identified by the combination of an issuer and a currency code. Therefore, it is possible to trade between two tokens with the same currency code and different issuers, or the same issuer and different currency codes.
As with all changes to the XRP Ledger, you need to send a [transaction](transaction-basics.html) to make a trade. A trade in the XRP Ledger is called an [Offer](offers.html). An Offer is effectively a [_limit order_](https://en.wikipedia.org/wiki/Order_(exchange)#Limit_order) to buy or sell a specific amount of one currency (XRP or a token) for a specific amount of another. When the network executes an Offer, if there are any matching Offers for the same currency pair, they are consumed starting with the best exchange rate first.
An Offer can be fully or partially filled; if it's not fully filled right away, it becomes a passive Offer object in the ledger for the remaining amount. Later on, other Offers or [Cross-currency payments](cross-currency-payments.html) can match and consume the Offer. Because of this, Offers can execute at better than their requested exchange rate when initially placed, or at exactly their stated exchange rate later on (aside from minor differences to account for rounding).
Offers can be manually or automatically canceled after being placed. For details on this and other properties of Offers, see [Offers](offers.html).
When trading two tokens, [auto-bridging](autobridging.html) improves exchange rates and liquidity by automatically trading token-to-XRP and XRP-to-token when doing so is cheaper than trading directly token-to-token.
### Example Trade
{{ include_svg("img/decentralized-exchange-example-trade.svg", "Diagram: Partially filled offer to buy a token for XRP.") }}
The above diagram shows an example trade in the decentralized exchange. In this example, a trader named Tran places an Offer to buy 100 tokens with the currency code FOO issued by a fictional business called WayGate. (For brevity, "FOO.WayGate" refers to these tokens.) Tran specifies that he is willing to spend up to 1000 XRP for the full total. When Tran's transaction is processed, the following things happen:
1. The network calculates the exchange rate of Tran's Offer, by dividing the amount to buy by the amount to pay.
0. The network finds the order book for the reverse of Tran's Offer: in this case, that means the order book for selling FOO.WayGate and buying XRP. This order book already has several existing Offers from other traders for varying amounts and exchange rates.
0. Tran's Offer "consumes" matching Offers, starting with the best exchange rate and working its way down, until either Tran's Offer has been fully filled, or there are no more Offers whose exchange rate is equal or better than the rate specified in Tran's Offer. In this example, only 22 FOO.WayGate are available at the requested rate or better. The consumed Offers are removed from the order book.
0. Tran receives the amount of FOO.WayGate that the trade was able to acquire, from the various traders who had previous placed orders to sell it. These tokens go to Tran's [trust line](trust-lines-and-issuing.html) to WayGate for FOO. (If Tran did not already have that trust line, one is automatically created.)
0. In return, those traders receive XRP from Tran according to their stated exchange rates.
0. The network calculates the remainder of Tran's Offer: since the original Offer was to buy 100 FOO.WayGate and so far Tran has received 22, the remainder is 78 FOO.WayGate. Using the original exchange rate, that means that the rest of Tran's Offer is now to buy 78 FOO.WayGate for 780 XRP.
0. The resulting "remainder" gets placed onto the order book for trades going the same direction as Tran's: selling XRP and buying FOO.WayGate.
Later transactions, including ones executed immediately after Tran's in the _same_ ledger, use the updated order books for their trades, so they can consume part or all of Tran's Offer until it's fully filled or Tran cancels it.
**Note:** The canonical order transactions execute in when a ledger is closed and validated is not the same as the order those transactions were sent. When multiple transactions affect the same order book in the same ledger, the final results of those transactions may be very different than the tentative results calculated at the time of transaction submission. For more details on when transactions' results are or are not final, see [Finality of Results](finality-of-results.html).
## Limitations
The decentralized exchange is designed with the following limitations:
Because trades are only executed each time a new ledger closes (approximately every 3-5 seconds), the XRP Ledger is not suitable for [high-frequency trading](https://en.wikipedia.org/wiki/High-frequency_trading). The order transactions execute within a ledger is designed to be unpredictable, to discourage [front-running](https://en.wikipedia.org/wiki/Front_running).
The XRP Ledger does not natively represent concepts such as market orders, stop orders, or trading on leverage. Some of these may be possible with creative use of custom tokens and Offer properties.
As a decentralized system, the XRP Ledger does not have any information on the actual people and organizations behind the [accounts](accounts.html) involved in trading. Therefore, the ledger itself cannot implement restrictions around who can or cannot participate in trading, and users and issuers must take care to follow any relevant laws to regulate trading tokens that represent various types of underlying assets. Features such as [freezes](freezes.html) and [authorized trust lines](authorized-trust-lines.html) are intended to help issuers comply with relevant laws and regulations.
## See Also
- **Concepts:**
- See [Offers](offers.html) for details on how trades work in the XRP Ledger.
- See [Tokens](tokens.html) for an overview of how various types of value can be represented in the XRP Ledger.
- **References:**
- [account_offers method][] to look up Offers placed by an account
- [book_offers method][] to look up Offers to buy or sell a given currency pair
- [OfferCreate transaction][] to place a new Offer or replace an existing Offer
- [OfferCancel transaction][] to cancel an existing Offer
- [Offer object][] for the data structure of passive Offers in the ledger
- [DirectoryNode object][] for the data structure that tracks all the Offers for a given currency pair and exchange rate.
<!-- NOTE: There aren't really any tutorials for using the DEX. When there are, add them here. -->
<!--{# common link defs #}-->
{% include '_snippets/rippled-api-links.md' %}
{% include '_snippets/tx-type-links.md' %}
{% include '_snippets/rippled_versions.md' %}

View File

@@ -7,85 +7,107 @@ labels:
---
# Offers
In the XRP Ledger's decentralized exchange, trade orders are called "Offers". Offers can trade XRP with [tokens](tokens.html), or tokens for other tokens, including tokens with the same currency code but different issuers. (Tokens with the same code but different issuers can also sometimes be exchanged through [rippling](rippling.html).)
In the XRP Ledger's [decentralized exchange](decentralized-exchange.html), trade orders are called "Offers". Offers can trade XRP with [tokens](tokens.html), or tokens for other tokens, including tokens with the same currency code but different issuers. (Tokens with the same code but different issuers can also sometimes be exchanged through [rippling](rippling.html).)
- To create an Offer, send an [OfferCreate transaction][].
- Offers that aren't fully filled immediately become [Offer objects](offer.html) in the ledger data. Later Offers and Payments can consume the Offer object from the ledger.
- [Cross-currency payments](cross-currency-payments.html) consume offers to provide liquidity.
- [Cross-currency payments](cross-currency-payments.html) consume Offers to provide liquidity. However, they never create Offer objects in the ledger.
## Lifecycle of an Offer
When an OfferCreate transaction is processed, it automatically consumes matching or crossing offers to the extent possible. (If existing offers provide a better rate than requested, the offer creator could pay less than the full `TakerGets` amount to receive the entire `TakerPays` amount.) If that does not completely fulfill the `TakerPays` amount, then the offer becomes an Offer object in the ledger. (You can use [OfferCreate Flags](offercreate.html#offercreate-flags) to modify this behavior.)
An [OfferCreate transaction][] is an instruction to conduct a trade, either between two tokens, or a token and XRP. Every such transaction contains a buy amount (`TakerPays`) and a sell amount (`TakerGets`). When the transaction is processed, it automatically consumes matching or crossing Offers to the extent possible. If that does not completely fill the new Offer, then the remainder becomes an Offer object in the ledger.
An offer in the ledger can be fulfilled either by additional OfferCreate transactions that match up with the existing offers, or by [Payment transactions][] that use the offer to connect the payment path. Offers can be partially fulfilled and partially funded. A single transaction can consume up to 850 Offers from the ledger. (Any more than that, and the metadata becomes too large, resulting in [`tecOVERSIZE`](tec-codes.html).)
The Offer object waits in the ledger until other Offers or cross-currency payments fully consume it. The account that placed the Offer is called the Offer's _owner_. You can cancel your own Offers at any time, using the dedicated [OfferCancel transaction][], or as an option of the [OfferCreate transaction][].
You can create an offer so long as you have at least some (any positive, nonzero amount) of the currency specified by the `TakerGets` parameter of the offer. The offer sells as much of the currency as you have, up to the `TakerGets` amount, until the `TakerPays` amount is satisfied. An offer cannot place anyone in debt.
While you have an Offer in the ledger, it sets aside some of your XRP toward the [owner reserve](reserves.html). When the Offer gets removed, for any reason, that XRP is freed up again.
If you place an offer that crosses any offers you have existing in the ledger, the old offers are automatically canceled regardless of the amounts involved.
### Variations
It is possible for an offer to become temporarily or permanently _unfunded_:
- **Buy vs. Sell:** By default, Offers are "buy" Offers and are considered fully filled when you have acquired the entire "buy" (`TakerPays`) amount. (You may spend less than you expected while receiving the specified amount.) By contrast, a "Sell" Offer is only considered fully filled when you have spent the entire "sell" (`TakerGets`) amount. (You may receive more than you expected while spending the specified amount.) This is only relevant if the Offer _initially_ executes at better than its requested exchange rate: after the Offer gets placed into the ledger, it only ever executes at _exactly_ the requested exchange rate.
- An **Immediate or Cancel** Offer is not placed into the ledger, so it only trades up to the amount that matches existing, matching Offers at the time the transaction is processed.
- A **Fill or Kill** Offer is not placed into the ledger, _and_ it is canceled if the full amount is not filled when it initially executes. This is similar to "Immediate or Cancel" except it _cannot_ be partially filled.
- A **Passive** Offer does not consume matching Offers that have the exact same exchange rate (going the other direction), and instead is placed directly into the ledger. You can use this to create an exact peg between two assets. Passive Offers still consume other Offers that have a _better_ exchange rate going the other way.
* If the creator no longer has any of the `TakerGets` currency.
* The offer becomes funded again when the creator obtains more of that currency.
* If the currency required to fund the offer is held in a [frozen trust line](freezes.html).
* The offer becomes funded again when the trust line is no longer frozen.
* If the creator does not have enough XRP for the reserve amount of a new trust line required by the offer. (See [Offers and Trust](#offers-and-trust).)
* The offer becomes funded again when the creator obtains more XRP, or the reserve requirements decrease.
* If the Expiration time included in the offer is before the close time of the most recently-closed ledger. (See [Offer Expiration](#offer-expiration).)
An unfunded offer can stay on the ledger indefinitely, but it does not have any effect. The only ways an offer can be *permanently* removed from the ledger are:
### Funding Requirements
* It becomes fully claimed by a Payment or a matching OfferCreate transaction.
* An OfferCancel or OfferCreate transaction explicitly cancels the offer.
* An OfferCreate transaction from the same account crosses the earlier offer. (In this case, the older offer is automatically canceled.)
* An offer is found to be unfunded during transaction processing, typically because it was at the tip of the order book.
* This includes cases where one side or the other of an offer is found to be closer to 0 than `rippled`'s precision supports.
When you try to place an Offer, the transaction is rejected as "unfunded" if you don't have at least some of the asset that the trade would sell. More specifically:
**To sell a token,** you must either:
- Hold any positive amount of that token, _or_
- Be the token's issuer.
However, you don't need to hold the full amount specified in the Offer. Placing an Offer does not lock up your funds, so you can place multiple Offers to sell the same tokens (or XRP), or place an Offer and hope to get enough tokens or XRP to fully fund it later.
**To sell XRP,** you must hold enough XRP to meet all the [reserve requirements](reserves.html), including the reserve for the Offer object to be placed in the ledger and for the trust line to hold the token you are buying. As long as you have any XRP left over after setting aside the reserve amount, you can place the Offer.
When another Offer matches yours, both Offers execute to the extent that their owners' funds permit at the the time. If there are matching Offers and you run out of funds before yours is fully filled, the remainder of your Offer is canceled. An Offer can't make your balance of a token negative, unless you are the issuer of that token. (If you are the issuer, you can use Offers to issue new tokens up to the total amount specified in your Offers; tokens you issue are represented as negative balances from your perspective.)
If you place an Offer that crosses any of your own Offers that exist in the ledger, the old, crossed Offers are automatically canceled regardless of the amounts involved.
It is possible for an Offer to become temporarily or permanently _unfunded_ in the following cases:
- If the owner no longer has any of the sell asset.
- The Offer becomes funded again when the owner obtains more of that asset.
- If the sell asset is a token in a [frozen trust line](freezes.html).
- The Offer becomes funded again when the trust line is no longer frozen.
- If the Offer needs to create a new trust line, but the owner does not have enough XRP for the increased [reserve](reserves.html). (See [Offers and Trust](#offers-and-trust).)
- The offer becomes funded again when the owner obtains more XRP, or the reserve requirements decrease.
- If the Offer is expired. (See [Offer Expiration](#offer-expiration).)
An unfunded Offer stays on the ledger until a transaction removes it. Ways that an Offer can be removed from the ledger include:
- A matching Offer or [Cross-currency payment](cross-currency-payments.html) fully consumes the Offer.
- The owner explicitly cancels the Offer.
- The owner implicitly cancels the Offer by sending a new Offer that crosses it.
- The Offer is found to be unfunded or expired during transaction processing. Typically this means that another Offer tried to consume it and could not.
- This includes cases where the remaining amount that can be paid out by the Offer rounds down to zero.
### Tracking Unfunded Offers
Tracking the funding status of all offers can be computationally taxing. In particular, addresses that are actively trading may have a large number of offers open. A single balance can affect the funding status of many offers to buy different currencies. Because of this, `rippled` does not proactively find and remove offers.
Tracking the funding status of all Offers can be computationally taxing. In particular, addresses that are actively trading may have a large number of Offers open. A single balance can affect the funding status of many Offers. Because of this, the XRP Ledger does not _proactively_ find and remove unfunded or expired Offers.
A client application can locally track the funding status of offers. To do this, first retrieve an order book using the [book_offers method][] and check the `taker_gets_funded` field of offers. Then, [subscribe](subscribe.html) to the `transactions` stream and watch the transaction metadata to see which offers are modified.
A client application can locally track the funding status of Offers. To do this, first retrieve an order book using the [book_offers method][] and check the `taker_gets_funded` field of Offers. Then, [subscribe](subscribe.html) to the `transactions` stream and watch the transaction metadata to see which Offers are modified.
## Offers and Trust
The limit values of [trust lines](trust-lines-and-issuing.html) do not affect Offers. In other words, you can use an Offer to acquire more than the maximum amount you trust an issuer to redeem.
The limit values of [trust lines](trust-lines-and-issuing.html) do not affect Offers. In other words, you can use an Offer to acquire more than the maximum amount you trust an issuer for.
However, holding non-XRP balances still requires a trust line to the address issuing those balances. When an offer is taken, it automatically creates any necessary trust lines, setting their limits to 0. Because [trust lines increase the reserve an account must hold](reserves.html), any offers that would require a new trust line also require the address to have enough XRP to meet the reserve for that trust line.
However, holding tokens still requires a trust line to the issuer. When an Offer is consumed, it automatically creates any necessary trust lines, setting their limits to 0. Because [trust lines increase the reserve an account must hold](reserves.html), any Offers that would require a new trust line also require the address to have enough XRP to meet the reserve for that trust line.
Trust lines limits protect you from receiving more of a token as payment than you want. Offers can go beyond those limits because they are an explicit statement of how much of the token you want.
Trust line limits protect you from receiving more of a token as payment than you want. Offers can go beyond those limits because they are an explicit statement of how much of the token you want.
## Offer Preference
Existing offers are grouped by exchange rate (sometimes called "offer quality"), which is measured as the ratio between `TakerGets` and `TakerPays`. Offers with a higher exchange rate are taken preferentially. (That is, the person accepting the offer receives as much as possible for the amount of currency they pay out.) Offers with the same exchange rate are taken on the basis of which offer was placed in the earliest ledger version.
Existing Offers are grouped by exchange rate, which is measured as the ratio between `TakerGets` and `TakerPays`. Offers with a higher exchange rate are taken preferentially. (That is, the person accepting the offer receives as much as possible for the amount of currency they pay out.) Offers with the same exchange rate are taken on the basis of which offer was placed first.
When offers of the same exchange rate are placed in the same ledger version, the order in which they are taken is determined by the [canonical order](https://github.com/ripple/rippled/blob/release/src/ripple/app/misc/CanonicalTXSet.cpp "Source: Transaction ordering") in which the transactions were [applied to the ledger](https://github.com/ripple/rippled/blob/5425a90f160711e46b2c1f1c93d68e5941e4bfb6/src/ripple/app/consensus/LedgerConsensus.cpp#L1435-L1538 "Source: Applying transactions"). This behavior is designed to be deterministic, efficient, and hard to game.
When Offers execute in the same ledger block, the order in which they execute is determined by the [canonical order](https://github.com/ripple/rippled/blob/release/src/ripple/app/misc/CanonicalTXSet.cpp "Source code: Transaction ordering") in which the transactions were [applied to the ledger](https://github.com/ripple/rippled/blob/5425a90f160711e46b2c1f1c93d68e5941e4bfb6/src/ripple/app/consensus/LedgerConsensus.cpp#L1435-L1538 "Source code: Applying transactions"). This behavior is designed to be deterministic, efficient, and hard to game.
## Offer Expiration
Since transactions can take time to propagate and confirm, the timestamp of a ledger is used to determine offer validity. An offer only expires when its Expiration time is before the most-recently validated ledger. In other words, an offer with an `Expiration` field is still considered "active" if its expiration time is later than the timestamp of the most-recently validated ledger, regardless of what your local clock says.
When you place an Offer, you can optionally add an expiration time to it. By default, Offers don't expire. You can't create a new Offer that is already expired.
You can determine the final disposition of an offer with an `Expiration` as soon as you see a fully-validated ledger with a close time equal to or greater than the expiration time.
Expiration times are specified down to the second, but the exact, real-world time when an Offer expires is less precise. An Offer is expired if it has an expiration time that is _earlier than or equal to_ the close time of the previous ledger. Otherwise, the Offer can still execute, even if the real-world time is later than the Offer's expiration. In other words, an Offer is still "active" if its expiration time is later than the close time of the latest validated ledger, regardless of what your clock says.
**Note:** Since only new transactions can modify the ledger, an expired offer can stay on the ledger after it becomes inactive. The offer is treated as unfunded and has no effect, but it can continue to appear in results (for example, from the [ledger_entry](ledger_entry.html) command). Later on, the expired offer can get finally deleted as a result of another transaction (such as another OfferCreate) if the server finds it while processing.
This is a consequence of how the network reaches agreement. For the entire peer-to-peer network to reach a consensus, all servers must agree which Offers are expired when executing transactions. Individual servers may have slight differences in their internal clock settings, so they might not reach the same conclusions about which Offers were expired if they each used the "current" time. The close time of a ledger is not known until after the transactions in that ledger have been executed, so servers use the official close time of the _previous_ ledger instead. The [close times of ledgers are rounded](ledgers.html#ledger-close-times), which further increases the potential difference between real-world time and the time used to determine if an Offer is expired.
**Note:** Expired Offers remain in the ledger data until a transaction removes them. Until then, they can continue to appear in data retrieved from the API (for example, using the [ledger_entry method][]). Transactions automatically delete any expired and unfunded Offers they find, usually while executing Offers or cross-currency payments that would have matched or canceled them. The owner reserve associated with an Offer is only made available again when the Offer is actually deleted.
If an OfferCreate transaction has an `Expiration` time that has already passed when the transaction first gets included in a ledger, the transaction does not execute the offer. The result code of such a transaction depends on whether the [Checks amendment][] is enabled. With the Checks amendment enabled, the transaction has the `tecEXPIRED` result code. Otherwise, the transaction has the `tesSUCCESS` transaction code. In either case, the transaction has no effect except to destroy the XRP paid as a [transaction cost](transaction-cost.html).
## See Also
- **Concepts:**
- [Tokens](tokens.html)
- [Paths](paths.html)
- **Tutorials:**
- [List Your Exchange on XRP Charts](list-your-exchange-on-xrp-charts.html) - for off-ledger exchanges
- **References:**
- [account_offers method][]
- [book_offers method][]
- [OfferCreate transaction][]
- [OfferCancel transaction][]
- [Offer object](offer.html)
<!--{# common link defs #}-->

View File

@@ -9,9 +9,7 @@ labels:
[[Source]](https://github.com/ripple/rippled/blob/master/src/ripple/app/tx/impl/CreateOffer.cpp "Source")
An OfferCreate transaction is effectively a [limit order](http://en.wikipedia.org/wiki/limit_order). It defines an intent to exchange currencies, and creates an [Offer object](offer.html) if not completely fulfilled when placed. Offers can be partially fulfilled.
For more information about how Offers work, see [Offers](offers.html).
An OfferCreate transaction places an [Offer](offers.html) in the [decentralized exchange](decentralized-exchange.html).
## Example {{currentpage.name}} JSON
@@ -38,10 +36,10 @@ For more information about how Offers work, see [Offers](offers.html).
| Field | JSON Type | [Internal Type][] | Description |
|:---------------|:--------------------|:------------------|:------------------|
| [`Expiration`](offers.html#offer-expiration) | Number | UInt32 | _(Optional)_ Time after which the offer is no longer active, in [seconds since the Ripple Epoch][]. |
| `OfferSequence` | Number | UInt32 | _(Optional)_ An offer to delete first, specified in the same way as [OfferCancel][]. |
| `TakerGets` | [Currency Amount][] | Amount | The amount and type of currency being provided by the offer creator. |
| `TakerPays` | [Currency Amount][] | Amount | The amount and type of currency being requested by the offer creator. |
| [`Expiration`](offers.html#offer-expiration) | Number | UInt32 | _(Optional)_ Time after which the Offer is no longer active, in [seconds since the Ripple Epoch][]. |
| `OfferSequence` | Number | UInt32 | _(Optional)_ An Offer to delete first, specified in the same way as [OfferCancel][]. |
| `TakerGets` | [Currency Amount][] | Amount | The amount and type of currency being sold. |
| `TakerPays` | [Currency Amount][] | Amount | The amount and type of currency being bought. |
## OfferCreate Flags
@@ -49,18 +47,32 @@ Transactions of the OfferCreate type support additional values in the [`Flags` f
| Flag Name | Hex Value | Decimal Value | Description |
|:----------------------|:-------------|:--------------|:----------------------|
| `tfPassive` | `0x00010000` | 65536 | If enabled, the offer does not consume offers that exactly match it, and instead becomes an Offer object in the ledger. It still consumes offers that cross it. |
| `tfImmediateOrCancel` | `0x00020000` | 131072 | Treat the offer as an [Immediate or Cancel order](http://en.wikipedia.org/wiki/Immediate_or_cancel). If enabled, the offer never becomes a ledger object: it only tries to match existing offers in the ledger. If the offer cannot match any offers immediately, it executes "successfully" without trading any currency. In this case, the transaction has the [result code](transaction-results.html) `tesSUCCESS`, but creates no [Offer objects](offer.html) in the ledger. |
| `tfFillOrKill` | `0x00040000` | 262144 | Treat the offer as a [Fill or Kill order](http://en.wikipedia.org/wiki/Fill_or_kill). Only try to match existing offers in the ledger, and only do so if the entire `TakerPays` quantity can be obtained. If the [fix1578 amendment][] is enabled and the offer cannot be executed when placed, the transaction has the [result code](transaction-results.html) `tecKILLED`; otherwise, the transaction uses the result code `tesSUCCESS` even when it was killed without trading any currency. |
| `tfPassive` | `0x00010000` | 65536 | If enabled, the Offer does not consume Offers that exactly match it, and instead becomes an Offer object in the ledger. It still consumes Offers that cross it. |
| `tfImmediateOrCancel` | `0x00020000` | 131072 | Treat the Offer as an [Immediate or Cancel order](http://en.wikipedia.org/wiki/Immediate_or_cancel). The Offer never creates an [Offer object][] in the ledger: it only trades as much as it can by consuming existing Offers at the time the transaction is processed. If no Offers match, it executes "successfully" without trading anything. In this case, the transaction still uses the [result code](transaction-results.html) `tesSUCCESS`. |
| `tfFillOrKill` | `0x00040000` | 262144 | Treat the offer as a [Fill or Kill order](http://en.wikipedia.org/wiki/Fill_or_kill). The Offer never creates an [Offer object][] in the ledger, and is canceled if it cannot be fully filled at the time of execution. By default, this means that the owner must receive the full `TakerPays` amount; if the `tfSell` flag is enabled, the owner must be able to spend the entire `TakerGets` amount instead. |
| `tfSell` | `0x00080000` | 524288 | Exchange the entire `TakerGets` amount, even if it means obtaining more than the `TakerPays` amount in exchange. |
The following invalid flag combination prompts a `temINVALID_FLAG` error:
* `tfImmediateOrCancel` and `tfFillOrKill`
## Error Cases
| Error Code | Description |
|:-------------------------|:--------------------------------------------------|
| `temINVALID_FLAG` | Occurs if the transaction specifies both `tfImmediateOrCancel` and `tfFillOrKill`. |
| `tecEXPIRED` | Occurs if the transaction specifies an `Expiration` time that has already passed _(Updated by the [DepositPreauth amendment][]: previously, the transaction used the result code `tesSUCCESS` in this case. In either case, the transaction has no effect except to destroy the XRP paid as a [transaction cost](transaction-cost.html).)_ |
| `tecKILLED` | Occurs if the transaction specifies `tfFillOrKill`, and the full amount cannot be filled. _(Updated by the [fix1578 amendment][]: previously, the transaction used the result code `tesSUCCESS` in this case. In either case, the transaction does not execute any trades.)_ |
| `temBAD_EXPIRATION` | Occurs if the transaction contains an `Expiration` field that is not validly formatted. |
| `temBAD_SEQUENCE` | Occurs if the transaction contains an `OfferSequence` that is not validly formatted, or is higher than the transaction's own `Sequence` number. |
| `temBAD_OFFER` | Occurs if the Offer tries to trade XRP for XRP, or tries to trade an invalid or negative amount of a token. |
| `temREDUNDANT` | Occurs if the transaction specifies a token for the same token (same issuer and currency code). |
| `temBAD_CURRENCY` | Occurs if the transaction specifies a token with the currency code "XRP". |
| `temBAD_ISSUER` | Occurs if the transaction specifies a token with an invalid `issuer` value. |
| `tecNO_ISSUER` | Occurs if the transaction specifies a token whose `issuer` value is not a funded account in the ledger. |
| `tecFROZEN` | Occurs if the transaction involves a token on a [frozen](freezes.html) trust line (including local and global freezes). |
| `tecUNFUNDED_OFFER` | Occurs if the owner does not hold a positive amount of the `TakerGets` currency. (Exception: if `TakerGets` specifies a token that the owner issues, the transaction can succeed.) |
| `tecNO_LINE` | Occurs if the transaction involves a token whose issuer uses [Authorized Trust Lines](authorized-trust-lines.html) and the necessary trust line does not exist. |
| `tecNO_AUTH` | Occurs if the transaction involves a token whose issuer uses [Authorized Trust Lines](authorized-trust-lines.html) and the the trust line that would receive the tokens exists but has not been authorized. |
| `tecINSUF_RESERVE_OFFER` | Occurs if the owner does not have enough XRP to meet the reserve requirement of adding a new Offer object to the ledger, and the transaction did not convert any currency. (If the transaction successfully traded any amount, the transaction succeeds with the result code `tesSUCCESS`, but does not create an Offer object in the ledger for the remainder.) |
| `tecDIR_FULL` | Occurs if the owner owns too many items in the ledger, or the order book contains too many Offers at the same exchange rate already. |

View File

@@ -798,13 +798,7 @@ pages:
targets:
- ja
- name: Decentralized Exchange
html: decentralized-exchange.html
parent: concepts.html
template: pagetype-category.html.jinja
blurb: The XRP Ledger contains a fully-functional exchange where users can trade issued currencies for XRP or each other.
targets:
- en
- md: concepts/decentralized-exchange/decentralized-exchange.md
- name: 分散型取引所
html: decentralized-exchange.html

View File

@@ -0,0 +1,543 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN'
'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'>
<svg fill-opacity="1" xmlns:xlink="http://www.w3.org/1999/xlink" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" width="1420" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" viewBox="20 20 1420 650" height="650" xmlns="http://www.w3.org/2000/svg" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12px" stroke-dashoffset="0" image-rendering="auto"
><!--Generated by the Batik Graphics2D SVG Generator--><defs id="genericDefs"
/><g
><defs id="defs1"
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath1"
><path d="M0 0 L2147483647 0 L2147483647 2147483647 L0 2147483647 L0 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath2"
><path d="M0 0 L0 80 L140 80 L140 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath3"
><path d="M0 0 L0 60 L270 60 L270 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath4"
><path d="M0 0 L0 30 L210 30 L210 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath5"
><path d="M0 0 L0 30 L120 30 L120 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath6"
><path d="M0 0 L0 30 L160 30 L160 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath7"
><path d="M0 0 L0 30 L70 30 L70 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath8"
><path d="M0 0 L0 30 L80 30 L80 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath9"
><path d="M0 0 L0 120 L490 120 L490 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath10"
><path d="M0 0 L0 90 L180 90 L180 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath11"
><path d="M0 0 L0 110 L60 110 L60 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath12"
><path d="M0 0 L0 210 L490 210 L490 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath13"
><path d="M0 0 L0 90 L200 90 L200 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath14"
><path d="M0 0 L0 80 L150 80 L150 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath15"
><path d="M0 0 L0 90 L130 90 L130 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath16"
><path d="M0 0 L0 120 L220 120 L220 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath17"
><path d="M0 0 L0 170 L470 170 L470 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath18"
><path d="M0 0 L0 30 L180 30 L180 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath19"
><path d="M0 0 L0 100 L30 100 L30 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath20"
><path d="M0 0 L0 210 L410 210 L410 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath21"
><path d="M0 0 L0 30 L110 30 L110 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath22"
><path d="M0 0 L0 120 L40 120 L40 0 Z"
/></clipPath
></defs
><g font-family="sans-serif" font-size="14px" transform="translate(760,280)"
><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath2)" stroke="none"
>Consumed Offers</text
><text x="5" xml:space="preserve" y="34.2188" clip-path="url(#clipPath2)" stroke="none"
>are removed</text
><text x="5" xml:space="preserve" y="50.3281" clip-path="url(#clipPath2)" stroke="none"
>from the order</text
><text x="5" xml:space="preserve" y="66.4375" clip-path="url(#clipPath2)" stroke="none"
>book.</text
></g
><g font-family="sans-serif" font-size="14px" transform="translate(90,40)"
><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath3)" stroke="none"
>Tran places an Offer to buy 100</text
><text x="5" xml:space="preserve" y="34.2188" clip-path="url(#clipPath3)" stroke="none"
>FOO issued by WayGate, by</text
><text x="5" xml:space="preserve" y="50.3281" clip-path="url(#clipPath3)" stroke="none"
>spending up to 1000 XRP.</text
></g
><g fill="lime" transform="translate(610,590)" stroke="lime"
><rect x="0.5" width="208.5" height="28.5" y="0.5" clip-path="url(#clipPath4)" stroke="none"
/><rect x="0.5" y="0.5" clip-path="url(#clipPath4)" fill="none" width="208.5" height="28.5" stroke="black"
/></g
><g font-family="sans-serif" font-size="14px" transform="translate(610,590)"
><text x="35" xml:space="preserve" y="18.1094" clip-path="url(#clipPath4)" stroke="none"
>78 FOO for 780 XRP</text
></g
><g fill="lime" transform="translate(820,590)" stroke="lime"
><rect x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath5)" stroke="none"
/><rect x="0.5" y="0.5" clip-path="url(#clipPath5)" fill="none" width="118.5" height="28.5" stroke="black"
/></g
><g font-family="sans-serif" font-size="14px" transform="translate(820,590)"
><text x="48" xml:space="preserve" y="18.1094" clip-path="url(#clipPath5)" stroke="none"
>0.1</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(820,620)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath5)" stroke="none"
/></g
><g transform="translate(820,620)"
><rect fill="none" x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath5)"
/><text x="53" font-size="14px" y="18.1094" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve"
>...</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(940,620)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="158.5" height="28.5" y="0.5" clip-path="url(#clipPath6)" stroke="none"
/></g
><g transform="translate(940,620)"
><rect fill="none" x="0.5" width="158.5" height="28.5" y="0.5" clip-path="url(#clipPath6)"
/><text x="73" font-size="14px" y="18.1094" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve"
>...</text
></g
><g fill="lime" transform="translate(940,590)" stroke="lime"
><rect x="0.5" width="158.5" height="28.5" y="0.5" clip-path="url(#clipPath6)" stroke="none"
/><rect x="0.5" y="0.5" clip-path="url(#clipPath6)" fill="none" width="158.5" height="28.5" stroke="black"
/></g
><g font-family="sans-serif" font-size="14px" transform="translate(940,590)"
><text x="64" xml:space="preserve" y="18.1094" clip-path="url(#clipPath6)" stroke="none"
>Tran</text
></g
><g font-family="sans-serif" font-size="14px" transform="translate(940,560)"
><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath7)" stroke="none"
>Owner</text
></g
><g font-family="sans-serif" font-size="14px" transform="translate(660,560)"
><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath8)" stroke="none"
>Amount</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(610,530)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="488.5" height="118.5" y="0.5" clip-path="url(#clipPath9)" stroke="none"
/></g
><g transform="translate(610,530)"
><rect fill="none" x="0.5" width="488.5" height="118.5" y="0.5" clip-path="url(#clipPath9)"
/><text x="135" font-size="14px" y="18.1094" clip-path="url(#clipPath9)" font-family="sans-serif" stroke="none" xml:space="preserve"
>Order Book: FOO.WayGate:XRP</text
><path fill="none" d="M1 24.1094 L489 24.1094" clip-path="url(#clipPath9)"
/></g
><g font-family="sans-serif" font-size="14px" transform="translate(820,560)"
><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath5)" stroke="none"
>Exchange Rate</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(610,620)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="208.5" height="28.5" y="0.5" clip-path="url(#clipPath4)" stroke="none"
/></g
><g transform="translate(610,620)"
><rect fill="none" x="0.5" width="208.5" height="28.5" y="0.5" clip-path="url(#clipPath4)"
/><text x="98" font-size="14px" y="18.1094" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve"
>...</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(820,430)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath5)" stroke="none"
/></g
><g transform="translate(820,430)"
><rect fill="none" x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath5)"
/><text x="44" font-size="14px" y="18.1094" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve"
>20.0</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(820,460)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath5)" stroke="none"
/></g
><g transform="translate(820,460)"
><rect fill="none" x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath5)"
/><text x="45" font-size="14px" y="18.1094" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve"
>≥20</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(940,460)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="158.5" height="28.5" y="0.5" clip-path="url(#clipPath6)" stroke="none"
/></g
><g transform="translate(940,460)"
><rect fill="none" x="0.5" width="158.5" height="28.5" y="0.5" clip-path="url(#clipPath6)"
/><text x="73" font-size="14px" y="18.1094" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve"
>...</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(940,430)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="158.5" height="28.5" y="0.5" clip-path="url(#clipPath6)" stroke="none"
/></g
><g transform="translate(940,430)"
><rect fill="none" x="0.5" width="158.5" height="28.5" y="0.5" clip-path="url(#clipPath6)"
/><text x="59" font-size="14px" y="18.1094" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve"
>David</text
></g
><g font-family="sans-serif" font-size="14px" transform="translate(990,400)"
><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath7)" stroke="none"
>Owner</text
></g
><g font-family="sans-serif" font-size="14px" transform="translate(680,400)"
><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath8)" stroke="none"
>Amount</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(610,370)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="488.5" height="118.5" y="0.5" clip-path="url(#clipPath9)" stroke="none"
/></g
><g transform="translate(610,370)"
><rect fill="none" x="0.5" width="488.5" height="118.5" y="0.5" clip-path="url(#clipPath9)"
/><text x="135" font-size="14px" y="18.1094" clip-path="url(#clipPath9)" font-family="sans-serif" stroke="none" xml:space="preserve"
>Order Book: XRP:FOO.WayGate</text
><path fill="none" d="M1 24.1094 L489 24.1094" clip-path="url(#clipPath9)"
/></g
><g font-family="sans-serif" font-size="14px" transform="translate(820,400)"
><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath5)" stroke="none"
>Exchange Rate</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(610,460)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="208.5" height="28.5" y="0.5" clip-path="url(#clipPath4)" stroke="none"
/></g
><g transform="translate(610,460)"
><rect fill="none" x="0.5" width="208.5" height="28.5" y="0.5" clip-path="url(#clipPath4)"
/><text x="98" font-size="14px" y="18.1094" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve"
>...</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(610,430)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="208.5" height="28.5" y="0.5" clip-path="url(#clipPath4)" stroke="none"
/></g
><g transform="translate(610,430)"
><rect fill="none" x="0.5" width="208.5" height="28.5" y="0.5" clip-path="url(#clipPath4)"
/><text x="17" font-size="14px" y="18.1094" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve"
>20000 XRP for 1000 FOO</text
></g
><g font-family="sans-serif" font-size="14px" transform="translate(1120,180)"
><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath10)" stroke="none"
>The owners of the</text
><text x="5" xml:space="preserve" y="34.2188" clip-path="url(#clipPath10)" stroke="none"
>matching Offers</text
><text x="5" xml:space="preserve" y="50.3281" clip-path="url(#clipPath10)" stroke="none"
>receive a total of 31</text
><text x="5" xml:space="preserve" y="66.4375" clip-path="url(#clipPath10)" stroke="none"
>XRP from Tran.</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(820,120)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath5)" stroke="none"
/></g
><g transform="translate(820,120)"
><rect fill="none" x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath5)"
/><text x="48" font-size="14px" y="18.1094" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve"
>0.5</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(820,150)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath5)" stroke="none"
/></g
><g transform="translate(820,150)"
><rect fill="none" x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath5)"
/><text x="39" font-size="14px" y="18.1094" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve"
>0.667</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(820,180)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath5)" stroke="none"
/></g
><g transform="translate(820,180)"
><rect fill="none" x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath5)"
/><text x="48" font-size="14px" y="18.1094" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve"
>4.0</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(820,210)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath5)" stroke="none"
/></g
><g transform="translate(820,210)"
><rect fill="none" x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath5)"
/><text x="44" font-size="14px" y="18.1094" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve"
>20.0</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(820,240)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath5)" stroke="none"
/></g
><g transform="translate(820,240)"
><rect fill="none" x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath5)"
/><text x="45" font-size="14px" y="18.1094" clip-path="url(#clipPath5)" font-family="sans-serif" stroke="none" xml:space="preserve"
>≥20</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(940,240)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="158.5" height="28.5" y="0.5" clip-path="url(#clipPath6)" stroke="none"
/></g
><g transform="translate(940,240)"
><rect fill="none" x="0.5" width="158.5" height="28.5" y="0.5" clip-path="url(#clipPath6)"
/><text x="73" font-size="14px" y="18.1094" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve"
>...</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1360,170)" stroke-opacity="0" stroke="rgb(255,255,255)"
><circle r="7" clip-path="url(#clipPath11)" cx="30.5" cy="7.5" stroke="none"
/></g
><g transform="translate(1360,170)"
><circle fill="none" r="7" clip-path="url(#clipPath11)" cx="30.5" cy="7.5"
/><path fill="none" d="M9.5 21.5 L51.5 21.5" clip-path="url(#clipPath11)"
/><path fill="none" d="M30.5 14.5 L30.5 42.5" clip-path="url(#clipPath11)"
/><path fill="none" d="M30.5 42.5 L16.5 70.5" clip-path="url(#clipPath11)"
/><path fill="none" d="M30.5 42.5 L44.5 70.5" clip-path="url(#clipPath11)"
/><text x="10" font-size="14px" y="93.1094" clip-path="url(#clipPath11)" font-family="sans-serif" stroke="none" xml:space="preserve"
>Omar</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(940,210)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="158.5" height="28.5" y="0.5" clip-path="url(#clipPath6)" stroke="none"
/></g
><g transform="translate(940,210)"
><rect fill="none" x="0.5" width="158.5" height="28.5" y="0.5" clip-path="url(#clipPath6)"
/><text x="59" font-size="14px" y="18.1094" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve"
>David</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(940,180)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="158.5" height="28.5" y="0.5" clip-path="url(#clipPath6)" stroke="none"
/></g
><g transform="translate(940,180)"
><rect fill="none" x="0.5" width="158.5" height="28.5" y="0.5" clip-path="url(#clipPath6)"
/><text x="60" font-size="14px" y="18.1094" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve"
>Omar</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(940,150)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="158.5" height="28.5" y="0.5" clip-path="url(#clipPath6)" stroke="none"
/></g
><g transform="translate(940,150)"
><rect fill="none" x="0.5" width="158.5" height="28.5" y="0.5" clip-path="url(#clipPath6)"
/><text x="63" font-size="14px" y="18.1094" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve"
>Brad</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(940,120)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="158.5" height="28.5" y="0.5" clip-path="url(#clipPath6)" stroke="none"
/></g
><g transform="translate(940,120)"
><rect fill="none" x="0.5" width="158.5" height="28.5" y="0.5" clip-path="url(#clipPath6)"
/><text x="64" font-size="14px" y="18.1094" clip-path="url(#clipPath6)" font-family="sans-serif" stroke="none" xml:space="preserve"
>Amy</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1300,220)" stroke-opacity="0" stroke="rgb(255,255,255)"
><circle r="7" clip-path="url(#clipPath11)" cx="30.5" cy="7.5" stroke="none"
/></g
><g transform="translate(1300,220)"
><circle fill="none" r="7" clip-path="url(#clipPath11)" cx="30.5" cy="7.5"
/><path fill="none" d="M9.5 21.5 L51.5 21.5" clip-path="url(#clipPath11)"
/><path fill="none" d="M30.5 14.5 L30.5 42.5" clip-path="url(#clipPath11)"
/><path fill="none" d="M30.5 42.5 L16.5 70.5" clip-path="url(#clipPath11)"
/><path fill="none" d="M30.5 42.5 L44.5 70.5" clip-path="url(#clipPath11)"
/><text x="9" font-size="14px" y="93.1094" clip-path="url(#clipPath11)" font-family="sans-serif" stroke="none" xml:space="preserve"
>David</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1350,60)" stroke-opacity="0" stroke="rgb(255,255,255)"
><circle r="7" clip-path="url(#clipPath11)" cx="30.5" cy="7.5" stroke="none"
/></g
><g transform="translate(1350,60)"
><circle fill="none" r="7" clip-path="url(#clipPath11)" cx="30.5" cy="7.5"
/><path fill="none" d="M9.5 21.5 L51.5 21.5" clip-path="url(#clipPath11)"
/><path fill="none" d="M30.5 14.5 L30.5 42.5" clip-path="url(#clipPath11)"
/><path fill="none" d="M30.5 42.5 L16.5 70.5" clip-path="url(#clipPath11)"
/><path fill="none" d="M30.5 42.5 L44.5 70.5" clip-path="url(#clipPath11)"
/><text x="14" font-size="14px" y="93.1094" clip-path="url(#clipPath11)" font-family="sans-serif" stroke="none" xml:space="preserve"
>Amy</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(1290,110)" stroke-opacity="0" stroke="rgb(255,255,255)"
><circle r="7" clip-path="url(#clipPath11)" cx="30.5" cy="7.5" stroke="none"
/></g
><g transform="translate(1290,110)"
><circle fill="none" r="7" clip-path="url(#clipPath11)" cx="30.5" cy="7.5"
/><path fill="none" d="M9.5 21.5 L51.5 21.5" clip-path="url(#clipPath11)"
/><path fill="none" d="M30.5 14.5 L30.5 42.5" clip-path="url(#clipPath11)"
/><path fill="none" d="M30.5 42.5 L16.5 70.5" clip-path="url(#clipPath11)"
/><path fill="none" d="M30.5 42.5 L44.5 70.5" clip-path="url(#clipPath11)"
/><text x="13" font-size="14px" y="93.1094" clip-path="url(#clipPath11)" font-family="sans-serif" stroke="none" xml:space="preserve"
>Brad</text
></g
><g font-family="sans-serif" font-size="14px" transform="translate(990,90)"
><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath7)" stroke="none"
>Owner</text
></g
><g font-family="sans-serif" font-size="14px" transform="translate(680,90)"
><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath8)" stroke="none"
>Amount</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(610,60)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="488.5" height="208.5" y="0.5" clip-path="url(#clipPath12)" stroke="none"
/></g
><g transform="translate(610,60)"
><rect fill="none" x="0.5" width="488.5" height="208.5" y="0.5" clip-path="url(#clipPath12)"
/><text x="135" font-size="14px" y="18.1094" clip-path="url(#clipPath12)" font-family="sans-serif" stroke="none" xml:space="preserve"
>Order Book: XRP:FOO.WayGate</text
><path fill="none" d="M1 24.1094 L489 24.1094" clip-path="url(#clipPath12)"
/></g
><g font-family="sans-serif" font-size="14px" transform="translate(210,500)"
><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath13)" stroke="none"
>The remainder of Tran's</text
><text x="5" xml:space="preserve" y="34.2188" clip-path="url(#clipPath13)" stroke="none"
>Offer is added to the</text
><text x="5" xml:space="preserve" y="50.3281" clip-path="url(#clipPath13)" stroke="none"
>opposite order book at its</text
><text x="5" xml:space="preserve" y="66.4375" clip-path="url(#clipPath13)" stroke="none"
>original exchange rate.</text
></g
><g font-family="sans-serif" font-size="14px" transform="translate(300,300)"
><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath14)" stroke="none"
>Tran receives a</text
><text x="5" xml:space="preserve" y="34.2188" clip-path="url(#clipPath14)" stroke="none"
>total of 22</text
><text x="5" xml:space="preserve" y="50.3281" clip-path="url(#clipPath14)" stroke="none"
>FOO.WayGate from</text
><text x="5" xml:space="preserve" y="66.4375" clip-path="url(#clipPath14)" stroke="none"
>the other traders.</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(60,340)" stroke-opacity="0" stroke="rgb(255,255,255)"
><circle r="7" clip-path="url(#clipPath11)" cx="30.5" cy="7.5" stroke="none"
/></g
><g transform="translate(60,340)"
><circle fill="none" r="7" clip-path="url(#clipPath11)" cx="30.5" cy="7.5"
/><path fill="none" d="M9.5 21.5 L51.5 21.5" clip-path="url(#clipPath11)"
/><path fill="none" d="M30.5 14.5 L30.5 42.5" clip-path="url(#clipPath11)"
/><path fill="none" d="M30.5 42.5 L16.5 70.5" clip-path="url(#clipPath11)"
/><path fill="none" d="M30.5 42.5 L44.5 70.5" clip-path="url(#clipPath11)"
/><text x="14" font-size="14px" y="93.1094" clip-path="url(#clipPath11)" font-family="sans-serif" stroke="none" xml:space="preserve"
>Tran</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(40,110)" stroke-opacity="0" stroke="rgb(255,255,255)"
><circle r="7" clip-path="url(#clipPath11)" cx="30.5" cy="7.5" stroke="none"
/></g
><g transform="translate(40,110)"
><circle fill="none" r="7" clip-path="url(#clipPath11)" cx="30.5" cy="7.5"
/><path fill="none" d="M9.5 21.5 L51.5 21.5" clip-path="url(#clipPath11)"
/><path fill="none" d="M30.5 14.5 L30.5 42.5" clip-path="url(#clipPath11)"
/><path fill="none" d="M30.5 42.5 L16.5 70.5" clip-path="url(#clipPath11)"
/><path fill="none" d="M30.5 42.5 L44.5 70.5" clip-path="url(#clipPath11)"
/><text x="14" font-size="14px" y="93.1094" clip-path="url(#clipPath11)" font-family="sans-serif" stroke="none" xml:space="preserve"
>Tran</text
></g
><g font-family="sans-serif" font-size="14px" transform="translate(820,90)"
><text x="5" xml:space="preserve" y="18.1094" clip-path="url(#clipPath5)" stroke="none"
>Exchange Rate</text
></g
><g font-family="sans-serif" font-size="14px" transform="translate(460,120)"
><text x="36" xml:space="preserve" y="18.1094" clip-path="url(#clipPath15)" stroke="none"
>These Offers</text
><text x="17" xml:space="preserve" y="34.2188" clip-path="url(#clipPath15)" stroke="none"
>match because</text
><text x="19" xml:space="preserve" y="50.3281" clip-path="url(#clipPath15)" stroke="none"
>their exchange</text
><text x="18" xml:space="preserve" y="66.4375" clip-path="url(#clipPath15)" stroke="none"
>rates are equal</text
><text x="58" xml:space="preserve" y="82.5469" clip-path="url(#clipPath15)" stroke="none"
>or better.</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(610,240)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="208.5" height="28.5" y="0.5" clip-path="url(#clipPath4)" stroke="none"
/></g
><g transform="translate(610,240)"
><rect fill="none" x="0.5" width="208.5" height="28.5" y="0.5" clip-path="url(#clipPath4)"
/><text x="98" font-size="14px" y="18.1094" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve"
>...</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(610,180)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="208.5" height="28.5" y="0.5" clip-path="url(#clipPath4)" stroke="none"
/></g
><g transform="translate(610,180)"
><rect fill="none" x="0.5" width="208.5" height="28.5" y="0.5" clip-path="url(#clipPath4)"
/><text x="44" font-size="14px" y="18.1094" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve"
>20 XRP for 5 FOO</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(610,210)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="208.5" height="28.5" y="0.5" clip-path="url(#clipPath4)" stroke="none"
/></g
><g transform="translate(610,210)"
><rect fill="none" x="0.5" width="208.5" height="28.5" y="0.5" clip-path="url(#clipPath4)"
/><text x="17" font-size="14px" y="18.1094" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve"
>20000 XRP for 1000 FOO</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(610,150)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="208.5" height="28.5" y="0.5" clip-path="url(#clipPath4)" stroke="none"
/></g
><g transform="translate(610,150)"
><rect fill="none" x="0.5" width="208.5" height="28.5" y="0.5" clip-path="url(#clipPath4)"
/><text x="39" font-size="14px" y="18.1094" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve"
>10 XRP for 15 FOO</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(610,120)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="208.5" height="28.5" y="0.5" clip-path="url(#clipPath4)" stroke="none"
/></g
><g transform="translate(610,120)"
><rect fill="none" x="0.5" width="208.5" height="28.5" y="0.5" clip-path="url(#clipPath4)"
/><text x="48" font-size="14px" y="18.1094" clip-path="url(#clipPath4)" font-family="sans-serif" stroke="none" xml:space="preserve"
>1 XRP for 2 FOO</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(140,110)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="218.5" height="118.5" y="0.5" clip-path="url(#clipPath16)" stroke="none"
/></g
><g transform="translate(140,110)"
><rect fill="none" x="0.5" width="218.5" height="118.5" y="0.5" clip-path="url(#clipPath16)"
/><text x="92" font-size="14px" y="18.1094" clip-path="url(#clipPath16)" font-family="sans-serif" stroke="none" xml:space="preserve"
>Offer</text
><path fill="none" d="M1 24.1094 L219 24.1094" clip-path="url(#clipPath16)"
/><text x="5" font-size="14px" y="39.2188" clip-path="url(#clipPath16)" font-family="sans-serif" stroke="none" xml:space="preserve"
>Buy: 100 FOO.WayGate</text
><text x="5" font-size="14px" y="55.3281" clip-path="url(#clipPath16)" font-family="sans-serif" stroke="none" xml:space="preserve"
>Spend: 1000 XRP</text
></g
><g stroke-miterlimit="5" font-size="14px" stroke-dasharray="1,2" font-family="sans-serif" transform="translate(140,110)" stroke-linecap="butt"
><path fill="none" d="M1 77.4375 L219 77.4375" clip-path="url(#clipPath16)"
/><text x="5" xml:space="preserve" y="92.5469" clip-path="url(#clipPath16)" stroke="none"
>(Exchange rate: </text
><text x="5" xml:space="preserve" y="108.6562" clip-path="url(#clipPath16)" stroke="none"
>10.0 XRP/FOO.WayGate)</text
></g
><g transform="translate(130,410)"
><path fill="none" d="M10.5 10.5 L449.5471 150.1968" clip-path="url(#clipPath17)"
/><path d="M437.3244 153.1288 L450.0235 150.3484 L441.266 140.7408 Z" clip-path="url(#clipPath17)" stroke="none"
/><path fill="none" d="M437.3244 153.1288 L450.0235 150.3484 L441.266 140.7408 Z" clip-path="url(#clipPath17)"
/></g
><g transform="translate(1110,160)"
><path fill="none" d="M10.5 10.5 L159.5 10.5" clip-path="url(#clipPath18)"
/><path d="M148.7417 17 L160 10.5 L148.7417 4 Z" clip-path="url(#clipPath18)" stroke="none"
/><path fill="none" d="M148.7417 17 L160 10.5 L148.7417 4 Z" clip-path="url(#clipPath18)"
/></g
><g transform="translate(710,270)"
><path fill="none" d="M10.5 10.5 L10.5 79.5" clip-path="url(#clipPath19)"
/><path d="M4 68.7417 L10.5 80 L17 68.7417 Z" clip-path="url(#clipPath19)" stroke="none"
/><path fill="none" d="M4 68.7417 L10.5 80 L17 68.7417 Z" clip-path="url(#clipPath19)"
/></g
><g transform="translate(110,190)"
><path fill="none" d="M390.5 10.5 L11.4037 190.0719" clip-path="url(#clipPath20)"
/><path d="M18.3439 179.5921 L10.9519 190.2859 L23.909 191.3407 Z" clip-path="url(#clipPath20)" stroke="none"
/><path fill="none" d="M18.3439 179.5921 L10.9519 190.2859 L23.909 191.3407 Z" clip-path="url(#clipPath20)"
/></g
><g transform="translate(70,130)"
><path fill="none" d="M10.5 10.5 L59.5 10.5" clip-path="url(#clipPath8)"
/><path d="M48.7417 17 L60 10.5 L48.7417 4 Z" clip-path="url(#clipPath8)" stroke="none"
/><path fill="none" d="M48.7417 17 L60 10.5 L48.7417 4 Z" clip-path="url(#clipPath8)"
/></g
><g transform="translate(360,150)"
><path fill="none" d="M10.5 10.5 L89.5 10.5" clip-path="url(#clipPath21)"
/><path d="M78.7417 17 L90 10.5 L78.7417 4 Z" clip-path="url(#clipPath21)" stroke="none"
/><path fill="none" d="M78.7417 17 L90 10.5 L78.7417 4 Z" clip-path="url(#clipPath21)"
/></g
><g stroke-dasharray="1,2" stroke-miterlimit="5" transform="translate(580,110)" stroke-linecap="butt"
><path fill="none" d="M20.5 100.5 L10.5 100.5" clip-path="url(#clipPath22)"
/><path fill="none" d="M10.5 100.5 L10.5 10.5" clip-path="url(#clipPath22)"
/><path fill="none" d="M10.5 10.5 L20.5 10.5" clip-path="url(#clipPath22)"
/></g
></g
></svg
>

After

Width:  |  Height:  |  Size: 33 KiB