edge-core-js 2.45.0 → 2.46.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.
@@ -26,10 +26,12 @@ import { AccountSync, fixUsername } from '../../client-side'
26
26
 
27
27
 
28
28
 
29
+
29
30
 
30
31
 
31
32
  import { makeEdgeResult } from '../../util/edgeResult'
32
33
  import { base58 } from '../../util/encoding'
34
+ import { saveWalletSettings } from '../currency/wallet/currency-wallet-files'
33
35
  import { getPublicWalletInfo } from '../currency/wallet/currency-wallet-pixie'
34
36
  import {
35
37
  finishWalletCreation,
@@ -55,13 +57,14 @@ import {
55
57
  import { changePin, checkPin2, deletePin } from '../login/pin2'
56
58
  import { changeRecovery, deleteRecovery } from '../login/recovery2'
57
59
  import { listSplittableWalletTypes, splitWalletInfo } from '../login/splitting'
60
+ import { asEdgeStorageKeys } from '../login/storage-keys'
58
61
  import { changeVoucherStatus } from '../login/vouchers'
59
62
  import {
60
63
  findCurrencyPluginId,
61
64
  getCurrencyTools
62
65
  } from '../plugins/plugins-selectors'
63
66
 
64
- import { makeLocalDisklet } from '../storage/repo'
67
+ import { makeLocalDisklet, makeRepoPaths } from '../storage/repo'
65
68
  import { makeStorageWalletApi } from '../storage/storage-api'
66
69
  import { fetchSwapQuotes } from '../swap/swap-api'
67
70
  import { changeWalletStates } from './account-files'
@@ -72,6 +75,26 @@ import { makeLobbyApi } from './lobby-api'
72
75
  import { makeMemoryWalletInner } from './memory-wallet'
73
76
  import { CurrencyConfig, SwapConfig } from './plugin-api'
74
77
 
78
+ async function prewriteWalletSettings(
79
+ ai,
80
+ walletInfo,
81
+ walletSettings
82
+ ) {
83
+ // Only persist settings for currencies that actually support them. Otherwise
84
+ // the data would be written to disk but never loaded or exposed, since the
85
+ // wallet layer reads settings only when `currencyInfo.hasWalletSettings`:
86
+ const { currency } = ai.props.state.plugins
87
+ const pluginId = findCurrencyPluginId(currency, walletInfo.type)
88
+ const { hasWalletSettings = false } = currency[pluginId].currencyInfo
89
+ if (!hasWalletSettings) return
90
+
91
+ const { io } = ai.props
92
+ const storageKeys = asEdgeStorageKeys(walletInfo.keys)
93
+ const { disklet } = makeRepoPaths(io, storageKeys)
94
+
95
+ await saveWalletSettings(disklet, walletSettings)
96
+ }
97
+
75
98
  /**
76
99
  * Creates an unwrapped account API object around an account state object.
77
100
  */
@@ -642,6 +665,9 @@ export function makeAccountApi(ai, accountId) {
642
665
  ai.props.log.breadcrumb('EdgeAccount.createCurrencyWallet', {})
643
666
 
644
667
  const walletInfo = await makeCurrencyWalletKeys(ai, walletType, opts)
668
+ if (opts.walletSettings != null) {
669
+ await prewriteWalletSettings(ai, walletInfo, opts.walletSettings)
670
+ }
645
671
  const childKey = decryptChildKey(stashTree, sessionKey, login.loginId)
646
672
  await applyKit(ai, sessionKey, makeKeysKit(ai, childKey, [walletInfo]))
647
673
  return await finishWalletCreation(ai, accountId, walletInfo.id, opts)
@@ -674,6 +700,14 @@ export function makeAccountApi(ai, accountId) {
674
700
  )
675
701
  )
676
702
 
703
+ // Prewrite wallet settings before applyKit triggers the pixie:
704
+ for (let i = 0; i < walletInfos.length; i++) {
705
+ const { walletSettings } = createWallets[i]
706
+ if (walletSettings != null) {
707
+ await prewriteWalletSettings(ai, walletInfos[i], walletSettings)
708
+ }
709
+ }
710
+
677
711
  // Store the keys on the server:
678
712
  const childKey = decryptChildKey(stashTree, sessionKey, login.loginId)
679
713
  await applyKit(ai, sessionKey, makeKeysKit(ai, childKey, walletInfos))
@@ -28,7 +28,7 @@ export const makeMemoryWalletInner = async (
28
28
  walletType,
29
29
  opts = {}
30
30
  ) => {
31
- const { keys } = opts
31
+ const { keys, walletSettings = {} } = opts
32
32
  if (keys == null) throw new Error('No keys provided')
33
33
 
34
34
  const walletId = `memorywallet-${memoryWalletCount++}`
@@ -113,6 +113,7 @@ export const makeMemoryWalletInner = async (
113
113
  lightMode: true,
114
114
  log,
115
115
  userSettings: { ...(_nullishCoalesce(config.userSettings, () => ( {}))) },
116
+ walletSettings,
116
117
  walletLocalDisklet: makeMemoryDisklet(),
117
118
  walletLocalEncryptedDisklet: makeMemoryDisklet()
118
119
  })
@@ -40,6 +40,7 @@ import {
40
40
 
41
41
 
42
42
 
43
+
43
44
 
44
45
 
45
46
  import { makeMetaTokens } from '../../account/custom-tokens'
@@ -63,6 +64,7 @@ import {
63
64
  loadTxFiles,
64
65
  renameCurrencyWallet,
65
66
  saveTxMetadataFile,
67
+ saveWalletSettingsFile,
66
68
  setCurrencyWalletFiat,
67
69
  setupNewTxMetadata,
68
70
  updateCurrencyWalletTxMetadata
@@ -135,6 +137,9 @@ export function makeCurrencyWalletApi(
135
137
  get id() {
136
138
  return storageWalletApi.id
137
139
  },
140
+ get imported() {
141
+ return walletInfo.imported === true
142
+ },
138
143
  get localDisklet() {
139
144
  return storageWalletApi.localDisklet
140
145
  },
@@ -193,6 +198,17 @@ export function makeCurrencyWalletApi(
193
198
  return div(nativeAmount, multiplier, multiplier.length)
194
199
  },
195
200
 
201
+ // User settings for this wallet:
202
+ get walletSettings() {
203
+ return input.props.walletState.walletSettings
204
+ },
205
+ async changeWalletSettings(settings) {
206
+ if (input.props.walletState.currencyInfo.hasWalletSettings !== true) {
207
+ throw new Error('Wallet settings unsupported')
208
+ }
209
+ await saveWalletSettingsFile(input, settings)
210
+ },
211
+
196
212
  // Chain state:
197
213
  get balances() {
198
214
  return input.props.walletState.balances
@@ -308,6 +308,10 @@ export const asTokensFile = asObject({
308
308
  detectedTokenIds: asArray(asString)
309
309
  })
310
310
 
311
+ export const asWalletSettingsFile = asObject({
312
+ walletSettings: asOptional(asJsonObject, () => ({}))
313
+ })
314
+
311
315
  const asTransactionAsset = asObject({
312
316
  assetAction: asOptional(asEdgeAssetAction),
313
317
  metadata: asEdgeMetadata,
@@ -10,6 +10,7 @@ import { justFiles, navigateDisklet } from 'disklet'
10
10
 
11
11
 
12
12
 
13
+
13
14
  import { makeJsonFile } from '../../../util/file-helpers'
14
15
  import { fetchAppIdInfo } from '../../account/lobby-api'
15
16
  import { toApiInput } from '../../root-pixie'
@@ -30,6 +31,7 @@ import {
30
31
  asTransactionFile,
31
32
  asWalletFiatFile,
32
33
  asWalletNameFile,
34
+ asWalletSettingsFile,
33
35
 
34
36
 
35
37
 
@@ -45,6 +47,7 @@ const LEGACY_TOKENS_FILE = 'EnabledTokens.json'
45
47
  const SEEN_TX_CHECKPOINT_FILE = 'seenTxCheckpoint.json'
46
48
  const TOKENS_FILE = 'Tokens.json'
47
49
  const WALLET_NAME_FILE = 'WalletName.json'
50
+ const WALLET_SETTINGS_FILE = 'WalletSettings.json'
48
51
 
49
52
  const legacyAddressFile = makeJsonFile(asLegacyAddressFile)
50
53
  const legacyMapFile = makeJsonFile(asLegacyMapFile)
@@ -55,6 +58,7 @@ const tokensFile = makeJsonFile(asTokensFile)
55
58
  const transactionFile = makeJsonFile(asTransactionFile)
56
59
  const walletFiatFile = makeJsonFile(asWalletFiatFile)
57
60
  const walletNameFile = makeJsonFile(asWalletNameFile)
61
+ const walletSettingsFile = makeJsonFile(asWalletSettingsFile)
58
62
 
59
63
  /**
60
64
  * Updates the enabled tokens on a wallet.
@@ -284,6 +288,52 @@ export async function loadTokensFile(
284
288
  })
285
289
  }
286
290
 
291
+ /**
292
+ * Loads wallet-specific settings.
293
+ */
294
+ export async function loadWalletSettingsFile(
295
+ input
296
+ ) {
297
+ const { dispatch, state, walletId } = input.props
298
+ const disklet = getStorageWalletDisklet(state, walletId)
299
+
300
+ const clean = await walletSettingsFile.load(disklet, WALLET_SETTINGS_FILE)
301
+ dispatch({
302
+ type: 'CURRENCY_WALLET_LOADED_WALLET_SETTINGS_FILE',
303
+ payload: {
304
+ walletId,
305
+ walletSettings: _nullishCoalesce(_optionalChain([clean, 'optionalAccess', _ => _.walletSettings]), () => ( {}))
306
+ }
307
+ })
308
+ }
309
+
310
+ /**
311
+ * Persists wallet settings to disk.
312
+ */
313
+ export async function saveWalletSettingsFile(
314
+ input,
315
+ walletSettings
316
+ ) {
317
+ const { dispatch, state, walletId } = input.props
318
+ const disklet = getStorageWalletDisklet(state, walletId)
319
+
320
+ await saveWalletSettings(disklet, walletSettings)
321
+
322
+ dispatch({
323
+ type: 'CURRENCY_WALLET_CHANGED_WALLET_SETTINGS',
324
+ payload: { walletId, walletSettings }
325
+ })
326
+ }
327
+
328
+ export async function saveWalletSettings(
329
+ disklet,
330
+ walletSettings
331
+ ) {
332
+ await walletSettingsFile.save(disklet, WALLET_SETTINGS_FILE, {
333
+ walletSettings
334
+ })
335
+ }
336
+
287
337
  /**
288
338
  * Loads transaction metadata files.
289
339
  */
@@ -437,7 +487,7 @@ export async function loadAddressFiles(
437
487
  )
438
488
 
439
489
  // Load these addresses into the engine:
440
- const engine = _optionalChain([input, 'access', _ => _.props, 'access', _2 => _2.walletOutput, 'optionalAccess', _3 => _3.engine])
490
+ const engine = _optionalChain([input, 'access', _2 => _2.props, 'access', _3 => _3.walletOutput, 'optionalAccess', _4 => _4.engine])
441
491
  if (engine != null) await engine.addGapLimitAddresses(out)
442
492
  }
443
493
 
@@ -482,9 +532,9 @@ export async function updateCurrencyWalletTxMetadata(
482
532
  const newFile = {
483
533
  ...oldFile,
484
534
  creationDate,
485
- currencies: new Map(_nullishCoalesce(_optionalChain([oldFile, 'optionalAccess', _4 => _4.currencies]), () => ( []))),
535
+ currencies: new Map(_nullishCoalesce(_optionalChain([oldFile, 'optionalAccess', _5 => _5.currencies]), () => ( []))),
486
536
  internal: true,
487
- tokens: new Map(_nullishCoalesce(_optionalChain([oldFile, 'optionalAccess', _5 => _5.tokens]), () => ( []))),
537
+ tokens: new Map(_nullishCoalesce(_optionalChain([oldFile, 'optionalAccess', _6 => _6.tokens]), () => ( []))),
488
538
  txid
489
539
  }
490
540
 
@@ -697,6 +747,10 @@ export async function reloadWalletFiles(
697
747
  if (changes.includes(TOKENS_FILE) || changes.includes(LEGACY_TOKENS_FILE)) {
698
748
  await loadTokensFile(input)
699
749
  }
750
+ const { hasWalletSettings = false } = input.props.walletState.currencyInfo
751
+ if (hasWalletSettings && changes.includes(WALLET_SETTINGS_FILE)) {
752
+ await loadWalletSettingsFile(input)
753
+ }
700
754
  if (changes.includes(CURRENCY_FILE)) {
701
755
  await loadFiatFile(input)
702
756
  }
@@ -16,6 +16,7 @@ import { update } from 'yaob'
16
16
 
17
17
 
18
18
 
19
+
19
20
  import { makeJsonFile } from '../../../util/file-helpers'
20
21
  import { makePeriodicTask, } from '../../../util/periodic-task'
21
22
  import { snooze } from '../../../util/snooze'
@@ -45,9 +46,14 @@ import {
45
46
  loadSeenTxCheckpointFile,
46
47
  loadTokensFile,
47
48
  loadTxFileNames,
49
+ loadWalletSettingsFile,
48
50
  writeTokensFile
49
51
  } from './currency-wallet-files'
50
- import { initialTokenIds } from './currency-wallet-reducer'
52
+ import {
53
+
54
+ initialTokenIds,
55
+ initialWalletSettings
56
+ } from './currency-wallet-reducer'
51
57
  import { tokenIdsToCurrencyCodes, uniqueStrings } from './enabled-tokens'
52
58
 
53
59
 
@@ -118,6 +124,11 @@ export const walletPixie = combinePixies({
118
124
  // so the engine can start in the right state:
119
125
  await loadTokensFile(input)
120
126
 
127
+ const { hasWalletSettings = false } = walletState.currencyInfo
128
+ if (hasWalletSettings) {
129
+ await loadWalletSettingsFile(input)
130
+ }
131
+
121
132
  // Start the engine:
122
133
  const accountState = state.accounts[accountId]
123
134
  const engine = await plugin.makeCurrencyEngine(publicWalletInfo, {
@@ -138,7 +149,8 @@ export const walletPixie = combinePixies({
138
149
  // User settings:
139
150
  customTokens: _nullishCoalesce(accountState.customTokens[pluginId], () => ( {})),
140
151
  enabledTokenIds: input.props.walletState.allEnabledTokenIds,
141
- userSettings: _nullishCoalesce(accountState.userSettings[pluginId], () => ( {}))
152
+ userSettings: _nullishCoalesce(accountState.userSettings[pluginId], () => ( {})),
153
+ walletSettings: input.props.walletState.walletSettings
142
154
  })
143
155
  input.onOutput(engine)
144
156
 
@@ -462,7 +474,8 @@ export const walletPixie = combinePixies({
462
474
 
463
475
  watcher(input) {
464
476
  let lastState
465
- let lastSettings = {}
477
+ let lastUserSettings = {}
478
+ let lastWalletSettings = initialWalletSettings
466
479
  let lastTokens = {}
467
480
  let lastEnabledTokenIds = initialTokenIds
468
481
 
@@ -480,11 +493,12 @@ export const walletPixie = combinePixies({
480
493
  lastState = walletState
481
494
 
482
495
  // Update engine settings:
483
- const userSettings = _nullishCoalesce(accountState.userSettings[pluginId], () => ( lastSettings))
484
- if (lastSettings !== userSettings && engine != null) {
496
+ const userSettings =
497
+ _nullishCoalesce(accountState.userSettings[pluginId], () => ( lastUserSettings))
498
+ if (lastUserSettings !== userSettings && engine != null) {
485
499
  await engine.changeUserSettings(userSettings)
486
500
  }
487
- lastSettings = userSettings
501
+ lastUserSettings = userSettings
488
502
 
489
503
  // Update the custom tokens:
490
504
  const customTokens = _nullishCoalesce(accountState.customTokens[pluginId], () => ( lastTokens))
@@ -505,6 +519,22 @@ export const walletPixie = combinePixies({
505
519
  }
506
520
  lastTokens = customTokens
507
521
 
522
+ // Update wallet-scoped settings:
523
+ const { hasWalletSettings = false } = walletState.currencyInfo
524
+ const { walletSettings } = walletState
525
+ const settingsChanged = lastWalletSettings !== walletSettings
526
+
527
+ if (
528
+ settingsChanged &&
529
+ _optionalChain([engine, 'optionalAccess', _5 => _5.changeWalletSettings]) != null &&
530
+ hasWalletSettings
531
+ ) {
532
+ await engine.changeWalletSettings(walletSettings).catch(error => {
533
+ input.props.onError(error)
534
+ })
535
+ }
536
+ lastWalletSettings = walletSettings
537
+
508
538
  // Update enabled tokens:
509
539
  const { allEnabledTokenIds } = walletState
510
540
  if (lastEnabledTokenIds !== allEnabledTokenIds && engine != null) {
@@ -15,6 +15,7 @@ import { buildReducer, filterReducer, memoizeReducer } from 'redux-keto'
15
15
 
16
16
 
17
17
 
18
+
18
19
  import { compare } from '../../../util/compare'
19
20
 
20
21
  import { findCurrencyPluginId } from '../../plugins/plugins-selectors'
@@ -117,6 +118,9 @@ import { uniqueStrings } from './enabled-tokens'
117
118
 
118
119
 
119
120
 
121
+
122
+
123
+ export const initialWalletSettings = {}
120
124
 
121
125
  // Used for detectedTokenIds & enabledTokenIds:
122
126
  export const initialTokenIds = []
@@ -250,6 +254,16 @@ const currencyWalletInner = buildReducer
250
254
  }
251
255
  },
252
256
 
257
+ walletSettings(state = initialWalletSettings, action) {
258
+ switch (action.type) {
259
+ case 'CURRENCY_WALLET_LOADED_WALLET_SETTINGS_FILE':
260
+ case 'CURRENCY_WALLET_CHANGED_WALLET_SETTINGS':
261
+ return action.payload.walletSettings
262
+ default:
263
+ return state
264
+ }
265
+ },
266
+
253
267
  engineFailure(state = null, action) {
254
268
  if (action.type === 'CURRENCY_ENGINE_FAILED') {
255
269
  const { error } = action.payload
@@ -172,18 +172,14 @@ export async function splitWalletInfo(
172
172
  // Restore anything that has simply been deleted:
173
173
  if (toRestore.length > 0) {
174
174
  const newStates = {}
175
- let hasChanges = false
176
175
  for (const existingWalletInfo of toRestore) {
177
- if (existingWalletInfo.archived || existingWalletInfo.deleted) {
178
- hasChanges = true
179
- newStates[existingWalletInfo.id] = {
180
- archived: false,
181
- deleted: false,
182
- migratedFromWalletId: existingWalletInfo.migratedFromWalletId
183
- }
176
+ newStates[existingWalletInfo.id] = {
177
+ archived: false,
178
+ deleted: false,
179
+ migratedFromWalletId: existingWalletInfo.migratedFromWalletId
184
180
  }
185
181
  }
186
- if (hasChanges) await changeWalletStates(ai, accountId, newStates)
182
+ await changeWalletStates(ai, accountId, newStates)
187
183
  }
188
184
 
189
185
  // Add the keys to the login: