Aggregated XRP-USD price info on the XRP Ledger.
Tags: xrp, xrpl, oracles, blockchain
Published: 2021-01-28 20:19:19

How to get reliable price information (1 XRP = ?? USD) to XUMM, and offer the same information to other developers and platforms as well?

While working on [one](https://xrpl-labs.canny.io/xumm/p/show-current-exchange-rate-and-fiat-value-when-sendingrequesting-a-payment) of [our](https://xrpl-labs.canny.io/xumm/p/create-payment-request-with-preset-fiat-amount-producing-a-qr-code-for-the-equiv) most [requested](https://xrpl-labs.canny.io/xumm/p/show-balance-fiat-value-like) features to [add](https://github.com/XRPL-Labs/XUMM-Issue-Tracker/issues/257) to XUMM, we went through our options.

1. Simply let XUMM (the mobile app) fetch prices at one exchange. Bad idea: exchange API's are down / report old data every now and then, and rate limits apply.
2. Provide a backend, add cache, scrape prices from all over the place and serve that to XUMM users. Nice for XUMM users, but what about other XRPL apps & developers? Everybody will have to run code & hit the exchange / price feed backends.
3. The same as #2, but provide the data with a special (non-native-XRPL) command at xrpl.ws (for WebSocket and RPC connections). Bad idea, as that will take away the freedom of projects and developers to use other XRPL nodes for transaction information.

### Enter an "XRPL Oracle"

While we're not fond of using the XRP ledger (blockchain technology for reliable and fast payments) to persist data, we have to admit the XPR Ledger is really efficient doing exactly that. As we don't need real time price information (updating it once per minute is more than enough) we decided that -in this case- it would make sense to fetch, aggregate and filter data, then to publish it on the XRP Ledger using a 'Trust Line Limit'.

The reason we went with a Trust Line is that it's a 'Ledger Object': one can always fetch it with one call, no matter the available history at the XRP Ledger node one is connected to. For source data used (to verify the most recent price) we include the filtered exchange price data in a Memo Attached to the `TrustSet` transaction used to update the price.

## On ledger price (XRPUSD) data

Every minute our code publishes the latest XRPUSD price as the `LimitAmount` of a TrustLine from our "Oracle account": [rXUMMaPpZqPutoRszR29jtC8amWq3APkx](https://bithomp.com/explorer/rXUMMaPpZqPutoRszR29jtC8amWq3APkx).

A sample transaction used to set the most recent price (random moment, old data) [can be viewed here](https://hash.xrp.fans/22297E5976DD0993F5A9EE6BD8912626D3A20186593872749DB621E40B01D448).

To get the most recent XRPUSD price (on ledger), one can issue this command when connected to an XRP Ledger node.

```
{
  "command": "account_lines",
  "account": "rXUMMaPpZqPutoRszR29jtC8amWq3APkx"
}
```

#### Try it:
{% runkit %}
const WebSocket = require('ws')
const account = 'rXUMMaPpZqPutoRszR29jtC8amWq3APkx'
const ws = new WebSocket('wss://xrpl.ws')

ws.on('open', () => {
  ws.send(JSON.stringify({ command: 'account_lines', account }))  
})

ws.on('message', data => {
  const lines = JSON.parse(data).result.lines
  console.log('XRPUSD = ' + lines.filter(l => l.currency === 'USD')[0].limit)
  ws.close()
})

'Getting XRPL Price Info...'
{% endrunkit %}

When connecting with an XRP Ledger node using JSON RPC, this is an example HTTP POST body to retrieve the same information:

```
{
  "method": "account_lines",
  "params": [ { "account": "rXUMMaPpZqPutoRszR29jtC8amWq3APkx" } ]
}
```

#### Try it:
{% runkit %}
const fetch = require('node-fetch')
const account = 'rXUMMaPpZqPutoRszR29jtC8amWq3APkx'

;(async () => {
  const call = await fetch('https://xrpl.ws', {
    method: 'POST',
    body: JSON.stringify({
      method: 'account_lines',
      params: [ { account } ]
    })
  })
  const lines = (await call.json()).result.lines
  console.log('XRPUSD = ' + lines.filter(l => l.currency === 'USD')[0].limit)
})()
{% endrunkit %}


## On ledger source price data

Every minute, when we send the `TrustSet` transaction to update the `TrustLimit` (to contain the most recent price), we include a Memo to the transaction containing the prices per data source in CSV format:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/r2jd903d4pkxbx00o6sn.png)

This information can easily be retrieved by fetching the most recent transaction from our 'Oracle' account (using the `account_tx` command), and decoding the Memo information from HEX to UTF-8.

When you are a developer you even [subscribe to live price updates](https://xrpl.org/subscribe.html) by using the `subscribe` command, subscribing to our account. Every minute, the second we submit a new transaction with the latest price, your application will be notified over an existing WebSocket connection. Using only on-ledger, native XRP Ledger features.

## Obtaining the data

To get the most recent XRPUSD price, we fetch price information using exchange API's. We do this every minute, currently from:

- Binance
- Bitfinex
- Bitstamp
- Cryptowatch
- HitBTC
- Kraken

We call every exchange four times, with a three second interval. We filter out missing results, then calculate the median and standard deviation. All results off by at least one standard deviation are ignored, and the median of the resulting price information is used in a new `TrustSet` transaction.

## Source

The source code to fetch the price information can be found here: https://github.com/XRPL-Labs/XRP-Price-Aggregator

The source code to persist the price information can be found here: https://github.com/XRPL-Labs/XRPL-Persist-Price-Oracle

# FAQ's

#### So anyone can now fetch the XRPUSD rate - on ledger?

Yes. The data is max. 1 minute old, and can be found by checking the `account_lines` (USD TrustLine) of our account: `rXUMMaPpZqPutoRszR29jtC8amWq3APkx`

#### Isn't this expensive for you? Running this service & paying for the transaction fee to update the TrustLine every minute?

Nope. Not really. The VPS to run this service is $2.50 a month and the fee is: 60 * 24 * 30 * 10 / 1000000 = 0.432 XRP per month. (`minutes per hour` * `hours per day` * `days per month` * `drops fee per tx` / `drops per XRP`). We'll live. And as we rely on this information ourselves, even if the costs to run this service would go up we'd make it back in the future, after the commercialization of our products (eg. XUMM Pro).

---

<small><span>Photo by <a href="https://unsplash.com/@omarg247?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Omar Flores</a> on <a href="https://unsplash.com/s/photos/network?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></span></small>