Skip to content

Commit 8b5c1d1

Browse files
committed
Add backend switching with walletSettings
1 parent 1fdb57e commit 8b5c1d1

File tree

3 files changed

+83
-21
lines changed

3 files changed

+83
-21
lines changed

src/monero/MoneroEngine.ts

Lines changed: 75 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ import {
1313
NoAmountSpecifiedError,
1414
PendingFundsError
1515
} from 'edge-core-js/types'
16-
import type { TransactionDirection } from 'react-native-monero-lwsf'
16+
import type {
17+
TransactionDirection,
18+
WalletBackend
19+
} from 'react-native-monero-lwsf'
1720
import { base64, base64url } from 'rfc4648'
1821

1922
import { CurrencyEngine } from '../common/CurrencyEngine'
@@ -36,13 +39,15 @@ import {
3639
asMoneroPrivateKeys,
3740
asMoneroUserSettings,
3841
asMoneroWalletOtherData,
42+
asMoneroWalletSettings,
3943
asSafeMoneroWalletInfo,
4044
LoginResponse,
4145
MoneroInitOptions,
4246
MoneroNetworkInfo,
4347
MoneroPrivateKeys,
4448
MoneroUserSettings,
4549
MoneroWalletOtherData,
50+
MoneroWalletSettings,
4651
SafeMoneroWalletInfo,
4752
translateFee
4853
} from './moneroTypes'
@@ -54,6 +59,7 @@ export class MoneroEngine extends CurrencyEngine<
5459
> {
5560
networkInfo: MoneroNetworkInfo
5661
currentSettings: MoneroUserSettings
62+
currentWalletSettings: MoneroWalletSettings
5763
otherData!: MoneroWalletOtherData
5864
initOptions: MoneroInitOptions
5965
unlockedBalance: string
@@ -63,6 +69,7 @@ export class MoneroEngine extends CurrencyEngine<
6369
private txSortOrder: 'asc' | 'desc' = 'asc'
6470
private unsubscribeWalletEvent?: () => void
6571
private abortKeysWait?: () => void
72+
private settingsChangeQueue: Promise<void> = Promise.resolve()
6673

6774
constructor(
6875
env: PluginEnvironment<MoneroNetworkInfo>,
@@ -77,7 +84,12 @@ export class MoneroEngine extends CurrencyEngine<
7784

7885
this.unlockedBalance = '0'
7986

87+
// Shared across all wallets using this engine:
8088
this.currentSettings = asMoneroUserSettings(opts.userSettings)
89+
// Unique to this particular wallet instance:
90+
this.currentWalletSettings = asMoneroWalletSettings(
91+
opts.walletSettings ?? {}
92+
)
8193

8294
// Singleton promise resolved once by the first syncNetwork call.
8395
// Stays resolved across restarts so onStart gets keys immediately.
@@ -98,36 +110,47 @@ export class MoneroEngine extends CurrencyEngine<
98110
base64.parse(this.walletId)
99111
)
100112

113+
const { backend } = this.currentWalletSettings
114+
this.log.warn('Using backend:', backend)
101115
const defaults = asMoneroUserSettings({})
102-
const daemonAddress = this.currentSettings.enableCustomServers
103-
? this.currentSettings.moneroLightwalletServer
104-
: defaults.moneroLightwalletServer
116+
const daemonAddress =
117+
backend === 'lws'
118+
? this.currentSettings.enableCustomServers
119+
? this.currentSettings.moneroLightwalletServer
120+
: defaults.moneroLightwalletServer
121+
: this.currentSettings.enableCustomMonerod
122+
? this.currentSettings.monerodServer
123+
: defaults.monerodServer
105124

106125
try {
107-
// LWS setup: API key and login
108-
const isEdgeLws = daemonAddress === this.networkInfo.edgeLwsServer
126+
// LWS-specific setup: API key and login
109127
let loginResult: LoginResponse | undefined
110-
await this.tools.cppBridge.setLwsApiKey(
111-
isEdgeLws ? this.initOptions.edgeApiKey : ''
112-
)
113-
if (isEdgeLws) {
114-
loginResult = await this.loginToLwsServer(
115-
daemonAddress,
116-
this.walletInfo.keys.moneroAddress,
117-
this.walletInfo.keys.moneroViewKeyPrivate
128+
if (backend === 'lws') {
129+
const isEdgeLws = daemonAddress === this.networkInfo.edgeLwsServer
130+
await this.tools.cppBridge.setLwsApiKey(
131+
isEdgeLws ? this.initOptions.edgeApiKey : ''
118132
)
133+
if (isEdgeLws) {
134+
loginResult = await this.loginToLwsServer(
135+
daemonAddress,
136+
this.walletInfo.keys.moneroAddress,
137+
this.walletInfo.keys.moneroViewKeyPrivate
138+
)
139+
}
119140
}
120141

121142
// Resolve birthday height (never open a wallet with height 0)
122143
const birthdayHeight = await this.resolveBirthdayHeight(
123144
keys.birthdayHeight,
145+
backend,
124146
daemonAddress,
147+
defaults.moneroLightwalletServer,
125148
loginResult
126149
)
127150

128151
await this.tools.cppBridge.openWallet(
129152
base64UrlWalletId,
130-
'lws',
153+
backend,
131154
keys.moneroKey,
132155
base64url.stringify(base64.parse(keys.dataKey)),
133156
this.networkInfo.networkType,
@@ -188,7 +211,9 @@ export class MoneroEngine extends CurrencyEngine<
188211
*/
189212
private async resolveBirthdayHeight(
190213
height: number | undefined,
214+
backend: WalletBackend,
191215
daemonAddress: string,
216+
edgeLwsServer: string,
192217
loginResult?: LoginResponse
193218
): Promise<number> {
194219
if (height != null) return height
@@ -198,12 +223,20 @@ export class MoneroEngine extends CurrencyEngine<
198223
return loginResult.start_height
199224
}
200225

201-
// Fall back to getAddressInfo
226+
// For monerod wallets, fall back to the Edge LWS server
227+
const serverUrl = backend === 'lws' ? daemonAddress : edgeLwsServer
202228
const addressInfo = await this.getAddressInfo(
203-
daemonAddress,
229+
serverUrl,
204230
this.walletInfo.keys.moneroAddress,
205231
this.walletInfo.keys.moneroViewKeyPrivate
206232
)
233+
234+
if (addressInfo.start_height === 0) {
235+
throw new Error(
236+
'Cannot open wallet: birthdayHeight is 0. ' +
237+
'The wallet creation height could not be determined.'
238+
)
239+
}
207240
return addressInfo.start_height
208241
}
209242

@@ -531,7 +564,7 @@ export class MoneroEngine extends CurrencyEngine<
531564
await this.clearBlockchainCache()
532565
await this.tools.cppBridge.deleteWallet(
533566
base64url.stringify(base64.parse(this.walletId)),
534-
'lws'
567+
this.currentWalletSettings.backend
535568
)
536569
await this.startEngine()
537570
}
@@ -542,9 +575,30 @@ export class MoneroEngine extends CurrencyEngine<
542575
return
543576
}
544577

545-
this.currentSettings = newSettings
546-
await this.killEngine()
547-
await this.startEngine()
578+
this.settingsChangeQueue = this.settingsChangeQueue.then(async () => {
579+
this.currentSettings = newSettings
580+
await this.killEngine()
581+
await this.startEngine()
582+
})
583+
await this.settingsChangeQueue
584+
}
585+
586+
async changeWalletSettings(walletSettings: JsonObject): Promise<void> {
587+
const newSettings = asMaybe(asMoneroWalletSettings)(walletSettings)
588+
if (
589+
newSettings == null ||
590+
matchJson(this.currentWalletSettings, newSettings)
591+
) {
592+
return
593+
}
594+
595+
this.settingsChangeQueue = this.settingsChangeQueue.then(async () => {
596+
this.currentWalletSettings = newSettings
597+
await this.killEngine()
598+
await this.clearBlockchainCache()
599+
await this.startEngine()
600+
})
601+
await this.settingsChangeQueue
548602
}
549603

550604
async getMaxSpendable(edgeSpendInfo: EdgeSpendInfo): Promise<string> {

src/monero/moneroInfo.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export const currencyInfo: EdgeCurrencyInfo = {
4141
],
4242

4343
defaultSettings,
44+
hasWalletSettings: true,
4445

4546
unsafeSyncNetwork: true,
4647
chainDisplayName: 'Monero',

src/monero/moneroTypes.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import {
66
asObject,
77
asOptional,
88
asString,
9+
asValue,
910
Cleaner
1011
} from 'cleaners'
1112
import type {
1213
NetworkType,
1314
TransactionPriority,
15+
WalletBackend,
1416
WalletEventData
1517
} from 'react-native-monero-lwsf'
1618
import type { Subscriber } from 'yaob'
@@ -36,6 +38,11 @@ export const asMoneroUserSettings = asObject({
3638
})
3739
export type MoneroUserSettings = ReturnType<typeof asMoneroUserSettings>
3840

41+
export const asMoneroWalletSettings = asObject({
42+
backend: asMaybe<WalletBackend>(asValue('lws', 'monerod'), 'lws')
43+
})
44+
export type MoneroWalletSettings = ReturnType<typeof asMoneroWalletSettings>
45+
3946
export const asMoneroKeyOptions = asObject({
4047
birthdayHeight: asNumber
4148
})

0 commit comments

Comments
 (0)