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,41 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Emulates the browser Fetch API more accurately than fetch JSON.
|
|
5
|
+
*/
|
|
6
|
+
export function getFetchCors(opts) {
|
|
7
|
+
const nativeIo = opts.nativeIo['edge-currency-accountbased']
|
|
8
|
+
if (nativeIo == null) return opts.io.fetch
|
|
9
|
+
|
|
10
|
+
return function fetch(uri, opts) {
|
|
11
|
+
return nativeIo.fetchText(uri, opts).then(reply => ({
|
|
12
|
+
ok: reply.ok,
|
|
13
|
+
status: reply.status,
|
|
14
|
+
statusText: reply.statusText,
|
|
15
|
+
url: reply.url,
|
|
16
|
+
json() {
|
|
17
|
+
return Promise.resolve().then(() => JSON.parse(reply.text))
|
|
18
|
+
},
|
|
19
|
+
text() {
|
|
20
|
+
return Promise.resolve(reply.text)
|
|
21
|
+
}
|
|
22
|
+
}))
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// TODO: Remove this entire file in the next breaking change.
|
|
27
|
+
export default function makePluginIo() {
|
|
28
|
+
return {
|
|
29
|
+
fetchText(uri, opts) {
|
|
30
|
+
return window.fetch(uri, opts).then(reply =>
|
|
31
|
+
reply.text().then(text => ({
|
|
32
|
+
ok: reply.ok,
|
|
33
|
+
status: reply.status,
|
|
34
|
+
statusText: reply.statusText,
|
|
35
|
+
url: reply.url,
|
|
36
|
+
text
|
|
37
|
+
}))
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Created by paul on 7/7/17.
|
|
3
|
+
*/
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
import { bns } from 'biggystring'
|
|
7
|
+
// import { currencyInfo } from './stellarInfo.js'
|
|
8
|
+
import {
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
InsufficientFundsError,
|
|
14
|
+
NoAmountSpecifiedError
|
|
15
|
+
} from 'edge-core-js/types'
|
|
16
|
+
|
|
17
|
+
import { CurrencyEngine } from '../common/engine.js'
|
|
18
|
+
import {
|
|
19
|
+
asyncWaterfall,
|
|
20
|
+
cleanTxLogs,
|
|
21
|
+
getDenomInfo,
|
|
22
|
+
getOtherParams,
|
|
23
|
+
promiseAny
|
|
24
|
+
} from '../common/utils.js'
|
|
25
|
+
import { StellarPlugin } from '../stellar/stellarPlugin.js'
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
const TX_QUERY_PAGING_LIMIT = 2
|
|
34
|
+
const ADDRESS_POLL_MILLISECONDS = 15000
|
|
35
|
+
const BLOCKCHAIN_POLL_MILLISECONDS = 30000
|
|
36
|
+
const TRANSACTION_POLL_MILLISECONDS = 5000
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
export class StellarEngine extends CurrencyEngine {
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
constructor(
|
|
53
|
+
currencyPlugin,
|
|
54
|
+
walletInfo,
|
|
55
|
+
opts
|
|
56
|
+
) {
|
|
57
|
+
super(currencyPlugin, walletInfo, opts)
|
|
58
|
+
this.stellarPlugin = currencyPlugin
|
|
59
|
+
this.stellarApi = {}
|
|
60
|
+
this.activatedAccountsCache = {}
|
|
61
|
+
this.pendingTransactionsIndex = 0
|
|
62
|
+
this.pendingTransactionsMap = {}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async multicastServers(
|
|
66
|
+
func,
|
|
67
|
+
...params
|
|
68
|
+
) {
|
|
69
|
+
let out = { result: '', server: '' }
|
|
70
|
+
let funcs
|
|
71
|
+
switch (func) {
|
|
72
|
+
// Functions that should waterfall from top to low priority servers
|
|
73
|
+
case 'loadAccount':
|
|
74
|
+
funcs = this.stellarPlugin.stellarApiServers.map(api => async () => {
|
|
75
|
+
const result = await api[func](...params)
|
|
76
|
+
return { server: api.serverName, result }
|
|
77
|
+
})
|
|
78
|
+
out = await asyncWaterfall(funcs)
|
|
79
|
+
break
|
|
80
|
+
|
|
81
|
+
case 'ledgers':
|
|
82
|
+
funcs = this.stellarPlugin.stellarApiServers.map(
|
|
83
|
+
serverApi => async () => {
|
|
84
|
+
const result = await serverApi
|
|
85
|
+
.ledgers()
|
|
86
|
+
.order('desc')
|
|
87
|
+
.limit(1)
|
|
88
|
+
.call()
|
|
89
|
+
const blockHeight = result.records[0].sequence
|
|
90
|
+
if (
|
|
91
|
+
this.walletLocalData.blockHeight <= blockHeight &&
|
|
92
|
+
blockHeight >= this.currencyPlugin.highestTxHeight
|
|
93
|
+
) {
|
|
94
|
+
return { server: serverApi.serverName, result }
|
|
95
|
+
} else {
|
|
96
|
+
throw new Error('Height out of date')
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
)
|
|
100
|
+
out = await asyncWaterfall(funcs)
|
|
101
|
+
break
|
|
102
|
+
|
|
103
|
+
case 'payments':
|
|
104
|
+
funcs = this.stellarPlugin.stellarApiServers.map(
|
|
105
|
+
serverApi => async () => {
|
|
106
|
+
const result = await serverApi
|
|
107
|
+
.payments()
|
|
108
|
+
.limit(TX_QUERY_PAGING_LIMIT)
|
|
109
|
+
.cursor(this.otherData.lastPagingToken)
|
|
110
|
+
.forAccount(...params)
|
|
111
|
+
.call()
|
|
112
|
+
return { server: serverApi.serverName, result }
|
|
113
|
+
}
|
|
114
|
+
)
|
|
115
|
+
out = await asyncWaterfall(funcs)
|
|
116
|
+
break
|
|
117
|
+
|
|
118
|
+
// Functions that should multicast to all servers
|
|
119
|
+
case 'submitTransaction':
|
|
120
|
+
out = await promiseAny(
|
|
121
|
+
this.stellarPlugin.stellarApiServers.map(async serverApi => {
|
|
122
|
+
const result = await serverApi[func](...params)
|
|
123
|
+
return { server: serverApi.serverName, result }
|
|
124
|
+
})
|
|
125
|
+
)
|
|
126
|
+
break
|
|
127
|
+
}
|
|
128
|
+
this.log(`multicastServers ${func} ${out.server} won`)
|
|
129
|
+
return out.result
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async processTransaction(tx) {
|
|
133
|
+
const ourReceiveAddresses = []
|
|
134
|
+
|
|
135
|
+
let currencyCode = ''
|
|
136
|
+
let exchangeAmount = ''
|
|
137
|
+
let fromAddress = ''
|
|
138
|
+
let toAddress, nativeAmount, networkFee
|
|
139
|
+
if (tx.type === 'create_account') {
|
|
140
|
+
fromAddress = tx.source_account
|
|
141
|
+
toAddress = tx.account
|
|
142
|
+
exchangeAmount = tx.starting_balance
|
|
143
|
+
currencyCode = this.currencyInfo.currencyCode
|
|
144
|
+
} else if (tx.type === 'payment') {
|
|
145
|
+
fromAddress = tx.from
|
|
146
|
+
toAddress = tx.to
|
|
147
|
+
exchangeAmount = tx.amount
|
|
148
|
+
if (tx.asset_type === 'native') {
|
|
149
|
+
currencyCode = this.currencyInfo.currencyCode
|
|
150
|
+
} else {
|
|
151
|
+
currencyCode = tx.asset_type
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const date = Date.parse(tx.created_at) / 1000
|
|
156
|
+
const denom = getDenomInfo(this.currencyInfo, currencyCode)
|
|
157
|
+
if (denom && denom.multiplier) {
|
|
158
|
+
nativeAmount = bns.mul(exchangeAmount, denom.multiplier)
|
|
159
|
+
} else {
|
|
160
|
+
throw new Error('ErrorDenomNotFound')
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
let rawTx
|
|
164
|
+
try {
|
|
165
|
+
rawTx = await tx.transaction()
|
|
166
|
+
networkFee = rawTx.fee_charged.toString()
|
|
167
|
+
} catch (e) {
|
|
168
|
+
this.log.error(`processTransaction rawTx Error ${e}`)
|
|
169
|
+
throw e
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (toAddress === this.walletLocalData.publicKey) {
|
|
173
|
+
ourReceiveAddresses.push(fromAddress)
|
|
174
|
+
if (fromAddress === this.walletLocalData.publicKey) {
|
|
175
|
+
// This is a spend to self. Make fee the only amount
|
|
176
|
+
nativeAmount = '-' + networkFee
|
|
177
|
+
}
|
|
178
|
+
} else {
|
|
179
|
+
// This is a spend. Include fee in amount and make amount negative
|
|
180
|
+
nativeAmount = bns.add(nativeAmount, networkFee)
|
|
181
|
+
nativeAmount = '-' + nativeAmount
|
|
182
|
+
}
|
|
183
|
+
const edgeTransaction = {
|
|
184
|
+
txid: tx.transaction_hash,
|
|
185
|
+
date,
|
|
186
|
+
currencyCode,
|
|
187
|
+
blockHeight: rawTx.ledger_attr > 0 ? rawTx.ledger_attr : 0, // API shows no ledger number ??
|
|
188
|
+
nativeAmount,
|
|
189
|
+
networkFee,
|
|
190
|
+
parentNetworkFee: '0',
|
|
191
|
+
ourReceiveAddresses,
|
|
192
|
+
signedTx: '',
|
|
193
|
+
otherParams: {
|
|
194
|
+
fromAddress,
|
|
195
|
+
toAddress
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
this.addTransaction(currencyCode, edgeTransaction)
|
|
200
|
+
return tx.paging_token
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Streaming version. Doesn't work in RN
|
|
204
|
+
// async checkTransactionsInnerLoop () {
|
|
205
|
+
// const address = this.walletLocalData.publicKey
|
|
206
|
+
// const txHandler = (tx) => {
|
|
207
|
+
// this.log('Got something:')
|
|
208
|
+
// this.processTransaction(tx)
|
|
209
|
+
// }
|
|
210
|
+
// let close
|
|
211
|
+
// const errorHandler = (e) => {
|
|
212
|
+
// if (close) {
|
|
213
|
+
// close()
|
|
214
|
+
// close = null
|
|
215
|
+
// this.checkTransactionsInnerLoop()
|
|
216
|
+
// }
|
|
217
|
+
// }
|
|
218
|
+
// close = this.stellarServer.payments()
|
|
219
|
+
// .forAccount(address)
|
|
220
|
+
// .limit(TX_QUERY_PAGING_LIMIT)
|
|
221
|
+
// .cursor(this.otherData.lastPagingToken)
|
|
222
|
+
// .stream({
|
|
223
|
+
// onmessage: txHandler,
|
|
224
|
+
// onerror: errorHandler
|
|
225
|
+
// })
|
|
226
|
+
// }
|
|
227
|
+
|
|
228
|
+
// Polling version
|
|
229
|
+
async checkTransactionsInnerLoop() {
|
|
230
|
+
const blockHeight = this.walletLocalData.blockHeight
|
|
231
|
+
|
|
232
|
+
const address = this.walletLocalData.publicKey
|
|
233
|
+
let page
|
|
234
|
+
let pagingToken
|
|
235
|
+
while (1) {
|
|
236
|
+
try {
|
|
237
|
+
if (!page) {
|
|
238
|
+
page = await this.multicastServers('payments', address)
|
|
239
|
+
} else {
|
|
240
|
+
page = await page.next()
|
|
241
|
+
}
|
|
242
|
+
if (page.records.length === 0) {
|
|
243
|
+
break
|
|
244
|
+
}
|
|
245
|
+
for (const tx of page.records) {
|
|
246
|
+
pagingToken = await this.processTransaction(tx)
|
|
247
|
+
}
|
|
248
|
+
} catch (e) {
|
|
249
|
+
if (e.response && e.response.title === 'Resource Missing') {
|
|
250
|
+
this.log('Account not found. Probably not activated w/minimum XLM')
|
|
251
|
+
this.tokenCheckTransactionsStatus.XLM = 1
|
|
252
|
+
this.updateOnAddressesChecked()
|
|
253
|
+
} else {
|
|
254
|
+
this.log.error(
|
|
255
|
+
`checkTransactionsInnerLoop Error fetching transaction info: ${e}`
|
|
256
|
+
)
|
|
257
|
+
}
|
|
258
|
+
return
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (this.transactionsChangedArray.length > 0) {
|
|
262
|
+
this.currencyEngineCallbacks.onTransactionsChanged(
|
|
263
|
+
this.transactionsChangedArray
|
|
264
|
+
)
|
|
265
|
+
this.transactionsChangedArray = []
|
|
266
|
+
}
|
|
267
|
+
if (pagingToken) {
|
|
268
|
+
this.otherData.lastPagingToken = pagingToken
|
|
269
|
+
this.walletLocalDataDirty = true
|
|
270
|
+
}
|
|
271
|
+
this.walletLocalData.lastAddressQueryHeight = blockHeight
|
|
272
|
+
this.tokenCheckTransactionsStatus.XLM = 1
|
|
273
|
+
this.updateOnAddressesChecked()
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
async checkUnconfirmedTransactionsFetch() {}
|
|
277
|
+
|
|
278
|
+
// Check all account balance and other relevant info
|
|
279
|
+
async checkAccountInnerLoop() {
|
|
280
|
+
const address = this.walletLocalData.publicKey
|
|
281
|
+
try {
|
|
282
|
+
const account = await this.multicastServers(
|
|
283
|
+
'loadAccount',
|
|
284
|
+
address
|
|
285
|
+
)
|
|
286
|
+
if (account.sequence !== this.otherData.accountSequence) {
|
|
287
|
+
this.otherData.accountSequence = account.sequence
|
|
288
|
+
}
|
|
289
|
+
for (const bal of account.balances) {
|
|
290
|
+
let currencyCode
|
|
291
|
+
if (bal.asset_type === 'native') {
|
|
292
|
+
currencyCode = this.currencyInfo.currencyCode
|
|
293
|
+
this.log('--Got balances--')
|
|
294
|
+
} else {
|
|
295
|
+
currencyCode = bal.asset_type
|
|
296
|
+
}
|
|
297
|
+
const denom = getDenomInfo(this.currencyInfo, currencyCode)
|
|
298
|
+
if (denom && denom.multiplier) {
|
|
299
|
+
const nativeAmount = bns.mul(bal.balance, denom.multiplier)
|
|
300
|
+
if (
|
|
301
|
+
typeof this.walletLocalData.totalBalances[currencyCode] ===
|
|
302
|
+
'undefined'
|
|
303
|
+
) {
|
|
304
|
+
this.walletLocalData.totalBalances[currencyCode] = '0'
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (
|
|
308
|
+
this.walletLocalData.totalBalances[currencyCode] !== nativeAmount
|
|
309
|
+
) {
|
|
310
|
+
this.walletLocalData.totalBalances[currencyCode] = nativeAmount
|
|
311
|
+
this.log.warn(`Updated ${currencyCode} balance ${nativeAmount}`)
|
|
312
|
+
this.currencyEngineCallbacks.onBalanceChanged(
|
|
313
|
+
currencyCode,
|
|
314
|
+
nativeAmount
|
|
315
|
+
)
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
this.tokenCheckBalanceStatus.XLM = 1
|
|
320
|
+
this.updateOnAddressesChecked()
|
|
321
|
+
} catch (e) {
|
|
322
|
+
if (e.response && e.response.title === 'Resource Missing') {
|
|
323
|
+
this.log('Account not found. Probably not activated w/minimum XLM')
|
|
324
|
+
this.tokenCheckBalanceStatus.XLM = 1
|
|
325
|
+
this.updateOnAddressesChecked()
|
|
326
|
+
} else {
|
|
327
|
+
this.log.error(
|
|
328
|
+
`checkAccountInnerLoop Error fetching address info: ${e}`
|
|
329
|
+
)
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
checkBlockchainInnerLoop() {
|
|
335
|
+
this.multicastServers('ledgers')
|
|
336
|
+
.then(r => {
|
|
337
|
+
const blockHeight = r.records[0].sequence
|
|
338
|
+
if (this.walletLocalData.blockHeight !== blockHeight) {
|
|
339
|
+
this.checkDroppedTransactionsThrottled()
|
|
340
|
+
this.walletLocalData.blockHeight = blockHeight
|
|
341
|
+
this.walletLocalDataDirty = true
|
|
342
|
+
this.currencyEngineCallbacks.onBlockHeightChanged(
|
|
343
|
+
this.walletLocalData.blockHeight
|
|
344
|
+
)
|
|
345
|
+
}
|
|
346
|
+
})
|
|
347
|
+
.catch(e => {
|
|
348
|
+
this.log.error(`checkBlockchainInnerLoop Error ${e}`)
|
|
349
|
+
})
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
async clearBlockchainCache() {
|
|
353
|
+
this.activatedAccountsCache = {}
|
|
354
|
+
this.pendingTransactionsIndex = 0
|
|
355
|
+
this.pendingTransactionsMap = {}
|
|
356
|
+
await super.clearBlockchainCache()
|
|
357
|
+
this.otherData.accountSequence = 0
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// ****************************************************************************
|
|
361
|
+
// Public methods
|
|
362
|
+
// ****************************************************************************
|
|
363
|
+
|
|
364
|
+
async startEngine() {
|
|
365
|
+
this.engineOn = true
|
|
366
|
+
this.addToLoop('checkBlockchainInnerLoop', BLOCKCHAIN_POLL_MILLISECONDS)
|
|
367
|
+
this.addToLoop('checkAccountInnerLoop', ADDRESS_POLL_MILLISECONDS)
|
|
368
|
+
this.addToLoop('checkTransactionsInnerLoop', TRANSACTION_POLL_MILLISECONDS)
|
|
369
|
+
super.startEngine()
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
async resyncBlockchain() {
|
|
373
|
+
await this.killEngine()
|
|
374
|
+
await this.clearBlockchainCache()
|
|
375
|
+
await this.startEngine()
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
async makeSpend(edgeSpendInfoIn) {
|
|
379
|
+
const { edgeSpendInfo, currencyCode, nativeBalance, denom } =
|
|
380
|
+
super.makeSpend(edgeSpendInfoIn)
|
|
381
|
+
|
|
382
|
+
if (edgeSpendInfo.spendTargets.length !== 1) {
|
|
383
|
+
throw new Error('Error: only one output allowed')
|
|
384
|
+
}
|
|
385
|
+
const publicAddress = edgeSpendInfo.spendTargets[0].publicAddress
|
|
386
|
+
// Check if destination address is activated
|
|
387
|
+
let mustCreateAccount = false
|
|
388
|
+
const activated = this.activatedAccountsCache[publicAddress]
|
|
389
|
+
if (activated === false) {
|
|
390
|
+
mustCreateAccount = true
|
|
391
|
+
} else if (activated === undefined) {
|
|
392
|
+
try {
|
|
393
|
+
await this.multicastServers('loadAccount', publicAddress)
|
|
394
|
+
this.activatedAccountsCache[publicAddress] = true
|
|
395
|
+
} catch (e) {
|
|
396
|
+
this.activatedAccountsCache[publicAddress] = false
|
|
397
|
+
mustCreateAccount = true
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
let nativeAmount = '0'
|
|
402
|
+
if (typeof edgeSpendInfo.spendTargets[0].nativeAmount === 'string') {
|
|
403
|
+
nativeAmount = edgeSpendInfo.spendTargets[0].nativeAmount
|
|
404
|
+
} else {
|
|
405
|
+
throw new NoAmountSpecifiedError()
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (bns.eq(nativeAmount, '0')) {
|
|
409
|
+
throw new NoAmountSpecifiedError()
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const exchangeAmount = bns.div(nativeAmount, denom.multiplier, 7)
|
|
413
|
+
|
|
414
|
+
const account = new this.stellarApi.Account(
|
|
415
|
+
this.walletLocalData.publicKey,
|
|
416
|
+
this.otherData.accountSequence
|
|
417
|
+
)
|
|
418
|
+
let memoId
|
|
419
|
+
if (
|
|
420
|
+
edgeSpendInfo.spendTargets[0].otherParams &&
|
|
421
|
+
edgeSpendInfo.spendTargets[0].otherParams.uniqueIdentifier
|
|
422
|
+
) {
|
|
423
|
+
memoId = edgeSpendInfo.spendTargets[0].otherParams.uniqueIdentifier
|
|
424
|
+
}
|
|
425
|
+
const txBuilder = new this.stellarApi.TransactionBuilder(account)
|
|
426
|
+
let transaction
|
|
427
|
+
|
|
428
|
+
if (mustCreateAccount) {
|
|
429
|
+
transaction = txBuilder.addOperation(
|
|
430
|
+
this.stellarApi.Operation.createAccount({
|
|
431
|
+
destination: publicAddress,
|
|
432
|
+
startingBalance: exchangeAmount
|
|
433
|
+
})
|
|
434
|
+
)
|
|
435
|
+
} else {
|
|
436
|
+
transaction = txBuilder.addOperation(
|
|
437
|
+
this.stellarApi.Operation.payment({
|
|
438
|
+
destination: publicAddress,
|
|
439
|
+
asset: this.stellarApi.Asset.native(),
|
|
440
|
+
amount: exchangeAmount
|
|
441
|
+
})
|
|
442
|
+
)
|
|
443
|
+
}
|
|
444
|
+
if (memoId) {
|
|
445
|
+
const memo = this.stellarApi.Memo.id(memoId)
|
|
446
|
+
transaction = transaction.addMemo(memo)
|
|
447
|
+
}
|
|
448
|
+
transaction = transaction.build()
|
|
449
|
+
|
|
450
|
+
const networkFee = transaction.fee.toString()
|
|
451
|
+
nativeAmount = bns.add(networkFee, nativeAmount) // Add fee to total
|
|
452
|
+
const nativeBalance2 = bns.sub(nativeBalance, '10000000') // Subtract the 1 min XLM
|
|
453
|
+
if (bns.gt(nativeAmount, nativeBalance2)) {
|
|
454
|
+
throw new InsufficientFundsError()
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
nativeAmount = `-${nativeAmount}`
|
|
458
|
+
const idInternal = this.pendingTransactionsIndex
|
|
459
|
+
const edgeTransaction = {
|
|
460
|
+
txid: '', // txid
|
|
461
|
+
date: 0, // date
|
|
462
|
+
currencyCode, // currencyCode
|
|
463
|
+
blockHeight: 0, // blockHeight
|
|
464
|
+
nativeAmount, // nativeAmount
|
|
465
|
+
networkFee, // networkFee
|
|
466
|
+
ourReceiveAddresses: [], // ourReceiveAddresses
|
|
467
|
+
signedTx: '', // signedTx
|
|
468
|
+
otherParams: {
|
|
469
|
+
idInternal,
|
|
470
|
+
fromAddress: this.walletLocalData.publicKey,
|
|
471
|
+
toAddress: publicAddress
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
this.pendingTransactionsMap[idInternal] = transaction
|
|
475
|
+
this.pendingTransactionsIndex++
|
|
476
|
+
|
|
477
|
+
// Clean up old pendingTransactions
|
|
478
|
+
if (this.pendingTransactionsMap[this.pendingTransactionsIndex - 20]) {
|
|
479
|
+
delete this.pendingTransactionsMap[this.pendingTransactionsIndex - 20]
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
this.log.warn('Stellar transaction prepared')
|
|
483
|
+
this.log.warn(`idInternal: ${idInternal}`)
|
|
484
|
+
this.log.warn(
|
|
485
|
+
`${nativeAmount} ${this.walletLocalData.publicKey} -> ${publicAddress}`
|
|
486
|
+
)
|
|
487
|
+
return edgeTransaction
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
async signTx(edgeTransaction) {
|
|
491
|
+
const otherParams = getOtherParams(edgeTransaction)
|
|
492
|
+
|
|
493
|
+
// Do signing
|
|
494
|
+
try {
|
|
495
|
+
const { idInternal } = otherParams
|
|
496
|
+
const transaction = this.pendingTransactionsMap[idInternal]
|
|
497
|
+
if (!transaction) {
|
|
498
|
+
throw new Error('ErrorInvalidTransaction')
|
|
499
|
+
}
|
|
500
|
+
this.log.warn('Signing...')
|
|
501
|
+
const keypair = this.stellarApi.Keypair.fromSecret(
|
|
502
|
+
this.walletInfo.keys.stellarKey
|
|
503
|
+
)
|
|
504
|
+
await transaction.sign(keypair)
|
|
505
|
+
} catch (e) {
|
|
506
|
+
this.log.error(
|
|
507
|
+
`FAILURE signTx\n${JSON.stringify(cleanTxLogs(edgeTransaction))} ${e}`
|
|
508
|
+
)
|
|
509
|
+
throw e
|
|
510
|
+
}
|
|
511
|
+
this.log.warn(`signTx\n${cleanTxLogs(edgeTransaction)}`)
|
|
512
|
+
return edgeTransaction
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
async broadcastTx(
|
|
516
|
+
edgeTransaction
|
|
517
|
+
) {
|
|
518
|
+
const otherParams = getOtherParams(edgeTransaction)
|
|
519
|
+
|
|
520
|
+
try {
|
|
521
|
+
const { idInternal } = otherParams
|
|
522
|
+
const transaction = this.pendingTransactionsMap[idInternal]
|
|
523
|
+
if (!transaction) {
|
|
524
|
+
throw new Error('ErrorInvalidTransaction')
|
|
525
|
+
}
|
|
526
|
+
this.log.warn(`Broadcasting...\n${cleanTxLogs(edgeTransaction)}`)
|
|
527
|
+
const result = await this.multicastServers(
|
|
528
|
+
'submitTransaction',
|
|
529
|
+
transaction
|
|
530
|
+
)
|
|
531
|
+
edgeTransaction.txid = result.hash
|
|
532
|
+
edgeTransaction.date = Date.now() / 1000
|
|
533
|
+
this.activatedAccountsCache[otherParams.toAddress] = true
|
|
534
|
+
this.otherData.accountSequence++
|
|
535
|
+
this.walletLocalDataDirty = true
|
|
536
|
+
this.log.warn(`SUCCESS broadcastTx\n${cleanTxLogs(edgeTransaction)}`)
|
|
537
|
+
} catch (e) {
|
|
538
|
+
this.log.error(
|
|
539
|
+
`FAILURE broadcastTx\n${JSON.stringify(
|
|
540
|
+
cleanTxLogs(edgeTransaction)
|
|
541
|
+
)} ${e}`
|
|
542
|
+
)
|
|
543
|
+
throw e
|
|
544
|
+
}
|
|
545
|
+
return edgeTransaction
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
getDisplayPrivateSeed() {
|
|
549
|
+
if (this.walletInfo.keys && this.walletInfo.keys.stellarKey) {
|
|
550
|
+
return this.walletInfo.keys.stellarKey
|
|
551
|
+
}
|
|
552
|
+
return ''
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
getDisplayPublicSeed() {
|
|
556
|
+
if (this.walletInfo.keys && this.walletInfo.keys.publicKey) {
|
|
557
|
+
return this.walletInfo.keys.publicKey
|
|
558
|
+
}
|
|
559
|
+
return ''
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
export { CurrencyEngine }
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const otherSettings = {
|
|
9
|
+
stellarServers: ['https://horizon.stellar.org']
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const defaultSettings = {
|
|
13
|
+
otherSettings
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const currencyInfo = {
|
|
17
|
+
// Basic currency information:
|
|
18
|
+
currencyCode: 'XLM',
|
|
19
|
+
displayName: 'Stellar',
|
|
20
|
+
pluginId: 'stellar',
|
|
21
|
+
walletType: 'wallet:stellar',
|
|
22
|
+
|
|
23
|
+
defaultSettings,
|
|
24
|
+
|
|
25
|
+
addressExplorer: 'https://stellarchain.io/address/%s',
|
|
26
|
+
transactionExplorer: 'https://stellarchain.io/tx/%s',
|
|
27
|
+
|
|
28
|
+
denominations: [
|
|
29
|
+
// An array of Objects of the possible denominations for this currency
|
|
30
|
+
{
|
|
31
|
+
name: 'XLM',
|
|
32
|
+
multiplier: '10000000',
|
|
33
|
+
symbol: '*'
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
metaTokens: []
|
|
37
|
+
}
|