UNPKG

3.2 kBPlain TextView Raw
1import BigNumber from 'bignumber.js'
2import { AccountInfo } from '../types/accounts'
3import { BackendInstance, BackendServices } from '../types/backend'
4
5import { create as createLogger } from '../common/log'
6const log = createLogger('randomizer-backend')
7
8export interface RandomizerOptions {
9 spread: number
10 variation: number
11}
12
13/**
14 * Backend which charges no spread and trades everything one-to-one.
15 */
16export default class RandomizerBackend implements BackendInstance {
17 protected spread: number
18 protected variation: number
19 protected getInfo: (accountId: string) => AccountInfo | undefined
20
21 /**
22 * Constructor.
23 *
24 * @param {Integer} opts.spread The spread we will use to mark up the FX rates
25 */
26 constructor (opts: RandomizerOptions, api: BackendServices) {
27 this.spread = opts.spread || 0
28 this.variation = opts.variation || 0.1
29 this.getInfo = api.getInfo
30
31 // Variation should be in the range 0 to 1
32 this.variation = Math.min(Math.abs(this.variation), 1)
33
34 log.warn('(!!!) using the randomizer backend. variation=%s', this.variation)
35 }
36
37 /**
38 * Nothing to do since this backend is totally static.
39 */
40 async connect () {
41 // Nothing to do
42 }
43
44 /**
45 * Get a rate for the given parameters.
46 *
47 * The one-to-one backend applies an exchange of 1, however, it will subtract
48 * the spread if a spread is set in the configuration.
49 *
50 * @param sourceAccount The account ID of the previous party
51 * @param destinationAccount The account ID of the next hop party
52 */
53 async getRate (sourceAccount: string, destinationAccount: string) {
54 const sourceInfo = this.getInfo(sourceAccount)
55 const destinationInfo = this.getInfo(destinationAccount)
56
57 if (!sourceInfo) {
58 log.error('unable to fetch account info for source account. accountId=%s', sourceAccount)
59 throw new Error('unable to fetch account info for source account. accountId=' + sourceAccount)
60 }
61 if (!destinationInfo) {
62 log.error('unable to fetch account info for destination account. accountId=%s', destinationAccount)
63 throw new Error('unable to fetch account info for destination account. accountId=' + destinationAccount)
64 }
65
66 const scaleDiff = destinationInfo.assetScale - sourceInfo.assetScale
67
68 // Math.random returns a number in the range [0, 1), so
69 // note that Math.random() - 0.5 is NOT the same as
70 // 0.5 - Math.random()
71 //
72 // By using
73 const randomness = Math.max((0.5 - Math.random()) * this.variation * 2, -1).toFixed(5)
74
75 // The spread is subtracted from the rate when going in either direction,
76 // so that the DestinationAmount always ends up being slightly less than
77 // the (equivalent) SourceAmount -- regardless of which of the 2 is fixed:
78 //
79 // SourceAmount * (1 + Random - Spread) = DestinationAmount
80 //
81 const rate = new BigNumber(1).plus(randomness).minus(this.spread).shiftedBy(scaleDiff).toPrecision(15)
82
83 return Number(rate)
84 }
85
86 /**
87 * This method is called to allow statistics to be collected by the backend.
88 *
89 * The randomizer backend does not support this functionality.
90 */
91 submitPayment () {
92 return Promise.resolve()
93 }
94}