edge-currency-accountbased 0.7.72
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/CHANGELOG.md +713 -0
- package/LICENSE +29 -0
- package/README.md +63 -0
- package/index.js +3 -0
- package/lib/binance/bnbEngine.js +591 -0
- package/lib/binance/bnbInfo.js +43 -0
- package/lib/binance/bnbPlugin.js +168 -0
- package/lib/binance/bnbSchema.js +83 -0
- package/lib/binance/bnbTypes.js +39 -0
- package/lib/common/engine.js +918 -0
- package/lib/common/plugin.js +152 -0
- package/lib/common/schema.js +108 -0
- package/lib/common/types.js +85 -0
- package/lib/common/utils.js +378 -0
- package/lib/eos/eosEngine.js +1216 -0
- package/lib/eos/eosInfo.js +98 -0
- package/lib/eos/eosPlugin.js +314 -0
- package/lib/eos/eosSchema.js +190 -0
- package/lib/eos/eosTypes.js +88 -0
- package/lib/eos/telosInfo.js +94 -0
- package/lib/eos/waxInfo.js +95 -0
- package/lib/ethereum/etcInfo.js +121 -0
- package/lib/ethereum/ethEngine.js +832 -0
- package/lib/ethereum/ethInfo.js +1300 -0
- package/lib/ethereum/ethMiningFees.js +157 -0
- package/lib/ethereum/ethNetwork.js +2195 -0
- package/lib/ethereum/ethPlugin.js +377 -0
- package/lib/ethereum/ethSchema.js +61 -0
- package/lib/ethereum/ethTypes.js +461 -0
- package/lib/ethereum/ftminfo.js +102 -0
- package/lib/ethereum/rskInfo.js +101 -0
- package/lib/fio/fioConst.js +38 -0
- package/lib/fio/fioEngine.js +1250 -0
- package/lib/fio/fioError.js +38 -0
- package/lib/fio/fioInfo.js +72 -0
- package/lib/fio/fioPlugin.js +486 -0
- package/lib/fio/fioSchema.js +56 -0
- package/lib/index.js +44 -0
- package/lib/pluginError.js +32 -0
- package/lib/react-native/edge-currency-accountbased.js +239635 -0
- package/lib/react-native/edge-currency-accountbased.js.map +1 -0
- package/lib/react-native-io.js +41 -0
- package/lib/stellar/stellarEngine.js +563 -0
- package/lib/stellar/stellarInfo.js +37 -0
- package/lib/stellar/stellarPlugin.js +215 -0
- package/lib/stellar/stellarSchema.js +54 -0
- package/lib/stellar/stellarTypes.js +66 -0
- package/lib/tezos/tezosEngine.js +497 -0
- package/lib/tezos/tezosInfo.js +60 -0
- package/lib/tezos/tezosPlugin.js +174 -0
- package/lib/tezos/tezosTypes.js +110 -0
- package/lib/xrp/xrpEngine.js +583 -0
- package/lib/xrp/xrpInfo.js +47 -0
- package/lib/xrp/xrpPlugin.js +229 -0
- package/lib/xrp/xrpSchema.js +74 -0
- package/lib/xrp/xrpTypes.js +38 -0
- package/package.json +139 -0
- package/postinstall.sh +7 -0
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Created by paul on 7/7/17.
|
|
3
|
+
*/
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
import { bns } from 'biggystring'
|
|
7
|
+
import {
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
InsufficientFundsError,
|
|
13
|
+
NoAmountSpecifiedError
|
|
14
|
+
} from 'edge-core-js/types'
|
|
15
|
+
|
|
16
|
+
import { CurrencyEngine } from '../common/engine.js'
|
|
17
|
+
import { cleanTxLogs, getOtherParams, validateObject } from '../common/utils.js'
|
|
18
|
+
import {
|
|
19
|
+
PluginError,
|
|
20
|
+
pluginErrorCodes,
|
|
21
|
+
pluginErrorName
|
|
22
|
+
} from '../pluginError.js'
|
|
23
|
+
import { currencyInfo } from './xrpInfo.js'
|
|
24
|
+
import { XrpPlugin } from './xrpPlugin.js'
|
|
25
|
+
import {
|
|
26
|
+
XrpGetBalancesSchema,
|
|
27
|
+
XrpGetServerInfoSchema,
|
|
28
|
+
XrpGetTransactionsSchema
|
|
29
|
+
} from './xrpSchema.js'
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
const ADDRESS_POLL_MILLISECONDS = 10000
|
|
37
|
+
const BLOCKHEIGHT_POLL_MILLISECONDS = 15000
|
|
38
|
+
const TRANSACTION_POLL_MILLISECONDS = 3000
|
|
39
|
+
const ADDRESS_QUERY_LOOKBACK_BLOCKS = 30 * 60 // ~ one minute
|
|
40
|
+
|
|
41
|
+
const PRIMARY_CURRENCY = currencyInfo.currencyCode
|
|
42
|
+
const MAX_DESTINATION_TAG_LENGTH = 10
|
|
43
|
+
const MAX_DESTINATION_TAG_LIMIT = 4294967295
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
export class XrpEngine extends CurrencyEngine {
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
// callbacksSetup: boolean
|
|
66
|
+
|
|
67
|
+
constructor(
|
|
68
|
+
currencyPlugin,
|
|
69
|
+
walletInfo,
|
|
70
|
+
opts
|
|
71
|
+
) {
|
|
72
|
+
super(currencyPlugin, walletInfo, opts)
|
|
73
|
+
this.xrpPlugin = currencyPlugin
|
|
74
|
+
// this.callbacksSetup = false
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async multicastServers(func, ...params) {
|
|
78
|
+
let out = { result: '', server: '' }
|
|
79
|
+
switch (func) {
|
|
80
|
+
// Functions that should waterfall from top to low priority servers
|
|
81
|
+
case 'getFee':
|
|
82
|
+
case 'getServerInfo':
|
|
83
|
+
case 'getBalances':
|
|
84
|
+
case 'getTransactions':
|
|
85
|
+
case 'disconnect':
|
|
86
|
+
case 'submit':
|
|
87
|
+
case 'preparePayment':
|
|
88
|
+
case 'sign':
|
|
89
|
+
out = {
|
|
90
|
+
result: await this.xrpPlugin.rippleApi[func](...params),
|
|
91
|
+
server: this.xrpPlugin.rippleApi.serverName
|
|
92
|
+
}
|
|
93
|
+
break
|
|
94
|
+
}
|
|
95
|
+
this.log(`multicastServers ${func} ${out.server} won`)
|
|
96
|
+
return out.result
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Poll on the blockheight
|
|
100
|
+
async checkServerInfoInnerLoop() {
|
|
101
|
+
try {
|
|
102
|
+
const fee = await this.multicastServers('getFee')
|
|
103
|
+
if (typeof fee === 'string') {
|
|
104
|
+
this.otherData.recommendedFee = fee
|
|
105
|
+
this.walletLocalDataDirty = true
|
|
106
|
+
}
|
|
107
|
+
} catch (e) {
|
|
108
|
+
this.log.error(`Error fetching recommended fee: ${e}. Using default fee.`)
|
|
109
|
+
if (this.otherData.recommendedFee !== currencyInfo.defaultSettings.fee) {
|
|
110
|
+
this.otherData.recommendedFee = currencyInfo.defaultSettings.fee
|
|
111
|
+
this.walletLocalDataDirty = true
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
const jsonObj = await this.multicastServers('getServerInfo')
|
|
116
|
+
const valid = validateObject(jsonObj, XrpGetServerInfoSchema)
|
|
117
|
+
if (valid) {
|
|
118
|
+
const blockHeight = jsonObj.validatedLedger.ledgerVersion
|
|
119
|
+
this.log(`Got block height ${blockHeight}`)
|
|
120
|
+
if (this.walletLocalData.blockHeight !== blockHeight) {
|
|
121
|
+
this.checkDroppedTransactionsThrottled()
|
|
122
|
+
this.walletLocalData.blockHeight = blockHeight // Convert to decimal
|
|
123
|
+
this.walletLocalDataDirty = true
|
|
124
|
+
this.currencyEngineCallbacks.onBlockHeightChanged(
|
|
125
|
+
this.walletLocalData.blockHeight
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
this.log.error(
|
|
130
|
+
`Invalid data returned from rippleApi.getServerInfo ${JSON.stringify(
|
|
131
|
+
jsonObj
|
|
132
|
+
)}`
|
|
133
|
+
)
|
|
134
|
+
}
|
|
135
|
+
} catch (err) {
|
|
136
|
+
this.log.error(`Error fetching height: ${err}`)
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
processRippleTransaction(tx) {
|
|
141
|
+
const ourReceiveAddresses = []
|
|
142
|
+
|
|
143
|
+
const balanceChanges =
|
|
144
|
+
tx.outcome.balanceChanges[this.walletLocalData.publicKey]
|
|
145
|
+
if (balanceChanges) {
|
|
146
|
+
for (const bc of balanceChanges) {
|
|
147
|
+
const currencyCode = bc.currency
|
|
148
|
+
const date = Date.parse(tx.outcome.timestamp) / 1000
|
|
149
|
+
const blockHeight =
|
|
150
|
+
tx.outcome.ledgerVersion > 0 ? tx.outcome.ledgerVersion : 0
|
|
151
|
+
const exchangeAmount = bc.value
|
|
152
|
+
if (exchangeAmount.slice(0, 1) !== '-') {
|
|
153
|
+
ourReceiveAddresses.push(this.walletLocalData.publicKey)
|
|
154
|
+
}
|
|
155
|
+
const nativeAmount = bns.mul(exchangeAmount, '1000000')
|
|
156
|
+
let networkFee
|
|
157
|
+
let parentNetworkFee
|
|
158
|
+
if (currencyCode === PRIMARY_CURRENCY) {
|
|
159
|
+
networkFee = bns.mul(tx.outcome.fee, '1000000')
|
|
160
|
+
} else {
|
|
161
|
+
networkFee = '0'
|
|
162
|
+
parentNetworkFee = bns.mul(tx.outcome.fee, '1000000')
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const edgeTransaction = {
|
|
166
|
+
txid: tx.id.toLowerCase(),
|
|
167
|
+
date,
|
|
168
|
+
currencyCode,
|
|
169
|
+
blockHeight,
|
|
170
|
+
nativeAmount,
|
|
171
|
+
networkFee,
|
|
172
|
+
parentNetworkFee,
|
|
173
|
+
ourReceiveAddresses,
|
|
174
|
+
signedTx: '',
|
|
175
|
+
otherParams: {}
|
|
176
|
+
}
|
|
177
|
+
this.addTransaction(currencyCode, edgeTransaction)
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async checkTransactionsInnerLoop() {
|
|
183
|
+
const blockHeight = this.walletLocalData.blockHeight
|
|
184
|
+
const address = this.walletLocalData.publicKey
|
|
185
|
+
let startBlock = 0
|
|
186
|
+
if (
|
|
187
|
+
this.walletLocalData.lastAddressQueryHeight >
|
|
188
|
+
ADDRESS_QUERY_LOOKBACK_BLOCKS
|
|
189
|
+
) {
|
|
190
|
+
// Only query for transactions as far back as ADDRESS_QUERY_LOOKBACK_BLOCKS from the last time we queried transactions
|
|
191
|
+
startBlock =
|
|
192
|
+
this.walletLocalData.lastAddressQueryHeight -
|
|
193
|
+
ADDRESS_QUERY_LOOKBACK_BLOCKS
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
let options
|
|
198
|
+
if (startBlock > ADDRESS_QUERY_LOOKBACK_BLOCKS) {
|
|
199
|
+
options = { minLedgerVersion: startBlock }
|
|
200
|
+
}
|
|
201
|
+
const transactions = await this.multicastServers(
|
|
202
|
+
'getTransactions',
|
|
203
|
+
address,
|
|
204
|
+
options
|
|
205
|
+
)
|
|
206
|
+
const valid = validateObject(transactions, XrpGetTransactionsSchema)
|
|
207
|
+
if (valid) {
|
|
208
|
+
this.log(
|
|
209
|
+
`Fetched transactions count: ${transactions.length} startBlock:${startBlock}`
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
// Get transactions
|
|
213
|
+
// Iterate over transactions in address
|
|
214
|
+
for (let i = 0; i < transactions.length; i++) {
|
|
215
|
+
const tx = transactions[i]
|
|
216
|
+
this.processRippleTransaction(tx)
|
|
217
|
+
}
|
|
218
|
+
if (this.transactionsChangedArray.length > 0) {
|
|
219
|
+
this.currencyEngineCallbacks.onTransactionsChanged(
|
|
220
|
+
this.transactionsChangedArray
|
|
221
|
+
)
|
|
222
|
+
this.transactionsChangedArray = []
|
|
223
|
+
}
|
|
224
|
+
this.walletLocalData.lastAddressQueryHeight = blockHeight
|
|
225
|
+
this.tokenCheckTransactionsStatus.XRP = 1
|
|
226
|
+
this.updateOnAddressesChecked()
|
|
227
|
+
} else {
|
|
228
|
+
this.log.error(
|
|
229
|
+
`Invalid data returned from rippleApi.getTransactions ${JSON.stringify(
|
|
230
|
+
transactions
|
|
231
|
+
)}`
|
|
232
|
+
)
|
|
233
|
+
}
|
|
234
|
+
} catch (e) {
|
|
235
|
+
this.log.error(`Error fetching transactions: ${e}`)
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async checkUnconfirmedTransactionsFetch() {}
|
|
240
|
+
|
|
241
|
+
// Check all account balance and other relevant info
|
|
242
|
+
async checkAccountInnerLoop() {
|
|
243
|
+
const address = this.walletLocalData.publicKey
|
|
244
|
+
try {
|
|
245
|
+
const jsonObj = await this.multicastServers('getBalances', address)
|
|
246
|
+
const valid = validateObject(jsonObj, XrpGetBalancesSchema)
|
|
247
|
+
if (valid) {
|
|
248
|
+
for (const bal of jsonObj) {
|
|
249
|
+
const currencyCode = bal.currency
|
|
250
|
+
const exchangeAmount = bal.value
|
|
251
|
+
const nativeAmount = bns.mul(exchangeAmount, '1000000')
|
|
252
|
+
|
|
253
|
+
if (
|
|
254
|
+
typeof this.walletLocalData.totalBalances[currencyCode] ===
|
|
255
|
+
'undefined'
|
|
256
|
+
) {
|
|
257
|
+
this.walletLocalData.totalBalances[currencyCode] = '0'
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (
|
|
261
|
+
this.walletLocalData.totalBalances[currencyCode] !== nativeAmount
|
|
262
|
+
) {
|
|
263
|
+
this.walletLocalData.totalBalances[currencyCode] = nativeAmount
|
|
264
|
+
this.log.warn(`Updated ${currencyCode} balance ${nativeAmount}`)
|
|
265
|
+
this.currencyEngineCallbacks.onBalanceChanged(
|
|
266
|
+
currencyCode,
|
|
267
|
+
nativeAmount
|
|
268
|
+
)
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
this.tokenCheckBalanceStatus.XRP = 1
|
|
272
|
+
this.updateOnAddressesChecked()
|
|
273
|
+
} else {
|
|
274
|
+
this.log.error(
|
|
275
|
+
`Invalid data returned from rippleApi.getBalances ${JSON.stringify(
|
|
276
|
+
jsonObj
|
|
277
|
+
)}`
|
|
278
|
+
)
|
|
279
|
+
}
|
|
280
|
+
} catch (e) {
|
|
281
|
+
if (e.data) {
|
|
282
|
+
if (e.data.error === 'actNotFound' || e.data.error_code === 19) {
|
|
283
|
+
this.log.warn(
|
|
284
|
+
'Account not found. Probably not activated w/minimum XRP'
|
|
285
|
+
)
|
|
286
|
+
this.tokenCheckBalanceStatus.XRP = 1
|
|
287
|
+
this.updateOnAddressesChecked()
|
|
288
|
+
return
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
this.log.error(`Error fetching address info: ${e}`)
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
async clearBlockchainCache() {
|
|
296
|
+
await super.clearBlockchainCache()
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// ****************************************************************************
|
|
300
|
+
// Public methods
|
|
301
|
+
// ****************************************************************************
|
|
302
|
+
|
|
303
|
+
// setupCallbacks () {
|
|
304
|
+
// // Callbacks are persistent so only do once
|
|
305
|
+
// if (!this.callbacksSetup) {
|
|
306
|
+
// this.currencyPlugin.connectionPool.on('ledger', (ledger) => {
|
|
307
|
+
// this.log('Ledger A closed', ledger)
|
|
308
|
+
// })
|
|
309
|
+
// this.currencyPlugin.connectionPool.on('transaction', (tx) => {
|
|
310
|
+
// const valid = validateObject(tx, XrpOnTransactionSchema)
|
|
311
|
+
// if (valid) {
|
|
312
|
+
// if (
|
|
313
|
+
// tx.Data.transaction.Account.toLowerCase() === this.walletLocalData.publicKey.toLowerCase() ||
|
|
314
|
+
// tx.Data.transaction.Destination.toLowerCase() === this.walletLocalData.publicKey.toLowerCase()
|
|
315
|
+
// ) {
|
|
316
|
+
// this.checkTransactionsInnerLoop()
|
|
317
|
+
// }
|
|
318
|
+
// } else {
|
|
319
|
+
// this.log('Invalid data from connectionPool on Transaction')
|
|
320
|
+
// }
|
|
321
|
+
// })
|
|
322
|
+
// this.callbacksSetup = true
|
|
323
|
+
// }
|
|
324
|
+
// }
|
|
325
|
+
|
|
326
|
+
// joinPool () {
|
|
327
|
+
// this.setupCallbacks()
|
|
328
|
+
// this.currencyPlugin.connectionPool.subscribeAccount(this.walletLocalData.publicKey)
|
|
329
|
+
// if (isEmpty(this.currencyPlugin.connectionClients)) {
|
|
330
|
+
// for (const s of this.currencyInfo.defaultSettings.otherSettings.rippledServers) {
|
|
331
|
+
// this.currencyPlugin.connectionPool.addServer(s)
|
|
332
|
+
// }
|
|
333
|
+
// }
|
|
334
|
+
// this.currencyPlugin.connectionClients[this.walletId] = true
|
|
335
|
+
// }
|
|
336
|
+
|
|
337
|
+
// leavePool () {
|
|
338
|
+
// this.currencyPlugin.connectionPool.unsubscribeAccount(this.walletLocalData.publicKey)
|
|
339
|
+
// const t = this.currencyPlugin.connectionPool.getRanking()
|
|
340
|
+
// this.log(t)
|
|
341
|
+
// delete this.currencyPlugin.connectionClients[this.walletId]
|
|
342
|
+
// if (isEmpty(this.currencyPlugin.connectionClients)) {
|
|
343
|
+
// for (const s of this.currencyInfo.defaultSettings.otherSettings.rippledServers) {
|
|
344
|
+
// this.currencyPlugin.connectionPool.removeServer(s)
|
|
345
|
+
// }
|
|
346
|
+
// }
|
|
347
|
+
// }
|
|
348
|
+
async startEngine() {
|
|
349
|
+
this.engineOn = true
|
|
350
|
+
// this.joinPool()
|
|
351
|
+
// try {
|
|
352
|
+
// const result = await this.currencyPlugin.connectionPool.send({
|
|
353
|
+
// command: 'account_info',
|
|
354
|
+
// account: this.walletLocalData.publicKey
|
|
355
|
+
// }, {
|
|
356
|
+
// serverTimeout: 1500,
|
|
357
|
+
// overallTimeout: 10000
|
|
358
|
+
// })
|
|
359
|
+
// console.log(result)
|
|
360
|
+
// } catch (e) {
|
|
361
|
+
// console.log('Error', e.message)
|
|
362
|
+
// }
|
|
363
|
+
try {
|
|
364
|
+
await this.xrpPlugin.connectApi(this.walletId)
|
|
365
|
+
} catch (e) {
|
|
366
|
+
this.log.error(`Error connecting to server`, String(e))
|
|
367
|
+
setTimeout(() => {
|
|
368
|
+
if (this.engineOn) {
|
|
369
|
+
this.startEngine()
|
|
370
|
+
}
|
|
371
|
+
}, 10000)
|
|
372
|
+
return
|
|
373
|
+
}
|
|
374
|
+
this.addToLoop('checkServerInfoInnerLoop', BLOCKHEIGHT_POLL_MILLISECONDS)
|
|
375
|
+
this.addToLoop('checkAccountInnerLoop', ADDRESS_POLL_MILLISECONDS)
|
|
376
|
+
this.addToLoop('checkTransactionsInnerLoop', TRANSACTION_POLL_MILLISECONDS)
|
|
377
|
+
super.startEngine()
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
async killEngine() {
|
|
381
|
+
await super.killEngine()
|
|
382
|
+
await this.xrpPlugin.disconnectApi(this.walletId)
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
async resyncBlockchain() {
|
|
386
|
+
await this.killEngine()
|
|
387
|
+
await this.clearBlockchainCache()
|
|
388
|
+
await this.startEngine()
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
async makeSpend(edgeSpendInfoIn) {
|
|
392
|
+
const { edgeSpendInfo, currencyCode, nativeBalance, denom } =
|
|
393
|
+
super.makeSpend(edgeSpendInfoIn)
|
|
394
|
+
|
|
395
|
+
if (edgeSpendInfo.spendTargets.length !== 1) {
|
|
396
|
+
throw new Error('Error: only one output allowed')
|
|
397
|
+
}
|
|
398
|
+
const publicAddress = edgeSpendInfo.spendTargets[0].publicAddress
|
|
399
|
+
|
|
400
|
+
let nativeAmount = '0'
|
|
401
|
+
if (typeof edgeSpendInfo.spendTargets[0].nativeAmount === 'string') {
|
|
402
|
+
nativeAmount = edgeSpendInfo.spendTargets[0].nativeAmount
|
|
403
|
+
} else {
|
|
404
|
+
throw new Error('Error: no amount specified')
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (bns.eq(nativeAmount, '0')) {
|
|
408
|
+
throw new NoAmountSpecifiedError()
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const nativeNetworkFee = bns.mul(this.otherData.recommendedFee, '1000000')
|
|
412
|
+
|
|
413
|
+
if (currencyCode === PRIMARY_CURRENCY) {
|
|
414
|
+
const totalTxAmount = bns.add(nativeNetworkFee, nativeAmount)
|
|
415
|
+
const virtualTxAmount = bns.add(totalTxAmount, '20000000')
|
|
416
|
+
if (bns.gt(virtualTxAmount, nativeBalance)) {
|
|
417
|
+
throw new InsufficientFundsError()
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const exchangeAmount = bns.div(nativeAmount, denom.multiplier, 6)
|
|
422
|
+
let uniqueIdentifier
|
|
423
|
+
if (
|
|
424
|
+
edgeSpendInfo.spendTargets[0].otherParams &&
|
|
425
|
+
edgeSpendInfo.spendTargets[0].otherParams.uniqueIdentifier
|
|
426
|
+
) {
|
|
427
|
+
if (
|
|
428
|
+
typeof edgeSpendInfo.spendTargets[0].otherParams.uniqueIdentifier ===
|
|
429
|
+
'string'
|
|
430
|
+
) {
|
|
431
|
+
uniqueIdentifier = parseInt(
|
|
432
|
+
edgeSpendInfo.spendTargets[0].otherParams.uniqueIdentifier
|
|
433
|
+
)
|
|
434
|
+
} else {
|
|
435
|
+
throw new Error('Error invalid destinationtag')
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Destination Tag Checks
|
|
439
|
+
const destinationTag =
|
|
440
|
+
edgeSpendInfo.spendTargets[0].otherParams.uniqueIdentifier
|
|
441
|
+
|
|
442
|
+
if (Number.isNaN(parseInt(destinationTag))) {
|
|
443
|
+
throw new PluginError(
|
|
444
|
+
'Please enter a valid Destination Tag',
|
|
445
|
+
pluginErrorName.XRP_ERROR,
|
|
446
|
+
pluginErrorCodes[0],
|
|
447
|
+
currencyInfo.defaultSettings.errorCodes.UNIQUE_IDENTIFIER_FORMAT
|
|
448
|
+
)
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (destinationTag.length > MAX_DESTINATION_TAG_LENGTH) {
|
|
452
|
+
throw new PluginError(
|
|
453
|
+
'XRP Destination Tag must be 10 characters or less',
|
|
454
|
+
pluginErrorName.XRP_ERROR,
|
|
455
|
+
pluginErrorCodes[0],
|
|
456
|
+
currencyInfo.defaultSettings.errorCodes.UNIQUE_IDENTIFIER_EXCEEDS_LENGTH
|
|
457
|
+
)
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (destinationTag > MAX_DESTINATION_TAG_LIMIT) {
|
|
461
|
+
throw new PluginError(
|
|
462
|
+
'XRP Destination Tag is above its maximum limit',
|
|
463
|
+
pluginErrorName.XRP_ERROR,
|
|
464
|
+
pluginErrorCodes[0],
|
|
465
|
+
currencyInfo.defaultSettings.errorCodes.UNIQUE_IDENTIFIER_EXCEEDS_LIMIT
|
|
466
|
+
)
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
const payment = {
|
|
470
|
+
source: {
|
|
471
|
+
address: this.walletLocalData.publicKey,
|
|
472
|
+
maxAmount: {
|
|
473
|
+
value: exchangeAmount,
|
|
474
|
+
currency: currencyCode
|
|
475
|
+
}
|
|
476
|
+
},
|
|
477
|
+
destination: {
|
|
478
|
+
address: publicAddress,
|
|
479
|
+
amount: {
|
|
480
|
+
value: exchangeAmount,
|
|
481
|
+
currency: currencyCode
|
|
482
|
+
},
|
|
483
|
+
tag: uniqueIdentifier
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
let preparedTx = {}
|
|
488
|
+
let i = 6
|
|
489
|
+
while (true) {
|
|
490
|
+
i--
|
|
491
|
+
try {
|
|
492
|
+
preparedTx = await this.multicastServers(
|
|
493
|
+
'preparePayment',
|
|
494
|
+
this.walletLocalData.publicKey,
|
|
495
|
+
payment,
|
|
496
|
+
{ maxLedgerVersionOffset: 300, fee: this.otherData.recommendedFee }
|
|
497
|
+
)
|
|
498
|
+
break
|
|
499
|
+
} catch (err) {
|
|
500
|
+
if (typeof err.message === 'string' && i) {
|
|
501
|
+
if (err.message.includes('has too many decimal places')) {
|
|
502
|
+
// HACK: ripple-js seems to have a bug where this error is intermittently thrown for no reason.
|
|
503
|
+
// Just retrying seems to resolve it. -paulvp
|
|
504
|
+
this.log.warn(
|
|
505
|
+
'Got "too many decimal places" error. Retrying... ' + i.toString()
|
|
506
|
+
)
|
|
507
|
+
continue
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
this.log.error(`makeSpend Error ${err}`)
|
|
511
|
+
throw new Error('Error in preparePayment')
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
const otherParams = {
|
|
516
|
+
preparedTx
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
nativeAmount = bns.add(nativeAmount, nativeNetworkFee)
|
|
520
|
+
nativeAmount = '-' + nativeAmount
|
|
521
|
+
|
|
522
|
+
const edgeTransaction = {
|
|
523
|
+
txid: '', // txid
|
|
524
|
+
date: 0, // date
|
|
525
|
+
currencyCode, // currencyCode
|
|
526
|
+
blockHeight: 0, // blockHeight
|
|
527
|
+
nativeAmount, // nativeAmount
|
|
528
|
+
networkFee: nativeNetworkFee, // networkFee
|
|
529
|
+
ourReceiveAddresses: [], // ourReceiveAddresses
|
|
530
|
+
signedTx: '', // signedTx
|
|
531
|
+
otherParams
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
this.log.warn('Payment transaction prepared...')
|
|
535
|
+
return edgeTransaction
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
async signTx(edgeTransaction) {
|
|
539
|
+
const otherParams = getOtherParams(edgeTransaction)
|
|
540
|
+
|
|
541
|
+
// Do signing
|
|
542
|
+
const txJson = otherParams.preparedTx.txJSON
|
|
543
|
+
const privateKey = this.walletInfo.keys.rippleKey
|
|
544
|
+
|
|
545
|
+
const { signedTransaction, id } = await this.multicastServers(
|
|
546
|
+
'sign',
|
|
547
|
+
txJson,
|
|
548
|
+
privateKey
|
|
549
|
+
)
|
|
550
|
+
this.log.warn('Payment transaction signed...')
|
|
551
|
+
|
|
552
|
+
edgeTransaction.signedTx = signedTransaction
|
|
553
|
+
edgeTransaction.txid = id.toLowerCase()
|
|
554
|
+
edgeTransaction.date = Date.now() / 1000
|
|
555
|
+
|
|
556
|
+
this.log.warn(`signTx\n${cleanTxLogs(edgeTransaction)}`)
|
|
557
|
+
return edgeTransaction
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
async broadcastTx(
|
|
561
|
+
edgeTransaction
|
|
562
|
+
) {
|
|
563
|
+
await this.multicastServers('submit', edgeTransaction.signedTx)
|
|
564
|
+
this.log.warn(`SUCCESS broadcastTx\n${cleanTxLogs(edgeTransaction)}`)
|
|
565
|
+
return edgeTransaction
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
getDisplayPrivateSeed() {
|
|
569
|
+
if (this.walletInfo.keys && this.walletInfo.keys.rippleKey) {
|
|
570
|
+
return this.walletInfo.keys.rippleKey
|
|
571
|
+
}
|
|
572
|
+
return ''
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
getDisplayPublicSeed() {
|
|
576
|
+
if (this.walletInfo.keys && this.walletInfo.keys.publicKey) {
|
|
577
|
+
return this.walletInfo.keys.publicKey
|
|
578
|
+
}
|
|
579
|
+
return ''
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
export { CurrencyEngine }
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const otherSettings = {
|
|
9
|
+
rippledServers: [
|
|
10
|
+
'wss://s2.ripple.com',
|
|
11
|
+
'wss://rippled.xrptipbot.com',
|
|
12
|
+
'wss://s1.ripple.com'
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const defaultSettings = {
|
|
17
|
+
otherSettings,
|
|
18
|
+
fee: '0.00001',
|
|
19
|
+
errorCodes: {
|
|
20
|
+
UNIQUE_IDENTIFIER_EXCEEDS_LENGTH: 'UNIQUE_IDENTIFIER_EXCEEDS_LENGTH',
|
|
21
|
+
UNIQUE_IDENTIFIER_EXCEEDS_LIMIT: 'UNIQUE_IDENTIFIER_EXCEEDS_LIMIT',
|
|
22
|
+
UNIQUE_IDENTIFIER_FORMAT: 'UNIQUE_IDENTIFIER_FORMAT'
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const currencyInfo = {
|
|
27
|
+
// Basic currency information:
|
|
28
|
+
currencyCode: 'XRP',
|
|
29
|
+
displayName: 'XRP',
|
|
30
|
+
pluginId: 'ripple',
|
|
31
|
+
walletType: 'wallet:ripple',
|
|
32
|
+
|
|
33
|
+
defaultSettings,
|
|
34
|
+
|
|
35
|
+
addressExplorer: 'https://bithomp.com/explorer/%s',
|
|
36
|
+
transactionExplorer: 'https://bithomp.com/explorer/%s',
|
|
37
|
+
|
|
38
|
+
denominations: [
|
|
39
|
+
// An array of Objects of the possible denominations for this currency
|
|
40
|
+
{
|
|
41
|
+
name: 'XRP',
|
|
42
|
+
multiplier: '1000000',
|
|
43
|
+
symbol: 'X'
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
metaTokens: []
|
|
47
|
+
}
|