forked from XRPLF/xrpl.js
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathapi.ts
279 lines (262 loc) · 9.97 KB
/
api.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
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
174
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
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
import * as _ from 'lodash'
import {EventEmitter} from 'events'
import {Connection, errors, validate} from './common'
import {
connect,
disconnect,
isConnected,
getServerInfo,
getFee,
getLedgerVersion,
formatLedgerClose
} from './server/server'
import getTransaction from './ledger/transaction'
import getTransactions from './ledger/transactions'
import getTrustlines from './ledger/trustlines'
import getBalances from './ledger/balances'
import getBalanceSheet from './ledger/balance-sheet'
import getPaths from './ledger/pathfind'
import getOrders from './ledger/orders'
import getOrderbook from './ledger/orderbook'
import getSettings from './ledger/settings'
import getAccountInfo from './ledger/accountinfo'
import getPaymentChannel from './ledger/payment-channel'
import preparePayment from './transaction/payment'
import prepareTrustline from './transaction/trustline'
import prepareOrder from './transaction/order'
import prepareOrderCancellation from './transaction/ordercancellation'
import prepareEscrowCreation from './transaction/escrow-creation'
import prepareEscrowExecution from './transaction/escrow-execution'
import prepareEscrowCancellation from './transaction/escrow-cancellation'
import preparePaymentChannelCreate from './transaction/payment-channel-create'
import preparePaymentChannelFund from './transaction/payment-channel-fund'
import preparePaymentChannelClaim from './transaction/payment-channel-claim'
import prepareCheckCreate from './transaction/check-create'
import prepareCheckCancel from './transaction/check-cancel'
import prepareCheckCash from './transaction/check-cash'
import prepareSettings from './transaction/settings'
import sign from './transaction/sign'
import combine from './transaction/combine'
import submit from './transaction/submit'
import {generateAddressAPI} from './offline/generate-address'
import computeLedgerHash from './offline/ledgerhash'
import signPaymentChannelClaim from './offline/sign-payment-channel-claim'
import verifyPaymentChannelClaim from './offline/verify-payment-channel-claim'
import getLedger from './ledger/ledger'
import {
AccountOffersRequest, AccountOffersResponse,
AccountInfoRequest, AccountInfoResponse,
AccountLinesRequest, AccountLinesResponse,
BookOffersRequest, BookOffersResponse,
GatewayBalancesRequest, GatewayBalancesResponse,
LedgerRequest, LedgerResponse,
LedgerEntryRequest, LedgerEntryResponse
} from './common/types/commands'
import RangeSet from './common/rangeset'
import * as ledgerUtils from './ledger/utils'
import * as schemaValidator from './common/schema-validator'
import {clamp} from './ledger/utils'
export type APIOptions = {
server?: string,
feeCushion?: number,
trace?: boolean,
proxy?: string,
timeout?: number
}
/**
* Get the response key / property name that contains the listed data for a
* command. This varies from command to command, but we need to know it to
* properly count across many requests.
*/
function getCollectKeyFromCommand(command: string): string|undefined {
switch (command) {
case 'account_offers':
case 'book_offers':
return 'offers'
case 'account_lines':
return 'lines'
default:
return undefined
}
}
// prevent access to non-validated ledger versions
export class RestrictedConnection extends Connection {
request(request: any, timeout?: number) {
const ledger_index = request.ledger_index
if (ledger_index !== undefined && ledger_index !== 'validated') {
if (!_.isNumber(ledger_index) || ledger_index > this._ledgerVersion) {
return Promise.reject(new errors.LedgerVersionError(
`ledgerVersion ${ledger_index} is greater than server\'s ` +
`most recent validated ledger: ${this._ledgerVersion}`))
}
}
return super.request(request, timeout)
}
}
class RippleAPI extends EventEmitter {
_feeCushion: number
connection: RestrictedConnection
// these are exposed only for use by unit tests; they are not part of the API.
static _PRIVATE = {
validate: validate,
RangeSet,
ledgerUtils,
schemaValidator
}
constructor(options: APIOptions = {}) {
super()
validate.apiOptions(options)
this._feeCushion = options.feeCushion || 1.2
const serverURL = options.server
if (serverURL !== undefined) {
this.connection = new RestrictedConnection(serverURL, options)
this.connection.on('ledgerClosed', message => {
this.emit('ledger', formatLedgerClose(message))
})
this.connection.on('error', (errorCode, errorMessage, data) => {
this.emit('error', errorCode, errorMessage, data)
})
this.connection.on('connected', () => {
this.emit('connected')
})
this.connection.on('disconnected', code => {
this.emit('disconnected', code)
})
} else {
// use null object pattern to provide better error message if user
// tries to call a method that requires a connection
this.connection = new RestrictedConnection(null, options)
}
}
/**
* Makes a simple request to the API with the given command and any
* additional request body parameters.
*
* NOTE: This command is under development and should not yet be relied
* on by external consumers.
*/
async _request(command: 'account_info', params: AccountInfoRequest):
Promise<AccountInfoResponse>
async _request(command: 'account_lines', params: AccountLinesRequest):
Promise<AccountLinesResponse>
async _request(command: 'account_offers', params: AccountOffersRequest):
Promise<AccountOffersResponse>
async _request(command: 'book_offers', params: BookOffersRequest):
Promise<BookOffersResponse>
async _request(command: 'gateway_balances', params: GatewayBalancesRequest):
Promise<GatewayBalancesResponse>
async _request(command: 'ledger', params: LedgerRequest):
Promise<LedgerResponse>
async _request(command: 'ledger_entry', params: LedgerEntryRequest):
Promise<LedgerEntryResponse>
async _request(command: string, params: any = {}) {
return this.connection.request({
...params,
command
})
}
/**
* Makes multiple paged requests to the API to return a given number of
* resources. __requestAll() will make multiple requests until the `limit`
* number of resources is reached (if no `limit` is provided, a single request
* will be made).
*
* If the command is unknown, an additional `collect` property is required to
* know which response key contains the array of resources.
*
* NOTE: This command is under development and should not yet be relied
* on by external consumers.
*/
async _requestAll(command: 'account_offers', params: AccountOffersRequest):
Promise<AccountOffersResponse[]>
async _requestAll(command: 'book_offers', params: BookOffersRequest):
Promise<BookOffersResponse[]>
async _requestAll(command: 'account_lines', params: AccountLinesRequest):
Promise<AccountLinesResponse[]>
async _requestAll(
command: string,
params: any = {},
options: {collect?: string} = {}): Promise<any[]> {
// The data under collection is keyed based on the command. Fail if command
// not recognized and collection key not provided.
const collectKey = options.collect || getCollectKeyFromCommand(command)
if (!collectKey) {
throw new errors.ValidationError(`no collect key for command ${command}`)
}
// If limit is not provided, fetches all data over multiple requests.
// NOTE: This may return much more than needed. Set limit when possible.
const countTo: number =
(params.limit !== undefined) ? params.limit : Infinity
let count: number = 0
let marker: string = params.marker
let lastBatchLength: number
const results = []
do {
const countRemaining = clamp(countTo - count, 10, 400)
const repeatProps = {
...params,
limit: countRemaining,
marker
}
// NOTE: We have to generalize the `this._request()` function signature
// here until we add support for unknown commands (since command is some
// unknown string).
const singleResult = await (<Function>this._request)(command, repeatProps)
const collectedData = singleResult[collectKey]
marker = singleResult.marker
results.push(singleResult)
// Make sure we handle when no data (not even an empty array) is returned.
const isExpectedFormat = Array.isArray(collectedData)
if (isExpectedFormat) {
count += collectedData.length
lastBatchLength = collectedData.length
} else {
lastBatchLength = 0
}
} while(!!marker && count < countTo && lastBatchLength !== 0)
return results
}
connect = connect
disconnect = disconnect
isConnected = isConnected
getServerInfo = getServerInfo
getFee = getFee
getLedgerVersion = getLedgerVersion
getTransaction = getTransaction
getTransactions = getTransactions
getTrustlines = getTrustlines
getBalances = getBalances
getBalanceSheet = getBalanceSheet
getPaths = getPaths
getOrders = getOrders
getOrderbook = getOrderbook
getSettings = getSettings
getAccountInfo = getAccountInfo
getPaymentChannel = getPaymentChannel
getLedger = getLedger
preparePayment = preparePayment
prepareTrustline = prepareTrustline
prepareOrder = prepareOrder
prepareOrderCancellation = prepareOrderCancellation
prepareEscrowCreation = prepareEscrowCreation
prepareEscrowExecution = prepareEscrowExecution
prepareEscrowCancellation = prepareEscrowCancellation
preparePaymentChannelCreate = preparePaymentChannelCreate
preparePaymentChannelFund = preparePaymentChannelFund
preparePaymentChannelClaim = preparePaymentChannelClaim
prepareCheckCreate = prepareCheckCreate
prepareCheckCash = prepareCheckCash
prepareCheckCancel = prepareCheckCancel
prepareSettings = prepareSettings
sign = sign
combine = combine
submit = submit
generateAddress = generateAddressAPI
computeLedgerHash = computeLedgerHash
signPaymentChannelClaim = signPaymentChannelClaim
verifyPaymentChannelClaim = verifyPaymentChannelClaim
errors = errors
}
export {
RippleAPI
}