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,918 @@
|
|
|
1
|
+
//
|
|
2
|
+
|
|
3
|
+
import { bns } from 'biggystring'
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
InsufficientFundsError,
|
|
22
|
+
SpendToSelfError
|
|
23
|
+
} from 'edge-core-js/types'
|
|
24
|
+
|
|
25
|
+
import { CurrencyPlugin } from './plugin.js'
|
|
26
|
+
import {
|
|
27
|
+
asCurrencyCodeOptions,
|
|
28
|
+
checkCustomToken,
|
|
29
|
+
checkEdgeSpendInfo
|
|
30
|
+
} from './schema.js'
|
|
31
|
+
import {
|
|
32
|
+
|
|
33
|
+
DATA_STORE_FILE,
|
|
34
|
+
TRANSACTION_STORE_FILE,
|
|
35
|
+
TXID_LIST_FILE,
|
|
36
|
+
TXID_MAP_FILE,
|
|
37
|
+
WalletLocalData
|
|
38
|
+
} from './types.js'
|
|
39
|
+
import { cleanTxLogs, getDenomInfo, normalizeAddress } from './utils.js'
|
|
40
|
+
|
|
41
|
+
const SAVE_DATASTORE_MILLISECONDS = 10000
|
|
42
|
+
const MAX_TRANSACTIONS = 1000
|
|
43
|
+
const DROPPED_TX_TIME_GAP = 3600 * 24 // 1 Day
|
|
44
|
+
|
|
45
|
+
export class CurrencyEngine {
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
// Each currency code can be a 0-1 value
|
|
53
|
+
// Each currency code can be a 0-1 value
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
// Maps txid to index of tx in
|
|
60
|
+
// Map of array of txids in chronological order
|
|
61
|
+
// Transactions that have changed and need to be added
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
constructor(
|
|
73
|
+
currencyPlugin,
|
|
74
|
+
walletInfo,
|
|
75
|
+
opts
|
|
76
|
+
) {
|
|
77
|
+
const currencyCode = currencyPlugin.currencyInfo.currencyCode
|
|
78
|
+
const { walletLocalDisklet, callbacks } = opts
|
|
79
|
+
|
|
80
|
+
this.currencyPlugin = currencyPlugin
|
|
81
|
+
this.io = currencyPlugin.io
|
|
82
|
+
this.log = opts.log
|
|
83
|
+
this.engineOn = false
|
|
84
|
+
this.addressesChecked = false
|
|
85
|
+
this.tokenCheckBalanceStatus = {}
|
|
86
|
+
this.tokenCheckTransactionsStatus = {}
|
|
87
|
+
this.walletLocalDataDirty = false
|
|
88
|
+
this.transactionsChangedArray = []
|
|
89
|
+
this.transactionList = {}
|
|
90
|
+
this.transactionListDirty = false
|
|
91
|
+
this.transactionsLoaded = false
|
|
92
|
+
this.txIdMap = {}
|
|
93
|
+
this.txIdList = {}
|
|
94
|
+
this.walletInfo = walletInfo
|
|
95
|
+
this.walletId = walletInfo.id ? `${walletInfo.id} - ` : ''
|
|
96
|
+
this.currencyInfo = currencyPlugin.currencyInfo
|
|
97
|
+
this.allTokens = currencyPlugin.currencyInfo.metaTokens.slice(0)
|
|
98
|
+
this.customTokens = []
|
|
99
|
+
this.timers = {}
|
|
100
|
+
|
|
101
|
+
this.transactionList[currencyCode] = []
|
|
102
|
+
this.txIdMap[currencyCode] = {}
|
|
103
|
+
this.txIdList[currencyCode] = []
|
|
104
|
+
|
|
105
|
+
if (opts.userSettings != null) {
|
|
106
|
+
this.currentSettings = opts.userSettings
|
|
107
|
+
} else {
|
|
108
|
+
this.currentSettings = this.currencyInfo.defaultSettings
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
this.currencyEngineCallbacks = callbacks
|
|
112
|
+
this.walletLocalDisklet = walletLocalDisklet
|
|
113
|
+
|
|
114
|
+
if (typeof this.walletInfo.keys.publicKey !== 'string') {
|
|
115
|
+
this.walletInfo.keys.publicKey = walletInfo.keys.publicKey
|
|
116
|
+
}
|
|
117
|
+
this.log(
|
|
118
|
+
`Created Wallet Type ${this.walletInfo.type} for Currency Plugin ${this.currencyInfo.pluginId}`
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
isSpendTx(edgeTransaction) {
|
|
123
|
+
if (edgeTransaction.nativeAmount) {
|
|
124
|
+
if (edgeTransaction.nativeAmount.slice(0, 1) === '-') {
|
|
125
|
+
return true
|
|
126
|
+
}
|
|
127
|
+
if (bns.gt(edgeTransaction.nativeAmount, '0')) {
|
|
128
|
+
return false
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
let out = true
|
|
132
|
+
if (
|
|
133
|
+
edgeTransaction.ourReceiveAddresses &&
|
|
134
|
+
edgeTransaction.ourReceiveAddresses.length
|
|
135
|
+
) {
|
|
136
|
+
for (const addr of edgeTransaction.ourReceiveAddresses) {
|
|
137
|
+
if (addr === this.walletLocalData.publicKey) {
|
|
138
|
+
out = false
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return out
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async loadTransactions() {
|
|
146
|
+
if (this.transactionsLoaded) {
|
|
147
|
+
this.log('Transactions already loaded')
|
|
148
|
+
return
|
|
149
|
+
}
|
|
150
|
+
this.transactionsLoaded = true
|
|
151
|
+
|
|
152
|
+
const disklet = this.walletLocalDisklet
|
|
153
|
+
let txIdList
|
|
154
|
+
let txIdMap
|
|
155
|
+
let transactionList
|
|
156
|
+
try {
|
|
157
|
+
const result = await disklet.getText(TXID_LIST_FILE)
|
|
158
|
+
txIdList = JSON.parse(result)
|
|
159
|
+
} catch (e) {
|
|
160
|
+
this.log('Could not load txidList file. Failure is ok on new device')
|
|
161
|
+
await disklet.setText(TXID_LIST_FILE, JSON.stringify(this.txIdList))
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
const result = await disklet.getText(TXID_MAP_FILE)
|
|
165
|
+
txIdMap = JSON.parse(result)
|
|
166
|
+
} catch (e) {
|
|
167
|
+
this.log('Could not load txidMap file. Failure is ok on new device')
|
|
168
|
+
await disklet.setText(TXID_MAP_FILE, JSON.stringify(this.txIdMap))
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
const result = await disklet.getText(TRANSACTION_STORE_FILE)
|
|
173
|
+
transactionList = JSON.parse(result)
|
|
174
|
+
} catch (e) {
|
|
175
|
+
if (e.code === 'ENOENT') {
|
|
176
|
+
this.log(
|
|
177
|
+
'Could not load transactionList file. Failure is ok on new device'
|
|
178
|
+
)
|
|
179
|
+
await disklet.setText(
|
|
180
|
+
TRANSACTION_STORE_FILE,
|
|
181
|
+
JSON.stringify(this.transactionList)
|
|
182
|
+
)
|
|
183
|
+
} else {
|
|
184
|
+
this.log.crash(e, this.walletLocalData)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
let isEmptyTransactions = true
|
|
189
|
+
for (const cc of Object.keys(this.transactionList)) {
|
|
190
|
+
if (this.transactionList[cc] && this.transactionList[cc].length > 0) {
|
|
191
|
+
isEmptyTransactions = false
|
|
192
|
+
break
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
for (const cc of Object.keys(this.transactionList)) {
|
|
197
|
+
if (
|
|
198
|
+
this.transactionList[cc] !== undefined &&
|
|
199
|
+
this.transactionList[cc].length > 0
|
|
200
|
+
) {
|
|
201
|
+
if (
|
|
202
|
+
transactionList !== undefined &&
|
|
203
|
+
transactionList[cc] !== undefined &&
|
|
204
|
+
transactionList[cc].length < this.transactionList[cc].length
|
|
205
|
+
) {
|
|
206
|
+
this.log.crash(
|
|
207
|
+
new Error(
|
|
208
|
+
`Transaction list length mismatch for ${cc}: on disk ${transactionList[cc].length} txs < in memory ${this.transactionList[cc].length} txs`
|
|
209
|
+
),
|
|
210
|
+
{
|
|
211
|
+
...transactionList,
|
|
212
|
+
...this.transactionList,
|
|
213
|
+
...this.walletLocalData
|
|
214
|
+
}
|
|
215
|
+
)
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (isEmptyTransactions) {
|
|
221
|
+
// Easy, just copy everything over
|
|
222
|
+
this.transactionList = transactionList || this.transactionList
|
|
223
|
+
this.txIdList = txIdList || this.txIdList
|
|
224
|
+
this.txIdMap = txIdMap || this.txIdMap
|
|
225
|
+
} else if (transactionList != null) {
|
|
226
|
+
// Manually add transactions via addTransaction()
|
|
227
|
+
for (const cc of Object.keys(transactionList)) {
|
|
228
|
+
for (const edgeTransaction of transactionList[cc]) {
|
|
229
|
+
this.addTransaction(cc, edgeTransaction)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
for (const currencyCode in this.transactionList) {
|
|
234
|
+
this.walletLocalData.numTransactions[currencyCode] =
|
|
235
|
+
this.transactionList[currencyCode].length
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async loadEngine(
|
|
240
|
+
plugin,
|
|
241
|
+
walletInfo,
|
|
242
|
+
opts
|
|
243
|
+
) {
|
|
244
|
+
if (!this.walletInfo.keys.publicKey) {
|
|
245
|
+
const pubKeys = await this.currencyPlugin.derivePublicKey(this.walletInfo)
|
|
246
|
+
this.walletInfo.keys.publicKey = pubKeys.publicKey
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const disklet = this.walletLocalDisklet
|
|
250
|
+
try {
|
|
251
|
+
const result = await disklet.getText(DATA_STORE_FILE)
|
|
252
|
+
this.walletLocalData = new WalletLocalData(
|
|
253
|
+
result,
|
|
254
|
+
this.currencyInfo.currencyCode
|
|
255
|
+
)
|
|
256
|
+
this.walletLocalData.publicKey = this.walletInfo.keys.publicKey
|
|
257
|
+
} catch (err) {
|
|
258
|
+
try {
|
|
259
|
+
this.log('No walletLocalData setup yet: Failure is ok')
|
|
260
|
+
this.walletLocalData = new WalletLocalData(
|
|
261
|
+
null,
|
|
262
|
+
this.currencyInfo.currencyCode
|
|
263
|
+
)
|
|
264
|
+
this.walletLocalData.publicKey = this.walletInfo.keys.publicKey
|
|
265
|
+
await disklet.setText(
|
|
266
|
+
DATA_STORE_FILE,
|
|
267
|
+
JSON.stringify(this.walletLocalData)
|
|
268
|
+
)
|
|
269
|
+
} catch (e) {
|
|
270
|
+
this.log.error(
|
|
271
|
+
'Error writing to localDataStore. Engine not started:' + err
|
|
272
|
+
)
|
|
273
|
+
throw e
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
for (const token of this.walletLocalData.enabledTokens) {
|
|
278
|
+
this.tokenCheckBalanceStatus[token] = 0
|
|
279
|
+
this.tokenCheckTransactionsStatus[token] = 0
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Initialize walletLocalData.lastTransactionQueryHeight for
|
|
283
|
+
// backwards-compatibility
|
|
284
|
+
if (!this.walletLocalData.lastTransactionQueryHeight) {
|
|
285
|
+
for (const token of this.walletLocalData.enabledTokens) {
|
|
286
|
+
this.walletLocalData.lastTransactionQueryHeight[token] =
|
|
287
|
+
this.walletLocalData.lastAddressQueryHeight || 0
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
this.doInitialBalanceCallback()
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
findTransaction(currencyCode, txid) {
|
|
294
|
+
if (this.txIdMap[currencyCode]) {
|
|
295
|
+
const index = this.txIdMap[currencyCode][txid]
|
|
296
|
+
if (typeof index === 'number') {
|
|
297
|
+
return index
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return -1
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
sortTxByDate(a, b) {
|
|
304
|
+
return b.date - a.date
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Add or update tx in transactionList
|
|
308
|
+
addTransaction(
|
|
309
|
+
currencyCode,
|
|
310
|
+
edgeTransaction,
|
|
311
|
+
lastSeenTime
|
|
312
|
+
) {
|
|
313
|
+
this.log('executing addTransaction: ', edgeTransaction.txid)
|
|
314
|
+
// set otherParams if not already set
|
|
315
|
+
if (!edgeTransaction.otherParams) {
|
|
316
|
+
edgeTransaction.otherParams = {}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (edgeTransaction.blockHeight < 1) {
|
|
320
|
+
edgeTransaction.otherParams.lastSeenTime =
|
|
321
|
+
lastSeenTime || Math.round(Date.now() / 1000)
|
|
322
|
+
}
|
|
323
|
+
const txid = normalizeAddress(edgeTransaction.txid)
|
|
324
|
+
const idx = this.findTransaction(currencyCode, txid)
|
|
325
|
+
// if blockHeight of transaction is higher than known blockHeight
|
|
326
|
+
// then set transaction's blockHeight as the highest known blockHeight
|
|
327
|
+
if (edgeTransaction.blockHeight > this.currencyPlugin.highestTxHeight) {
|
|
328
|
+
this.currencyPlugin.highestTxHeight = edgeTransaction.blockHeight
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
let needsReSort = false
|
|
332
|
+
// if transaction doesn't exist in database
|
|
333
|
+
if (idx === -1) {
|
|
334
|
+
if (
|
|
335
|
+
// if unconfirmed spend then increment # uncofirmed spend TX's
|
|
336
|
+
this.isSpendTx(edgeTransaction) &&
|
|
337
|
+
edgeTransaction.blockHeight === 0
|
|
338
|
+
) {
|
|
339
|
+
this.walletLocalData.numUnconfirmedSpendTxs++
|
|
340
|
+
this.walletLocalDataDirty = true
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
needsReSort = true
|
|
344
|
+
// if currency's transactionList is uninitialized then initialize
|
|
345
|
+
if (typeof this.transactionList[currencyCode] === 'undefined') {
|
|
346
|
+
this.transactionList[currencyCode] = []
|
|
347
|
+
} else if (
|
|
348
|
+
this.transactionList[currencyCode].length >= MAX_TRANSACTIONS
|
|
349
|
+
) {
|
|
350
|
+
return
|
|
351
|
+
}
|
|
352
|
+
// add transaction to list of tx's, and array of changed transactions
|
|
353
|
+
this.transactionList[currencyCode].push(edgeTransaction)
|
|
354
|
+
this.walletLocalData.numTransactions[currencyCode] =
|
|
355
|
+
this.transactionList[currencyCode].length
|
|
356
|
+
this.walletLocalDataDirty = true
|
|
357
|
+
|
|
358
|
+
this.transactionListDirty = true
|
|
359
|
+
this.transactionsChangedArray.push(edgeTransaction)
|
|
360
|
+
this.log.warn('addTransaction new tx: ', edgeTransaction.txid)
|
|
361
|
+
} else {
|
|
362
|
+
// Already have this tx in the database. See if anything changed
|
|
363
|
+
const transactionsArray = this.transactionList[currencyCode]
|
|
364
|
+
const edgeTx = transactionsArray[idx]
|
|
365
|
+
|
|
366
|
+
const { otherParams: otherParamsOld = {} } = edgeTx
|
|
367
|
+
const { otherParams: otherParamsNew = {} } = edgeTransaction
|
|
368
|
+
if (
|
|
369
|
+
// if something in the transaction has changed?
|
|
370
|
+
edgeTx.blockHeight < edgeTransaction.blockHeight ||
|
|
371
|
+
(edgeTx.blockHeight === 0 && edgeTransaction.blockHeight < 0) ||
|
|
372
|
+
(edgeTx.blockHeight === edgeTransaction.blockHeight &&
|
|
373
|
+
(edgeTx.networkFee !== edgeTransaction.networkFee ||
|
|
374
|
+
edgeTx.nativeAmount !== edgeTransaction.nativeAmount ||
|
|
375
|
+
otherParamsOld.lastSeenTime !== otherParamsNew.lastSeenTime ||
|
|
376
|
+
edgeTx.date !== edgeTransaction.date))
|
|
377
|
+
) {
|
|
378
|
+
// If a spend transaction goes from unconfirmed to dropped or confirmed,
|
|
379
|
+
// decrement numUnconfirmedSpendTxs
|
|
380
|
+
if (
|
|
381
|
+
this.isSpendTx(edgeTransaction) &&
|
|
382
|
+
edgeTransaction.blockHeight !== 0 &&
|
|
383
|
+
edgeTx.blockHeight === 0
|
|
384
|
+
) {
|
|
385
|
+
this.walletLocalData.numUnconfirmedSpendTxs--
|
|
386
|
+
}
|
|
387
|
+
if (edgeTx.date !== edgeTransaction.date) {
|
|
388
|
+
needsReSort = true
|
|
389
|
+
}
|
|
390
|
+
this.log.warn(
|
|
391
|
+
`addTransaction: update ${edgeTransaction.txid} height:${edgeTransaction.blockHeight}`
|
|
392
|
+
)
|
|
393
|
+
this.walletLocalDataDirty = true
|
|
394
|
+
this.updateTransaction(currencyCode, edgeTransaction, idx)
|
|
395
|
+
} else {
|
|
396
|
+
// this.log(sprintf('Old transaction. No Update: %s', tx.hash))
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (needsReSort) {
|
|
400
|
+
this.sortTransactions(currencyCode)
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
sortTransactions(currencyCode) {
|
|
405
|
+
// Sort
|
|
406
|
+
this.transactionList[currencyCode].sort(this.sortTxByDate)
|
|
407
|
+
// Add to txidMap
|
|
408
|
+
const txIdList = []
|
|
409
|
+
let i = 0
|
|
410
|
+
for (const tx of this.transactionList[currencyCode]) {
|
|
411
|
+
if (!this.txIdMap[currencyCode]) {
|
|
412
|
+
this.txIdMap[currencyCode] = {}
|
|
413
|
+
}
|
|
414
|
+
this.txIdMap[currencyCode][normalizeAddress(tx.txid)] = i
|
|
415
|
+
txIdList.push(normalizeAddress(tx.txid))
|
|
416
|
+
i++
|
|
417
|
+
}
|
|
418
|
+
this.txIdList[currencyCode] = txIdList
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
checkDroppedTransactionsThrottled() {
|
|
422
|
+
const now = Date.now() / 1000
|
|
423
|
+
if (
|
|
424
|
+
now - this.walletLocalData.lastCheckedTxsDropped >
|
|
425
|
+
DROPPED_TX_TIME_GAP
|
|
426
|
+
) {
|
|
427
|
+
this.checkDroppedTransactions(now)
|
|
428
|
+
this.walletLocalData.lastCheckedTxsDropped = now
|
|
429
|
+
this.walletLocalDataDirty = true
|
|
430
|
+
if (this.transactionsChangedArray.length > 0) {
|
|
431
|
+
this.currencyEngineCallbacks.onTransactionsChanged(
|
|
432
|
+
this.transactionsChangedArray
|
|
433
|
+
)
|
|
434
|
+
this.transactionsChangedArray = []
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
checkDroppedTransactions(dateNow) {
|
|
440
|
+
let numUnconfirmedSpendTxs = 0
|
|
441
|
+
for (const currencyCode in this.transactionList) {
|
|
442
|
+
// const droppedTxIndices: Array<number> = []
|
|
443
|
+
for (let i = 0; i < this.transactionList[currencyCode].length; i++) {
|
|
444
|
+
const tx = this.transactionList[currencyCode][i]
|
|
445
|
+
if (tx.blockHeight === 0) {
|
|
446
|
+
const { otherParams = {} } = tx
|
|
447
|
+
const lastSeen = otherParams.lastSeenTime
|
|
448
|
+
if (dateNow - lastSeen > DROPPED_TX_TIME_GAP) {
|
|
449
|
+
// droppedTxIndices.push(i)
|
|
450
|
+
tx.blockHeight = -1
|
|
451
|
+
tx.nativeAmount = '0'
|
|
452
|
+
this.transactionsChangedArray.push(tx)
|
|
453
|
+
// delete this.txIdMap[currencyCode][tx.txid]
|
|
454
|
+
} else if (this.isSpendTx(tx)) {
|
|
455
|
+
// Still have a pending spend transaction in the tx list
|
|
456
|
+
numUnconfirmedSpendTxs++
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
// Delete transactions in reverse order
|
|
461
|
+
// for (let i = droppedTxIndices.length - 1; i >= 0; i--) {
|
|
462
|
+
// const droppedIndex = droppedTxIndices[i]
|
|
463
|
+
// this.transactionList[currencyCode].splice(droppedIndex, 1)
|
|
464
|
+
// }
|
|
465
|
+
// if (droppedTxIndices.length) {
|
|
466
|
+
// this.sortTransactions(currencyCode)
|
|
467
|
+
// }
|
|
468
|
+
}
|
|
469
|
+
this.walletLocalData.numUnconfirmedSpendTxs = numUnconfirmedSpendTxs
|
|
470
|
+
this.walletLocalDataDirty = true
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
updateTransaction(
|
|
474
|
+
currencyCode,
|
|
475
|
+
edgeTransaction,
|
|
476
|
+
idx
|
|
477
|
+
) {
|
|
478
|
+
// Update the transaction
|
|
479
|
+
this.transactionList[currencyCode][idx] = edgeTransaction
|
|
480
|
+
this.transactionListDirty = true
|
|
481
|
+
this.transactionsChangedArray.push(edgeTransaction)
|
|
482
|
+
this.log.warn('updateTransaction:' + edgeTransaction.txid)
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// *************************************
|
|
486
|
+
// Save the wallet data store
|
|
487
|
+
// *************************************
|
|
488
|
+
async saveWalletLoop() {
|
|
489
|
+
const disklet = this.walletLocalDisklet
|
|
490
|
+
const promises = []
|
|
491
|
+
if (this.transactionListDirty) {
|
|
492
|
+
await this.loadTransactions()
|
|
493
|
+
this.log('transactionListDirty. Saving...')
|
|
494
|
+
let jsonString = JSON.stringify(this.transactionList)
|
|
495
|
+
promises.push(
|
|
496
|
+
disklet.setText(TRANSACTION_STORE_FILE, jsonString).catch(e => {
|
|
497
|
+
this.log.error('Error saving transactionList')
|
|
498
|
+
this.log.error(e)
|
|
499
|
+
})
|
|
500
|
+
)
|
|
501
|
+
jsonString = JSON.stringify(this.txIdList)
|
|
502
|
+
promises.push(
|
|
503
|
+
disklet.setText(TXID_LIST_FILE, jsonString).catch(e => {
|
|
504
|
+
this.log.error('Error saving txIdList')
|
|
505
|
+
this.log.error(e)
|
|
506
|
+
})
|
|
507
|
+
)
|
|
508
|
+
jsonString = JSON.stringify(this.txIdMap)
|
|
509
|
+
promises.push(
|
|
510
|
+
disklet.setText(TXID_MAP_FILE, jsonString).catch(e => {
|
|
511
|
+
this.log.error('Error saving txIdMap')
|
|
512
|
+
this.log.error(e)
|
|
513
|
+
})
|
|
514
|
+
)
|
|
515
|
+
await Promise.all(promises)
|
|
516
|
+
this.transactionListDirty = false
|
|
517
|
+
}
|
|
518
|
+
if (this.walletLocalDataDirty) {
|
|
519
|
+
this.log('walletLocalDataDirty. Saving...')
|
|
520
|
+
const jsonString = JSON.stringify(this.walletLocalData)
|
|
521
|
+
await disklet
|
|
522
|
+
.setText(DATA_STORE_FILE, jsonString)
|
|
523
|
+
.then(() => {
|
|
524
|
+
this.walletLocalDataDirty = false
|
|
525
|
+
})
|
|
526
|
+
.catch(e => {
|
|
527
|
+
this.log.error('Error saving walletLocalData')
|
|
528
|
+
this.log.error(e)
|
|
529
|
+
})
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
doInitialBalanceCallback() {
|
|
534
|
+
for (const currencyCode of this.walletLocalData.enabledTokens) {
|
|
535
|
+
try {
|
|
536
|
+
this.currencyEngineCallbacks.onBalanceChanged(
|
|
537
|
+
currencyCode,
|
|
538
|
+
this.walletLocalData.totalBalances[currencyCode]
|
|
539
|
+
)
|
|
540
|
+
} catch (e) {
|
|
541
|
+
this.log.error(
|
|
542
|
+
'doInitialBalanceCallback Error for currencyCode',
|
|
543
|
+
currencyCode,
|
|
544
|
+
e
|
|
545
|
+
)
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
doInitialTransactionsCallback() {
|
|
551
|
+
for (const currencyCode of this.walletLocalData.enabledTokens) {
|
|
552
|
+
try {
|
|
553
|
+
this.currencyEngineCallbacks.onTransactionsChanged(
|
|
554
|
+
this.transactionList[currencyCode]
|
|
555
|
+
)
|
|
556
|
+
} catch (e) {
|
|
557
|
+
this.log.error(
|
|
558
|
+
'doInitialTransactionsCallback Error for currencyCode',
|
|
559
|
+
currencyCode,
|
|
560
|
+
e
|
|
561
|
+
)
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
async addToLoop(func, timer) {
|
|
567
|
+
try {
|
|
568
|
+
// $FlowFixMe
|
|
569
|
+
await this[func]()
|
|
570
|
+
} catch (e) {
|
|
571
|
+
this.log.error('Error in Loop:', func, e)
|
|
572
|
+
}
|
|
573
|
+
if (this.engineOn) {
|
|
574
|
+
this.timers[func] = setTimeout(() => {
|
|
575
|
+
if (this.engineOn) {
|
|
576
|
+
this.addToLoop(func, timer)
|
|
577
|
+
}
|
|
578
|
+
}, timer)
|
|
579
|
+
}
|
|
580
|
+
return true
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
getTokenInfo(token) {
|
|
584
|
+
return this.allTokens.find(element => {
|
|
585
|
+
return element.currencyCode === token
|
|
586
|
+
})
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
updateOnAddressesChecked() {
|
|
590
|
+
if (this.addressesChecked) {
|
|
591
|
+
return
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
const activeTokens = this.walletLocalData.enabledTokens
|
|
595
|
+
const perTokenSlice = 1 / activeTokens.length
|
|
596
|
+
let totalStatus = 0
|
|
597
|
+
let numComplete = 0
|
|
598
|
+
for (const token of activeTokens) {
|
|
599
|
+
const balanceStatus = this.tokenCheckBalanceStatus[token] || 0
|
|
600
|
+
const txStatus = this.tokenCheckTransactionsStatus[token] || 0
|
|
601
|
+
totalStatus += ((balanceStatus + txStatus) / 2) * perTokenSlice
|
|
602
|
+
if (balanceStatus === 1 && txStatus === 1) {
|
|
603
|
+
numComplete++
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
if (numComplete === activeTokens.length) {
|
|
607
|
+
totalStatus = 1
|
|
608
|
+
this.addressesChecked = true
|
|
609
|
+
}
|
|
610
|
+
this.log(`${this.walletInfo.id} syncRatio of: ${totalStatus}`)
|
|
611
|
+
// note that sometimes callback does not get triggered on Android debug
|
|
612
|
+
this.currencyEngineCallbacks.onAddressesChecked(totalStatus)
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
async startEngine() {
|
|
616
|
+
this.addToLoop('saveWalletLoop', SAVE_DATASTORE_MILLISECONDS)
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// *************************************
|
|
620
|
+
// Public methods
|
|
621
|
+
// *************************************
|
|
622
|
+
|
|
623
|
+
async killEngine() {
|
|
624
|
+
// Set status flag to false
|
|
625
|
+
this.engineOn = false
|
|
626
|
+
// Clear Inner loops timers
|
|
627
|
+
for (const timer in this.timers) {
|
|
628
|
+
clearTimeout(this.timers[timer])
|
|
629
|
+
}
|
|
630
|
+
this.timers = {}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
async changeUserSettings(userSettings) {
|
|
634
|
+
this.currentSettings = userSettings
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
async clearBlockchainCache() {
|
|
638
|
+
const temp = JSON.stringify({
|
|
639
|
+
enabledTokens: this.walletLocalData.enabledTokens,
|
|
640
|
+
publicKey: this.walletLocalData.publicKey
|
|
641
|
+
})
|
|
642
|
+
this.walletLocalData = new WalletLocalData(
|
|
643
|
+
temp,
|
|
644
|
+
this.currencyInfo.currencyCode
|
|
645
|
+
)
|
|
646
|
+
this.walletLocalDataDirty = true
|
|
647
|
+
this.addressesChecked = false
|
|
648
|
+
this.tokenCheckBalanceStatus = {}
|
|
649
|
+
this.tokenCheckTransactionsStatus = {}
|
|
650
|
+
this.transactionList = {}
|
|
651
|
+
this.txIdList = {}
|
|
652
|
+
this.txIdMap = {}
|
|
653
|
+
this.transactionListDirty = true
|
|
654
|
+
this.otherData = this.walletLocalData.otherData
|
|
655
|
+
await this.saveWalletLoop()
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
getBlockHeight() {
|
|
659
|
+
return parseInt(this.walletLocalData.blockHeight)
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
enableTokensSync(tokens) {
|
|
663
|
+
for (const token of tokens) {
|
|
664
|
+
if (this.walletLocalData.enabledTokens.indexOf(token) === -1) {
|
|
665
|
+
this.walletLocalData.enabledTokens.push(token)
|
|
666
|
+
this.walletLocalDataDirty = true
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
if (this.walletLocalDataDirty) {
|
|
670
|
+
this.saveWalletLoop()
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
async enableTokens(tokens) {
|
|
675
|
+
this.enableTokensSync(tokens)
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
disableTokensSync(tokens) {
|
|
679
|
+
for (const token of tokens) {
|
|
680
|
+
if (token === this.currencyInfo.currencyCode) {
|
|
681
|
+
continue
|
|
682
|
+
}
|
|
683
|
+
const index = this.walletLocalData.enabledTokens.indexOf(token)
|
|
684
|
+
if (index !== -1) {
|
|
685
|
+
this.walletLocalData.enabledTokens.splice(index, 1)
|
|
686
|
+
this.walletLocalDataDirty = true
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
if (this.walletLocalDataDirty) {
|
|
690
|
+
this.saveWalletLoop()
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
async disableTokens(tokens) {
|
|
695
|
+
this.disableTokensSync(tokens)
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
async getEnabledTokens() {
|
|
699
|
+
return this.walletLocalData.enabledTokens
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
async addCustomToken(obj, contractAddress) {
|
|
703
|
+
checkCustomToken(obj)
|
|
704
|
+
|
|
705
|
+
const tokenObj = obj
|
|
706
|
+
// If token is already in currencyInfo, error as it cannot be changed
|
|
707
|
+
for (const tk of this.currencyInfo.metaTokens) {
|
|
708
|
+
if (
|
|
709
|
+
tk.currencyCode.toLowerCase() === tokenObj.currencyCode.toLowerCase() ||
|
|
710
|
+
tk.currencyName.toLowerCase() === tokenObj.currencyName.toLowerCase()
|
|
711
|
+
) {
|
|
712
|
+
throw new Error('ErrorCannotModifyToken')
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// Validate the token object
|
|
717
|
+
if (tokenObj.currencyCode.toUpperCase() !== tokenObj.currencyCode) {
|
|
718
|
+
throw new Error('ErrorInvalidCurrencyCode')
|
|
719
|
+
}
|
|
720
|
+
if (tokenObj.currencyCode.length < 2 || tokenObj.currencyCode.length > 7) {
|
|
721
|
+
throw new Error('ErrorInvalidCurrencyCodeLength')
|
|
722
|
+
}
|
|
723
|
+
if (tokenObj.currencyName.length < 3 || tokenObj.currencyName.length > 20) {
|
|
724
|
+
throw new Error('ErrorInvalidCurrencyNameLength')
|
|
725
|
+
}
|
|
726
|
+
if (
|
|
727
|
+
bns.lt(tokenObj.multiplier, '1') ||
|
|
728
|
+
bns.gt(tokenObj.multiplier, '100000000000000000000000000000000')
|
|
729
|
+
) {
|
|
730
|
+
throw new Error('ErrorInvalidMultiplier')
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
for (const tk of this.customTokens) {
|
|
734
|
+
if (
|
|
735
|
+
tk.currencyCode.toLowerCase() === tokenObj.currencyCode.toLowerCase() ||
|
|
736
|
+
tk.currencyName.toLowerCase() === tokenObj.currencyName.toLowerCase()
|
|
737
|
+
) {
|
|
738
|
+
// Remove old token first then re-add it to incorporate any modifications
|
|
739
|
+
const idx = this.customTokens.findIndex(
|
|
740
|
+
element => element.currencyCode === tokenObj.currencyCode
|
|
741
|
+
)
|
|
742
|
+
if (idx !== -1) {
|
|
743
|
+
this.customTokens.splice(idx, 1)
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// Create a token object for inclusion in customTokens
|
|
749
|
+
const denom = {
|
|
750
|
+
name: tokenObj.currencyCode,
|
|
751
|
+
multiplier: tokenObj.multiplier
|
|
752
|
+
}
|
|
753
|
+
const edgeMetaToken = {
|
|
754
|
+
currencyCode: tokenObj.currencyCode,
|
|
755
|
+
currencyName: tokenObj.currencyName,
|
|
756
|
+
denominations: [denom],
|
|
757
|
+
contractAddress: contractAddress || tokenObj.contractAddress
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
this.customTokens.push(edgeMetaToken)
|
|
761
|
+
this.allTokens = this.currencyInfo.metaTokens.concat(this.customTokens)
|
|
762
|
+
this.enableTokensSync([edgeMetaToken.currencyCode])
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
getTokenStatus(token) {
|
|
766
|
+
return this.walletLocalData.enabledTokens.indexOf(token) !== -1
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
getBalance(options) {
|
|
770
|
+
const cleanOptions = asCurrencyCodeOptions(options)
|
|
771
|
+
const { currencyCode = this.currencyInfo.currencyCode } = cleanOptions
|
|
772
|
+
|
|
773
|
+
if (this.walletLocalData.totalBalances[currencyCode] == null) {
|
|
774
|
+
return '0'
|
|
775
|
+
}
|
|
776
|
+
const nativeBalance = this.walletLocalData.totalBalances[currencyCode]
|
|
777
|
+
return nativeBalance
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
getNumTransactions(options) {
|
|
781
|
+
const cleanOptions = asCurrencyCodeOptions(options)
|
|
782
|
+
const { currencyCode = this.currencyInfo.currencyCode } = cleanOptions
|
|
783
|
+
|
|
784
|
+
if (this.walletLocalData.numTransactions[currencyCode] == null) {
|
|
785
|
+
return 0
|
|
786
|
+
} else {
|
|
787
|
+
return this.walletLocalData.numTransactions[currencyCode]
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
async getTransactions(
|
|
792
|
+
options
|
|
793
|
+
) {
|
|
794
|
+
const cleanOptions = asCurrencyCodeOptions(options)
|
|
795
|
+
const { currencyCode = this.currencyInfo.currencyCode } = cleanOptions
|
|
796
|
+
|
|
797
|
+
await this.loadTransactions()
|
|
798
|
+
|
|
799
|
+
if (this.transactionList[currencyCode] == null) {
|
|
800
|
+
return []
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
let startIndex = 0
|
|
804
|
+
let startEntries = 0
|
|
805
|
+
if (options === null) {
|
|
806
|
+
return this.transactionList[currencyCode].slice(0)
|
|
807
|
+
}
|
|
808
|
+
if (options.startIndex && options.startIndex > 0) {
|
|
809
|
+
startIndex = options.startIndex
|
|
810
|
+
if (startIndex >= this.transactionList[currencyCode].length) {
|
|
811
|
+
startIndex = this.transactionList[currencyCode].length - 1
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
if (options.startEntries && options.startEntries > 0) {
|
|
815
|
+
startEntries = options.startEntries
|
|
816
|
+
if (
|
|
817
|
+
startEntries + startIndex >
|
|
818
|
+
this.transactionList[currencyCode].length
|
|
819
|
+
) {
|
|
820
|
+
// Don't read past the end of the transactionList
|
|
821
|
+
startEntries = this.transactionList[currencyCode].length - startIndex
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// Copy the appropriate entries from the arrayTransactions
|
|
826
|
+
let returnArray = []
|
|
827
|
+
|
|
828
|
+
if (startEntries) {
|
|
829
|
+
returnArray = this.transactionList[currencyCode].slice(
|
|
830
|
+
startIndex,
|
|
831
|
+
startEntries + startIndex
|
|
832
|
+
)
|
|
833
|
+
} else {
|
|
834
|
+
returnArray = this.transactionList[currencyCode].slice(startIndex)
|
|
835
|
+
}
|
|
836
|
+
return returnArray
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
getFreshAddress(options) {
|
|
840
|
+
return { publicAddress: this.walletLocalData.publicKey }
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
addGapLimitAddresses(addresses, options) {}
|
|
844
|
+
|
|
845
|
+
isAddressUsed(address, options) {
|
|
846
|
+
return false
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
dumpData() {
|
|
850
|
+
const dataDump = {
|
|
851
|
+
walletId: this.walletId.split(' - ')[0],
|
|
852
|
+
walletType: this.walletInfo.type,
|
|
853
|
+
pluginType: this.currencyInfo.pluginId,
|
|
854
|
+
data: {
|
|
855
|
+
walletLocalData: this.walletLocalData
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
return dataDump
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
makeSpend(edgeSpendInfo) {
|
|
862
|
+
checkEdgeSpendInfo(edgeSpendInfo)
|
|
863
|
+
|
|
864
|
+
for (const st of edgeSpendInfo.spendTargets) {
|
|
865
|
+
if (st.publicAddress === this.walletLocalData.publicKey) {
|
|
866
|
+
throw new SpendToSelfError()
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
let currencyCode = ''
|
|
871
|
+
if (typeof edgeSpendInfo.currencyCode === 'string') {
|
|
872
|
+
currencyCode = edgeSpendInfo.currencyCode
|
|
873
|
+
if (currencyCode !== this.currencyInfo.currencyCode) {
|
|
874
|
+
if (!this.getTokenStatus(currencyCode)) {
|
|
875
|
+
throw new Error('Error: Token not supported or enabled')
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
} else {
|
|
879
|
+
currencyCode = this.currencyInfo.currencyCode
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
const nativeBalance = this.walletLocalData.totalBalances[currencyCode]
|
|
883
|
+
if (!nativeBalance || bns.eq(nativeBalance, '0')) {
|
|
884
|
+
throw new InsufficientFundsError()
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
edgeSpendInfo.currencyCode = currencyCode
|
|
888
|
+
const denom = getDenomInfo(
|
|
889
|
+
this.currencyInfo,
|
|
890
|
+
currencyCode,
|
|
891
|
+
this.customTokens
|
|
892
|
+
)
|
|
893
|
+
if (!denom) {
|
|
894
|
+
throw new Error('InternalErrorInvalidCurrencyCode')
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
return { edgeSpendInfo, nativeBalance, currencyCode, denom }
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
// called by GUI after sliding to confirm
|
|
901
|
+
async saveTx(edgeTransaction) {
|
|
902
|
+
// add the transaction to disk and fire off callback (alert in GUI)
|
|
903
|
+
this.addTransaction(edgeTransaction.currencyCode, edgeTransaction)
|
|
904
|
+
this.transactionsChangedArray.forEach(tx =>
|
|
905
|
+
this.log.warn(
|
|
906
|
+
`executing back in saveTx and this.transactionsChangedArray is: ${cleanTxLogs(
|
|
907
|
+
tx
|
|
908
|
+
)}`
|
|
909
|
+
)
|
|
910
|
+
)
|
|
911
|
+
|
|
912
|
+
if (this.transactionsChangedArray.length > 0) {
|
|
913
|
+
this.currencyEngineCallbacks.onTransactionsChanged(
|
|
914
|
+
this.transactionsChangedArray
|
|
915
|
+
)
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
}
|