Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Unreleased

- added: `EdgeCurrencyWallet.walletSettings` and `EdgeCurrencyWallet.changeWalletSettings`, plus matching engine plumbing.

## 2.42.0 (2026-02-10)

- added: `EdgeCurrencyEngineCallbacks.onSyncStatusChanged` callback.
Expand Down
3 changes: 2 additions & 1 deletion src/core/account/memory-wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const makeMemoryWalletInner = async (
walletType: string,
opts: EdgeCreateCurrencyWalletOptions = {}
): Promise<EdgeMemoryWallet> => {
const { keys } = opts
const { keys, walletSettings = {} } = opts
if (keys == null) throw new Error('No keys provided')

const walletId = `memorywallet-${memoryWalletCount++}`
Expand Down Expand Up @@ -113,6 +113,7 @@ export const makeMemoryWalletInner = async (
lightMode: true,
log,
userSettings: { ...(config.userSettings ?? {}) },
walletSettings,
walletLocalDisklet: makeMemoryDisklet(),
walletLocalEncryptedDisklet: makeMemoryDisklet()
})
Expand Down
17 changes: 16 additions & 1 deletion src/core/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
EdgeTokenMap,
EdgeTransaction,
EdgeWalletInfo,
EdgeWalletStates
EdgeWalletStates,
JsonObject
} from '../types/types'
import { SwapSettings } from './account/account-types'
import { ClientInfo } from './context/client-file'
Expand Down Expand Up @@ -359,6 +360,20 @@ export type RootAction =
walletId: string
}
}
| {
type: 'CURRENCY_WALLET_CHANGED_WALLET_SETTINGS'
payload: {
walletId: string
walletSettings: JsonObject
}
}
| {
type: 'CURRENCY_WALLET_LOADED_WALLET_SETTINGS_FILE'
payload: {
walletId: string
walletSettings: JsonObject
}
}
| {
type: 'INFO_CACHE_FETCHED'
payload: InfoCacheFile
Expand Down
15 changes: 14 additions & 1 deletion src/core/currency/wallet/currency-wallet-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ import {
EdgeTokenId,
EdgeTokenIdOptions,
EdgeTransaction,
EdgeWalletInfo
EdgeWalletInfo,
JsonObject
} from '../../../types/types'
import { makeMetaTokens } from '../../account/custom-tokens'
import { splitWalletInfo } from '../../login/splitting'
Expand All @@ -63,6 +64,7 @@ import {
loadTxFiles,
renameCurrencyWallet,
saveTxMetadataFile,
saveWalletSettingsFile,
setCurrencyWalletFiat,
setupNewTxMetadata,
updateCurrencyWalletTxMetadata
Expand Down Expand Up @@ -193,6 +195,17 @@ export function makeCurrencyWalletApi(
return div(nativeAmount, multiplier, multiplier.length)
},

// User settings for this wallet:
get walletSettings(): JsonObject {
return input.props.walletState.walletSettings
},
async changeWalletSettings(settings: JsonObject): Promise<void> {
if (input.props.walletState.currencyInfo.hasWalletSettings !== true) {
throw new Error('Wallet settings unsupported')
}
await saveWalletSettingsFile(input, settings)
},

// Chain state:
get balances(): EdgeBalances {
return input.props.walletState.balances
Expand Down
4 changes: 4 additions & 0 deletions src/core/currency/wallet/currency-wallet-cleaners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,10 @@ export const asTokensFile = asObject({
detectedTokenIds: asArray(asString)
})

export const asWalletSettingsFile = asObject({
walletSettings: asOptional(asJsonObject, () => ({}))
})

const asTransactionAsset = asObject<TransactionAsset>({
assetAction: asOptional(asEdgeAssetAction),
metadata: asEdgeMetadata,
Expand Down
49 changes: 48 additions & 1 deletion src/core/currency/wallet/currency-wallet-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
EdgeSubscribedAddress,
EdgeTokenId,
EdgeTransaction,
EdgeTxAction
EdgeTxAction,
JsonObject
} from '../../../types/types'
import { makeJsonFile } from '../../../util/file-helpers'
import { fetchAppIdInfo } from '../../account/lobby-api'
Expand All @@ -30,6 +31,7 @@ import {
asTransactionFile,
asWalletFiatFile,
asWalletNameFile,
asWalletSettingsFile,
LegacyTransactionFile,
TransactionAsset,
TransactionFile
Expand All @@ -45,6 +47,7 @@ const LEGACY_TOKENS_FILE = 'EnabledTokens.json'
const SEEN_TX_CHECKPOINT_FILE = 'seenTxCheckpoint.json'
const TOKENS_FILE = 'Tokens.json'
const WALLET_NAME_FILE = 'WalletName.json'
const WALLET_SETTINGS_FILE = 'WalletSettings.json'

const legacyAddressFile = makeJsonFile(asLegacyAddressFile)
const legacyMapFile = makeJsonFile(asLegacyMapFile)
Expand All @@ -55,6 +58,7 @@ const tokensFile = makeJsonFile(asTokensFile)
const transactionFile = makeJsonFile(asTransactionFile)
const walletFiatFile = makeJsonFile(asWalletFiatFile)
const walletNameFile = makeJsonFile(asWalletNameFile)
const walletSettingsFile = makeJsonFile(asWalletSettingsFile)

/**
* Updates the enabled tokens on a wallet.
Expand Down Expand Up @@ -284,6 +288,45 @@ export async function loadTokensFile(
})
}

/**
* Loads wallet-specific settings.
*/
export async function loadWalletSettingsFile(
input: CurrencyWalletInput
): Promise<void> {
const { dispatch, state, walletId } = input.props
const disklet = getStorageWalletDisklet(state, walletId)

const clean = await walletSettingsFile.load(disklet, WALLET_SETTINGS_FILE)
dispatch({
type: 'CURRENCY_WALLET_LOADED_WALLET_SETTINGS_FILE',
payload: {
walletId,
walletSettings: clean?.walletSettings ?? {}
}
})
}

/**
* Persists wallet settings to disk.
*/
export async function saveWalletSettingsFile(
input: CurrencyWalletInput,
walletSettings: JsonObject
): Promise<void> {
const { dispatch, state, walletId } = input.props
const disklet = getStorageWalletDisklet(state, walletId)

await walletSettingsFile.save(disklet, WALLET_SETTINGS_FILE, {
walletSettings
})

dispatch({
type: 'CURRENCY_WALLET_CHANGED_WALLET_SETTINGS',
payload: { walletId, walletSettings }
})
}

/**
* Loads transaction metadata files.
*/
Expand Down Expand Up @@ -697,6 +740,10 @@ export async function reloadWalletFiles(
if (changes.includes(TOKENS_FILE) || changes.includes(LEGACY_TOKENS_FILE)) {
await loadTokensFile(input)
}
const { hasWalletSettings = false } = input.props.walletState.currencyInfo
if (hasWalletSettings && changes.includes(WALLET_SETTINGS_FILE)) {
await loadWalletSettingsFile(input)
}
if (changes.includes(CURRENCY_FILE)) {
await loadFiatFile(input)
}
Expand Down
42 changes: 35 additions & 7 deletions src/core/currency/wallet/currency-wallet-pixie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import {
EdgeCurrencyTools,
EdgeCurrencyWallet,
EdgeTokenMap,
EdgeWalletInfo
EdgeWalletInfo,
JsonObject
} from '../../../types/types'
import { makeJsonFile } from '../../../util/file-helpers'
import { makePeriodicTask, PeriodicTask } from '../../../util/periodic-task'
Expand Down Expand Up @@ -45,9 +46,14 @@ import {
loadSeenTxCheckpointFile,
loadTokensFile,
loadTxFileNames,
loadWalletSettingsFile,
writeTokensFile
} from './currency-wallet-files'
import { CurrencyWalletState, initialTokenIds } from './currency-wallet-reducer'
import {
CurrencyWalletState,
initialTokenIds,
initialWalletSettings
} from './currency-wallet-reducer'
import { tokenIdsToCurrencyCodes, uniqueStrings } from './enabled-tokens'

export interface CurrencyWalletOutput {
Expand Down Expand Up @@ -118,6 +124,11 @@ export const walletPixie: TamePixie<CurrencyWalletProps> = combinePixies({
// so the engine can start in the right state:
await loadTokensFile(input)

const { hasWalletSettings = false } = walletState.currencyInfo
if (hasWalletSettings) {
await loadWalletSettingsFile(input)
}

// Start the engine:
const accountState = state.accounts[accountId]
const engine = await plugin.makeCurrencyEngine(publicWalletInfo, {
Expand All @@ -138,7 +149,8 @@ export const walletPixie: TamePixie<CurrencyWalletProps> = combinePixies({
// User settings:
customTokens: accountState.customTokens[pluginId] ?? {},
enabledTokenIds: input.props.walletState.allEnabledTokenIds,
userSettings: accountState.userSettings[pluginId] ?? {}
userSettings: accountState.userSettings[pluginId] ?? {},
walletSettings: input.props.walletState.walletSettings
})
input.onOutput(engine)

Expand Down Expand Up @@ -462,7 +474,8 @@ export const walletPixie: TamePixie<CurrencyWalletProps> = combinePixies({

watcher(input: CurrencyWalletInput) {
let lastState: CurrencyWalletState | undefined
let lastSettings: object = {}
let lastUserSettings: object = {}
let lastWalletSettings: JsonObject = initialWalletSettings
let lastTokens: EdgeTokenMap = {}
let lastEnabledTokenIds: string[] = initialTokenIds

Expand All @@ -480,11 +493,12 @@ export const walletPixie: TamePixie<CurrencyWalletProps> = combinePixies({
lastState = walletState

// Update engine settings:
const userSettings = accountState.userSettings[pluginId] ?? lastSettings
if (lastSettings !== userSettings && engine != null) {
const userSettings =
accountState.userSettings[pluginId] ?? lastUserSettings
if (lastUserSettings !== userSettings && engine != null) {
await engine.changeUserSettings(userSettings)
}
lastSettings = userSettings
lastUserSettings = userSettings

// Update the custom tokens:
const customTokens = accountState.customTokens[pluginId] ?? lastTokens
Expand All @@ -505,6 +519,20 @@ export const walletPixie: TamePixie<CurrencyWalletProps> = combinePixies({
}
lastTokens = customTokens

// Update wallet-scoped settings:
const { hasWalletSettings = false } = walletState.currencyInfo
const { walletSettings } = walletState
if (
lastWalletSettings !== walletSettings &&
engine?.changeWalletSettings != null &&
hasWalletSettings
) {
await engine
.changeWalletSettings(walletSettings)
.catch(error => input.props.onError(error))
}
lastWalletSettings = walletSettings

// Update enabled tokens:
const { allEnabledTokenIds } = walletState
if (lastEnabledTokenIds !== allEnabledTokenIds && engine != null) {
Expand Down
16 changes: 15 additions & 1 deletion src/core/currency/wallet/currency-wallet-reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import {
EdgeTransaction,
EdgeTxAction,
EdgeWalletInfo,
EdgeWalletInfoFull
EdgeWalletInfoFull,
JsonObject
} from '../../../types/types'
import { compare } from '../../../util/compare'
import { RootAction } from '../../actions'
Expand Down Expand Up @@ -75,6 +76,7 @@ export interface CurrencyWalletState {
readonly enabledTokenIds: string[]
readonly tokenFileDirty: boolean
readonly tokenFileLoaded: boolean
readonly walletSettings: JsonObject
readonly engineFailure: Error | null
readonly engineStarted: boolean
readonly fiat: string
Expand Down Expand Up @@ -118,6 +120,8 @@ export interface CurrencyWalletNext {
readonly self: CurrencyWalletState
}

export const initialWalletSettings: JsonObject = {}

// Used for detectedTokenIds & enabledTokenIds:
export const initialTokenIds: string[] = []

Expand Down Expand Up @@ -250,6 +254,16 @@ const currencyWalletInner = buildReducer<
}
},

walletSettings(state = initialWalletSettings, action): JsonObject {
switch (action.type) {
case 'CURRENCY_WALLET_LOADED_WALLET_SETTINGS_FILE':
case 'CURRENCY_WALLET_CHANGED_WALLET_SETTINGS':
return action.payload.walletSettings
default:
return state
}
},

engineFailure(state = null, action): Error | null {
if (action.type === 'CURRENCY_ENGINE_FAILED') {
const { error } = action.payload
Expand Down
14 changes: 5 additions & 9 deletions src/core/login/splitting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,18 +172,14 @@ export async function splitWalletInfo(
// Restore anything that has simply been deleted:
if (toRestore.length > 0) {
const newStates: EdgeWalletStates = {}
let hasChanges = false
for (const existingWalletInfo of toRestore) {
if (existingWalletInfo.archived || existingWalletInfo.deleted) {
hasChanges = true
newStates[existingWalletInfo.id] = {
archived: false,
deleted: false,
migratedFromWalletId: existingWalletInfo.migratedFromWalletId
}
newStates[existingWalletInfo.id] = {
archived: false,
deleted: false,
migratedFromWalletId: existingWalletInfo.migratedFromWalletId
}
}
if (hasChanges) await changeWalletStates(ai, accountId, newStates)
await changeWalletStates(ai, accountId, newStates)
}

// Add the keys to the login:
Expand Down
8 changes: 8 additions & 0 deletions src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,7 @@ export interface EdgeCurrencyInfo {
unsafeMakeSpend?: boolean
unsafeSyncNetwork?: boolean
usesChangeServer?: boolean
hasWalletSettings?: boolean

/** Show the total sync percentage with this many decimal digits */
syncDisplayPrecision?: number
Expand Down Expand Up @@ -1041,10 +1042,12 @@ export interface EdgeCurrencyEngineOptions {
customTokens: EdgeTokenMap
enabledTokenIds: string[]
userSettings: JsonObject | undefined
walletSettings: JsonObject
}

export interface EdgeCurrencyEngine {
readonly changeUserSettings: (settings: JsonObject) => Promise<void>
readonly changeWalletSettings?: (settings: JsonObject) => Promise<void>

/**
* Starts any persistent resources the engine needs, such as WebSockets.
Expand Down Expand Up @@ -1344,6 +1347,10 @@ export interface EdgeCurrencyWallet {
readonly currencyConfig: EdgeCurrencyConfig // eslint-disable-line no-use-before-define
readonly currencyInfo: EdgeCurrencyInfo

// User settings for this wallet:
readonly walletSettings: JsonObject
readonly changeWalletSettings: (settings: JsonObject) => Promise<void>

// Chain state:
readonly balanceMap: EdgeBalanceMap
readonly balances: EdgeBalances
Expand Down Expand Up @@ -1649,6 +1656,7 @@ export interface EdgeCreateCurrencyWalletOptions {
enabledTokenIds?: string[]
fiatCurrencyCode?: string
name?: string
walletSettings?: JsonObject
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wallet settings silently dropped during non-memory wallet creation

High Severity

walletSettings was added to EdgeCreateCurrencyWalletOptions and is correctly handled for memory wallets in memory-wallet.ts, but finishWalletCreation in keys.ts does not destructure or use walletSettings from opts. When a non-memory wallet is created via createCurrencyWallet or createCurrencyWallets with walletSettings, the settings are silently ignored and never persisted to disk via wallet.changeWalletSettings().

Fix in Cursor Fix in Web


// Create a private key from some text:
importText?: string
Expand Down
Loading