@stellar-broker/client 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +160 -109
- package/jest.config.cjs +4 -0
- package/lib/stellarbroker.js +1 -1
- package/lib/stellarbroker.js.map +1 -1
- package/package.json +14 -12
- package/src/asset.js +51 -47
- package/src/authorization.js +65 -0
- package/src/client.js +353 -369
- package/src/errors.js +55 -53
- package/src/index.d.ts +95 -25
- package/src/index.js +4 -3
- package/src/mediator.js +309 -0
- package/src/quote-request.js +56 -60
- package/src/tx-processor.js +133 -161
package/src/client.js
CHANGED
|
@@ -1,369 +1,353 @@
|
|
|
1
|
-
import {Networks,
|
|
2
|
-
import errors from './errors.js'
|
|
3
|
-
import {buildEvent} from './events.js'
|
|
4
|
-
import {validateQuoteRequest} from './quote-request.js'
|
|
5
|
-
import {processTxRequest} from './tx-processor.js'
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
this.
|
|
14
|
-
this.
|
|
15
|
-
this.
|
|
16
|
-
if (!params.account || !StrKey.isValidEd25519PublicKey(params.account))
|
|
17
|
-
throw errors.invalidQuoteParam('account', 'Invalid trader account address: ' + (!params.account ? 'missing' : params.account))
|
|
18
|
-
this.trader = params.account
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
*
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
*
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
*
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
*
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
*
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
this.socket.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
sold: raw.sold,
|
|
174
|
-
bought: raw.bought
|
|
175
|
-
}, '
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
this.
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
* @
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
* @
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
* @
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
* @typedef {object} SwapQuoteResult
|
|
355
|
-
* @property {string} sellingAsset
|
|
356
|
-
* @property {string} buyingAsset
|
|
357
|
-
* @property {number} slippageTolerance
|
|
358
|
-
* @property {string} destination
|
|
359
|
-
* @property {number} ledger
|
|
360
|
-
* @property {string} [sellingAmount]
|
|
361
|
-
* @property {string} [estimatedBuyingAmount]
|
|
362
|
-
* @property {string} [buyingAmount]
|
|
363
|
-
* @property {string} [estimatedSellingAmount]
|
|
364
|
-
* @property {{selling: string, buying: string, path: string[]}} [directTrade]
|
|
365
|
-
*/
|
|
366
|
-
|
|
367
|
-
/**
|
|
368
|
-
* @typedef {function(TransactionI|Buffer):Promise<TransactionI|Buffer>} ClientAuthorizationCallback
|
|
369
|
-
*/
|
|
1
|
+
import {Networks, StrKey} from '@stellar/stellar-sdk'
|
|
2
|
+
import errors from './errors.js'
|
|
3
|
+
import {buildEvent} from './events.js'
|
|
4
|
+
import {validateQuoteRequest} from './quote-request.js'
|
|
5
|
+
import {processTxRequest} from './tx-processor.js'
|
|
6
|
+
import {AuthorizationWrapper} from './authorization.js'
|
|
7
|
+
|
|
8
|
+
export default class StellarBrokerClient {
|
|
9
|
+
/**
|
|
10
|
+
* @param {ClientInitializationParams} params
|
|
11
|
+
*/
|
|
12
|
+
constructor(params) {
|
|
13
|
+
this.partnerKey = params.partnerKey
|
|
14
|
+
this.emitter = new EventTarget()
|
|
15
|
+
this.network = Networks.PUBLIC
|
|
16
|
+
if (!params.account || !StrKey.isValidEd25519PublicKey(params.account))
|
|
17
|
+
throw errors.invalidQuoteParam('account', 'Invalid trader account address: ' + (!params.account ? 'missing' : params.account))
|
|
18
|
+
this.trader = params.account
|
|
19
|
+
this.authorization = new AuthorizationWrapper(params.authorization)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @type {string}
|
|
24
|
+
* @private
|
|
25
|
+
*/
|
|
26
|
+
uid
|
|
27
|
+
/**
|
|
28
|
+
* @type {ClientStatus}
|
|
29
|
+
* @readonly
|
|
30
|
+
*/
|
|
31
|
+
status = 'disconnected'
|
|
32
|
+
/**
|
|
33
|
+
* @type {WebSocket}
|
|
34
|
+
* @private
|
|
35
|
+
*/
|
|
36
|
+
socket
|
|
37
|
+
/**
|
|
38
|
+
* @type {EventTarget}
|
|
39
|
+
* @private
|
|
40
|
+
*/
|
|
41
|
+
emitter
|
|
42
|
+
/**
|
|
43
|
+
* @type {string}
|
|
44
|
+
* @private
|
|
45
|
+
*/
|
|
46
|
+
origin = 'https://api.stellar.broker'
|
|
47
|
+
/**
|
|
48
|
+
* Stellar network passphrase
|
|
49
|
+
* @type {string}
|
|
50
|
+
* @readonly
|
|
51
|
+
*/
|
|
52
|
+
network = ''
|
|
53
|
+
/**
|
|
54
|
+
* Last quote request submitted by the client
|
|
55
|
+
* @type {SwapQuoteParams}
|
|
56
|
+
* @readonly
|
|
57
|
+
*/
|
|
58
|
+
quoteRequest
|
|
59
|
+
/**
|
|
60
|
+
* Last quote received from the sever
|
|
61
|
+
* @type {SwapQuoteResult}
|
|
62
|
+
* @readonly
|
|
63
|
+
*/
|
|
64
|
+
lastQuote
|
|
65
|
+
/**
|
|
66
|
+
* Current quote accepted for the trading
|
|
67
|
+
* @private
|
|
68
|
+
*/
|
|
69
|
+
tradeQuote
|
|
70
|
+
/**
|
|
71
|
+
* API key of the partner
|
|
72
|
+
* @type {string}
|
|
73
|
+
* @readonly
|
|
74
|
+
*/
|
|
75
|
+
partnerKey
|
|
76
|
+
/**
|
|
77
|
+
* Account secret key or authorization callback
|
|
78
|
+
* @type {AuthorizationWrapper}
|
|
79
|
+
* @private
|
|
80
|
+
*/
|
|
81
|
+
authorization
|
|
82
|
+
/**
|
|
83
|
+
* Trader account public key
|
|
84
|
+
* @type {string}
|
|
85
|
+
* @readonly
|
|
86
|
+
*/
|
|
87
|
+
trader
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Connect to the StellarBroker server
|
|
91
|
+
* @return {Promise<StellarBrokerClient>}
|
|
92
|
+
*/
|
|
93
|
+
connect() {
|
|
94
|
+
if (this.socket?.readyState === WebSocket.OPEN)
|
|
95
|
+
return Promise.resolve(this) //already opened
|
|
96
|
+
this.socket = new WebSocket(this.origin + '/ws?partner=' + encodeURIComponent(this.partnerKey))
|
|
97
|
+
this.socket.onmessage = this.processMessage.bind(this)
|
|
98
|
+
this.socket.onclose = () => {
|
|
99
|
+
if (this.status !== 'disconnected') {
|
|
100
|
+
this.status = 'disconnected'
|
|
101
|
+
this.notifyError(errors.notConnected())
|
|
102
|
+
}
|
|
103
|
+
console.log('Connection closed')
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
this.socket.onerror = e => console.error(e)
|
|
107
|
+
|
|
108
|
+
return new Promise((confirm, reject) => { //TODO: use 'once'
|
|
109
|
+
const expirationTimeout = setTimeout(() => reject(this), 2000) // 2s timeout
|
|
110
|
+
this.onSocketOpen = () => {
|
|
111
|
+
this.status = 'ready'
|
|
112
|
+
this.heartbeat()
|
|
113
|
+
this.onSocketOpen = undefined
|
|
114
|
+
clearTimeout(expirationTimeout)
|
|
115
|
+
confirm(this)
|
|
116
|
+
}
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Process incoming message
|
|
122
|
+
* @param message
|
|
123
|
+
* @private
|
|
124
|
+
*/
|
|
125
|
+
processMessage(message) {
|
|
126
|
+
const raw = JSON.parse(message.data)
|
|
127
|
+
switch (raw.type) {
|
|
128
|
+
case 'connected':
|
|
129
|
+
this.uid = raw.uid
|
|
130
|
+
if (this.onSocketOpen) {
|
|
131
|
+
this.onSocketOpen()
|
|
132
|
+
}
|
|
133
|
+
if (this.status === 'disconnected') {
|
|
134
|
+
this.status = 'ready'
|
|
135
|
+
}
|
|
136
|
+
break
|
|
137
|
+
case 'quote':
|
|
138
|
+
this.lastQuote = raw.quote
|
|
139
|
+
this.lastQuote.ts = new Date()
|
|
140
|
+
//send event to the client app
|
|
141
|
+
this.emitter.dispatchEvent(buildEvent('quote', this.lastQuote))
|
|
142
|
+
break
|
|
143
|
+
case 'paused':
|
|
144
|
+
//quotation paused due to inactivity
|
|
145
|
+
this.emitter.dispatchEvent(buildEvent('paused', {}))
|
|
146
|
+
break
|
|
147
|
+
case 'tx':
|
|
148
|
+
if (this.status !== 'trade') {
|
|
149
|
+
console.log('Received tx in non-trading state', this.status, raw)
|
|
150
|
+
return //skip unless trading is in progress
|
|
151
|
+
}
|
|
152
|
+
processTxRequest(this, raw)
|
|
153
|
+
.then(xdr => {
|
|
154
|
+
this.send({
|
|
155
|
+
type: 'tx',
|
|
156
|
+
hash: raw.hash,
|
|
157
|
+
xdr
|
|
158
|
+
})
|
|
159
|
+
})
|
|
160
|
+
.catch(e => this.notifyError(e))
|
|
161
|
+
break
|
|
162
|
+
case 'stop':
|
|
163
|
+
this.emitter.dispatchEvent(buildEvent('finished', {
|
|
164
|
+
status: raw.status,
|
|
165
|
+
sold: raw.sold,
|
|
166
|
+
bought: raw.bought
|
|
167
|
+
}, 'result'))
|
|
168
|
+
this.status = 'ready'
|
|
169
|
+
this.tradeQuote = undefined
|
|
170
|
+
break
|
|
171
|
+
case 'progress':
|
|
172
|
+
this.emitter.dispatchEvent(buildEvent('progress', {
|
|
173
|
+
sold: raw.sold,
|
|
174
|
+
bought: raw.bought
|
|
175
|
+
}, 'status'))
|
|
176
|
+
break
|
|
177
|
+
case 'ping':
|
|
178
|
+
if (raw.uid === this.uid) {
|
|
179
|
+
this.heartbeat()
|
|
180
|
+
this.send({type: 'pong', uid: this.uid})
|
|
181
|
+
}
|
|
182
|
+
break
|
|
183
|
+
case 'error':
|
|
184
|
+
this.stop()
|
|
185
|
+
this.notifyError(raw.error)
|
|
186
|
+
break
|
|
187
|
+
default:
|
|
188
|
+
console.log('Unknown message type: ' + raw.type)
|
|
189
|
+
break
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Request swap quote
|
|
195
|
+
* @param {SwapQuoteParams} params - Quote parameters
|
|
196
|
+
*/
|
|
197
|
+
quote(params) {
|
|
198
|
+
if (this.status === 'trade')
|
|
199
|
+
throw errors.tradeInProgress()
|
|
200
|
+
this.quoteRequest = validateQuoteRequest(params)
|
|
201
|
+
this.status = 'quote'
|
|
202
|
+
this.connect()
|
|
203
|
+
.then(() => {
|
|
204
|
+
this.status = 'quote'
|
|
205
|
+
this.send({
|
|
206
|
+
type: 'quote',
|
|
207
|
+
...this.quoteRequest
|
|
208
|
+
})
|
|
209
|
+
})
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Confirm current quote and start trading
|
|
214
|
+
*/
|
|
215
|
+
confirmQuote() {
|
|
216
|
+
if (this.status === 'disconnected')
|
|
217
|
+
throw errors.notConnected()
|
|
218
|
+
if (this.status === 'trade')
|
|
219
|
+
throw errors.tradeInProgress()
|
|
220
|
+
if (this.status !== 'quote' || !this.lastQuote)
|
|
221
|
+
throw errors.quoteNotSet()
|
|
222
|
+
if ((new Date() - this.lastQuote.ts) > 10_000) //do not allow stale quotes quoted more than 10s ago
|
|
223
|
+
throw errors.quoteExpired()
|
|
224
|
+
if (this.lastQuote.status !== 'success')
|
|
225
|
+
throw errors.quoteError(this.lastQuote.error || 'quote not available')
|
|
226
|
+
|
|
227
|
+
this.tradeQuote = this.lastQuote
|
|
228
|
+
this.send({
|
|
229
|
+
type: 'trade',
|
|
230
|
+
account: this.trader
|
|
231
|
+
})
|
|
232
|
+
this.status = 'trade'
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Stop quotation/trading
|
|
237
|
+
*/
|
|
238
|
+
stop() {
|
|
239
|
+
if (this.status !== 'trade' && this.status !== 'quote')
|
|
240
|
+
return
|
|
241
|
+
this.send({type: 'stop'})
|
|
242
|
+
this.tradeQuote = undefined
|
|
243
|
+
this.status = 'ready'
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* @param {{}} data
|
|
248
|
+
* @private
|
|
249
|
+
*/
|
|
250
|
+
send(data) {
|
|
251
|
+
this.socket.send(JSON.stringify(data))
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* @private
|
|
256
|
+
*/
|
|
257
|
+
heartbeat() {
|
|
258
|
+
clearTimeout(this.pingHandler)
|
|
259
|
+
this.pingHandler = setTimeout(() => {
|
|
260
|
+
console.warn('Lost connection with the server')
|
|
261
|
+
this.socket.close()
|
|
262
|
+
}, 7_000) // 7 seconds heartbeat timeout
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Add event listener
|
|
267
|
+
* @param {StellarBrokerClientEvent} type
|
|
268
|
+
* @param {function} callback
|
|
269
|
+
*/
|
|
270
|
+
on(type, callback) {
|
|
271
|
+
validateEventType(type)
|
|
272
|
+
this.emitter.addEventListener(type, callback)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Add event listener that will be executed once
|
|
277
|
+
* @param {StellarBrokerClientEvent} type
|
|
278
|
+
* @param {function} callback
|
|
279
|
+
*/
|
|
280
|
+
once(type, callback) {
|
|
281
|
+
validateEventType(type)
|
|
282
|
+
this.emitter.addEventListener(type, callback, {once: true})
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Remove event listener
|
|
287
|
+
* @param {StellarBrokerClientEvent} type
|
|
288
|
+
* @param {function} callback
|
|
289
|
+
*/
|
|
290
|
+
off(type, callback) {
|
|
291
|
+
validateEventType(type)
|
|
292
|
+
this.emitter.removeEventListener(type, callback)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Close underlying connection and finalize the client
|
|
297
|
+
*/
|
|
298
|
+
close() {
|
|
299
|
+
try {
|
|
300
|
+
//TODO: remove all attached event listeners
|
|
301
|
+
this.status = 'disconnected'
|
|
302
|
+
this.socket.close()
|
|
303
|
+
} catch (e) {
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* @param {Error} e
|
|
309
|
+
* @private
|
|
310
|
+
*/
|
|
311
|
+
notifyError(e) {
|
|
312
|
+
console.error(e)
|
|
313
|
+
try {
|
|
314
|
+
this.emitter.dispatchEvent(buildEvent('error', e instanceof Error ? e.message : e))
|
|
315
|
+
} catch (e) {
|
|
316
|
+
console.error(e)
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function validateEventType(type) {
|
|
322
|
+
if (!StellarBrokerEvents.includes(type))
|
|
323
|
+
throw errors.unsupportedEventType(type)
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export const StellarBrokerEvents = ['quote', 'paused', 'progress', 'finished', 'error']
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* @typedef {object} ClientInitializationParams
|
|
330
|
+
* @property {string} account - Trader account address
|
|
331
|
+
* @property {ClientAuthorizationParams} authorization - Authorization method, either account secret key or an authorization callback
|
|
332
|
+
* @property {string} [partnerKey] - Partner key
|
|
333
|
+
*/
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* @typedef {'disconnected'|'ready'|'quote'|'trade'} ClientStatus
|
|
337
|
+
*/
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* @typedef {'quote'|'paused'|'progress'|'finished'|'error'} StellarBrokerClientEvent
|
|
341
|
+
*/
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* @typedef {object} SwapQuoteResult
|
|
345
|
+
* @property {string} ts - Quote timestamp formatted as ISO date
|
|
346
|
+
* @property {string} sellingAsset - Asset to sell
|
|
347
|
+
* @property {string} buyingAsset - Asset to buy
|
|
348
|
+
* @property {number} slippageTolerance - Swap slippage tolerance
|
|
349
|
+
* @property {string} sellingAmount - Amount of the selling asset
|
|
350
|
+
* @property {string} [estimatedBuyingAmount] - Estimated amount of buyingAsset to receive
|
|
351
|
+
* @property {{selling: string, buying: string, path: string[]}} [directTrade] - Equivalent direct path_payment trade estimate
|
|
352
|
+
* @property {string} [error] - Error details from the server (for failed quotes)
|
|
353
|
+
*/
|