edge-core-js 2.2.1 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/android/src/main/assets/edge-core-js/edge-core.js +1 -1
- package/android/src/main/assets/edge-core-js/edge-core.js.map +1 -1
- package/android/src/main/assets/edge-core-js/index.html +25 -0
- package/lib/core/account/account-api.js +2 -2
- package/lib/core/account/account-pixie.js +3 -6
- package/lib/core/account/lobby-api.js +1 -3
- package/lib/core/actions.js +6 -0
- package/lib/core/context/context-pixie.js +47 -2
- package/lib/core/context/info-cache-file.js +18 -0
- package/lib/core/currency/currency-pixie.js +32 -2
- package/lib/core/currency/wallet/currency-wallet-callbacks.js +25 -18
- package/lib/core/currency/wallet/metadata.js +2 -1
- package/lib/core/fake/fake-db.js +3 -3
- package/lib/core/fake/fake-server.js +6 -6
- package/lib/core/fake/fake-world.js +5 -2
- package/lib/core/plugins/plugins-actions.js +6 -3
- package/lib/core/plugins/plugins-selectors.js +1 -1
- package/lib/core/root-reducer.js +21 -2
- package/lib/core/root.js +33 -16
- package/lib/core/storage/storage-actions.js +3 -3
- package/lib/core/swap/swap-api.js +5 -4
- package/lib/flow/types.js +9 -2
- package/lib/io/react-native/native-bridge.js +1 -0
- package/lib/node/index.js +177 -72
- package/lib/types/types.js +7 -0
- package/lib/util/match-json.js +47 -0
- package/package.json +1 -1
- package/src/types/types.ts +9 -2
- package/lib/core/context/context-reducer.js +0 -31
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>edge core dev-server</title>
|
|
5
|
+
<meta charset="utf-8" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<script src="edge-core.js"></script>
|
|
10
|
+
<script>
|
|
11
|
+
function load() {
|
|
12
|
+
var script = document.createElement('script')
|
|
13
|
+
script.charset = 'utf-8'
|
|
14
|
+
script.async = true
|
|
15
|
+
script.addEventListener('error', window.lockEdgeCorePlugins)
|
|
16
|
+
script.addEventListener('load', window.lockEdgeCorePlugins)
|
|
17
|
+
script.src = 'plugin-bundle.js'
|
|
18
|
+
document.head.appendChild(script)
|
|
19
|
+
}
|
|
20
|
+
setTimeout(load, 200)
|
|
21
|
+
|
|
22
|
+
console.log('CORE SERVER!')
|
|
23
|
+
</script>
|
|
24
|
+
</body>
|
|
25
|
+
</html>
|
|
@@ -621,8 +621,8 @@ export function makeAccountApi(ai, accountId) {
|
|
|
621
621
|
throw new Error(
|
|
622
622
|
`activateWallet unsupported by walletId ${activateWalletId}`
|
|
623
623
|
)
|
|
624
|
-
const walletId = _optionalChain([paymentInfo, 'optionalAccess', _ => _.walletId])
|
|
625
|
-
const wallet = currencyWallets[
|
|
624
|
+
const walletId = _nullishCoalesce(_optionalChain([paymentInfo, 'optionalAccess', _ => _.walletId]), () => ( ''))
|
|
625
|
+
const wallet = currencyWallets[walletId]
|
|
626
626
|
|
|
627
627
|
if (wallet == null) {
|
|
628
628
|
throw new Error(`No wallet for walletId ${walletId}`)
|
|
@@ -154,10 +154,7 @@ const accountPixie = combinePixies({
|
|
|
154
154
|
|
|
155
155
|
return {
|
|
156
156
|
update() {
|
|
157
|
-
|
|
158
|
-
if (accountOutput == null) return
|
|
159
|
-
const { accountApi } = accountOutput
|
|
160
|
-
if (accountApi == null) return
|
|
157
|
+
if (_optionalChain([input, 'access', _ => _.props, 'access', _2 => _2.accountOutput, 'optionalAccess', _3 => _3.accountApi]) == null) return
|
|
161
158
|
|
|
162
159
|
// Start once the EdgeAccount API exists:
|
|
163
160
|
dataTask.start({ wait: true })
|
|
@@ -244,14 +241,14 @@ const accountPixie = combinePixies({
|
|
|
244
241
|
lastActiveWalletIds = activeWalletIds
|
|
245
242
|
|
|
246
243
|
let lastOut = {}
|
|
247
|
-
if (_optionalChain([accountOutput, 'optionalAccess',
|
|
244
|
+
if (_optionalChain([accountOutput, 'optionalAccess', _4 => _4.currencyWallets]) != null) {
|
|
248
245
|
lastOut = accountOutput.currencyWallets
|
|
249
246
|
}
|
|
250
247
|
|
|
251
248
|
const out = {}
|
|
252
249
|
const { wallets } = input.props.output.currency
|
|
253
250
|
for (const walletId of activeWalletIds) {
|
|
254
|
-
const api = _optionalChain([wallets, 'access',
|
|
251
|
+
const api = _optionalChain([wallets, 'access', _5 => _5[walletId], 'optionalAccess', _6 => _6.walletApi])
|
|
255
252
|
if (api !== lastOut[walletId]) dirty = true
|
|
256
253
|
if (api != null) out[walletId] = api
|
|
257
254
|
}
|
|
@@ -37,9 +37,7 @@ export async function fetchAppIdInfo(
|
|
|
37
37
|
appId
|
|
38
38
|
) {
|
|
39
39
|
try {
|
|
40
|
-
const infoServerUri = shuffle(
|
|
41
|
-
ai.props.state.contextConfig.edgeServers.infoServers
|
|
42
|
-
)[0]
|
|
40
|
+
const [infoServerUri] = shuffle(ai.props.state.infoServers)
|
|
43
41
|
const url = `${infoServerUri}/v1/appIdInfo/${appId}`
|
|
44
42
|
const response = await ai.props.io.fetch(url)
|
|
45
43
|
if (response.status === 404) {
|
package/lib/core/actions.js
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
combinePixies,
|
|
3
|
+
filterPixie,
|
|
4
|
+
stopUpdates,
|
|
5
|
+
|
|
6
|
+
} from 'redux-pixies'
|
|
2
7
|
import { close, update } from 'yaob'
|
|
3
8
|
|
|
4
9
|
|
|
10
|
+
import { makePeriodicTask } from '../../util/periodic-task'
|
|
11
|
+
import { shuffle } from '../../util/shuffle'
|
|
5
12
|
|
|
6
13
|
import { makeContextApi } from './context-api'
|
|
14
|
+
import {
|
|
15
|
+
asInfoCacheFile,
|
|
16
|
+
INFO_CACHE_FILE_NAME,
|
|
17
|
+
infoCacheFile
|
|
18
|
+
} from './info-cache-file'
|
|
7
19
|
|
|
8
20
|
|
|
9
21
|
|
|
@@ -41,5 +53,38 @@ export const context = combinePixies({
|
|
|
41
53
|
}
|
|
42
54
|
}
|
|
43
55
|
}
|
|
44
|
-
}
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
infoFetcher: filterPixie(
|
|
59
|
+
(input) => {
|
|
60
|
+
async function doInfoSync() {
|
|
61
|
+
const { dispatch, io } = input.props
|
|
62
|
+
|
|
63
|
+
const [infoServerUri] = shuffle(input.props.state.infoServers)
|
|
64
|
+
const response = await fetch(`${infoServerUri}/v1/coreRollup`, {
|
|
65
|
+
headers: { accept: 'application/json' }
|
|
66
|
+
})
|
|
67
|
+
if (!response.ok) return
|
|
68
|
+
const json = await response.json()
|
|
69
|
+
|
|
70
|
+
const infoCache = asInfoCacheFile(json)
|
|
71
|
+
dispatch({
|
|
72
|
+
type: 'INFO_CACHE_FETCHED',
|
|
73
|
+
payload: infoCache
|
|
74
|
+
})
|
|
75
|
+
await infoCacheFile.save(io.disklet, INFO_CACHE_FILE_NAME, infoCache)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const infoTask = makePeriodicTask(doInfoSync, 10 * 60 * 1000)
|
|
79
|
+
infoTask.start()
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
update() {},
|
|
83
|
+
destroy() {
|
|
84
|
+
infoTask.stop()
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
props => (props.state.paused ? undefined : props)
|
|
89
|
+
)
|
|
45
90
|
})
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { asArray, asObject, asString } from 'cleaners'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import { asJsonObject, makeJsonFile } from '../../util/file-helpers'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
export const INFO_CACHE_FILE_NAME = 'infoCache.json'
|
|
12
|
+
|
|
13
|
+
export const asInfoCacheFile = asObject({
|
|
14
|
+
corePlugins: asObject(asJsonObject),
|
|
15
|
+
syncServers: asArray(asString)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
export const infoCacheFile = makeJsonFile(asInfoCacheFile)
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { combinePixies, mapPixie, } from 'redux-pixies'
|
|
1
|
+
function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }import { combinePixies, mapPixie, } from 'redux-pixies'
|
|
2
|
+
|
|
3
|
+
import { matchJson } from '../../util/match-json'
|
|
2
4
|
|
|
3
5
|
|
|
4
6
|
import {
|
|
@@ -21,5 +23,33 @@ export const currency = combinePixies({
|
|
|
21
23
|
walletState: props.state.currency.wallets[walletId],
|
|
22
24
|
walletOutput: props.output.currency.wallets[walletId]
|
|
23
25
|
})
|
|
24
|
-
)
|
|
26
|
+
),
|
|
27
|
+
|
|
28
|
+
pluginUpdater(input) {
|
|
29
|
+
let lastInfo
|
|
30
|
+
|
|
31
|
+
return async () => {
|
|
32
|
+
const { infoCache, plugins } = input.props.state
|
|
33
|
+
|
|
34
|
+
// Bail out quickly if nothing has changed:
|
|
35
|
+
if (lastInfo === infoCache) return
|
|
36
|
+
|
|
37
|
+
// Update plugins after the first run:
|
|
38
|
+
if (lastInfo != null) {
|
|
39
|
+
for (const pluginId of Object.keys(plugins.currency)) {
|
|
40
|
+
const plugin = plugins.currency[pluginId]
|
|
41
|
+
const newPayload = _nullishCoalesce(_optionalChain([infoCache, 'access', _ => _.corePlugins, 'optionalAccess', _2 => _2[pluginId]]), () => ( {}))
|
|
42
|
+
const oldPayload = _nullishCoalesce(_optionalChain([lastInfo, 'access', _3 => _3.corePlugins, 'optionalAccess', _4 => _4[pluginId]]), () => ( {}))
|
|
43
|
+
|
|
44
|
+
if (
|
|
45
|
+
plugin.updateInfoPayload != null &&
|
|
46
|
+
!matchJson(oldPayload, newPayload)
|
|
47
|
+
) {
|
|
48
|
+
await plugin.updateInfoPayload(newPayload)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
lastInfo = infoCache
|
|
53
|
+
}
|
|
54
|
+
}
|
|
25
55
|
})
|
|
@@ -10,6 +10,7 @@ import { upgradeCurrencyCode } from '../../../types/type-helpers'
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
|
|
13
14
|
import { compare } from '../../../util/compare'
|
|
14
15
|
import { enableTestMode, pushUpdate } from '../../../util/updateQueue'
|
|
15
16
|
import {
|
|
@@ -30,11 +31,7 @@ import {
|
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
|
|
33
|
-
import {
|
|
34
|
-
|
|
35
|
-
mergeTx,
|
|
36
|
-
|
|
37
|
-
} from './currency-wallet-reducer'
|
|
34
|
+
import { mergeTx, } from './currency-wallet-reducer'
|
|
38
35
|
import { uniqueStrings } from './enabled-tokens'
|
|
39
36
|
|
|
40
37
|
let throttleRateLimitMs = 5000
|
|
@@ -198,7 +195,7 @@ export function makeCurrencyWalletCallbacks(
|
|
|
198
195
|
return
|
|
199
196
|
}
|
|
200
197
|
pushUpdate({
|
|
201
|
-
id: `${walletId}==${tokenId}`,
|
|
198
|
+
id: `${walletId}==${String(tokenId)}`,
|
|
202
199
|
action: 'onTokenBalanceChanged',
|
|
203
200
|
updateFunc: () => {
|
|
204
201
|
input.props.dispatch({
|
|
@@ -219,15 +216,12 @@ export function makeCurrencyWalletCallbacks(
|
|
|
219
216
|
const { txs } = input.props.walletState
|
|
220
217
|
for (const txid of Object.keys(txs)) {
|
|
221
218
|
const reduxTx = txs[txid]
|
|
222
|
-
if (
|
|
223
|
-
reduxTx.confirmations !== 'confirmed' &&
|
|
224
|
-
reduxTx.confirmations !== 'dropped'
|
|
225
|
-
) {
|
|
219
|
+
if (shouldCoreDetermineConfirmations(reduxTx.confirmations)) {
|
|
226
220
|
const { requiredConfirmations } =
|
|
227
221
|
input.props.walletState.currencyInfo
|
|
228
222
|
const { height } = input.props.walletState
|
|
229
223
|
|
|
230
|
-
reduxTx.confirmations =
|
|
224
|
+
reduxTx.confirmations = determineConfirmations(
|
|
231
225
|
reduxTx,
|
|
232
226
|
height,
|
|
233
227
|
requiredConfirmations
|
|
@@ -322,14 +316,11 @@ export function makeCurrencyWalletCallbacks(
|
|
|
322
316
|
const { txid } = tx
|
|
323
317
|
|
|
324
318
|
// DEPRECATE: After all currency plugins implement new Confirmations API
|
|
325
|
-
if (
|
|
326
|
-
tx.confirmations !== 'confirmed' &&
|
|
327
|
-
tx.confirmations !== 'dropped'
|
|
328
|
-
) {
|
|
319
|
+
if (shouldCoreDetermineConfirmations(tx.confirmations)) {
|
|
329
320
|
const { requiredConfirmations } = input.props.walletState.currencyInfo
|
|
330
321
|
const { height } = input.props.walletState
|
|
331
322
|
|
|
332
|
-
tx.confirmations =
|
|
323
|
+
tx.confirmations = determineConfirmations(
|
|
333
324
|
tx,
|
|
334
325
|
height,
|
|
335
326
|
requiredConfirmations
|
|
@@ -417,8 +408,24 @@ export function watchCurrencyWallet(input) {
|
|
|
417
408
|
checkChangesLoop()
|
|
418
409
|
}
|
|
419
410
|
|
|
420
|
-
|
|
421
|
-
|
|
411
|
+
/**
|
|
412
|
+
* Returns true if the core needs to calculate the transaction's confirmation state,
|
|
413
|
+
* because it still depends on the current block height.
|
|
414
|
+
*
|
|
415
|
+
* @deprecated Remove once all currency plugins support the new confirmations API.
|
|
416
|
+
*/
|
|
417
|
+
const shouldCoreDetermineConfirmations = (
|
|
418
|
+
confirmations
|
|
419
|
+
) => {
|
|
420
|
+
return (
|
|
421
|
+
confirmations !== 'confirmed' &&
|
|
422
|
+
confirmations !== 'dropped' &&
|
|
423
|
+
confirmations !== 'failed'
|
|
424
|
+
)
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
export const determineConfirmations = (
|
|
428
|
+
tx, // Either EdgeTransaction or MergedTransaction
|
|
422
429
|
blockHeight,
|
|
423
430
|
requiredConfirmations = 1 // Default confirmation rule is 1 block
|
|
424
431
|
) => {
|
|
@@ -7,8 +7,9 @@ export const asEdgeMetadata = raw => {
|
|
|
7
7
|
const { exchangeAmount = {} } = clean
|
|
8
8
|
|
|
9
9
|
// Delete corrupt amounts that exceed the Javascript number range:
|
|
10
|
-
for (const fiat of Object.keys(
|
|
10
|
+
for (const fiat of Object.keys(exchangeAmount)) {
|
|
11
11
|
if (String(exchangeAmount[fiat]).includes('e')) {
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
12
13
|
delete exchangeAmount[fiat]
|
|
13
14
|
}
|
|
14
15
|
}
|
package/lib/core/fake/fake-db.js
CHANGED
|
@@ -30,9 +30,9 @@ export class FakeDb {
|
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
constructor() {
|
|
33
|
-
this.lobbies =
|
|
33
|
+
this.lobbies = new Map()
|
|
34
34
|
this.logins = []
|
|
35
|
-
this.repos =
|
|
35
|
+
this.repos = new Map()
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
getLoginById(loginId) {
|
|
@@ -80,7 +80,7 @@ export class FakeDb {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
setupRepo(syncKey, repo) {
|
|
83
|
-
this.repos
|
|
83
|
+
this.repos.set(syncKey, repo)
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
dumpLogin(login) {
|
|
@@ -279,7 +279,7 @@ function createLogin(request, login) {
|
|
|
279
279
|
keyBoxes: []
|
|
280
280
|
}))(body.data)
|
|
281
281
|
for (const syncKey of keys.newSyncKeys) {
|
|
282
|
-
db.repos
|
|
282
|
+
db.repos.set(syncKey, {})
|
|
283
283
|
}
|
|
284
284
|
|
|
285
285
|
// Start building the new database row:
|
|
@@ -326,7 +326,7 @@ const addKeysRoute = withLogin2(request => {
|
|
|
326
326
|
|
|
327
327
|
// Set up repos:
|
|
328
328
|
for (const syncKey of clean.newSyncKeys) {
|
|
329
|
-
db.repos
|
|
329
|
+
db.repos.set(syncKey, {})
|
|
330
330
|
}
|
|
331
331
|
login.keyBoxes = softCat(login.keyBoxes, clean.keyBoxes)
|
|
332
332
|
|
|
@@ -596,7 +596,7 @@ const withLobby =
|
|
|
596
596
|
request => {
|
|
597
597
|
const { db, path } = request
|
|
598
598
|
const lobbyId = path.split('/')[4]
|
|
599
|
-
const lobby = db.lobbies
|
|
599
|
+
const lobby = db.lobbies.get(lobbyId)
|
|
600
600
|
return lobby != null
|
|
601
601
|
? server({ ...request, lobby, lobbyId })
|
|
602
602
|
: fallback({ ...request, lobbyId })
|
|
@@ -619,7 +619,7 @@ const createLobbyRoute = withLobby(
|
|
|
619
619
|
const { timeout = 600 } = clean
|
|
620
620
|
const expires = new Date(Date.now() + 1000 * timeout).toISOString()
|
|
621
621
|
|
|
622
|
-
db.lobbies
|
|
622
|
+
db.lobbies.set(lobbyId, { request: clean, replies: [], expires })
|
|
623
623
|
return statusResponse()
|
|
624
624
|
}
|
|
625
625
|
)
|
|
@@ -643,7 +643,7 @@ const getLobbyRoute = withLobby(request => {
|
|
|
643
643
|
|
|
644
644
|
const deleteLobbyRoute = withLobby(request => {
|
|
645
645
|
const { db, lobbyId } = request
|
|
646
|
-
|
|
646
|
+
db.lobbies.delete(lobbyId)
|
|
647
647
|
return statusResponse()
|
|
648
648
|
})
|
|
649
649
|
|
|
@@ -682,7 +682,7 @@ const withRepo =
|
|
|
682
682
|
const syncKey = elements[4]
|
|
683
683
|
// const hash = elements[5]
|
|
684
684
|
|
|
685
|
-
const repo = db.repos
|
|
685
|
+
const repo = db.repos.get(syncKey)
|
|
686
686
|
if (repo == null) {
|
|
687
687
|
// This is not the auth server, so we have a different format:
|
|
688
688
|
return jsonResponse({ msg: 'Hash not found' }, { status: 404 })
|
|
@@ -158,7 +158,9 @@ export function makeFakeWorld(
|
|
|
158
158
|
|
|
159
159
|
// Find the data on the server:
|
|
160
160
|
const login = fakeDb.getLoginById(loginId)
|
|
161
|
-
if (login == null)
|
|
161
|
+
if (login == null) {
|
|
162
|
+
throw new Error(`Cannot find user ${account.rootLoginId}`)
|
|
163
|
+
}
|
|
162
164
|
|
|
163
165
|
// Figure out which repos to use:
|
|
164
166
|
const syncKeys = []
|
|
@@ -171,7 +173,8 @@ export function makeFakeWorld(
|
|
|
171
173
|
}
|
|
172
174
|
const repos = {}
|
|
173
175
|
for (const syncKey of syncKeys) {
|
|
174
|
-
|
|
176
|
+
const repo = fakeDb.repos.get(syncKey)
|
|
177
|
+
if (repo != null) repos[syncKey] = wasEdgeRepoDump(repo)
|
|
175
178
|
}
|
|
176
179
|
|
|
177
180
|
return {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { navigateDisklet } from 'disklet'
|
|
1
|
+
function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }import { navigateDisklet } from 'disklet'
|
|
2
|
+
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
|
|
@@ -35,7 +36,7 @@ export function addEdgeCorePlugins(plugins) {
|
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
// Save the new plugins:
|
|
38
|
-
for (const pluginId
|
|
39
|
+
for (const pluginId of Object.keys(plugins)) {
|
|
39
40
|
allPlugins[pluginId] = plugins[pluginId]
|
|
40
41
|
}
|
|
41
42
|
|
|
@@ -56,6 +57,7 @@ export function lockEdgeCorePlugins() {
|
|
|
56
57
|
*/
|
|
57
58
|
export function watchPlugins(
|
|
58
59
|
ios,
|
|
60
|
+
infoCache,
|
|
59
61
|
logBackend,
|
|
60
62
|
pluginsInit,
|
|
61
63
|
dispatch
|
|
@@ -66,7 +68,7 @@ export function watchPlugins(
|
|
|
66
68
|
function pluginsAdded(plugins) {
|
|
67
69
|
const out = {}
|
|
68
70
|
|
|
69
|
-
for (const pluginId
|
|
71
|
+
for (const pluginId of Object.keys(plugins)) {
|
|
70
72
|
const plugin = plugins[pluginId]
|
|
71
73
|
const log = makeLog(logBackend, pluginId)
|
|
72
74
|
const initOptions = pluginsInit[pluginId]
|
|
@@ -76,6 +78,7 @@ export function watchPlugins(
|
|
|
76
78
|
try {
|
|
77
79
|
if (typeof plugin === 'function') {
|
|
78
80
|
const opts = {
|
|
81
|
+
infoPayload: _nullishCoalesce(_optionalChain([infoCache, 'access', _ => _.corePlugins, 'optionalAccess', _2 => _2[pluginId]]), () => ( {})),
|
|
79
82
|
initOptions: typeof initOptions === 'object' ? initOptions : {},
|
|
80
83
|
io: legacyIo,
|
|
81
84
|
log,
|
|
@@ -70,7 +70,7 @@ export async function waitForPlugins(ai) {
|
|
|
70
70
|
|
|
71
71
|
const { currency, swap } = props.state.plugins
|
|
72
72
|
const missingPlugins = []
|
|
73
|
-
for (const pluginId
|
|
73
|
+
for (const pluginId of Object.keys(init)) {
|
|
74
74
|
const shouldLoad = init[pluginId] !== false && init[pluginId] != null
|
|
75
75
|
if (shouldLoad && currency[pluginId] == null && swap[pluginId] == null) {
|
|
76
76
|
missingPlugins.push(pluginId)
|
package/lib/core/root-reducer.js
CHANGED
|
@@ -3,7 +3,7 @@ import { buildReducer, mapReducer } from 'redux-keto'
|
|
|
3
3
|
|
|
4
4
|
import { accountReducer, } from './account/account-reducer'
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
import { currency, } from './currency/currency-reducer'
|
|
8
8
|
import { login, } from './login/login-reducer'
|
|
9
9
|
import { plugins, } from './plugins/plugins-reducer'
|
|
@@ -26,6 +26,8 @@ import { storageWallets, } from './storage/storage-reducer'
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
|
|
30
|
+
|
|
29
31
|
|
|
30
32
|
|
|
31
33
|
export const defaultLogSettings = {
|
|
@@ -64,6 +66,20 @@ export const reducer = buildReducer({
|
|
|
64
66
|
return action.type === 'INIT' ? action.payload.hideKeys : state
|
|
65
67
|
},
|
|
66
68
|
|
|
69
|
+
infoCache(state = {}, action) {
|
|
70
|
+
switch (action.type) {
|
|
71
|
+
case 'INIT':
|
|
72
|
+
return action.payload.infoCache
|
|
73
|
+
case 'INFO_CACHE_FETCHED':
|
|
74
|
+
return action.payload
|
|
75
|
+
}
|
|
76
|
+
return state
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
infoServers(state = [], action) {
|
|
80
|
+
return action.type === 'INIT' ? action.payload.infoServers : state
|
|
81
|
+
},
|
|
82
|
+
|
|
67
83
|
lastAccountId(state, action, next) {
|
|
68
84
|
return `login${next.accountCount}`
|
|
69
85
|
},
|
|
@@ -90,7 +106,10 @@ export const reducer = buildReducer({
|
|
|
90
106
|
return action.type === 'INIT' ? action.payload.skipBlockHeight : state
|
|
91
107
|
},
|
|
92
108
|
|
|
93
|
-
|
|
109
|
+
syncServers(state = [], action) {
|
|
110
|
+
return action.type === 'INIT' ? action.payload.syncServers : state
|
|
111
|
+
},
|
|
112
|
+
|
|
94
113
|
currency,
|
|
95
114
|
login,
|
|
96
115
|
plugins,
|
package/lib/core/root.js
CHANGED
|
@@ -7,6 +7,7 @@ import { emit } from 'yaob'
|
|
|
7
7
|
import { validateServer } from '../util/validateServer'
|
|
8
8
|
|
|
9
9
|
import { CLIENT_FILE_NAME, clientFile } from './context/client-file'
|
|
10
|
+
import { INFO_CACHE_FILE_NAME, infoCacheFile } from './context/info-cache-file'
|
|
10
11
|
import { filterLogs, makeLog } from './log/log'
|
|
11
12
|
import { loadStashes } from './login/login-stash'
|
|
12
13
|
import { watchPlugins } from './plugins/plugins-actions'
|
|
@@ -35,23 +36,33 @@ export async function makeContext(
|
|
|
35
36
|
apiKey,
|
|
36
37
|
appId = '',
|
|
37
38
|
authServer = 'https://login.edge.app/api',
|
|
38
|
-
infoServer
|
|
39
|
-
syncServer
|
|
40
|
-
'https://sync-us1.edge.app',
|
|
41
|
-
'https://sync-us2.edge.app',
|
|
42
|
-
'https://sync-us3.edge.app',
|
|
43
|
-
'https://sync-us4.edge.app',
|
|
44
|
-
'https://sync-us5.edge.app',
|
|
45
|
-
'https://sync-us6.edge.app',
|
|
46
|
-
'https://sync-eu.edge.app'
|
|
47
|
-
],
|
|
39
|
+
infoServer,
|
|
40
|
+
syncServer,
|
|
48
41
|
deviceDescription = null,
|
|
49
42
|
hideKeys = false,
|
|
50
43
|
plugins: pluginsInit = {},
|
|
51
44
|
skipBlockHeight = false
|
|
52
45
|
} = opts
|
|
53
|
-
const infoServers =
|
|
54
|
-
|
|
46
|
+
const infoServers =
|
|
47
|
+
typeof infoServer === 'string'
|
|
48
|
+
? [infoServer]
|
|
49
|
+
: infoServer != null && infoServer.length > 0
|
|
50
|
+
? infoServer
|
|
51
|
+
: ['https://info-eu1.edge.app', 'https://info-us1.edge.app']
|
|
52
|
+
const syncServers =
|
|
53
|
+
typeof syncServer === 'string'
|
|
54
|
+
? [syncServer]
|
|
55
|
+
: syncServer != null && syncServer.length > 0
|
|
56
|
+
? syncServer
|
|
57
|
+
: [
|
|
58
|
+
'https://sync-us1.edge.app',
|
|
59
|
+
'https://sync-us2.edge.app',
|
|
60
|
+
'https://sync-us3.edge.app',
|
|
61
|
+
'https://sync-us4.edge.app',
|
|
62
|
+
'https://sync-us5.edge.app',
|
|
63
|
+
'https://sync-us6.edge.app',
|
|
64
|
+
'https://sync-eu.edge.app'
|
|
65
|
+
]
|
|
55
66
|
const logSettings = { ...defaultLogSettings, ...opts.logSettings }
|
|
56
67
|
if (apiKey == null) {
|
|
57
68
|
throw new Error('No API key provided')
|
|
@@ -71,21 +82,26 @@ export async function makeContext(
|
|
|
71
82
|
})
|
|
72
83
|
const log = makeLog(logBackend, 'edge-core')
|
|
73
84
|
|
|
74
|
-
|
|
75
|
-
|
|
85
|
+
let [clientInfo, infoCache = {}, stashes] = await Promise.all([
|
|
86
|
+
clientFile.load(io.disklet, CLIENT_FILE_NAME),
|
|
87
|
+
infoCacheFile.load(io.disklet, INFO_CACHE_FILE_NAME),
|
|
88
|
+
loadStashes(io.disklet, log)
|
|
89
|
+
])
|
|
90
|
+
|
|
91
|
+
// Save the clientId if we don't have one:
|
|
76
92
|
if (clientInfo == null) {
|
|
77
93
|
clientInfo = { clientId: io.random(16) }
|
|
78
94
|
await clientFile.save(io.disklet, CLIENT_FILE_NAME, clientInfo)
|
|
79
95
|
}
|
|
80
96
|
|
|
81
97
|
// Load the login stashes from disk:
|
|
82
|
-
const stashes = await loadStashes(io.disklet, log)
|
|
83
98
|
redux.dispatch({
|
|
84
99
|
type: 'INIT',
|
|
85
100
|
payload: {
|
|
86
101
|
apiKey,
|
|
87
102
|
appId,
|
|
88
103
|
authServer,
|
|
104
|
+
infoCache,
|
|
89
105
|
infoServers,
|
|
90
106
|
syncServers,
|
|
91
107
|
clientId: clientInfo.clientId,
|
|
@@ -101,13 +117,14 @@ export async function makeContext(
|
|
|
101
117
|
// Subscribe to new plugins:
|
|
102
118
|
const closePlugins = watchPlugins(
|
|
103
119
|
ios,
|
|
120
|
+
infoCache,
|
|
104
121
|
logBackend,
|
|
105
122
|
pluginsInit,
|
|
106
123
|
redux.dispatch
|
|
107
124
|
)
|
|
108
125
|
|
|
109
126
|
// Create sync client:
|
|
110
|
-
const syncClient =
|
|
127
|
+
const syncClient = makeSyncClient({
|
|
111
128
|
log,
|
|
112
129
|
fetch: io.fetch,
|
|
113
130
|
edgeServers: { infoServers, syncServers }
|
|
@@ -43,9 +43,9 @@ export async function addStorageWallet(
|
|
|
43
43
|
const { syncKey } = walletInfo.keys
|
|
44
44
|
const { lastHash } = status
|
|
45
45
|
ai.props.log.error(
|
|
46
|
-
`Could not sync ${syncKey} with last hash ${String(
|
|
47
|
-
|
|
48
|
-
)}`
|
|
46
|
+
`Could not sync ${String(syncKey)} with last hash ${String(
|
|
47
|
+
lastHash
|
|
48
|
+
)}: ${String(error)}`
|
|
49
49
|
)
|
|
50
50
|
onError(error)
|
|
51
51
|
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }import { gt, lt } from 'biggystring'
|
|
1
|
+
function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }import { gt, lt } from 'biggystring'
|
|
2
2
|
import { bridgifyObject, close } from 'yaob'
|
|
3
3
|
|
|
4
4
|
import {
|
|
@@ -33,11 +33,11 @@ export async function fetchSwapQuotes(
|
|
|
33
33
|
promoCodes = {},
|
|
34
34
|
slowResponseMs = 20000
|
|
35
35
|
} = opts
|
|
36
|
-
const { log } = ai.props
|
|
36
|
+
const { log, state } = ai.props
|
|
37
37
|
|
|
38
|
-
const account =
|
|
38
|
+
const account = state.accounts[accountId]
|
|
39
39
|
const { swapSettings, userSettings } = account
|
|
40
|
-
const swapPlugins =
|
|
40
|
+
const swapPlugins = state.plugins.swap
|
|
41
41
|
|
|
42
42
|
log.warn(
|
|
43
43
|
'Requesting swap quotes for: ',
|
|
@@ -62,6 +62,7 @@ export async function fetchSwapQuotes(
|
|
|
62
62
|
promises.push(
|
|
63
63
|
swapPlugins[pluginId]
|
|
64
64
|
.fetchSwapQuote(request, userSettings[pluginId], {
|
|
65
|
+
infoPayload: _nullishCoalesce(_optionalChain([state, 'access', _ => _.infoCache, 'access', _2 => _2.corePlugins, 'optionalAccess', _3 => _3[pluginId]]), () => ( {})),
|
|
65
66
|
promoCode: promoCodes[pluginId]
|
|
66
67
|
})
|
|
67
68
|
.then(
|